diff --git a/makefile b/makefile index dabe5d2..93b7bf5 100755 --- a/makefile +++ b/makefile @@ -1,9 +1,28 @@ +CC := cc + ifeq ($(PREFIX),) PREFIX := /usr/local endif +BUILD_FILES_COMMON := \ + src/ss/*.c \ + src/sysfs.c \ + src/zenmonitor-lib.c + +BUILD_FILES_GUI := \ + $(BUILD_FILES_COMMON) \ + src/gui.c \ + src/zenmonitor.c + +BUILD_FILES_CLI := \ + $(BUILD_FILES_COMMON) \ + src/zenmonitor-cli.c + 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 -Wall + $(CC) -Isrc/include `pkg-config --cflags gtk+-3.0` $(BUILD_FILES_GUI) -o zenmonitor `pkg-config --libs gtk+-3.0` -lm -no-pie -Wall $(CFLAGS) + +build-cli: + $(CC) -Isrc/include `pkg-config --cflags glib-2.0` $(BUILD_FILES_CLI) -o zenmonitor-cli `pkg-config --libs glib-2.0` -lm -no-pie -Wall $(CFLAGS) install: mkdir -p $(DESTDIR)$(PREFIX)/bin @@ -14,6 +33,10 @@ install: data/zenmonitor.desktop.in > \ $(DESTDIR)$(PREFIX)/share/applications/zenmonitor.desktop +install-cli: + mkdir -p $(DESTDIR)$(PREFIX)/bin + install -m 755 zenmonitor-cli $(DESTDIR)$(PREFIX)/bin + install-polkit: sed -e "s|@APP_EXEC@|${DESTDIR}${PREFIX}/bin/zenmonitor|" \ data/zenmonitor-root.desktop.in > \ @@ -29,5 +52,9 @@ uninstall: rm -f $(DESTDIR)$(PREFIX)/share/applications/zenmonitor-root.desktop rm -f $(DESTDIR)/usr/share/polkit-1/actions/org.pkexec.zenmonitor.policy +all: build build-cli + clean: rm -f zenmonitor + rm -f zenmonitor-cli + rm -f *.o diff --git a/src/include/gui.h b/src/include/gui.h index 0bc2501..96ca7f8 100644 --- a/src/include/gui.h +++ b/src/include/gui.h @@ -1 +1,6 @@ +#ifndef __ZENMONITOR_GUI_H__ +#define __ZENMONITOR_GUI_H__ + int start_gui(); + +#endif /* __ZENMONITOR_GUI_H__ */ diff --git a/src/include/msr.h b/src/include/msr.h index 664a5ee..887e6e8 100644 --- a/src/include/msr.h +++ b/src/include/msr.h @@ -1,4 +1,11 @@ +#ifndef __ZENMONITOR_MSR_H__ +#define __ZENMONITOR_MSR_H__ + +#include + gboolean msr_init(); void msr_update(); void msr_clear_minmax(); GSList* msr_get_sensors(); + +#endif /* __ZENMONITOR_MSR_H__ */ diff --git a/src/include/os.h b/src/include/os.h index 9d35850..41db073 100644 --- a/src/include/os.h +++ b/src/include/os.h @@ -1,4 +1,11 @@ +#ifndef __ZENMONITOR_OS_H__ +#define __ZENMONITOR_OS_H__ + +#include + gboolean os_init(void); void os_update(void); void os_clear_minmax(void); GSList* os_get_sensors(void); + +#endif /* __ZENMONITOR_OS_H__ */ diff --git a/src/include/sysfs.h b/src/include/sysfs.h index 59ab701..949bb09 100644 --- a/src/include/sysfs.h +++ b/src/include/sysfs.h @@ -1,3 +1,8 @@ +#ifndef __ZENMONITOR_SYSFS_H__ +#define __ZENMONITOR_SYSFS_H__ + +#include + #define SYSFS_DIR_CPUS "/sys/devices/system/cpu" struct cpudev { @@ -6,3 +11,5 @@ struct cpudev { }; struct cpudev * get_cpu_dev_ids(void); + +#endif /* __ZENMONITOR_SYSFS_H__ */ diff --git a/src/include/zenmonitor.h b/src/include/zenmonitor.h index 43a6e3f..e135c35 100644 --- a/src/include/zenmonitor.h +++ b/src/include/zenmonitor.h @@ -1,3 +1,9 @@ +#ifndef __ZENMONITOR_ZENMONITOR_H__ +#define __ZENMONITOR_ZENMONITOR_H__ + +#include +#include + #define ERROR_VALUE -999.0 #define VERSION "1.4.2" @@ -22,9 +28,23 @@ typedef struct { GSList *sensors; } SensorSource; +typedef struct { + GPtrArray *labels; + GPtrArray *data; + GArray *time; +} SensorDataStore; + SensorInit* sensor_init_new(void); void sensor_init_free(SensorInit *s); gboolean check_zen(); gchar *cpu_model(); guint get_core_count(); +SensorDataStore* sensor_data_store_new(); +void sensor_data_store_add_entry(SensorDataStore *store, gchar *entry); +gint sensor_data_store_drop_entry(SensorDataStore *store, gchar *entry); +void sensor_data_store_keep_time(SensorDataStore *store); +gint sensor_data_store_add_data(SensorDataStore *store, gchar *entry, float data); +void sensor_data_store_free(SensorDataStore *store); extern gboolean display_coreid; + +#endif /* __ZENMONITOR_ZENMONITOR_H__ */ diff --git a/src/include/zenpower.h b/src/include/zenpower.h index 54978d6..a07cbe8 100644 --- a/src/include/zenpower.h +++ b/src/include/zenpower.h @@ -1,4 +1,11 @@ +#ifndef __ZENMONITOR_ZENPOWER_H__ +#define __ZENMONITOR_ZENPOWER_H__ + +#include + gboolean zenpower_init(); GSList* zenpower_get_sensors(); void zenpower_update(); void zenpower_clear_minmax(); + +#endif /* __ZENMONITOR_ZENPOWER_H__ */ diff --git a/src/zenmonitor-cli.c b/src/zenmonitor-cli.c new file mode 100644 index 0000000..7cf79f1 --- /dev/null +++ b/src/zenmonitor-cli.c @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include +#include +#include "msr.h" +#include "os.h" +#include "zenpower.h" +#include "zenmonitor.h" + +gboolean display_coreid = 0; +gdouble delay = 0.5; +gchar *file = ""; +SensorDataStore *store; +int quit = 0; + +static GOptionEntry options[] = { + {"file", 'f', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &file, + "Output to csv file", "FILE"}, + {"delay", 'd', G_OPTION_FLAG_NONE, G_OPTION_ARG_DOUBLE, &delay, + "Interval of refreshing informations", "SECONDS"}, + {"coreid", 'c', 0, G_OPTION_ARG_NONE, &display_coreid, + "Display core_id instead of core index", NULL}, + {NULL}}; + +static SensorSource sensor_sources[] = { + { + "zenpower", + zenpower_init, zenpower_get_sensors, zenpower_update, zenpower_clear_minmax, + FALSE, NULL + }, + { + "msr", + msr_init, msr_get_sensors, msr_update, msr_clear_minmax, + FALSE, NULL + }, + { + "os", + os_init, os_get_sensors, os_update, os_clear_minmax, + FALSE, NULL + }, + { + NULL + } +}; + +void flush_to_csv() +{ + FILE *csv; + csv = fopen(file, "w"); + guint i = 0; + int cont = 1; + + fprintf(csv, "time(epoch),"); + while(cont) + { + fprintf(csv, "%s", (char*)g_ptr_array_index(store->labels, i++)); + if(g_ptr_array_index(store->labels, i)) + { + fprintf(csv, ","); + } + else + { + cont = 0; + } + } + + fprintf(csv, "\n"); + cont = 1; + i = 0; + + while(cont) + { + struct timespec ts = g_array_index(store->time, struct timespec, i); + fprintf(csv, "%ld.%.9ld,", ts.tv_sec, ts.tv_nsec); + + int j = 0; + int cont2 = 1; + while(cont2) + { + GArray *data = g_ptr_array_index(store->data, j++); + fprintf(csv, "%f", g_array_index(data, float, i)); + if(g_ptr_array_index(store->data, j)) + { + fprintf(csv, ","); + } + else + { + cont2 = 0; + } + } + fprintf(csv, "\n"); + + i++; + + if(g_array_index(store->time, struct timespec, i).tv_sec <= 0) + { + cont = 0; + } + } + + fclose(csv); + + quit = 1; +} + +void init_sensors() +{ + GSList *sensor; + SensorSource *source; + const SensorInit *data; + + 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; + sensor_data_store_add_entry(store, data->label); + sensor = sensor->next; + } + } + } + } +} + +void update_data() +{ + SensorSource *source; + GSList *node; + const SensorInit *sensorData; + + sensor_data_store_keep_time(store); + + for(source = sensor_sources; source->drv; source++) + { + if(source->enabled) + { + source->func_update(); + if(source->sensors) + { + node = source->sensors; + + while(node) + { + sensorData = (SensorInit*)node->data; + sensor_data_store_add_data(store, sensorData->label, *sensorData->value); + printf("%s\t%f\n", sensorData->label, *sensorData->value); + node = node->next; + } + } + } + } + printf("\v"); +} + +void start_watching() +{ + while(!quit) + { + update_data(); + usleep(delay * 1000 * 1000); + } +} + +int main(int argc, char *argv[]) +{ + GError *error = NULL; + GOptionContext *context; + + context = g_option_context_new("- Zenmonitor options"); + g_option_context_add_main_entries(context, options, NULL); + if(!g_option_context_parse(context, &argc, &argv, &error)) { + g_print ("option parsing failed: %s\n", error->message); + exit (1); + } + + if(strcmp(file, "") != 0) + { + signal(SIGINT, flush_to_csv); + } + store = sensor_data_store_new(); + + init_sensors(); + start_watching(); + + sensor_data_store_free(store); + + return EXIT_SUCCESS; +} diff --git a/src/zenmonitor-lib.c b/src/zenmonitor-lib.c new file mode 100644 index 0000000..a59680b --- /dev/null +++ b/src/zenmonitor-lib.c @@ -0,0 +1,170 @@ +#include +#include +#include +#include + +#include "zenpower.h" +#include "msr.h" +#include "os.h" +#include "zenmonitor.h" + +#define AMD_STRING "AuthenticAMD" +#define ZEN_FAMILY 0x17 +#define ZEN3_FAMILY 0x19 + +const guint SENSOR_DATA_STORE_NUM = 4096; + +// AMD PPR = https://www.amd.com/system/files/TechDocs/54945_PPR_Family_17h_Models_00h-0Fh.pdf + +gboolean check_zen() { + guint32 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 && ext_family != ZEN3_FAMILY){ + return FALSE; + } + + return TRUE; +} + +gchar *cpu_model() { + guint32 eax = 0, ebx = 0, ecx = 0, edx = 0; + char model[48]; + + // AMD PPR: page 65-68 - CPUID_Fn80000002_EAX-CPUID_Fn80000004_EDX + __get_cpuid(0x80000002, &eax, &ebx, &ecx, &edx); + memcpy(model, &eax, 4); + memcpy(model+4, &ebx, 4); + memcpy(model+8, &ecx, 4); + memcpy(model+12, &edx, 4); + + __get_cpuid(0x80000003, &eax, &ebx, &ecx, &edx); + memcpy(model+16, &eax, 4); + memcpy(model+20, &ebx, 4); + memcpy(model+24, &ecx, 4); + memcpy(model+28, &edx, 4); + + __get_cpuid(0x80000004, &eax, &ebx, &ecx, &edx); + memcpy(model+32, &eax, 4); + memcpy(model+36, &ebx, 4); + memcpy(model+40, &ecx, 4); + memcpy(model+44, &edx, 4); + + model[48] = 0; + return g_strdup(g_strchomp(model)); +} + +guint get_core_count() { + guint eax = 0, ebx = 0, ecx = 0, edx = 0; + guint logical_cpus, threads_per_code; + + // 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; +} + +SensorDataStore *sensor_data_store_new() +{ + SensorDataStore *ret; + + ret = g_new0(SensorDataStore, 1); + ret->labels = g_ptr_array_new(); + ret->data = g_ptr_array_new(); + ret->time = g_array_new(FALSE, TRUE, sizeof(struct timespec)); + + return ret; +} + +void sensor_data_store_add_entry(SensorDataStore *store, gchar *entry) +{ + GArray *data; + data = g_array_new(TRUE, TRUE, sizeof(float)); + + g_ptr_array_add(store->labels, entry); + g_ptr_array_add(store->data, data); +} + +void sensor_data_store_keep_time(SensorDataStore *store) +{ + struct timespec ts; + timespec_get(&ts, TIME_UTC); + g_array_append_val(store->time, ts); +} + +gint sensor_data_store_drop_entry(SensorDataStore *store, gchar *entry) +{ + guint index = 0; + gboolean found = g_ptr_array_find(store->labels, entry, &index); + if(!found) + { + return 1; + } + + g_ptr_array_remove_index(store->labels, index); + g_ptr_array_remove_index(store->data, index); + + return 0; +} + +gint sensor_data_store_add_data(SensorDataStore *store, gchar *entry, float value) +{ + guint index = 0; + gboolean found = g_ptr_array_find(store->labels, entry, &index); + + if(!found) + { + return 1; + } + + GArray *data = g_ptr_array_index(store->data, index); + g_array_append_val(data, value); + + return 0; +} + +void sensor_data_store_free(SensorDataStore *store) +{ + if(store) + { + g_array_free(store->time, TRUE); + g_ptr_array_free(store->labels, TRUE); + g_ptr_array_free(store->data, TRUE); + g_free(store); + } +} + +SensorInit *sensor_init_new() { + return g_new0(SensorInit, 1); +} + +void sensor_init_free(SensorInit *s) { + if (s) { + g_free(s->label); + g_free(s->hint); + g_free(s); + } +} + diff --git a/src/zenmonitor.c b/src/zenmonitor.c index 3a64524..cb35ce2 100644 --- a/src/zenmonitor.c +++ b/src/zenmonitor.c @@ -1,88 +1,14 @@ #include -#include #include #include -#include "zenmonitor.h" + #include "zenpower.h" #include "msr.h" #include "os.h" #include "gui.h" +#include "zenmonitor.h" -#define AMD_STRING "AuthenticAMD" -#define ZEN_FAMILY 0x17 -#define ZEN3_FAMILY 0x19 - -// AMD PPR = https://www.amd.com/system/files/TechDocs/54945_PPR_Family_17h_Models_00h-0Fh.pdf - -gboolean check_zen() { - guint32 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 && ext_family != ZEN3_FAMILY){ - return FALSE; - } - - return TRUE; -} - -gchar *cpu_model() { - guint32 eax = 0, ebx = 0, ecx = 0, edx = 0; - char model[48]; - - // AMD PPR: page 65-68 - CPUID_Fn80000002_EAX-CPUID_Fn80000004_EDX - __get_cpuid(0x80000002, &eax, &ebx, &ecx, &edx); - memcpy(model, &eax, 4); - memcpy(model+4, &ebx, 4); - memcpy(model+8, &ecx, 4); - memcpy(model+12, &edx, 4); - - __get_cpuid(0x80000003, &eax, &ebx, &ecx, &edx); - memcpy(model+16, &eax, 4); - memcpy(model+20, &ebx, 4); - memcpy(model+24, &ecx, 4); - memcpy(model+28, &edx, 4); - - __get_cpuid(0x80000004, &eax, &ebx, &ecx, &edx); - memcpy(model+32, &eax, 4); - memcpy(model+36, &ebx, 4); - memcpy(model+40, &ecx, 4); - memcpy(model+44, &edx, 4); - - model[48] = 0; - return g_strdup(g_strchomp(model)); -} - -guint get_core_count() { - guint eax = 0, ebx = 0, ecx = 0, edx = 0; - guint logical_cpus, threads_per_code; - - // 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; -} +gboolean display_coreid = 0; static SensorSource sensor_sources[] = { { @@ -105,20 +31,6 @@ static SensorSource sensor_sources[] = { } }; -SensorInit *sensor_init_new() { - return g_new0(SensorInit, 1); -} - -void sensor_init_free(SensorInit *s) { - if (s) { - g_free(s->label); - g_free(s->hint); - g_free(s); - } -} - -gboolean display_coreid = 0; - static GOptionEntry options[] = { { "coreid", 'c', 0, G_OPTION_ARG_NONE, &display_coreid, "Display core_id instead of core index", NULL },