Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright 2015 Advanced Micro Devices, Inc.
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a
  5.  * copy of this software and associated documentation files (the "Software"),
  6.  * to deal in the Software without restriction, including without limitation
  7.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8.  * and/or sell copies of the Software, and to permit persons to whom the
  9.  * Software is furnished to do so, subject to the following conditions:
  10.  *
  11.  * The above copyright notice and this permission notice (including the next
  12.  * paragraph) shall be included in all copies or substantial portions of the
  13.  * Software.
  14.  *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21.  * SOFTWARE.
  22.  *
  23.  * Authors: Marek Olšák <maraeo@gmail.com>
  24.  *
  25.  */
  26.  
  27. /* The GPU load is measured as follows.
  28.  *
  29.  * There is a thread which samples the GRBM_STATUS register at a certain
  30.  * frequency and the "busy" or "idle" counter is incremented based on
  31.  * whether the GUI_ACTIVE bit is set or not.
  32.  *
  33.  * Then, the user can sample the counters twice and calculate the average
  34.  * GPU load between the two samples.
  35.  */
  36.  
  37. #include "r600_pipe_common.h"
  38. #include "os/os_time.h"
  39.  
  40. /* For good accuracy at 1000 fps or lower. This will be inaccurate for higher
  41.  * fps (there are too few samples per frame). */
  42. #define SAMPLES_PER_SEC 10000
  43.  
  44. #define GRBM_STATUS             0x8010
  45. #define GUI_ACTIVE(x)           (((x) >> 31) & 0x1)
  46.  
  47. static bool r600_is_gpu_busy(struct r600_common_screen *rscreen)
  48. {
  49.         uint32_t value = 0;
  50.  
  51.         rscreen->ws->read_registers(rscreen->ws, GRBM_STATUS, 1, &value);
  52.         return GUI_ACTIVE(value);
  53. }
  54.  
  55. static PIPE_THREAD_ROUTINE(r600_gpu_load_thread, param)
  56. {
  57.         struct r600_common_screen *rscreen = (struct r600_common_screen*)param;
  58.         const int period_us = 1000000 / SAMPLES_PER_SEC;
  59.         int sleep_us = period_us;
  60.         int64_t cur_time, last_time = os_time_get();
  61.  
  62.         while (!p_atomic_read(&rscreen->gpu_load_stop_thread)) {
  63.                 if (sleep_us)
  64.                         os_time_sleep(sleep_us);
  65.  
  66.                 /* Make sure we sleep the ideal amount of time to match
  67.                  * the expected frequency. */
  68.                 cur_time = os_time_get();
  69.  
  70.                 if (os_time_timeout(last_time, last_time + period_us,
  71.                                     cur_time))
  72.                         sleep_us = MAX2(sleep_us - 1, 1);
  73.                 else
  74.                         sleep_us += 1;
  75.  
  76.                 /*printf("Hz: %.1f\n", 1000000.0 / (cur_time - last_time));*/
  77.                 last_time = cur_time;
  78.  
  79.                 /* Update the counters. */
  80.                 if (r600_is_gpu_busy(rscreen))
  81.                         p_atomic_inc(&rscreen->gpu_load_counter_busy);
  82.                 else
  83.                         p_atomic_inc(&rscreen->gpu_load_counter_idle);
  84.         }
  85.         p_atomic_dec(&rscreen->gpu_load_stop_thread);
  86.         return 0;
  87. }
  88.  
  89. void r600_gpu_load_kill_thread(struct r600_common_screen *rscreen)
  90. {
  91.         if (!rscreen->gpu_load_thread)
  92.                 return;
  93.  
  94.         p_atomic_inc(&rscreen->gpu_load_stop_thread);
  95.         pipe_thread_wait(rscreen->gpu_load_thread);
  96.         rscreen->gpu_load_thread = 0;
  97. }
  98.  
  99. static uint64_t r600_gpu_load_read_counter(struct r600_common_screen *rscreen)
  100. {
  101.         /* Start the thread if needed. */
  102.         if (!rscreen->gpu_load_thread) {
  103.                 pipe_mutex_lock(rscreen->gpu_load_mutex);
  104.                 /* Check again inside the mutex. */
  105.                 if (!rscreen->gpu_load_thread)
  106.                         rscreen->gpu_load_thread =
  107.                                 pipe_thread_create(r600_gpu_load_thread, rscreen);
  108.                 pipe_mutex_unlock(rscreen->gpu_load_mutex);
  109.         }
  110.  
  111.         /* The busy counter is in the lower 32 bits.
  112.          * The idle counter is in the upper 32 bits. */
  113.         return p_atomic_read(&rscreen->gpu_load_counter_busy) |
  114.                ((uint64_t)p_atomic_read(&rscreen->gpu_load_counter_idle) << 32);
  115. }
  116.  
  117. /**
  118.  * Just return the counters.
  119.  */
  120. uint64_t r600_gpu_load_begin(struct r600_common_screen *rscreen)
  121. {
  122.         return r600_gpu_load_read_counter(rscreen);
  123. }
  124.  
  125. unsigned r600_gpu_load_end(struct r600_common_screen *rscreen, uint64_t begin)
  126. {
  127.         uint64_t end = r600_gpu_load_read_counter(rscreen);
  128.         unsigned busy = (end & 0xffffffff) - (begin & 0xffffffff);
  129.         unsigned idle = (end >> 32) - (begin >> 32);
  130.  
  131.         /* Calculate the GPU load.
  132.          *
  133.          * If no counters have been incremented, return the current load.
  134.          * It's for the case when the load is queried faster than
  135.          * the counters are updated.
  136.          */
  137.         if (idle || busy)
  138.                 return busy*100 / (busy + idle);
  139.         else
  140.                 return r600_is_gpu_busy(rscreen) ? 100 : 0;
  141. }
  142.