From 1b85de18fe8e1863ba0d83023e58adfd839aedda Mon Sep 17 00:00:00 2001 From: Carl Philipp Klemm Date: Tue, 28 Oct 2025 22:17:39 +0100 Subject: [PATCH] inital commit --- CMakeLists.txt | 11 +++ main.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 main.c diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..6f85926 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.20) + +project(vrmode C) + +set(CMAKE_C_STANDARD 17) +set(SRC_FILES main.c) +set(LIBS -lnuma) + +add_executable(${PROJECT_NAME} ${SRC_FILES}) +target_link_libraries(${PROJECT_NAME} ${LIBS}) +install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin PERMISSIONS WORLD_EXECUTE WORLD_READ SETUID) diff --git a/main.c b/main.c new file mode 100644 index 0000000..e75e212 --- /dev/null +++ b/main.c @@ -0,0 +1,185 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +pid_t child_pid; + +const char* drm_sysfs_path = "/sys/class/drm"; +const char* rx6800xt_id = "fd4107589d5b1bb0\n"; +const char* auto_str = "auto\n"; +const char* manual_str = "manual\n"; + +void sig_handler(int sig) +{ + if(child_pid != 0) + kill(child_pid, sig); +} + +int find_gpu(const char* id) +{ + char path[255]; + int i; + + for(i = 0; i < 9; ++i) + { + snprintf(path, sizeof(path), "%s/card%i/device/unique_id", drm_sysfs_path, i); + if(access(path, F_OK) == 0) + { + char id[255] = {}; + int id_fd = open(path, O_RDONLY); + if(id_fd < 0) + continue; + read(id_fd, id, sizeof(id)-1); + close(id_fd); + + if(strcmp(id, rx6800xt_id) == 0) + { + snprintf(path, sizeof(path), "%s/card%i/device/power_dpm_force_performance_level", drm_sysfs_path, i); + int fd = open(path, O_RDONLY); + return i; + } + } + } + return -1; +} + +bool set_gpu_mode(const char* level, const char* mode, int card) +{ + char path[255]; + + snprintf(path, sizeof(path), "%s/card%i/device/power_dpm_force_performance_level", drm_sysfs_path, card); + int level_fd = open(path, O_WRONLY); + if(level_fd < 0) + { + printf("Unable to open %s: %s\n", path, strerror(errno)); + return false; + } + int ret = write(level_fd, level, strlen(level)); + close(level_fd); + if(ret != strlen(level)) + { + printf("Unable to write %s to %s: %s\n", level, path, strerror(errno)); + return false; + } + + snprintf(path, sizeof(path), "%s/card%i/device/pp_power_profile_mode", drm_sysfs_path, card); + int mode_fd = open(path, O_WRONLY); + if(mode_fd < 0) + { + printf("Unable to open %s: %s\n", path, strerror(errno)); + return false; + } + ret = write(mode_fd, mode, strlen(mode)); + close(mode_fd); + if(ret != strlen(mode)) + { + printf("Unable to write %s to %s: %s\n", level, path, strerror(errno)); + return false; + } + return true; +} + +bool enable_vr_mode() +{ + int card = find_gpu(rx6800xt_id); + + return set_gpu_mode(manual_str, "4\n", card); +} + +void disable_vr_mode() +{ + int card = find_gpu(rx6800xt_id); + set_gpu_mode(auto_str, "0\n", card); +} + +int main(int argc, char** argv) +{ + uid_t user = getuid(); + uid_t effective_user = geteuid(); + printf("User id %u, effective user %u\n", user, effective_user); + + for(int i = 1; i < _NSIG; ++i) + signal(i, &sig_handler); + + if(argc < 3) + { + printf("Usage: %s [base_numa_node] [command] [options...]\n", argv[0]); + return 1; + } + + if(!enable_vr_mode()) + return 1; + + child_pid = fork(); + if(child_pid == 0) + { + /*int ret = setpriority(PRIO_PROCESS, 0, -20); + if(ret) + { + printf("Warning: Cant set process priority\n"); + }*/ + + int ret = setuid(user); + if(ret) + { + printf("Unable to setuid\n"); + return 1; + } + + ret = numa_available(); + if(ret < 0) + { + printf("Warning: NUMA not available\n"); + } + else + { + int requested_node = atoi(argv[1]); + if(numa_max_node() < requested_node+1) + { + printf("Numa nodes %i and %i requested, but only %i nodes available\n", requested_node, requested_node+1, numa_max_node()+1); + return 1; + } + + struct bitmask* nodes = numa_allocate_nodemask(); + numa_bitmask_setbit(nodes, requested_node); + numa_bitmask_setbit(nodes, requested_node+1); + printf("Using numa mask: "); + for(size_t i = 0; i < numa_max_node()+1; ++i) + printf("%i, ", numa_bitmask_isbitset(nodes, i)); + putc('\n', stdout); + numa_bind(nodes); + numa_free_nodemask(nodes); + } + + ret = execvp(argv[2], argv+2); + if(ret) + { + printf("Unable to exec %s: %s\n", argv[2], strerror(errno)); + return 1; + } + } + else if(child_pid < 0) + { + printf("Unable to fork: %s\n", strerror(errno)); + disable_vr_mode(); + return 1; + } + else + { + int ret; + waitpid(child_pid, &ret, 0); + printf("Exiting vr mode\n"); + disable_vr_mode(); + return ret; + } + + return 0; +}