Add the ability to sample GPU_POWER sensors.  Because
the sensors have a high latency we read them from a background
thread which means we've added the requirement for pthreads.

Signed-off-by: Tom St Denis <tom.stde...@amd.com>

(v2) Cleaned up CMake around pthreads
---
 CMakeLists.txt         |  4 +++
 README                 |  6 ++--
 src/app/top.c          | 88 +++++++++++++++++++++++++++++++++++++++++---------
 src/lib/CMakeLists.txt |  1 +
 src/lib/read_sensor.c  | 37 +++++++++++++++++++++
 src/umr.h              |  5 +++
 6 files changed, 123 insertions(+), 18 deletions(-)
 create mode 100644 src/lib/read_sensor.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
index ef78c97ad763..8d89445c39e3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,6 +19,9 @@ add_definitions(-DUMR_BUILD_REV=\"${GIT_REV}\")
 # Add local repository for FindXXX.cmake modules.
 SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules/" 
${CMAKE_MODULE_PATH})
 
+set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
+find_package(Threads REQUIRED)
+
 find_package(Curses REQUIRED)
 include_directories(${CURSES_INCLUDE_DIRS})
 
@@ -31,6 +34,7 @@ include_directories(${LIBDRM_INCLUDE_DIR})
 set(REQUIRED_EXTERNAL_LIBS
   ${CURSES_LIBRARIES}
   ${PCIACCESS_LIBRARIES}
+  Threads::Threads
 )
 
 # Global setting: build everything position independent
diff --git a/README b/README
index 13cdac663d20..8a8de8485ac7 100644
--- a/README
+++ b/README
@@ -28,9 +28,9 @@ mailing list at:
 Building
 ---------
 
-To build umr you will need pciaccess, ncurses, and libdrm headers and
-libraries.  Which are available in both Fedora and Ubuntu (as well as
-other distributions).  To build umr:
+To build umr you will need pciaccess, ncurses, libdrm, and pthread 
+headers and libraries.  Which are available in both Fedora and Ubuntu 
+(as well as other distributions).  To build umr:
 
     $ mkdir build && cd build/ && cmake ../
     $ make
diff --git a/src/app/top.c b/src/app/top.c
index b081515a5b40..60f629d247f3 100644
--- a/src/app/top.c
+++ b/src/app/top.c
@@ -54,6 +54,7 @@ enum sensor_maps {
        SENSOR_IDENTITY=0, // x = x
        SENSOR_D1000,    // x = x/1000
        SENSOR_D100,    // x = x/100
+       SENSOR_WATT,
 };
 
 enum sensor_print {
@@ -61,6 +62,7 @@ enum sensor_print {
        SENSOR_MHZ,
        SENSOR_PERCENT,
        SENSOR_TEMP,
+       SENSOR_POWER,
 };
 
 enum drm_print {
@@ -171,19 +173,14 @@ static struct umr_bitfield stat_uvd_pgfsm7_bits[] = {
 static struct umr_bitfield stat_mc_hub_bits[] = {
         { "OUTSTANDING_READ", 255, 255, &umr_bitfield_default },
         { "OUTSTANDING_WRITE", 255, 255, &umr_bitfield_default },
-//      { "OUTSTANDING_ATOMIC", 255, 255, &umr_bitfield_default },
         { "OUTSTANDING_HUB_RDREQ", 255, 255, &umr_bitfield_default },
         { "OUTSTANDING_HUB_RDRET", 255, 255, &umr_bitfield_default },
         { "OUTSTANDING_HUB_WRREQ", 255, 255, &umr_bitfield_default },
         { "OUTSTANDING_HUB_WRRET", 255, 255, &umr_bitfield_default },
-//      { "OUTSTANDING_HUB_ATOMIC_REQ", 255, 255, &umr_bitfield_default },
-//      { "OUTSTANDING_HUB_ATOMIC_RET", 255, 255, &umr_bitfield_default },
         { "OUTSTANDING_RPB_READ", 255, 255, &umr_bitfield_default },
         { "OUTSTANDING_RPB_WRITE", 255, 255, &umr_bitfield_default },
-//      { "OUTSTANDING_RPB_ATOMIC", 255, 255, &umr_bitfield_default },
         { "OUTSTANDING_MCD_READ", 255, 255, &umr_bitfield_default },
         { "OUTSTANDING_MCD_WRITE", 255, 255, &umr_bitfield_default },
-//      { "OUTSTANDING_MCD_ATOMIC", 255, 255, &umr_bitfield_default },
         { NULL, 0, 0, NULL },
 };
 
@@ -227,6 +224,10 @@ static struct umr_bitfield stat_vi_sensor_bits[] = {
        { "GFX_MCLK", AMDGPU_PP_SENSOR_GFX_MCLK, SENSOR_D100|(SENSOR_MHZ<<4), 
&umr_bitfield_default },
        { "GPU_LOAD", AMDGPU_PP_SENSOR_GPU_LOAD, SENSOR_PERCENT<<4, 
&umr_bitfield_default },
        { "GPU_TEMP", AMDGPU_PP_SENSOR_GPU_TEMP, SENSOR_D1000|(SENSOR_TEMP<<4), 
&umr_bitfield_default },
+       { "VDDC",     AMDGPU_PP_SENSOR_GPU_POWER, 
SENSOR_WATT|(SENSOR_POWER<<4), &umr_bitfield_default },
+       { "VDDCI",    AMDGPU_PP_SENSOR_GPU_POWER, 
SENSOR_WATT|(SENSOR_POWER<<4), &umr_bitfield_default },
+       { "MAX_GPU",  AMDGPU_PP_SENSOR_GPU_POWER, 
SENSOR_WATT|(SENSOR_POWER<<4), &umr_bitfield_default },
+       { "AVG_GPU",  AMDGPU_PP_SENSOR_GPU_POWER, 
SENSOR_WATT|(SENSOR_POWER<<4), &umr_bitfield_default },
        { NULL, 0, 0, NULL },
 };
 
@@ -256,6 +257,21 @@ static struct umr_bitfield stat_drm_bits[] = {
 
 static FILE *logfile = NULL;
 
+static volatile int sensor_thread_quit = 0;
+static uint32_t gpu_power_data[4];
+static void *vi_sensor_thread(void *data)
+{
+       struct umr_asic asic = *((struct umr_asic*)data);
+       int size = sizeof(gpu_power_data);
+       char fname[128];
+
+       snprintf(fname, sizeof(fname)-1, 
"/sys/kernel/debug/dri/%d/amdgpu_sensors", asic.instance);
+       asic.fd.sensors = open(fname, O_RDWR);
+       while (!sensor_thread_quit)
+               umr_read_sensor(&asic, AMDGPU_PP_SENSOR_GPU_POWER, 
gpu_power_data, &size);
+       close(asic.fd.sensors);
+       return NULL;
+}
 
 static unsigned long last_fence_emitted, last_fence_signaled, 
fence_signal_count, fence_emit_count;
 static void analyze_fence_info(struct umr_asic *asic)
@@ -428,6 +444,9 @@ static void print_sensors(struct umr_bitfield *bits, 
uint64_t *counts)
                                case SENSOR_TEMP:
                                        printw("%5d C  ", counts[i]);
                                        break;
+                               case SENSOR_POWER:
+                                       printw("%3d.%02d W ", counts[i]/100, 
counts[i]%100);
+                                       break;
                        };
                        if ((++print_j & (top_options.wide ? 3 : 1)) != 0)
                                printw(" |");
@@ -496,8 +515,8 @@ static void parse_bits(struct umr_asic *asic, uint32_t 
addr, struct umr_bitfield
 
 static void parse_sensors(struct umr_asic *asic, uint32_t addr, struct 
umr_bitfield *bits, uint64_t *counts, uint32_t *mask, uint32_t *cmp, uint64_t 
addr_mask)
 {
-       int j;
-       int32_t value;
+       int j, size, x;
+       uint32_t value[16];
 
        (void)addr;
        (void)mask;
@@ -507,13 +526,34 @@ static void parse_sensors(struct umr_asic *asic, uint32_t 
addr, struct umr_bitfi
        if (asic->fd.sensors < 0)
                return;
 
-       for (j = 0; bits[j].regname; j++) {
-               lseek(asic->fd.sensors, bits[j].start * 4, SEEK_SET);
-               read(asic->fd.sensors, &value, 4);
-               switch (bits[j].stop & 0x0F) {
-                       case SENSOR_IDENTITY:   counts[j] = value; break; // 
identity
-                       case SENSOR_D1000:      counts[j] = value/1000; break; 
// divide by 1000 (e.g. KHz => MHz)
-                       case SENSOR_D100:       counts[j] = value/100; break; 
// divide by 100 (e.g. 10KHz => MHz)
+       for (j = 0; bits[j].regname; ) {
+               size = 4;
+               if (bits[j].start == AMDGPU_PP_SENSOR_GPU_POWER || 
!umr_read_sensor(asic, bits[j].start, &value[0], &size)) {
+                       x = 0;
+                       if (bits[j].start == AMDGPU_PP_SENSOR_GPU_POWER) {
+                               size = 4 * sizeof(uint32_t);
+                               memcpy(value, gpu_power_data, size);
+                       }
+
+                       while (size) {
+                               switch (bits[j].stop & 0x0F) {
+                                       case SENSOR_IDENTITY:   counts[j] = 
value[x]; break; // identity
+                                       case SENSOR_D1000:      counts[j] = 
value[x]/1000; break; // divide by 1000 (e.g. KHz => MHz)
+                                       case SENSOR_D100:       counts[j] = 
value[x]/100; break; // divide by 100 (e.g. 10KHz => MHz)
+                                       case SENSOR_WATT:       counts[j] = 
((value[x]>>8)*1000);
+                                                               if 
((value[x]&0xFF) < 100)
+                                                                       
counts[j] += (value[x]&0xFF)*10;
+                                                               else
+                                                                       
counts[j] += value[x];
+                                                               counts[j] /= 
10; // convert to centiwatts since we don't need 3 digits of excess precision
+                                                               break;
+                               }
+                               size -= 4;
+                               ++j;
+                               ++x;
+                       }
+               } else {
+                       ++j;
                }
        }
 }
@@ -818,12 +858,13 @@ static void toggle_logger(void)
 
 void umr_top(struct umr_asic *asic)
 {
-       int i, j, k;
+       int i, j, k, use_thread;
        struct timespec req;
        uint32_t rep;
        time_t tt;
        uint64_t ts;
        char hostname[64] = { 0 };
+       pthread_t sensor_thread;
 
        if (getenv("HOSTNAME")) strcpy(hostname, getenv("HOSTNAME"));
 
@@ -844,6 +885,18 @@ void umr_top(struct umr_asic *asic)
                if (stat_counters[i].is_sensor == 0)
                        grab_bits(stat_counters[i].name, asic, 
stat_counters[i].bits, &stat_counters[i].addr);
 
+       sensor_thread_quit = 0;
+       use_thread = 0;
+
+       // start thread to grab sensor data for VI
+       if (asic->family == FAMILY_VI) {
+               if (pthread_create(&sensor_thread, NULL, vi_sensor_thread, 
asic)) {
+                       fprintf(stderr, "[ERROR] Cannot create 
vi_sensor_thread\n");
+                       return;
+               }
+               use_thread = 1;
+       }
+
        initscr();
        start_color();
        cbreak();
@@ -973,4 +1026,9 @@ void umr_top(struct umr_asic *asic)
                refresh();
        }
        endwin();
+
+       if (use_thread) {
+               sensor_thread_quit = 1;
+               pthread_join(sensor_thread, NULL);
+       }
 }
diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt
index 46c75d61acb4..a5f0bda38689 100644
--- a/src/lib/CMakeLists.txt
+++ b/src/lib/CMakeLists.txt
@@ -14,6 +14,7 @@ add_library(umrcore STATIC
   find_reg.c
   mmio.c
   query_drm.c
+  read_sensor.c
   read_sgpr.c
   read_vram.c
   ring_decode.c
diff --git a/src/lib/read_sensor.c b/src/lib/read_sensor.c
new file mode 100644
index 000000000000..c4907f83208f
--- /dev/null
+++ b/src/lib/read_sensor.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2017 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Tom St Denis <tom.stde...@amd.com>
+ *
+ */
+#include "umr.h"
+
+int umr_read_sensor(struct umr_asic *asic, int sensor, void *dst, int *size)
+{
+       int r;
+       lseek(asic->fd.sensors, sensor*4, SEEK_SET);
+       r = read(asic->fd.sensors, dst, *size);
+       if (r != *size) {
+               return -1;
+       }
+       *size = r;
+       return 0;
+}
diff --git a/src/umr.h b/src/umr.h
index f2bce13d104b..34e8809eb415 100644
--- a/src/umr.h
+++ b/src/umr.h
@@ -31,6 +31,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <pciaccess.h>
+#include <pthread.h>
 
 /* sourced from amd_powerplay.h from the kernel */
 enum amd_pp_sensors {
@@ -43,6 +44,9 @@ enum amd_pp_sensors {
        AMDGPU_PP_SENSOR_GPU_LOAD,
        AMDGPU_PP_SENSOR_GFX_MCLK,
        AMDGPU_PP_SENSOR_GPU_TEMP,
+       AMDGPU_PP_SENSOR_VCE_POWER,
+       AMDGPU_PP_SENSOR_UVD_POWER,
+       AMDGPU_PP_SENSOR_GPU_POWER,
 };
 
 enum chipfamily {
@@ -409,6 +413,7 @@ void umr_enumerate_devices(void);
 int umr_get_wave_status(struct umr_asic *asic, unsigned se, unsigned sh, 
unsigned cu, unsigned simd, unsigned wave, struct umr_wave_status *ws);
 int umr_get_wave_sq_info(struct umr_asic *asic, unsigned se, unsigned sh, 
unsigned cu, struct umr_wave_status *ws);
 int umr_read_sgprs(struct umr_asic *asic, struct umr_wave_status *ws, uint32_t 
*dst);
+int umr_read_sensor(struct umr_asic *asic, int sensor, void *dst, int *size);
 
 /* mmio helpers */
 uint32_t umr_find_reg(struct umr_asic *asic, char *regname);
-- 
2.11.0

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Reply via email to