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 /constant_cycles_kernel.cu | |
| 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.
Diffstat (limited to 'constant_cycles_kernel.cu')
| -rw-r--r-- | constant_cycles_kernel.cu | 56 |
1 files changed, 56 insertions, 0 deletions
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 | } | ||
