Download src/ds4_gpu_args.c from julianmb/ds4fa: direct link, hf CLI and curl.
- Browser
- Download file 8.59 kB
-
https://huggingface.co/julianmb/ds4fa/resolve/main/src/ds4_gpu_args.c
- Command line
-
hf download hf://julianmb/ds4fa/src/ds4_gpu_args.c
-
curl -L -o ds4_gpu_args.c https://huggingface.co/julianmb/ds4fa/resolve/main/src/ds4_gpu_args.c
8.59 kB
| /* ds4_gpu_args.c — shared parser for --gpu-vram and --gpu-devices. | |
| * | |
| * See ds4_gpu_args.h. The actual CUDA probing for the "auto" branch | |
| * lives in ds4_cuda.cu so this .c file never includes <cuda_runtime.h> | |
| * directly (mirroring the rest of the tree's separation between .c and | |
| * .cu compilation units). | |
| */ | |
| /* Helper: copy at most outlen-1 bytes of msg into out and NUL-terminate. */ | |
| static void errbuf_set(char *out, size_t outlen, const char *msg) { | |
| if (!out || outlen == 0) return; | |
| size_t n = strlen(msg); | |
| if (n >= outlen) n = outlen - 1; | |
| memcpy(out, msg, n); | |
| out[n] = '\0'; | |
| } | |
| static void errbuf_setf(char *out, size_t outlen, const char *fmt, ...) { | |
| if (!out || outlen == 0) return; | |
| va_list ap; | |
| va_start(ap, fmt); | |
| vsnprintf(out, outlen, fmt, ap); | |
| va_end(ap); | |
| } | |
| /* Maximum per-entry values. Generous, but small enough to keep all | |
| * downstream arithmetic safely inside size_t/int. */ | |
| /* Parse a comma-separated list of nonnegative integers into out_count | |
| * entries of out[]. Returns 0 on success, nonzero on parse error. | |
| * Empty entries (",,") or trailing/leading commas error. Per-entry | |
| * upper bound enforced via max_value (use LONG_MAX for "no cap"). */ | |
| static int parse_csv_int_list(const char *s, | |
| long *out, | |
| int *out_count, | |
| int max_count, | |
| long max_value, | |
| char *errbuf, | |
| size_t errbuflen, | |
| const char *what) { | |
| *out_count = 0; | |
| if (!s || !*s) { | |
| errbuf_setf(errbuf, errbuflen, "%s: empty value", what); | |
| return 1; | |
| } | |
| const char *p = s; | |
| while (*p) { | |
| /* Disallow leading whitespace inside the list. */ | |
| while (*p == ' ' || *p == '\t') p++; | |
| char *end = NULL; | |
| errno = 0; | |
| long v = strtol(p, &end, 10); | |
| if (end == p) { | |
| errbuf_setf(errbuf, errbuflen, "%s: not a number: '%s'", what, p); | |
| return 1; | |
| } | |
| if (errno != 0 || v < 0 || v > max_value) { | |
| errbuf_setf(errbuf, errbuflen, | |
| "%s: out-of-range value: '%s' (allowed 0..%ld)", | |
| what, p, max_value); | |
| return 1; | |
| } | |
| if (*out_count >= max_count) { | |
| errbuf_setf(errbuf, errbuflen, "%s: too many entries (max %d)", what, max_count); | |
| return 1; | |
| } | |
| out[*out_count] = v; | |
| (*out_count)++; | |
| while (*end == ' ' || *end == '\t') end++; | |
| if (*end == ',') { | |
| end++; | |
| if (*end == '\0' || *end == ',') { | |
| errbuf_setf(errbuf, errbuflen, "%s: empty entry near '%s'", what, end); | |
| return 1; | |
| } | |
| } else if (*end != '\0') { | |
| errbuf_setf(errbuf, errbuflen, "%s: junk after value: '%s'", what, end); | |
| return 1; | |
| } | |
| p = end; | |
| } | |
| if (*out_count == 0) { | |
| errbuf_setf(errbuf, errbuflen, "%s: no values parsed", what); | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| int parse_gpu_vram_arg(const char *vram_arg, | |
| const char *devices_arg, | |
| ds4_gpu_config *out, | |
| bool *out_skip_cuda, | |
| char *errbuf, | |
| size_t errbuflen) { | |
| if (!out || !out_skip_cuda) { | |
| errbuf_set(errbuf, errbuflen, "internal: NULL out parameter"); | |
| return 1; | |
| } | |
| *out_skip_cuda = false; | |
| /* Caller zeroed *out — just confirm. */ | |
| out->n_gpus = 0; | |
| out->safety_margin_bytes = DS4_GPU_ARGS_DEFAULT_SAFETY_MARGIN; | |
| /* Parse devices_arg first so we have the filter when handling "auto". */ | |
| long dev_list[DS4_MAX_GPUS] = {0}; | |
| int dev_count = 0; | |
| if (devices_arg) { | |
| if (parse_csv_int_list(devices_arg, dev_list, &dev_count, | |
| DS4_MAX_GPUS, | |
| DS4_GPU_ARGS_MAX_DEVICE_INDEX, | |
| errbuf, errbuflen, | |
| "--gpu-devices") != 0) { | |
| return 1; | |
| } | |
| } | |
| /* Case 1: vram_arg unset. */ | |
| if (vram_arg == NULL) { | |
| if (devices_arg == NULL) { | |
| errbuf_set(errbuf, errbuflen, "internal: parse_gpu_vram_arg called with both args NULL"); | |
| return 1; | |
| } | |
| /* --gpu-devices given without --gpu-vram: implicit auto with filter. */ | |
| vram_arg = "auto"; | |
| } | |
| /* Case 2: --gpu-vram 0 — short-circuit. */ | |
| if (!strcmp(vram_arg, "0")) { | |
| if (devices_arg) { | |
| errbuf_set(errbuf, errbuflen, | |
| "--gpu-vram 0 conflicts with --gpu-devices"); | |
| return 1; | |
| } | |
| *out_skip_cuda = true; | |
| return 0; | |
| } | |
| /* Case 3: --gpu-vram auto. */ | |
| if (!strcmp(vram_arg, "auto")) { | |
| int filter_buf[DS4_MAX_GPUS]; | |
| const int *filter_ptr = NULL; | |
| if (dev_count > 0) { | |
| for (int i = 0; i < dev_count; i++) filter_buf[i] = (int)dev_list[i]; | |
| filter_ptr = filter_buf; | |
| } | |
| if (ds4_gpu_args_probe_auto_cuda(filter_ptr, dev_count, out, | |
| out->safety_margin_bytes, | |
| errbuf, errbuflen) != 0) { | |
| return 1; | |
| } | |
| return 0; | |
| (void)dev_list; (void)dev_count; | |
| errbuf_set(errbuf, errbuflen, | |
| "--gpu-vram auto requires a CUDA build"); | |
| return 1; | |
| } | |
| /* Case 4: explicit GB budgets — "N[,N...]" */ | |
| long vram_list[DS4_MAX_GPUS] = {0}; | |
| int vram_count = 0; | |
| if (parse_csv_int_list(vram_arg, vram_list, &vram_count, | |
| DS4_MAX_GPUS, | |
| DS4_GPU_ARGS_MAX_VRAM_GB, | |
| errbuf, errbuflen, | |
| "--gpu-vram") != 0) { | |
| return 1; | |
| } | |
| if (dev_count > 0 && dev_count != vram_count) { | |
| errbuf_setf(errbuf, errbuflen, | |
| "--gpu-devices count (%d) does not match --gpu-vram count (%d)", | |
| dev_count, vram_count); | |
| return 1; | |
| } | |
| out->n_gpus = vram_count; | |
| for (int i = 0; i < vram_count; i++) { | |
| int dev_id = (dev_count > 0) ? (int)dev_list[i] : i; | |
| out->device_indices[i] = dev_id; | |
| out->vram_bytes[i] = (size_t)vram_list[i] * (size_t)1024 * 1024 * 1024; | |
| } | |
| return 0; | |
| } | |
| int format_gpu_layout_line(const ds4_gpu_config *cfg, | |
| bool was_auto, | |
| char *out, | |
| size_t outlen) { | |
| if (!out || outlen == 0 || !cfg) return -1; | |
| /* "ds4: GPU config: N devices [d0,d1,...] requested, budgets G0,G1,... GB; auto=<bool>" */ | |
| int written = snprintf(out, outlen, | |
| "ds4: GPU config: %d device%s [", | |
| cfg->n_gpus, cfg->n_gpus == 1 ? "" : "s"); | |
| if (written < 0 || (size_t)written >= outlen) return written; | |
| for (int i = 0; i < cfg->n_gpus; i++) { | |
| int n = snprintf(out + written, outlen - (size_t)written, | |
| "%s%d", i ? "," : "", cfg->device_indices[i]); | |
| if (n < 0 || (size_t)(written + n) >= outlen) return written + n; | |
| written += n; | |
| } | |
| int n = snprintf(out + written, outlen - (size_t)written, | |
| "] requested, budgets "); | |
| if (n < 0 || (size_t)(written + n) >= outlen) return written + n; | |
| written += n; | |
| for (int i = 0; i < cfg->n_gpus; i++) { | |
| double gb = (double)cfg->vram_bytes[i] / (1024.0 * 1024.0 * 1024.0); | |
| int m = snprintf(out + written, outlen - (size_t)written, | |
| "%s%.0f", i ? "," : "", gb); | |
| if (m < 0 || (size_t)(written + m) >= outlen) return written + m; | |
| written += m; | |
| } | |
| int t = snprintf(out + written, outlen - (size_t)written, | |
| " GB; auto=%s", was_auto ? "true" : "false"); | |
| if (t < 0) return t; | |
| written += t; | |
| return written; | |
| } | |