From 37fc68ca76571bbb1ccf8c21ea159e5273bcde4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ondrej=20=C4=8Cerman?= Date: Sat, 15 Jun 2019 16:51:21 +0200 Subject: [PATCH] New version - code rewritten to c, added GTK3 gui, added Core and Package Power monitoring via MSR --- README.md | 44 ++++++++++- makefile | 2 + screenshot.png | Bin 0 -> 29300 bytes src/gui.c | 164 +++++++++++++++++++++++++++++++++++++++ src/include/gui.h | 1 + src/include/msr.h | 3 + src/include/zenmonitor.h | 23 ++++++ src/include/zenpower.h | 3 + src/ss/msr.c | 156 +++++++++++++++++++++++++++++++++++++ src/ss/zenpower.c | 91 ++++++++++++++++++++++ src/zenmonitor.c | 57 ++++++++++++++ zenmonitor | 44 ----------- 12 files changed, 542 insertions(+), 46 deletions(-) create mode 100755 makefile create mode 100644 screenshot.png create mode 100644 src/gui.c create mode 100644 src/include/gui.h create mode 100644 src/include/msr.h create mode 100644 src/include/zenmonitor.h create mode 100644 src/include/zenpower.h create mode 100644 src/ss/msr.c create mode 100644 src/ss/zenpower.c create mode 100644 src/zenmonitor.c delete mode 100755 zenmonitor diff --git a/README.md b/README.md index 258f2da..9d94c3f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,42 @@ -# zenmonitor -Sensors monitor for [zenpower](https://github.com/ocerman/zenpower/) +# Zen monitor +Zen monitor is monitoring software for AMD Zen-based CPUs. + +It can monitor these values: + - CPU Temperature + - CPU Core (SVI2) Voltage, Current and Power + - SOC (SVI2) Voltage, Current and Power + - Package and Core Power + +![screenshot](screenshot.png) + +## Dependencies + - [zenpower driver](https://github.com/ocerman/zenpower/) - For monitoring CPU temperature and SVI2 sensors + - MSR driver - For monitoring Package/Core Power + +Follow [zenpower README.md](https://github.com/ocerman/zenpower/blob/master/README.md) to install and activate zenpower module. +Enter `sudo modprobe msr` to enable MSR driver. + +## Building +Make sure that GTK3 dev package and common build tools are installed. +``` +make +``` + +## Running +``` +sudo ./zenpower +``` + +## Setup on ubuntu +First follow [installation instructions on zenpower](https://github.com/ocerman/zenpower/blob/master/README.md#installation-commands-for-ubuntu) +Then: +``` +sudo modprobe msr +sudo bash -c 'echo "msr" > /etc/modules-load.d/msr.conf' +sudo apt install build-essential libgtk-3-dev git +cd ~ +git clone https://github.com/ocerman/zenmonitor +cd zenmonitor +make +sudo ./zenmonitor +``` diff --git a/makefile b/makefile new file mode 100755 index 0000000..643bd12 --- /dev/null +++ b/makefile @@ -0,0 +1,2 @@ +build: + cc -Isrc/include `pkg-config --cflags gtk+-3.0` src/*.c src/ss/*.c -o zenmonitor `pkg-config --libs gtk+-3.0` -lm -no-pie diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..3666da44caa5d4f89c5b0ec1100debaea3d257f0 GIT binary patch literal 29300 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 ViKs{e;BO?R literal 0 HcmV?d00001 diff --git a/src/gui.c b/src/gui.c new file mode 100644 index 0000000..c59b19d --- /dev/null +++ b/src/gui.c @@ -0,0 +1,164 @@ +#include +#include +#include "gui.h" +#include "zenmonitor.h" + +static GtkTreeModel *model = NULL; +static guint timeout = 0; +static SensorSource *sensor_sources; + +enum { + COLUMN_NAME, + COLUMN_VALUE, + NUM_COLUMNS +}; + +static void init_sensors() { + GtkTreeIter iter; + GSList *sensor; + GtkListStore *store; + SensorSource *source; + const SensorInit *data; + gboolean added; + guint i = 0; + + store = GTK_LIST_STORE(model); + for (source = sensor_sources; source->drv; source++) { + if (source->func_init()){ + source->sensors = source->func_get_sensors(); + if (source->sensors != NULL) { + source->enabled = TRUE; + + sensor = source->sensors; + while (sensor) { + data = (SensorInit*)sensor->data; + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + COLUMN_NAME, data->label, + COLUMN_VALUE, " --- ", + -1); + sensor = sensor->next; + i++; + } + } + } + } +} + +static GtkTreeModel* create_model (void) { + GtkListStore *store; + store = gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING); + return GTK_TREE_MODEL (store); +} + +static gboolean update_data (gpointer data) { + GtkTreeIter iter; + guint number; + GSList *node; + gchar *value; + SensorSource *source; + const SensorInit *sensorData; + + if (model == NULL) + return G_SOURCE_REMOVE; + + if (!gtk_tree_model_get_iter_first (model, &iter)) + return G_SOURCE_REMOVE; + + for (source = sensor_sources; source->drv; source++) { + if (!source->enabled) + continue; + + source->func_update(); + if (source->sensors){ + node = source->sensors; + + while(node) { + sensorData = (SensorInit*)node->data; + if (*(sensorData->value) != ERROR_VALUE) + value = g_strdup_printf(sensorData->printf_format, *(sensorData->value)); + else + value = g_strdup(" ? ? ?"); + + gtk_list_store_set(GTK_LIST_STORE (model), &iter, COLUMN_VALUE, value, -1); + node = node->next; + if (!gtk_tree_model_iter_next(model, &iter)) + break; + } + } + } + return G_SOURCE_CONTINUE; +} + +static void add_columns (GtkTreeView *treeview) { + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeModel *model = gtk_tree_view_get_model (treeview); + + // NAME + renderer = gtk_cell_renderer_text_new (); + + column = gtk_tree_view_column_new_with_attributes ("Sensor", renderer, + "text", COLUMN_NAME, + NULL); + g_object_set(renderer, "family", "monotype", NULL); + gtk_tree_view_append_column (treeview, column); + + //VALUE + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Value", renderer, + "text", COLUMN_VALUE, + NULL); + g_object_set(renderer, "family", "monotype", NULL); + gtk_tree_view_append_column (treeview, column); +} + + +int start_gui (SensorSource *ss) { + GtkWidget *window; + GtkWidget *treeview; + GtkWidget *sw; + GtkWidget *vbox; + GtkWidget *dialog; + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), "Zen monitor"); + gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); + gtk_window_set_default_size(GTK_WINDOW(window), 330, 300); + + g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); + + vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); + gtk_container_add(GTK_CONTAINER (window), vbox); + + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_box_pack_start(GTK_BOX (vbox), sw, TRUE, TRUE, 0); + + model = create_model(); + treeview = gtk_tree_view_new_with_model(model); + g_object_unref(model); + + gtk_container_add (GTK_CONTAINER(sw), treeview); + add_columns(GTK_TREE_VIEW(treeview)); + gtk_widget_show_all(window); + + if (check_zen()){ + sensor_sources = ss; + init_sensors(); + timeout = g_timeout_add(300, update_data, NULL); + } + else{ + dialog = gtk_message_dialog_new(GTK_WINDOW (window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, + "Zen CPU not detected!"); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + } + + gtk_main(); + return 0; +} + diff --git a/src/include/gui.h b/src/include/gui.h new file mode 100644 index 0000000..0bc2501 --- /dev/null +++ b/src/include/gui.h @@ -0,0 +1 @@ +int start_gui(); diff --git a/src/include/msr.h b/src/include/msr.h new file mode 100644 index 0000000..33471ca --- /dev/null +++ b/src/include/msr.h @@ -0,0 +1,3 @@ +gboolean msr_init(); +void msr_update(); +GSList* msr_get_sensors(); diff --git a/src/include/zenmonitor.h b/src/include/zenmonitor.h new file mode 100644 index 0000000..3a753c7 --- /dev/null +++ b/src/include/zenmonitor.h @@ -0,0 +1,23 @@ +#define ERROR_VALUE -999.0 + +typedef struct +{ + gchar *label; + float *value; + const gchar *printf_format; +} +SensorInit; + +typedef struct { + const gchar *drv; + gboolean (*func_init)(); + GSList* (*func_get_sensors)(); + void (*func_update)(); + gboolean enabled; + GSList *sensors; + +} SensorSource; + +SensorInit* sensor_init_new(void); +void sensor_init_free(SensorInit *s); +gboolean check_zen(); diff --git a/src/include/zenpower.h b/src/include/zenpower.h new file mode 100644 index 0000000..4feeb15 --- /dev/null +++ b/src/include/zenpower.h @@ -0,0 +1,3 @@ +gboolean zenpower_init(); +GSList* zenpower_get_sensors(); +void zenpower_update(); diff --git a/src/ss/msr.c b/src/ss/msr.c new file mode 100644 index 0000000..0085363 --- /dev/null +++ b/src/ss/msr.c @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include +#include +#include "zenmonitor.h" +#include "msr.h" + +#define MSR_PWR_PRINTF_FORMAT " %8.3f W" +#define MESUREMENT_TIME 0.1 + +// AMD PPR = https://www.amd.com/system/files/TechDocs/54945_PPR_Family_17h_Models_00h-0Fh.pdf +// AMD OSRR = https://developer.amd.com/wp-content/resources/56255_3_03.PDF + +guint cores = 0; +guint threads_per_code = 0; +gdouble energy_unit = 0; + +gint *msr_files = NULL; + +gulong package_eng_b = 0; +gulong package_eng_a = 0; +gulong *core_eng_b = NULL; +gulong *core_eng_a = NULL; + +gfloat package_power; +gfloat *core_power; + +static guint get_core_count() { + guint eax = 0, ebx = 0, ecx = 0, edx = 0; + guint logical_cpus; + + // AMD PPR: page 57 - CPUID_Fn00000001_EBX + __get_cpuid(1, &eax, &ebx, &ecx, &edx); + logical_cpus = (ebx >> 16) & 0xFF; + + // AMD PPR: page 82 - CPUID_Fn8000001E_EBX + __get_cpuid(0x8000001E, &eax, &ebx, &ecx, &edx); + threads_per_code = ((ebx >> 8) & 0xF) + 1; + + if (threads_per_code == 0) + return logical_cpus; + + return logical_cpus / threads_per_code; +} + +static gint open_msr(gshort core) { + gchar msr_path[20]; + sprintf(msr_path, "/dev/cpu/%d/msr", core * threads_per_code); + return open(msr_path, O_RDONLY); +} + +static gboolean read_msr(gint file, guint index, gulong *data) { + if (file < 0) + return FALSE; + + return pread(file, data, sizeof *data, index) == sizeof *data; +} + +gdouble get_energy_unit() { + gulong data; + // AMD OSRR: page 139 - MSRC001_0299 + if (!read_msr(msr_files[0], 0xC0010299, &data)) + return 0.0; + + return pow(1.0/2.0, (double)((data >> 8) & 0x1F)); +} + +gulong get_package_energy() { + gulong data; + // AMD OSRR: page 139 - MSRC001_029B + if (!read_msr(msr_files[0], 0xC001029B, &data)) + return 0; + + return data; +} + +gulong get_core_energy(gint core) { + gulong data; + // AMD OSRR: page 139 - MSRC001_029A + if (!read_msr(msr_files[core], 0xC001029A, &data)) + return 0; + + return data; +} + +gboolean msr_init() { + int i; + + if (!check_zen()) + return FALSE; + + cores = get_core_count(); + if (cores == 0) + return FALSE; + + msr_files = malloc(cores * sizeof (gint)); + for (i = 0; i < cores; i++) { + msr_files[i] = open_msr(i); + } + + energy_unit = get_energy_unit(); + if (energy_unit == 0) + return FALSE; + + core_eng_b = malloc(cores * sizeof (gulong)); + core_eng_a = malloc(cores * sizeof (gulong)); + core_power = malloc(cores * sizeof (gfloat)); + + return TRUE; +} + +void msr_update() { + GSList *list = NULL; + gint i; + + package_eng_b = get_package_energy(); + for (i = 0; i < cores; i++) { + core_eng_b[i] = get_core_energy(i); + } + + usleep(MESUREMENT_TIME*1000000); + + package_eng_a = get_package_energy(); + for (i = 0; i < cores; i++) { + core_eng_a[i] = get_core_energy(i); + } + + package_power = (package_eng_a - package_eng_b) * energy_unit / MESUREMENT_TIME; + for (i = 0; i < cores; i++) { + core_power[i] = (core_eng_a[i] - core_eng_b[i]) * energy_unit / MESUREMENT_TIME; + } +} + +GSList* msr_get_sensors() { + GSList *list = NULL; + SensorInit *data; + gint i; + + data = sensor_init_new(); + data->label = g_strdup("Package Power"); + data->value = &package_power; + data->printf_format = MSR_PWR_PRINTF_FORMAT; + list = g_slist_append(list, data); + + for (i = 0; i < cores; i++) { + data = sensor_init_new(); + data->label = g_strdup_printf("Core %d Power", i); + data->value = &(core_power[i]); + data->printf_format = MSR_PWR_PRINTF_FORMAT; + list = g_slist_append(list, data); + } + + return list; +} diff --git a/src/ss/zenpower.c b/src/ss/zenpower.c new file mode 100644 index 0000000..e67211e --- /dev/null +++ b/src/ss/zenpower.c @@ -0,0 +1,91 @@ +#include +#include "zenmonitor.h" +#include "zenpower.h" + +static gchar *zenpowerDir = NULL; + +typedef struct +{ + const gchar *label; + const gchar *file; + const gchar *printf_format; + const double adjust_ratio; + float current_value; +} HwmonSensor; + +HwmonSensor hwmon_sensors[] = { + {"CPU Temperature (tCtrl)", "temp1_input", " %6.2f°C", 1000.0, 0.0}, + {"CPU Temperature (tDie)", "temp2_input", " %6.2f°C", 1000.0, 0.0}, + {"CPU Core Voltage (SVI2)", "in1_input", " %8.3f V", 1000.0, 0.0}, + {"SOC Voltage (SVI2)", "in2_input", " %8.3f V", 1000.0, 0.0}, + {"CPU Core Current (SVI2)", "curr1_input", " %8.3f A", 1000.0, 0.0}, + {"SOC Current (SVI2)", "curr2_input", " %8.3f A", 1000.0, 0.0}, + {"CPU Core Power (SVI2)", "power1_input", " %8.3f W", 1000000.0, 0.0}, + {"SOC Power (SVI2)", "power2_input", " %8.3f W", 1000000.0, 0.0}, + {0, NULL} +}; + +static gboolean read_raw_hwmon_value(const gchar *dir, const gchar *file, gchar **result) { + gchar *full_path; + gboolean file_result; + + full_path = g_strdup_printf("/sys/class/hwmon/%s/%s", dir, file); + file_result = g_file_get_contents(full_path, result, NULL, NULL); + + g_free(full_path); + return file_result; +} + +gboolean zenpower_init() { + GDir *hwmon; + const gchar *entry; + gchar* name = NULL; + + hwmon = g_dir_open("/sys/class/hwmon", 0, NULL); + if (!hwmon) + return FALSE; + + while ((entry = g_dir_read_name(hwmon))) { + read_raw_hwmon_value(entry, "name", &name); + if (strcmp(name, "zenpower")) { + zenpowerDir = g_strdup(entry); + break; + } + g_free(name); + } + + if (!zenpowerDir) + return FALSE; +} + +void zenpower_update() { + gchar *tmp = NULL; + GSList *list = NULL; + HwmonSensor *sensor; + + for (sensor = hwmon_sensors; sensor->label; sensor++) { + if (read_raw_hwmon_value(zenpowerDir, sensor->file, &tmp)){ + sensor->current_value = atof(tmp) / sensor->adjust_ratio; + g_free(tmp); + } + else{ + sensor->current_value = ERROR_VALUE; + } + } +} + +GSList* zenpower_get_sensors() { + GSList *list = NULL; + HwmonSensor *sensor; + SensorInit *data; + + for (sensor = hwmon_sensors; sensor->label; sensor++) { + data = sensor_init_new(); + data->label = g_strdup(sensor->label); + data->value = &sensor->current_value; + data->printf_format = sensor->printf_format; + list = g_slist_append(list, data); + } + + return list; +} diff --git a/src/zenmonitor.c b/src/zenmonitor.c new file mode 100644 index 0000000..5fe042a --- /dev/null +++ b/src/zenmonitor.c @@ -0,0 +1,57 @@ +#include +#include +#include "zenmonitor.h" +#include "zenpower.h" +#include "msr.h" +#include "gui.h" + +#define AMD_STRING "AuthenticAMD" +#define ZEN_FAMILY 0x17 + +gboolean check_zen() { + unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0, ext_family; + char vendor[13]; + + __get_cpuid(0, &eax, &ebx, &ecx, &edx); + + memcpy(vendor, &ebx, 4); + memcpy(vendor+4, &edx, 4); + memcpy(vendor+8, &ecx, 4); + vendor[12] = 0; + + if (strcmp(vendor, AMD_STRING) != 0){ + return FALSE; + } + + __get_cpuid(1, &eax, &ebx, &ecx, &edx); + + ext_family = ((eax >> 8) & 0xF) + ((eax >> 20) & 0xFF); + if (ext_family != ZEN_FAMILY){ + return FALSE; + } + + return TRUE; +} + +static SensorSource sensor_sources[] = { + { "zenpower", zenpower_init, zenpower_get_sensors, zenpower_update, FALSE, NULL }, + { "msr", msr_init, msr_get_sensors, msr_update, FALSE, NULL }, + { NULL } +}; + +SensorInit *sensor_init_new() { + return g_new0(SensorInit, 1); +} + +void sensor_init_free(SensorInit *s) { + if (s) { + g_free(s->label); + g_free(s); + } +} + +int main (int argc, char *argv[]) +{ + gtk_init(&argc, &argv); + start_gui(sensor_sources); +} diff --git a/zenmonitor b/zenmonitor deleted file mode 100755 index 4f31716..0000000 --- a/zenmonitor +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -hwmon="/sys/class/hwmon" -mdevs=`ls $hwmon` -zenmon="" - -echo -n "Looking for zenpower ..." - -for dev in $mdevs; do - path="$hwmon/$dev" - devname=`cat $path/name` - if [ "$devname" == "zenpower" ]; then - zenmon="$path" - fi -done - -if [ -z "$zenmon" ]; then - echo "NOT FOUND" - exit -else - echo "Found" -fi - -echo Starting Monitor... -echo Press Q to exit. -echo - -while true; do - core=(`cat $zenmon/in1_input $zenmon/curr1_input $zenmon/power1_input`) - soc=(`cat $zenmon/in2_input $zenmon/curr2_input $zenmon/power2_input`) - temps=(`cat $zenmon/temp1_input $zenmon/temp2_input`) - - echo "${core[0]} ${core[1]} ${core[2]}" | awk '{ printf " Core: %7.3fV %7.3fA %7.3fW\n", $1 / 1000, $2 / 1000, $3 / 1000000 }' - echo "${soc[0]} ${soc[1]} ${soc[2]}" | awk '{ printf " SoC: %7.3fV %7.3fA %7.3fW\n", $1 / 1000, $2 / 1000, $3 / 1000000 }' - echo "${temps[0]} ${temps[1]}" | awk '{ printf " tDie: %6.2f°C\ntCtrl: %6.2f°C\n", $1 / 1000, $2 / 1000 }' - - read -t 0.2 -N 1 input - if [[ $input = "q" ]] || [[ $input = "Q" ]]; then - echo - break - fi - - echo -en "\e[4A" -done