aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoshua Bakita <bakitajoshua@gmail.com>2025-05-05 03:13:30 -0400
committerJoshua Bakita <bakitajoshua@gmail.com>2025-05-05 03:13:30 -0400
commitc250928930cb5c95bffc878913301f9a5d4efcb7 (patch)
tree8de8e20d727b69c5fa6228ce35daa8b1fbf96c12
parent72ba87e277572eddb25784563faa3eac111c9556 (diff)
De-duplicate CUDA version checks and omit when building with CUDA > 6.5HEADmaster
Code built with CUDA > 6.5 cannot run on CUDA 6.5 or older, so the check added unecessary overhead. Tested on CUDA 6.5 and CUDA 10.2 to generate the correct code, and global and next tested to work on GTX 1060 3 GB with either build while using CUDA 10.2 at runtime.
-rw-r--r--libsmctrl.c37
1 files changed, 16 insertions, 21 deletions
diff --git a/libsmctrl.c b/libsmctrl.c
index 5a45611..5ee94fb 100644
--- a/libsmctrl.c
+++ b/libsmctrl.c
@@ -119,10 +119,23 @@ static void setup_sm_control_callback() {
119 int (*enable)(uint32_t enable, uint32_t hndl, int domain, int cbid); 119 int (*enable)(uint32_t enable, uint32_t hndl, int domain, int cbid);
120 uintptr_t* tbl_base; 120 uintptr_t* tbl_base;
121 uint32_t my_hndl; 121 uint32_t my_hndl;
122 // Avoid race conditions (setup can only be called once) 122 // Avoid race conditions (setup should only run once)
123 if (__atomic_test_and_set(&sm_control_setup_called, __ATOMIC_SEQ_CST)) 123 if (__atomic_test_and_set(&sm_control_setup_called, __ATOMIC_SEQ_CST))
124 return; 124 return;
125 125
126#if CUDA_VERSION <= 6050
127 // Verify supported CUDA version
128 // It's impossible for us to run with a version of CUDA older than we were
129 // built by, so this check is excluded if built with CUDA > 6.5.
130 int ver = 0;
131 cuDriverGetVersion(&ver);
132 if (ver < 6050)
133 abort(1, ENOSYS, "Global or next masking requires at least CUDA 6.5; "
134 "this application is using CUDA %d.%d",
135 ver / 1000, (ver % 100));
136#endif
137
138 // Set up callback
126 cuGetExportTable((const void**)&tbl_base, &callback_funcs_id); 139 cuGetExportTable((const void**)&tbl_base, &callback_funcs_id);
127 uintptr_t subscribe_func_addr = *(tbl_base + 3); 140 uintptr_t subscribe_func_addr = *(tbl_base + 3);
128 uintptr_t enable_func_addr = *(tbl_base + 6); 141 uintptr_t enable_func_addr = *(tbl_base + 6);
@@ -139,31 +152,13 @@ static void setup_sm_control_callback() {
139 152
140// Set default mask for all launches 153// Set default mask for all launches
141void libsmctrl_set_global_mask(uint64_t mask) { 154void libsmctrl_set_global_mask(uint64_t mask) {
142 if (!sm_control_setup_called) { 155 setup_sm_control_callback();
143 // The version will not change while running, so only check once
144 int ver = 0;
145 cuDriverGetVersion(&ver);
146 if (ver < 6050)
147 abort(1, ENOSYS, "Global masking requires at least CUDA 6.5; "
148 "this application is using CUDA %d.%d",
149 ver / 1000, (ver % 100));
150 setup_sm_control_callback();
151 }
152 g_sm_mask = mask; 156 g_sm_mask = mask;
153} 157}
154 158
155// Set mask for next launch from this thread 159// Set mask for next launch from this thread
156void libsmctrl_set_next_mask(uint64_t mask) { 160void libsmctrl_set_next_mask(uint64_t mask) {
157 if (!sm_control_setup_called) { 161 setup_sm_control_callback();
158 // The version will not change while running, so only check once
159 int ver = 0;
160 cuDriverGetVersion(&ver);
161 if (ver < 6050)
162 abort(1, ENOSYS, "Next masking requires at least CUDA 6.5; "
163 "this application is using CUDA %d.%d",
164 ver / 1000, (ver % 100));
165 setup_sm_control_callback();
166 }
167 g_next_sm_mask = mask; 162 g_next_sm_mask = mask;
168} 163}
169 164
class="hl ppc">#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <time.h> #include <string.h> #include <inttypes.h> #include <assert.h> #include <limits.h> #include <fcntl.h> #include <errno.h> /* #include "litmus.h" #include "common.h" */ /* CPU time consumed so far in seconds */ double cputime(void) { struct timespec ts; int err; err = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); if (err != 0) perror("clock_gettime"); return (ts.tv_sec + 1E-9 * ts.tv_nsec); } /* wall-clock time in seconds */ double wctime(void) { struct timeval tv; gettimeofday(&tv, NULL); return (tv.tv_sec + 1E-6 * tv.tv_usec); } void bail_out(const char* msg) { perror(msg); exit(-1 * errno); } #include "extra.h" #define PAGE_SIZE (4096) #define CACHELINE_SIZE 64 #define INTS_IN_CACHELINE (CACHELINE_SIZE/sizeof(int)) #define CACHELINES_IN_1KB (1024 / sizeof(cacheline_t)) #define INTS_IN_1KB (1024 / sizeof(int)) typedef struct cacheline { int line[INTS_IN_CACHELINE]; } __attribute__((aligned(CACHELINE_SIZE))) cacheline_t; static volatile cacheline_t* arena = NULL; #define UNCACHE_DEV "/dev/litmus/uncache" #define FAKE_DEV "/dev/litmus/fakedev0" static cacheline_t* alloc_arena(size_t size, int use_huge_pages, int use_uncache_pages) { int flags = MAP_PRIVATE | MAP_POPULATE; cacheline_t* arena = NULL; int fd; if(use_huge_pages) flags |= MAP_HUGETLB; if(use_uncache_pages == 1) { fd = open(UNCACHE_DEV, O_RDWR|O_SYNC); if (fd == -1) bail_out("Failed to open uncache device. Are you running the LITMUS^RT kernel?"); } else if (use_uncache_pages == 2) { fd = open(FAKE_DEV, O_RDWR|O_SYNC); if (fd == -1) bail_out("Failed to open fake device. Are you running the LITMUS^RT kernel?"); } else { fd = -1; flags |= MAP_ANONYMOUS; } arena = (cacheline_t*)mmap(0, size, PROT_READ | PROT_WRITE, flags, fd, 0); if(use_uncache_pages) close(fd); assert(arena); return arena; } static void dealloc_arena(cacheline_t* arena, size_t size) { int ret = munmap((void*)arena, size); if(ret != 0) bail_out("munmap() error"); } static int randrange(int min, int max) { // Range is [min, max) assert(max - min - 1 <= RAND_MAX); return rand() % (max - min) + min; //return (rand() % (max - min + 1)) + min; /* generate a random number on the range [min, max) w/o skew */ /*int limit = max - min; int devisor = RAND_MAX/limit; int retval; do { retval = rand() / devisor; } while(retval == limit); retval += min; return retval;*/ } static void init_arena(volatile cacheline_t* arena, size_t size) { int i; size_t num_arena_elem = size / sizeof(cacheline_t); /* Generate a cycle among the cache lines using Sattolo's algorithm. Every int in the cache line points to the same cache line. Note: Sequential walk doesn't care about these values. */ for (i = 0; i < num_arena_elem; i++) { int j; for(j = 0; j < INTS_IN_CACHELINE; j++) arena[i].line[j] = i; arena[i].line[1] = 0; } /*while(1 < i--) { int j = randrange(0, i); cacheline_t temp = arena[j]; arena[j] = arena[i]; arena[i] = temp; }*/ for (int j = 0; j < num_arena_elem-1; j++) { int k = randrange(j+1, num_arena_elem); cacheline_t temp = arena[j]; arena[j] = arena[k]; arena[k] = temp; } } /* Random walk around the arena in cacheline-sized chunks. Cacheline-sized chucks ensures the same utilization of each hit line as sequential read. (Otherwise, our utilization would only be 1/INTS_IN_CACHELINE.) */ static int random_walk(volatile cacheline_t *mem, int wss, int write_cycle) { /* a random cycle among the cache lines was set up by init_arena(). */ int sum, i, next; // Always do the same number of hops int numlines = 33554432 / CACHELINE_SIZE;//wss * CACHELINES_IN_1KB; sum = 0; /* contents of arena is structured s.t. offsets are all w.r.t. to start of arena, so compute the initial offset */ next = mem - arena; if (write_cycle == 0) { for (i = 0; i < numlines; i++) { next = arena[next].line[0]; arena[next].line[1] = 1; // Record that we touched this line sum += next; for (int j = 2; j < INTS_IN_CACHELINE; j++) arena[next].line[j]++; } } else { int w, which_line; for (i = 0, w = 0; i < numlines; i++) { which_line = next; next = arena[next].line[0]; if((w % write_cycle) != (write_cycle - 1)) { // This is equivalent to 1 % 1 != 1 - 1 which is always false sum += next; } else { // I /think/ that this just writes back to the address it read from arena[which_line].line[0] = next; } } } return sum; } volatile static cacheline_t* random_start(int wss) { return arena + randrange(0, ((wss * 1024)/sizeof(cacheline_t))); } /* static int sequential_walk(cacheline_t *_mem, int wss, int write_cycle) { int sum = 0, i; int* mem = (int*)_mem; // treat as raw buffer of ints int num_ints = wss * INTS_IN_1KB; if (write_cycle > 0) { for (i = 0; i < num_ints; i++) { if (i % write_cycle == (write_cycle - 1)) mem[i]++; else sum += mem[i]; } } else { // sequential access, pure read for (i = 0; i < num_ints; i++) sum += mem[i]; } return sum; } static cacheline_t* sequential_start(int wss) { static int pos = 0; int num_cachelines = wss * CACHELINES_IN_1KB; cacheline_t *mem; * Don't allow re-use between allocations. * At most half of the arena may be used * at any one time. * if (num_cachelines * 2 > ((wss * 1024)/sizeof(cacheline_t))) ;//bail_out("static memory arena too small"); if (pos + num_cachelines > ((wss * 1024)/sizeof(cacheline_t))) { // wrap to beginning mem = arena; pos = num_cachelines; } else { mem = arena + pos; pos += num_cachelines; } return mem; } */ static volatile int dont_optimize_me = 0; #define RANDOM_WALK 1 static int loop_once(int wss, int write) { volatile cacheline_t *mem; int temp; #ifdef RANDOM_WALK mem = random_start(wss); // printf("Using start offset %ld. Data here is %d. data size: %ld\n", mem-arena, mem->line[0], sizeof(mem->line[0])); temp = random_walk(mem, wss, write); #else mem = sequential_start(wss); temp = sequential_walk(mem, wss, write); #endif dont_optimize_me = temp; // printf("%d", dont_optimize_me); return dont_optimize_me; } int main(int argc, char** argv) { SET_UP int write; long wss; double duration; double program_end; // Reads in benchmark params from stdin // <long: wss in bytes> <float: duration in seconds> <bool: if we should also write> if (scanf("%ld %lf %d", &wss, &duration, &write) != 3) { fprintf(stderr, "Bad input, please enter 3 parameters: <WSS (Int)> <Duration (Double)> <Write (Bool)>.\n"); exit(1); } printf("random_walk: Using parameters: %ld, %lf, %d\n", wss, duration, write); wss /= 1024; program_end = duration + wctime(); // Initialize memory size_t arena_sz = wss*1024; arena = alloc_arena(arena_sz*2, 0, 0); init_arena(arena, arena_sz); loop_once(wss, write); // This loop contains the original content of job(int wss, int write, double exec_time, double program_end) while (1) { double emergency_exit = program_end + 1; if (wctime() > program_end) { break; } else { double last_loop = 0, loop_start; int tmp = 0; double start = cputime(); double now = cputime(); //while (now + last_loop < start) {// + exec_time) { loop_start = now; START_LOOP tmp += loop_once(wss, write); STOP_LOOP now = cputime(); last_loop = now - loop_start; if (emergency_exit && wctime() > emergency_exit) { /* Oops --- this should only be possible if the execution time tracking * is broken in the LITMUS^RT kernel. */ fprintf(stderr, "!!! rtspin/%d emergency exit!\n", getpid()); fprintf(stderr, "Something is seriously wrong! Do not ignore this.\n"); break; }