Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions dttools/src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ SOURCES = \
username.c \
uuid.c \
xxmalloc.c \
gpu_commons.c \
nvidia_nvml_library.c \
gpu.c \


HEADERS_PUBLIC = \
auth.h \
Expand Down Expand Up @@ -175,6 +179,9 @@ HEADERS_PUBLIC = \
timestamp.h \
unlink_recursive.h \
xxmalloc.h \
gpu_commons.h \
nvidia_nvml_library.h \
gpu.h \

LIBRARIES = libdttools.a

Expand Down
79 changes: 79 additions & 0 deletions dttools/src/gpu.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
Copyright (C) 2022 The University of Notre Dame
This software is distributed under the GNU General Public License.
See the file COPYING for details.
*/

#include "gpu.h"
#include "debug.h"
#include "gpu_commons.h"
#include "nvidia_nvml_library.h"

// nvidia libray name as macro
const char * NVIDIA_LIBRARY_NAME = "libnvidia-ml.so";
// AMD library need to check for now we are only intrested in Nvidia
// the below library is not verified but referenced for future use case
const char * AMD_LIBRARY_NAME = "libhsa-runtime64.so";


struct gpu_library * gpu_lib_init(){
struct gpu_library * gpu_lib = calloc(1, sizeof(*gpu_lib));
if (!gpu_lib) {
debug(D_DEBUG,"Out of memory allocating gpu_library");
return NULL;
}

enum gpu_vendor vendor = NVIDIA;

// TODO: write a logic to figure out the vendor
// for now stick with nvidia

if(vendor == NVIDIA) {
gpu_lib->vendor = NVIDIA;
struct library_search_result gpu_lib_path = find_library_by_name(NVIDIA_LIBRARY_NAME);
if(gpu_lib_path.found){
gpu_lib->nvidia_lib = nvml_library_open(gpu_lib_path);
} else {
// not found so lets return null
free(gpu_lib);
return NULL;
}
Comment thread
LaxminarayanaV7416 marked this conversation as resolved.
Outdated

} else if(vendor == AMD) {
gpu_lib->vendor = AMD;
struct library_search_result gpu_lib_path = find_library_by_name(AMD_LIBRARY_NAME);
if(gpu_lib_path.found){
// work around that we are not supporting the GPU for now
free(gpu_lib);
return NULL;
} else {
// not found so lets return null
free(gpu_lib);
return NULL;
}
}
return gpu_lib;
}


void gpu_lib_close(struct gpu_library * gpu_lib){
if(gpu_lib->vendor == NVIDIA){
// call the close function from nvidia_library
nvml_library_close(gpu_lib->nvidia_lib);
free(gpu_lib);
} else if(gpu_lib->vendor == AMD){
// call the close function from amd_library
free(gpu_lib);
}
}
Comment thread
LaxminarayanaV7416 marked this conversation as resolved.
Outdated

char *gpu_name_get_new(struct gpu_library * gpu_lib){
char * name = malloc(64);
if(gpu_lib->vendor == NVIDIA){
name = nvml_gpu_name(gpu_lib->nvidia_lib);
} else if(gpu_lib->vendor == AMD){
// todo work in future
name = "AMD GPU Not Available";
}
return name;
Comment thread
LaxminarayanaV7416 marked this conversation as resolved.
Outdated
}
34 changes: 34 additions & 0 deletions dttools/src/gpu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
Copyright (C) 2022 The University of Notre Dame
This software is distributed under the GNU General Public License.
See the file COPYING for details.
*/

#ifndef GPU
#define GPU
Comment thread
LaxminarayanaV7416 marked this conversation as resolved.
Outdated

#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <dlfcn.h>
#include <stdlib.h>

// enum for the GPU vendor
enum gpu_vendor {
NVIDIA = 0,
AMD = 1,
};

// generic gpu options which can be used everywhere
struct gpu_library {
enum gpu_vendor vendor;
struct nvml_library * nvidia_lib;
struct amd_rocm_hsa_library * amd_lib;
// ... add more if we decide to support more
};
Comment thread
LaxminarayanaV7416 marked this conversation as resolved.

struct gpu_library * gpu_lib_init();
void gpu_lib_close(struct gpu_library * gpu_lib);
char *gpu_name_get_new(struct gpu_library * gpu_lib);

#endif
38 changes: 38 additions & 0 deletions dttools/src/gpu_commons.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
Copyright (C) 2022 The University of Notre Dame
This software is distributed under the GNU General Public License.
See the file COPYING for details.
*/

#include "gpu_commons.h"
#include "debug.h"


const char * LIBRARY_SEARCH_COMMAND = "ldconfig -p | grep %s | awk '{print $NF}'";

struct library_search_result find_library_by_name(const char *lib_name) {
char command[256];
char result[512];
struct library_search_result lib_result = {{0}, false};

snprintf(command, sizeof(command), LIBRARY_SEARCH_COMMAND, lib_name);

FILE *fp = popen(command, "r");
if (fp == NULL) {
debug(D_ERROR,"popen failed to run ldconfig command");
return lib_result;
}

if (fgets(result, sizeof(result), fp) != NULL) {
result[strcspn(result, "\n")] = 0;
strncpy(lib_result.path, result, sizeof(lib_result.path) - 1);
lib_result.path[sizeof(lib_result.path) - 1] = '\0';
lib_result.found = true;
debug(D_DEBUG, "GPU Library found at path %s\n", lib_result.path);
} else {
Comment thread
LaxminarayanaV7416 marked this conversation as resolved.
Outdated
debug(D_DEBUG,"GPU Library %s not found in system search paths.\n", lib_name);
}

pclose(fp);
return lib_result;
}
26 changes: 26 additions & 0 deletions dttools/src/gpu_commons.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
Copyright (C) 2022 The University of Notre Dame
This software is distributed under the GNU General Public License.
See the file COPYING for details.
*/

#ifndef GPU_COMMONS
#define GPU_COMMONS

#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>

// this says whether the searched library exists or not
struct library_search_result {
char path[512];
bool found;
};

// AMD place holder library
struct amd_rocm_hsa_library {};

Copilot AI Apr 11, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

struct amd_rocm_hsa_library {} is an empty struct; empty structs are not valid in standard C and will fail to compile with many toolchains/flags. Use a forward declaration (struct amd_rocm_hsa_library;) or give it at least one dummy member.

Suggested change
struct amd_rocm_hsa_library {};
struct amd_rocm_hsa_library;

Copilot uses AI. Check for mistakes.

struct library_search_result find_library_by_name(const char *lib_name);

#endif
136 changes: 136 additions & 0 deletions dttools/src/nvidia_nvml_library.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
Copyright (C) 2022 The University of Notre Dame
This software is distributed under the GNU General Public License.
See the file COPYING for details.
*/

#include "nvidia_nvml_library.h"
#include "debug.h"
#include <string.h>

#define LOAD_SYMBOL(handle, field, type, name) \
do { \
dlerror(); \
(field) = (type)dlsym((handle), (name)); \
const char *sym_err = dlerror(); \
if (sym_err) { \
debug(D_ERROR, "dlsym failed for %s: %s", \
(name), sym_err); \
goto fail; \
} \
} while (0)

struct nvml_library *nvml_library_open(struct library_search_result res) {
struct nvml_library *nvml = calloc(1, sizeof(*nvml));
if (!nvml) {
debug(D_ERROR, "Out of memory allocating nvml_library");
return NULL;
}

if (!res.found || res.path[0] == '\0') {
debug(D_ERROR, "Error: GPU Library path was not found.");
free(nvml);
return NULL;
}

debug(D_DEBUG, "GPU library opening from path %s", res.path);
nvml->lib_handle = dlopen(res.path, RTLD_NOW | RTLD_LOCAL);
if (!nvml->lib_handle) {
debug(D_ERROR, "dlopen failed: %s", dlerror());
free(nvml);
return NULL;
}

LOAD_SYMBOL(nvml->lib_handle, nvml->nvmlInit,
nvmlReturn_t (*)(void), "nvmlInit");
LOAD_SYMBOL(nvml->lib_handle, nvml->nvmlShutdown,
nvmlReturn_t (*)(void), "nvmlShutdown");
LOAD_SYMBOL(nvml->lib_handle, nvml->nvmlDeviceGetHandleByIndex,
nvmlReturn_t (*)(int, nvmlDevice_t *), "nvmlDeviceGetHandleByIndex");
LOAD_SYMBOL(nvml->lib_handle, nvml->nvmlDeviceGetMemoryInfo,
nvmlReturn_t (*)(nvmlDevice_t, nvmlMemory_t *), "nvmlDeviceGetMemoryInfo");
LOAD_SYMBOL(nvml->lib_handle, nvml->nvmlDeviceGetUtilizationRates,
nvmlReturn_t (*)(nvmlDevice_t, nvmlUtilization_t *), "nvmlDeviceGetUtilizationRates");
LOAD_SYMBOL(nvml->lib_handle, nvml->nvmlDeviceGetCount,
nvmlReturn_t (*)(int *), "nvmlDeviceGetCount");
LOAD_SYMBOL(nvml->lib_handle, nvml->nvmlDeviceGetName,
nvmlReturn_t (*)(nvmlDevice_t, char *, unsigned int), "nvmlDeviceGetName");
LOAD_SYMBOL(nvml->lib_handle, nvml->nvmlErrorString,
char * (*)(nvmlReturn_t), "nvmlErrorString");

debug(D_DEBUG, "library nvml load completed!");

nvmlReturn_t init_result = nvml->nvmlInit();
printf("initializtion result %d\n",init_result);
if (init_result != NVML_SUCCESS) {
debug(D_ERROR, "GPU initializtion failed with error code %i", init_result);
Comment thread
LaxminarayanaV7416 marked this conversation as resolved.
Outdated
goto fail;
}
return nvml;

fail:
nvml_library_close(nvml);
return NULL;
}

void nvml_library_close(struct nvml_library *lib) {
if (!lib) {
return;
}
// now call the shutdown function to properly close the nvml lib
nvmlReturn_t shutdown_result = lib->nvmlShutdown();
if (shutdown_result != NVML_SUCCESS) {
debug(D_ERROR, "GPU shutdown failed with error code %i", shutdown_result);
//doesnt matter now close the lib anyways
Comment thread
LaxminarayanaV7416 marked this conversation as resolved.
Outdated
}
if (lib->lib_handle) {
dlclose(lib->lib_handle);
}
free(lib);
}

char * nvml_gpu_name(struct nvml_library *nvml_lib){
if (!nvml_lib) {
debug(D_ERROR, "nvml_gpu_name called with NULL nvml_lib");
return NULL;
}

int device_count = 0;
nvmlReturn_t count_result = nvml_lib->nvmlDeviceGetCount(&device_count);
if (count_result != NVML_SUCCESS) {
debug(D_ERROR, "Failed to get device count: %s",
nvml_lib->nvmlErrorString(count_result));
return NULL;
}

if (device_count <= 0) {
debug(D_ERROR, "No GPU devices found");
return NULL;
}

char *name = malloc(NVML_DEVICE_NAME_BUFFER_SIZE);
if (!name) {
debug(D_ERROR, "Out of memory allocating GPU name buffer");
return NULL;
}

nvmlDevice_t device;
nvmlReturn_t result = nvml_lib->nvmlDeviceGetHandleByIndex(0, &device);
if (result != NVML_SUCCESS) {
debug(D_ERROR, "Failed to get device handle: %s",
nvml_lib->nvmlErrorString(result));
free(name);
return NULL;
}

result = nvml_lib->nvmlDeviceGetName(device, name, NVML_DEVICE_NAME_BUFFER_SIZE);
if (result != NVML_SUCCESS) {
debug(D_ERROR, "Failed to get device name: %s",
nvml_lib->nvmlErrorString(result));
free(name);
return NULL;
}

debug(D_DEBUG, "GPU Name: %s", name);
return name;
}
Loading
Loading