diff --git a/src/common/args.cpp b/src/common/args.cpp index bea2855..4d3534f 100644 --- a/src/common/args.cpp +++ b/src/common/args.cpp @@ -2,30 +2,81 @@ #include #include #include +#include #include "args.hpp" #include "global.hpp" +#define OVERFLOW -1 +#define UNDERFLOW -2 +#define INVALID_ARG -3 #define NUM_COLORS 4 struct args_struct { bool help_flag; bool version_flag; + int gpu_idx; STYLE style; struct color** colors; }; +int errn = 0; +static struct args_struct args; + const char args_chr[] = { + /* [ARG_CHAR_GPU] = */ 'g', /* [ARG_CHAR_HELP] = */ 'h', /* [ARG_CHAR_VERSION] = */ 'V', }; const char *args_str[] = { + /* [ARG_CHAR_GPU] = */ "gpu", /* [ARG_CHAR_HELP] = */ "help", /* [ARG_CHAR_VERSION] = */ "version", }; -static struct args_struct args; +int getarg_int(char* str) { + errn = 0; + + char* endptr; + long tmp = strtol(str, &endptr, 10); + + if(*endptr) { + errn = INVALID_ARG; + return -1; + } + if(tmp == LONG_MIN) { + errn = UNDERFLOW; + return -1; + } + if(tmp == LONG_MAX) { + errn = OVERFLOW; + return -1; + } + if(tmp >= INT_MIN && tmp <= INT_MAX) { + return (int)tmp; + } + + errn = OVERFLOW; + return -1; +} + +void print_getarg_error() { + switch (errn) { + case OVERFLOW: + printf("overflow detected while parsing the arguments\n"); + break; + case UNDERFLOW: + printf("underflow detected while parsing the arguments\n"); + break; + case INVALID_ARG: + printf("invalid argument\n"); + break; + default: + printf("invalid error: %d\n", errn); + break; + } +} STYLE get_style() { return args.style; @@ -35,6 +86,10 @@ struct color** get_colors() { return args.colors; } +int get_gpu_idx() { + return args.gpu_idx; +} + bool show_help() { return args.help_flag; } @@ -58,7 +113,7 @@ char* build_short_options() { char* str = (char *) emalloc(sizeof(char) * (len*2 + 1)); memset(str, 0, sizeof(char) * (len*2 + 1)); - sprintf(str, "%c%c", + sprintf(str, "%c:%c%c", c[ARG_GPU], c[ARG_HELP], c[ARG_VERSION]); return str; @@ -71,8 +126,10 @@ bool parse_args(int argc, char* argv[]) { args.version_flag = false; args.help_flag = false; + args.gpu_idx = 0; const struct option long_options[] = { + {args_str[ARG_GPU], required_argument, 0, args_chr[ARG_GPU] }, {args_str[ARG_HELP], no_argument, 0, args_chr[ARG_HELP] }, {args_str[ARG_VERSION], no_argument, 0, args_chr[ARG_VERSION] }, {0, 0, 0, 0} @@ -82,7 +139,16 @@ bool parse_args(int argc, char* argv[]) { opt = getopt_long(argc, argv, short_options, long_options, &option_index); while (!args.help_flag && !args.version_flag && opt != -1) { - if(opt == args_chr[ARG_HELP]) { + if(opt == args_chr[ARG_GPU]) { + args.gpu_idx = getarg_int(optarg); + if(errn != 0) { + printErr("Option %s: ", args_str[ARG_GPU]); + print_getarg_error(); + args.help_flag = true; + return false; + } + } + else if(opt == args_chr[ARG_HELP]) { args.help_flag = true; } else if(opt == args_chr[ARG_VERSION]) { diff --git a/src/common/args.hpp b/src/common/args.hpp index a8be61f..c6de463 100644 --- a/src/common/args.hpp +++ b/src/common/args.hpp @@ -19,6 +19,7 @@ enum { }; enum { + ARG_GPU, ARG_HELP, ARG_VERSION }; @@ -33,6 +34,7 @@ bool parse_args(int argc, char* argv[]); bool show_help(); bool show_version(); void free_colors_struct(struct color** cs); +int get_gpu_idx(); struct color** get_colors(); STYLE get_style(); diff --git a/src/common/main.cpp b/src/common/main.cpp index 8b2cb9d..92eb14a 100644 --- a/src/common/main.cpp +++ b/src/common/main.cpp @@ -18,6 +18,7 @@ void print_help(char *argv[]) { printf("Simple yet fancy GPU architecture fetching tool\n\n"); printf("Options: \n"); + printf(" -%c, --%s %*s Selects the GPU to use (default: 0)\n", c[ARG_GPU], t[ARG_GPU], (int) (max_len-strlen(t[ARG_GPU])), ""); printf(" -%c, --%s %*s Prints this help and exit\n", c[ARG_HELP], t[ARG_HELP], (int) (max_len-strlen(t[ARG_HELP])), ""); printf(" -%c, --%s %*s Prints gpufetch version and exit\n", c[ARG_VERSION], t[ARG_VERSION], (int) (max_len-strlen(t[ARG_VERSION])), ""); @@ -56,7 +57,7 @@ If you want to help to improve gpufetch, please compare the output of the progra with a reliable source which you know is right (e.g, techpowerup.com) and report\n\ any inconsistencies to https://github.com/Dr-Noob/gpufetch/issues"); - struct gpu_info* gpu = get_gpu_info(); + struct gpu_info* gpu = get_gpu_info(get_gpu_idx()); if(gpu == NULL) return EXIT_FAILURE; diff --git a/src/common/printer.cpp b/src/common/printer.cpp index ca7f9b5..93a5f3b 100644 --- a/src/common/printer.cpp +++ b/src/common/printer.cpp @@ -399,12 +399,6 @@ bool print_gpufetch_cuda(struct gpu_info* gpu, STYLE s, struct color** cs, struc free(art->attributes); free(art); - /* if(cs != NULL) free_colors_struct(cs); - free_cache_struct(cpu->cach); - free_topo_struct(cpu->topo); - free_freq_struct(cpu->freq); - free_cpuinfo_struct(cpu);*/ - return true; } diff --git a/src/cuda/cuda.cpp b/src/cuda/cuda.cpp index 562e4fd..e140bb4 100644 --- a/src/cuda/cuda.cpp +++ b/src/cuda/cuda.cpp @@ -64,25 +64,43 @@ int64_t get_peak_performance(struct gpu_info* gpu) { return gpu->freq * 1000000 * gpu->topo->cuda_cores * 2; } -struct gpu_info* get_gpu_info() { +struct gpu_info* get_gpu_info(int gpu_idx) { struct gpu_info* gpu = (struct gpu_info*) emalloc(sizeof(struct gpu_info)); gpu->pci = NULL; + if(gpu_idx < 0) { + printErr("GPU index must be equal or greater than zero"); + return NULL; + } + printf("Waiting for CUDA driver to start..."); fflush(stdout); - int dev = 0; - cudaSetDevice(dev); - cudaDeviceProp deviceProp; - cudaGetDeviceProperties(&deviceProp, dev); + + int num_gpus = -1; + cudaGetDeviceCount(&num_gpus); printf("\r "); + if(num_gpus <= 0) { + printErr("No CUDA capable devices found!"); + return NULL; + } + + if(gpu_idx+1 > num_gpus) { + printErr("Requested GPU index %d in a system with %d GPUs", gpu_idx, num_gpus); + return NULL; + } + + cudaSetDevice(gpu_idx); + cudaDeviceProp deviceProp; + cudaGetDeviceProperties(&deviceProp, gpu_idx); + gpu->freq = deviceProp.clockRate * 1e-3f; gpu->vendor = GPU_VENDOR_NVIDIA; gpu->name = (char *) emalloc(sizeof(char) * (strlen(deviceProp.name) + 1)); strcpy(gpu->name, deviceProp.name); gpu->nvmld = nvml_init(); - if(nvml_get_pci_info(dev, gpu->nvmld)) { + if(nvml_get_pci_info(gpu_idx, gpu->nvmld)) { gpu->pci = get_pci_from_nvml(gpu->nvmld); } diff --git a/src/cuda/cuda.hpp b/src/cuda/cuda.hpp index 72ea92a..cbd4d8f 100644 --- a/src/cuda/cuda.hpp +++ b/src/cuda/cuda.hpp @@ -3,7 +3,7 @@ #include "../common/gpu.hpp" -struct gpu_info* get_gpu_info(); +struct gpu_info* get_gpu_info(int gpu_idx); char* get_str_sm(struct gpu_info* gpu); char* get_str_cores_sm(struct gpu_info* gpu); char* get_str_cuda_cores(struct gpu_info* gpu);