diff options
| author | Joshua Bakita <bakitajoshua@gmail.com> | 2023-06-09 19:38:01 -0400 |
|---|---|---|
| committer | Joshua Bakita <bakitajoshua@gmail.com> | 2023-06-09 19:38:01 -0400 |
| commit | 5ba80e14efb595688a3dc3d49c212bc393840513 (patch) | |
| tree | 87b57ee39eaf0c12603eb1b6f4ea9e0889a20e8e | |
| parent | e63404cfda97050b9d516232ceb4f918f48edcfc (diff) | |
Add constant_cycles_kernel benchmark + header split and Makefile
Benchmark supports:
=> Looping on the GPU for a specified number of iterations
=> Looping infinitely on the GPU
=> Logging the sum time (ns and ms) for all iterations to complete
Also splits `testbench.h` out of `copy_testbench.h` for use in other
benchmarks.
| -rw-r--r-- | Makefile | 7 | ||||
| -rw-r--r-- | constant_cycles_kernel.cu | 56 | ||||
| -rw-r--r-- | copy_experiments/Makefile | 3 | ||||
| -rw-r--r-- | copy_experiments/copy_testbench.h | 15 | ||||
| -rw-r--r-- | testbench.h | 14 |
5 files changed, 80 insertions, 15 deletions
| @@ -1,4 +1,9 @@ | |||
| 1 | .PHONY: copy_experiments | 1 | .PHONY: all copy_experiments |
| 2 | |||
| 3 | all: constant_cycles_kernel copy_experiments | ||
| 4 | |||
| 5 | constant_cycles_kernel: constant_cycles_kernel.cu testbench.h | ||
| 6 | nvcc constant_cycles_kernel.cu -o constant_cycles_kernel | ||
| 2 | 7 | ||
| 3 | copy_experiments: | 8 | copy_experiments: |
| 4 | $(MAKE) -C $@ | 9 | $(MAKE) -C $@ |
diff --git a/constant_cycles_kernel.cu b/constant_cycles_kernel.cu new file mode 100644 index 0000000..eda963d --- /dev/null +++ b/constant_cycles_kernel.cu | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | /* Copyright 2021-2023 Joshua Bakita | ||
| 2 | * Simple kernel that spins on the GPU for a specified number of iterations, | ||
| 3 | * while tracking and printing the necessary CPU time. | ||
| 4 | */ | ||
| 5 | #include <time.h> | ||
| 6 | #include <stdio.h> | ||
| 7 | #include <cuda.h> | ||
| 8 | |||
| 9 | #include "testbench.h" | ||
| 10 | |||
| 11 | __global__ void loop_on_gpu(unsigned long iters, int *__unused) { | ||
| 12 | for (volatile int i = 0; i < iters; i++) (*__unused)++; | ||
| 13 | } | ||
| 14 | |||
| 15 | int main(int argc, char **argv) { | ||
| 16 | cudaError_t err; | ||
| 17 | int res, *__unused; | ||
| 18 | struct timespec start, end; | ||
| 19 | |||
| 20 | if (argc != 2) { | ||
| 21 | fprintf(stderr, "Usage: %s <# of millions of iterations, or -1 for infinite>\n", | ||
| 22 | argv[0]); | ||
| 23 | return 1; | ||
| 24 | } | ||
| 25 | |||
| 26 | // Input is multiplied by one million, unless infinite | ||
| 27 | unsigned long num_iters = strtoul(argv[1], NULL, 10); | ||
| 28 | if (num_iters != (unsigned long)(-1)) | ||
| 29 | num_iters *= 1000 * 1000; | ||
| 30 | |||
| 31 | // Initialize CUDA and a context (hack) | ||
| 32 | SAFE(cudaMalloc(&__unused, 8)); | ||
| 33 | |||
| 34 | // Run iterations on a single thread | ||
| 35 | clock_gettime(CLOCK_MONOTONIC_RAW, &start); | ||
| 36 | loop_on_gpu<<<1,1>>>(num_iters, __unused); | ||
| 37 | SAFE(cudaGetLastError() /* Check successful launch */); | ||
| 38 | SAFE(cudaDeviceSynchronize()); | ||
| 39 | clock_gettime(CLOCK_MONOTONIC_RAW, &end); | ||
| 40 | |||
| 41 | // Print detailed timing information | ||
| 42 | long elapsed = timediff(start, end); | ||
| 43 | fprintf(stderr, "Started at %ld ns, ended at %ld ns\n", | ||
| 44 | s2ns(start.tv_sec) + start.tv_nsec, s2ns(end.tv_sec) + end.tv_nsec); | ||
| 45 | fprintf(stderr, "%ld ns (%.2f ms) elapsed\n", elapsed, elapsed / (1000 * 1000.)); | ||
| 46 | |||
| 47 | // Verify success (fool optimizer) | ||
| 48 | SAFE(cudaMemcpy(&res, __unused, 8, cudaMemcpyDeviceToHost)); | ||
| 49 | // Theoretically this can happen if `__unused` wraps around; maybe for a | ||
| 50 | // very small `long` type, or a very long run. More likely indicates an error. | ||
| 51 | if (!res) | ||
| 52 | fprintf(stderr, "CRITICAL: Zero iterations seem completed. Likely incorrect " | ||
| 53 | "arguments, internal error, or corruption of CUDA internal state.\n"); | ||
| 54 | |||
| 55 | return 0; | ||
| 56 | } | ||
diff --git a/copy_experiments/Makefile b/copy_experiments/Makefile index 2358c60..b6b5a38 100644 --- a/copy_experiments/Makefile +++ b/copy_experiments/Makefile | |||
| @@ -1,3 +1,2 @@ | |||
| 1 | 1 | copy_contender: copy_contender.cu copy_testbench.h ../testbench.h | |
| 2 | copy_contender: copy_contender.cu copy_testbench.h | ||
| 3 | /usr/local/cuda/bin/nvcc copy_contender.cu -o $@ -lcuda -g | 2 | /usr/local/cuda/bin/nvcc copy_contender.cu -o $@ -lcuda -g |
diff --git a/copy_experiments/copy_testbench.h b/copy_experiments/copy_testbench.h index e1c4aa5..fed62ba 100644 --- a/copy_experiments/copy_testbench.h +++ b/copy_experiments/copy_testbench.h | |||
| @@ -1,24 +1,15 @@ | |||
| 1 | /* Copyright 2023 Joshua Bakita | 1 | /* Copyright 2021-2023 Joshua Bakita |
| 2 | * Header-only library that provides an ultra-low-overhead GPU timing function, | 2 | * Header-only library that provides an ultra-low-overhead GPU timing function, |
| 3 | * a copy monitoring kernel, and other useful sundries. | 3 | * a copy monitoring kernel, and other useful sundries. |
| 4 | */ | 4 | */ |
| 5 | #include <stdio.h> | 5 | #include <stdio.h> |
| 6 | #include <stdint.h> | 6 | #include <stdint.h> |
| 7 | 7 | ||
| 8 | #include "../testbench.h" | ||
| 9 | |||
| 8 | // 4k pages (4096 bytes) | 10 | // 4k pages (4096 bytes) |
| 9 | #define PG_SZ 0x1000 | 11 | #define PG_SZ 0x1000 |
| 10 | 12 | ||
| 11 | #define SAFE(x) \ | ||
| 12 | if ((err = (cudaError_t)(x)) != 0) { \ | ||
| 13 | printf("CUDA error %d! %s\n", err, cudaGetErrorString(err)); \ | ||
| 14 | printf("Suspect line: %s\n", #x); \ | ||
| 15 | exit(1); \ | ||
| 16 | } | ||
| 17 | |||
| 18 | #define s2ns(s) ((s)*1000l*1000l*1000l) | ||
| 19 | #define ns2ms(s) ((s)/(1000l*1000l)) | ||
| 20 | #define timediff(start, end) ((s2ns((end).tv_sec) + (end).tv_nsec) - (s2ns((start).tv_sec) + (start).tv_nsec)) | ||
| 21 | |||
| 22 | // Compiles to 5 inline SASS instructions on sm_52 | 13 | // Compiles to 5 inline SASS instructions on sm_52 |
| 23 | static __device__ inline uint64_t gclock64_fast(void) { | 14 | static __device__ inline uint64_t gclock64_fast(void) { |
| 24 | uint32_t lo_bits; | 15 | uint32_t lo_bits; |
diff --git a/testbench.h b/testbench.h new file mode 100644 index 0000000..28d7f77 --- /dev/null +++ b/testbench.h | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | /* Copyright 2021-2023 Joshua Bakita | ||
| 2 | * Header for miscellaneous experimental helper functions. | ||
| 3 | */ | ||
| 4 | |||
| 5 | #define SAFE(x) \ | ||
| 6 | if ((err = (cudaError_t)(x)) != 0) { \ | ||
| 7 | printf("CUDA error %d! %s\n", err, cudaGetErrorString(err)); \ | ||
| 8 | printf("Suspect line: %s\n", #x); \ | ||
| 9 | exit(1); \ | ||
| 10 | } | ||
| 11 | |||
| 12 | #define s2ns(s) ((s)*1000l*1000l*1000l) | ||
| 13 | #define ns2ms(s) ((s)/(1000l*1000l)) | ||
| 14 | #define timediff(start, end) ((s2ns((end).tv_sec) + (end).tv_nsec) - (s2ns((start).tv_sec) + (start).tv_nsec)) | ||
