diff --git a/meson.build b/meson.build index 3f535cd..fe65aa3 100644 --- a/meson.build +++ b/meson.build @@ -1,3 +1,7 @@ project('tuxclocker') +cc = meson.get_compiler('c') + +incdir = include_directories('src/include') + subdir('src') diff --git a/src/include/tc_assignable.h b/src/include/tc_assignable.h index 1f70fbe..78c1a9d 100644 --- a/src/include/tc_assignable.h +++ b/src/include/tc_assignable.h @@ -9,13 +9,16 @@ enum tc_assignable_value_category {TC_ASSIGNABLE_RANGE, TC_ASSIGNABLE_ENUM}; // Is the range double or integer -enum tc_assignable_range_data_type {TC_ASSIGNABLE_RANGE_INT, TC_ASSIGNABLE_RANGE_DOUBLE}; +enum tc_assignable_range_data_type { + TC_ASSIGNABLE_RANGE_INT, + TC_ASSIGNABLE_RANGE_DOUBLE +}; -typedef struct tc_assignable_range_double_t{ +typedef struct tc_assignable_range_double_t { double min, max; } tc_assignable_range_double_t; -typedef struct tc_assignable_range_int_t{ +typedef struct tc_assignable_range_int_t { int64_t min, max; } tc_assignable_range_int_t; @@ -32,8 +35,6 @@ typedef struct { char **properties; } tc_assignable_enum_t; - - typedef struct tc_assignable_node_t { // Assignable name eg. fan speed char *name; @@ -54,3 +55,12 @@ typedef struct tc_assignable_node_t { uint16_t children_count; struct tc_assignable_node_t **children_nodes; } tc_assignable_node_t; + +/* Utility functions for assignables */ +// Allocates memory for a tunable node +tc_assignable_node_t *tc_assignable_node_new(); +// Deallocates memory of the node +void tc_assignable_node_destroy(tc_assignable_node_t *node); + +// Add a child to a node +int8_t tc_assignable_node_add_child(tc_assignable_node_t *node, tc_assignable_node_t *child); diff --git a/src/include/tc_common.h b/src/include/tc_common.h new file mode 100644 index 0000000..912baf2 --- /dev/null +++ b/src/include/tc_common.h @@ -0,0 +1,8 @@ +#pragma once + +// Common definitions for tuxclocker + +// Error values +#define TC_SUCCESS 0 +#define TC_EGENERIC (-1) +#define TC_ENOMEM (-2) diff --git a/src/include/tc_module.h b/src/include/tc_module.h index 36ea689..9f07105 100644 --- a/src/include/tc_module.h +++ b/src/include/tc_module.h @@ -2,6 +2,21 @@ #include +// Categories for modules. +enum tc_module_category { + TC_CATEGORY_ASSIGNABLE, + TC_CATEGORY_PROPERTY +}; + + + typedef struct tc_module_t { + enum tc_module_category category; + const char *name; + + // Initializes the module's internal state + int8_t (*init_callback)(); + // Frees the internal memory of the module + int8_t (*close_callback)(); } tc_module_t; diff --git a/src/lib/meson.build b/src/lib/meson.build new file mode 100644 index 0000000..e69de29 diff --git a/src/lib/tc_assignable.c b/src/lib/tc_assignable.c new file mode 100644 index 0000000..262b004 --- /dev/null +++ b/src/lib/tc_assignable.c @@ -0,0 +1,27 @@ +#include + +#include +#include + +tc_assignable_node_t *tc_assignable_node_new() { + tc_assignable_node_t *node = calloc(1, sizeof(tc_assignable_node_t)); + return node; +} + +void tc_assignable_node_destroy(tc_assignable_node_t *node) { + // The name is allocated on the heap + if (node->name != NULL) { + free(node->name); + } + + free(node); +} + +int8_t tc_assignable_node_add_child(tc_assignable_node_t *parent, tc_assignable_node_t *child) { + parent->children_count++; + if ((parent->children_nodes = realloc(parent->children_nodes, parent->children_count)) == NULL) { + return TC_ENOMEM; + } + parent->children_nodes[parent->children_count] = child; + return TC_SUCCESS; +} diff --git a/src/meson.build b/src/meson.build index 10e3011..f4fe4f2 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1 +1,7 @@ +# Define libtuxclocker target here since others depend on it +libtuxclocker = shared_library('libtuxclocker', + ['lib/tc_assignable.c'], + include_directories : incdir) + subdir('modules') +subdir('lib') diff --git a/src/modules/assignable/meson.build b/src/modules/assignable/meson.build index 1855fb8..f1f2ac9 100644 --- a/src/modules/assignable/meson.build +++ b/src/modules/assignable/meson.build @@ -1 +1,12 @@ -shared_library('libnvidia', 'nvidia.c') + +libnvml = cc.find_library('nvidia-ml') +libx = cc.find_library('X11') +libxnvctrl = cc.find_library('XNVCtrl') + +nvml_h = cc.has_header('nvml.h') + +shared_library('libnvidia', 'nvidia_linux.c', + include_directories : incdir, + dependencies : [libnvml, libx, libxnvctrl], + link_with : libtuxclocker) + diff --git a/src/modules/assignable/nvidia.c b/src/modules/assignable/nvidia.c deleted file mode 100644 index 4e29248..0000000 --- a/src/modules/assignable/nvidia.c +++ /dev/null @@ -1,5 +0,0 @@ -#include "/opt/cuda/include/nvml.h" - -#define MAX_GPUS 32 - -static nvmlDevice_t nvml_handles[MAX_GPUS]; diff --git a/src/modules/assignable/nvidia_linux.c b/src/modules/assignable/nvidia_linux.c new file mode 100644 index 0000000..dbd0fa2 --- /dev/null +++ b/src/modules/assignable/nvidia_linux.c @@ -0,0 +1,82 @@ +#include "/opt/cuda/include/nvml.h" +#include +#include + +#include +#include + +#define MAX_GPUS 32 + +// Local function declarations +static int8_t init(); +static int8_t close(); +static int8_t generate_assignable_tree(); + +static uint32_t gpu_count; +static nvmlDevice_t nvml_handles[MAX_GPUS]; +static Display *dpy; +static tc_assignable_node_t *root_node; + +static int8_t init() { + // Initialize library + if (nvmlInit_v2() != NVML_SUCCESS) { + return TC_EGENERIC; + } + + // Query GPU count + if (nvmlDeviceGetCount(&gpu_count) != NVML_SUCCESS) { + return TC_EGENERIC; + } + + if (gpu_count > MAX_GPUS) { + return TC_ENOMEM; + } + + // Get nvml handles + uint32_t valid_count = 0; + for (uint8_t i = 0; i < gpu_count; i++) { + nvmlDevice_t dev; + + if (nvmlDeviceGetHandleByIndex_v2(i, &dev) == NVML_SUCCESS) { + nvml_handles[valid_count] = dev; + valid_count++; + } + } + gpu_count = valid_count; + + // Get X11 display + if ((dpy = XOpenDisplay(NULL)) == NULL) { + return TC_EGENERIC; + } + + // Generate the tree structure of assignables for every GPU. Free in close(). + generate_assignable_tree(); + + return TC_SUCCESS; +} + +static int8_t close() { + +} + +static int8_t generate_assignable_tree() { + // Allocate memory for root node + root_node = tc_assignable_node_new(); + + for (uint32_t i = 0; i < gpu_count; i++) { + // Get GPU name and use it as the root item for GPU + char gpu_name[NVML_DEVICE_NAME_BUFFER_SIZE]; + + if (nvmlDeviceGetName(nvml_handles[i], gpu_name, NVML_DEVICE_NAME_BUFFER_SIZE) != NVML_SUCCESS) { + continue; + } + // Got the name, append the item to the root item + tc_assignable_node_t *gpu_name_node = tc_assignable_node_new(); + gpu_name_node->name = strdup(gpu_name); + + // Append to the root node + if (tc_assignable_node_add_child(root_node, gpu_name_node) != TC_SUCCESS) { + + } + } +}