Download tests/test_gpu_model_cache.c from julianmb/ds4fa: direct link, hf CLI and curl.
- Browser
- Download file 5.85 kB
-
https://huggingface.co/julianmb/ds4fa/resolve/main/tests/test_gpu_model_cache.c
- Command line
-
hf download hf://julianmb/ds4fa/tests/test_gpu_model_cache.c
-
curl -L -o test_gpu_model_cache.c https://huggingface.co/julianmb/ds4fa/resolve/main/tests/test_gpu_model_cache.c
5.85 kB
| /* Unit test for the per-device selective model cache | |
| * (mgpu-selective-model-cache). | |
| * | |
| * Exercises: | |
| * - ds4_gpu_device_cache_tensors with disjoint ranges on device 0 | |
| * - ds4_gpu_lookup_cache at range bases and at interior offsets | |
| * (proves the subrange pointer offset arithmetic is right) | |
| * - device-id resolution | |
| * - on multi-GPU boxes: caching on device 1 and active-device | |
| * preference in lookup */ | |
| int main(void) { | |
| int dev_count = 0; | |
| (void)cudaGetDeviceCount(&dev_count); | |
| fprintf(stderr, "test_gpu_model_cache: %d CUDA devices visible\n", | |
| dev_count); | |
| if (dev_count < 1) { | |
| fprintf(stderr, "no CUDA devices\n"); | |
| return 0; | |
| } | |
| CHECK(ds4_gpu_init(), "ds4_gpu_init"); | |
| /* Build a synthetic 1-MiB "model" in host memory. */ | |
| const size_t total = 1024 * 1024; | |
| void *host = NULL; | |
| CHECK(cudaMallocHost(&host, total) == cudaSuccess, "cudaMallocHost"); | |
| unsigned char *bytes = (unsigned char *)host; | |
| for (size_t i = 0; i < total; i++) bytes[i] = (unsigned char)(i & 0xff); | |
| CHECK(ds4_gpu_set_model_map(host, total), "set_model_map"); | |
| /* Three disjoint ranges on device 0. */ | |
| ds4_tensor_range ranges[3]; | |
| ranges[0].source_offset = 0; ranges[0].bytes = 256 * 1024; ranges[0].target_device = 0; | |
| ranges[1].source_offset = 384 * 1024; ranges[1].bytes = 128 * 1024; ranges[1].target_device = 0; | |
| ranges[2].source_offset = 768 * 1024; ranges[2].bytes = 256 * 1024; ranges[2].target_device = 0; | |
| CHECK(ds4_gpu_device_cache_tensors(0, ranges, 3) == 0, | |
| "device_cache_tensors dev 0 (3 ranges)"); | |
| /* Base lookups + interior offset arithmetic. */ | |
| int dev = -1; void *base0 = NULL, *interior0 = NULL; | |
| CHECK(ds4_gpu_lookup_cache(0, 1024, &dev, &base0) == 1, "lookup range 0 base"); | |
| CHECK(dev == 0, "range 0 device"); | |
| CHECK(base0 != NULL, "range 0 ptr"); | |
| /* An interior offset must return base0 + delta. */ | |
| CHECK(ds4_gpu_lookup_cache(100, 1024, &dev, &interior0) == 1, "lookup range 0 interior"); | |
| CHECK(dev == 0, "range 0 interior device"); | |
| CHECK(interior0 == (char *)base0 + 100, "interior offset arithmetic"); | |
| void *base1 = NULL; | |
| CHECK(ds4_gpu_lookup_cache(384 * 1024, 1024, &dev, &base1) == 1, "lookup range 1 base"); | |
| CHECK(dev == 0, "range 1 device"); | |
| /* Interior of range 1 at +200 bytes should be base1 + 200. */ | |
| void *interior1 = NULL; | |
| CHECK(ds4_gpu_lookup_cache(384 * 1024 + 200, 1024, &dev, &interior1) == 1, "lookup range 1 interior"); | |
| CHECK(interior1 == (char *)base1 + 200, "range 1 interior offset"); | |
| void *base2 = NULL; | |
| CHECK(ds4_gpu_lookup_cache(900 * 1024, 1024, &dev, &base2) == 1, "lookup range 2"); | |
| CHECK(dev == 0 && base2 != NULL, "range 2 device+ptr"); | |
| /* Convenience wrapper. */ | |
| CHECK(ds4_gpu_lookup_cache_device(0, 1024) == 0, "lookup_device range 0"); | |
| /* Lookup must be overflow-safe: a query with bytes=UINT64_MAX must | |
| * not wrap around into a false hit. */ | |
| int dev_overflow = -1; void *ptr_overflow = NULL; | |
| int hit = ds4_gpu_lookup_cache(100, UINT64_MAX, &dev_overflow, &ptr_overflow); | |
| /* Either miss (preferred), or hit but the path must NOT have wrapped. | |
| * Accept miss only — a wrap-induced hit would be a bug. */ | |
| CHECK(hit == 0, "lookup with bytes=UINT64_MAX does not wrap into a false hit"); | |
| /* Bounds-check: ranges that overflow the model must be rejected | |
| * before any allocation. */ | |
| ds4_tensor_range bad_overflow = { 0, total + 1, 0 }; | |
| CHECK(ds4_gpu_device_cache_tensors(0, &bad_overflow, 1) != 0, | |
| "overflow range rejected"); | |
| ds4_tensor_range bad_offset = { total + 1, 16, 0 }; | |
| CHECK(ds4_gpu_device_cache_tensors(0, &bad_offset, 1) != 0, | |
| "out-of-range offset rejected"); | |
| ds4_tensor_range bad_wrap = { total - 4, UINT64_MAX, 0 }; | |
| CHECK(ds4_gpu_device_cache_tensors(0, &bad_wrap, 1) != 0, | |
| "wrap-around range rejected"); | |
| /* Gap not covered by selective ranges. The legacy chunked path may | |
| * happen to cover it (it caches the whole model span); accept either | |
| * outcome, but if it returns 1 the device must be 0. */ | |
| int dev_gap = -1; void *ptr_gap = NULL; | |
| int gap_hit = ds4_gpu_lookup_cache(300 * 1024, 1024, &dev_gap, &ptr_gap); | |
| if (gap_hit) { | |
| CHECK(dev_gap == 0, "gap fallback device"); | |
| } | |
| if (dev_count >= 2) { | |
| /* Cache a different range on device 1. */ | |
| ds4_tensor_range r2; | |
| r2.source_offset = 256 * 1024; | |
| r2.bytes = 128 * 1024; | |
| r2.target_device = 1; | |
| CHECK(ds4_gpu_device_cache_tensors(1, &r2, 1) == 0, "cache dev 1"); | |
| /* With cudaGetDevice() == 1, the lookup should resolve to dev 1 | |
| * for this range (the only selective entry covering it). */ | |
| (void)cudaSetDevice(1); | |
| int dd = -1; void *pp = NULL; | |
| CHECK(ds4_gpu_lookup_cache(256 * 1024 + 10, 1024, &dd, &pp) == 1, | |
| "lookup dev 1"); | |
| CHECK(dd == 1, "lookup resolves to dev 1"); | |
| CHECK(pp != NULL, "lookup ptr non-null"); | |
| (void)cudaSetDevice(0); | |
| } | |
| ds4_gpu_cleanup(); | |
| (void)cudaFreeHost(host); | |
| fprintf(stderr, "test_gpu_model_cache PASS (devs=%d)\n", dev_count); | |
| return 0; | |
| } | |