diff options
Diffstat (limited to 'copy_experiments/mon_cross_ctx_copies.cu')
| -rw-r--r-- | copy_experiments/mon_cross_ctx_copies.cu | 93 |
1 files changed, 65 insertions, 28 deletions
diff --git a/copy_experiments/mon_cross_ctx_copies.cu b/copy_experiments/mon_cross_ctx_copies.cu index b38d037..65ccd4e 100644 --- a/copy_experiments/mon_cross_ctx_copies.cu +++ b/copy_experiments/mon_cross_ctx_copies.cu | |||
| @@ -13,6 +13,22 @@ | |||
| 13 | #include <unistd.h> | 13 | #include <unistd.h> |
| 14 | #include <cuda.h> | 14 | #include <cuda.h> |
| 15 | #include <pthread.h> | 15 | #include <pthread.h> |
| 16 | #include <argp.h> | ||
| 17 | |||
| 18 | // Data for the help text(s) | ||
| 19 | const char* maintainer = "<jbakita@cs.unc.edu>"; | ||
| 20 | const char* version = "mon_cross_ctx_copies 2023.06"; | ||
| 21 | const char* desc = | ||
| 22 | "Copy data to, from, or between GPU(s) and log the time that each block " | ||
| 23 | "of the copy completes. Data need not be transferred sequentially for " | ||
| 24 | "transfer times to be properly recorded."; | ||
| 25 | |||
| 26 | const struct argp_option opts[] = { | ||
| 27 | {"copy_size", 's', "NUM_PAGES", 0, "Number of 4KiB pages to copy"}, | ||
| 28 | {"gpu", 'g', /*"DIRECTION"*/0, 0, "Add a GPU-monitored copy thread (can be duplicated)"}, | ||
| 29 | {"cpu", 'c', /*"DIRECTION"*/0, 0, "Add a CPU-monitored copy thread (can be duplicated)"}, | ||
| 30 | {0} | ||
| 31 | }; | ||
| 16 | 32 | ||
| 17 | // CPU-only monitoring can only go a fraction of the speed of GPU monitoring. | 33 | // CPU-only monitoring can only go a fraction of the speed of GPU monitoring. |
| 18 | // This sets how much slower it should go. | 34 | // This sets how much slower it should go. |
| @@ -47,7 +63,7 @@ typedef enum { | |||
| 47 | } my_config_t; | 63 | } my_config_t; |
| 48 | 64 | ||
| 49 | typedef struct { | 65 | typedef struct { |
| 50 | int *cond_var; | 66 | int is_ready; |
| 51 | my_config_t config; | 67 | my_config_t config; |
| 52 | } copy_thread_args_t; | 68 | } copy_thread_args_t; |
| 53 | 69 | ||
| @@ -127,7 +143,7 @@ void* copy_thread(void* args_raw) { | |||
| 127 | } | 143 | } |
| 128 | 144 | ||
| 129 | // Tell our parent we're ready | 145 | // Tell our parent we're ready |
| 130 | *args->cond_var = 1; | 146 | args->is_ready = 1; |
| 131 | // Wait for our parent to tell us to go | 147 | // Wait for our parent to tell us to go |
| 132 | while (!READY) | 148 | while (!READY) |
| 133 | continue; | 149 | continue; |
| @@ -193,29 +209,42 @@ void* copy_thread(void* args_raw) { | |||
| 193 | return times; | 209 | return times; |
| 194 | } | 210 | } |
| 195 | 211 | ||
| 212 | const int MAX_THREADS = 32; | ||
| 213 | |||
| 214 | typedef struct { | ||
| 215 | int num_threads; | ||
| 216 | copy_thread_args_t thread_args[MAX_THREADS]; | ||
| 217 | } global_args_t; | ||
| 218 | |||
| 219 | static error_t arg_parser(int key, char* arg, struct argp_state *state) { | ||
| 220 | global_args_t* g_args = (global_args_t*)state->input; | ||
| 221 | switch (key) { | ||
| 222 | case 's': | ||
| 223 | if (atol(arg) < CPU_MON_DIVISOR * 2) | ||
| 224 | argp_error(state, "Please specify a larger copy size. It must be at least %d pages for accurate tracking.\n", CPU_MON_DIVISOR * 2); | ||
| 225 | COPY_SIZE = atol(arg) * PG_SZ; | ||
| 226 | break; | ||
| 227 | case 'g': | ||
| 228 | if (g_args->num_threads == MAX_THREADS) | ||
| 229 | argp_error(state, "Please specify less than %d monitoring threads, or increase the compiled in MAX_THREADS constraint.\n", MAX_THREADS); | ||
| 230 | g_args->thread_args[g_args->num_threads++] = {0, GPU_MONITORING}; | ||
| 231 | break; | ||
| 232 | case 'c': | ||
| 233 | if (g_args->num_threads == MAX_THREADS) | ||
| 234 | argp_error(state, "Please specify less than %d monitoring threads, or increase the compiled in MAX_THREADS constraint.\n", MAX_THREADS); | ||
| 235 | g_args->thread_args[g_args->num_threads++] = {0, CPU_MONITORING}; | ||
| 236 | break; | ||
| 237 | default: | ||
| 238 | return ARGP_ERR_UNKNOWN; | ||
| 239 | } | ||
| 240 | return 0; | ||
| 241 | } | ||
| 242 | |||
| 196 | int main(int argc, char**argv) { | 243 | int main(int argc, char**argv) { |
| 197 | int tmp, dev; | 244 | int tmp, dev; |
| 198 | const int NUM_THREADS = 4; | 245 | uint64_t *ctx_times[MAX_THREADS] = {0}; |
| 199 | pthread_t t[NUM_THREADS]; | 246 | pthread_t t[MAX_THREADS]; |
| 200 | int is_thread_ready[NUM_THREADS] = {0}; | 247 | global_args_t g_args = {0}; |
| 201 | uint64_t *ctx_times[NUM_THREADS] = {0}; | ||
| 202 | // Setup thread condition variables and configuration (my_config_t enum) | ||
| 203 | copy_thread_args_t thread_args[NUM_THREADS] = { | ||
| 204 | {&is_thread_ready[0], CPU_MONITORING}, | ||
| 205 | {&is_thread_ready[1], CPU_MONITORING}, | ||
| 206 | {&is_thread_ready[2], CPU_MONITORING}, | ||
| 207 | {&is_thread_ready[3], CPU_MONITORING}, | ||
| 208 | };//, {&is_thread_ready[1], GPU_MONITORING}};//, {&is_thread_ready[2], CPU_MONITORING}, {&is_thread_ready[3], CPU_MONITORING}, {&is_thread_ready[4], CPU_MONITORING}, {&is_thread_ready[5], CPU_MONITORING}, {&is_thread_ready[6], CPU_MONITORING}, {&is_thread_ready[7], CPU_MONITORING}, {&is_thread_ready[8], CPU_MONITORING}}; | ||
| 209 | |||
| 210 | if (argc != 2) { | ||
| 211 | fprintf(stderr, "Usage: %s <# of 4KB pages to copy to GPU>\n", argv[0]); | ||
| 212 | return 1; | ||
| 213 | } | ||
| 214 | if (atol(argv[1]) < CPU_MON_DIVISOR * 2) { | ||
| 215 | fprintf(stderr, "Please specify a larger copy size. It must be at least %d pages for accurate tracking.\n", CPU_MON_DIVISOR * 2); | ||
| 216 | return 2; | ||
| 217 | } | ||
| 218 | COPY_SIZE = atol(argv[1]) * PG_SZ; | ||
| 219 | 248 | ||
| 220 | // Due to some laziness in how we handle barriers, this flag needs to be true | 249 | // Due to some laziness in how we handle barriers, this flag needs to be true |
| 221 | /// XXX: Still seems to work fine if it isn't??? | 250 | /// XXX: Still seems to work fine if it isn't??? |
| @@ -226,6 +255,14 @@ int main(int argc, char**argv) { | |||
| 226 | exit(1); | 255 | exit(1); |
| 227 | }*/ | 256 | }*/ |
| 228 | 257 | ||
| 258 | struct argp argp = {opts, arg_parser, 0, desc}; | ||
| 259 | argp_parse(&argp, argc, argv, 0, 0, &g_args); | ||
| 260 | |||
| 261 | if (g_args.num_threads == 0) { | ||
| 262 | fprintf(stderr, "At least one copy thread must be specified with --gpu or --cpu arguments.\n"); | ||
| 263 | return 3; | ||
| 264 | } | ||
| 265 | |||
| 229 | // TODO: Rewrite this so that it's all (u)int64_t | 266 | // TODO: Rewrite this so that it's all (u)int64_t |
| 230 | // Skip, as this is 1-to-1 on GV100 and GV11B | 267 | // Skip, as this is 1-to-1 on GV100 and GV11B |
| 231 | //double d2h_scale = GetGPUTimerScale(dev); | 268 | //double d2h_scale = GetGPUTimerScale(dev); |
| @@ -237,21 +274,21 @@ int main(int argc, char**argv) { | |||
| 237 | 274 | ||
| 238 | srand(0); | 275 | srand(0); |
| 239 | // Spawn and wait for children to intialize | 276 | // Spawn and wait for children to intialize |
| 240 | for (int tid = 0; tid < NUM_THREADS; tid++) { | 277 | for (int tid = 0; tid < g_args.num_threads; tid++) { |
| 241 | pthread_create(&t[tid], NULL, copy_thread, &thread_args[tid]); | 278 | pthread_create(&t[tid], NULL, copy_thread, &g_args.thread_args[tid]); |
| 242 | while (!is_thread_ready[tid]) | 279 | while (!g_args.thread_args[tid].is_ready) |
| 243 | continue; | 280 | continue; |
| 244 | } | 281 | } |
| 245 | // Tell children initialization is done and that they can go | 282 | // Tell children initialization is done and that they can go |
| 246 | READY = 1; | 283 | READY = 1; |
| 247 | // Wait for threads to finish, and determine the earliest recorded time | 284 | // Wait for threads to finish, and determine the earliest recorded time |
| 248 | uint64_t smallest = UINT64_MAX; | 285 | uint64_t smallest = UINT64_MAX; |
| 249 | for (int tid = 0; tid < NUM_THREADS; tid++) { | 286 | for (int tid = 0; tid < g_args.num_threads; tid++) { |
| 250 | pthread_join(t[tid], (void**)&ctx_times[tid]); | 287 | pthread_join(t[tid], (void**)&ctx_times[tid]); |
| 251 | smallest = min(smallest, ctx_times[tid][0]); | 288 | smallest = min(smallest, ctx_times[tid][0]); |
| 252 | } | 289 | } |
| 253 | // Rebase times to 0 and print | 290 | // Rebase times to 0 and print |
| 254 | for (int tid = 0; tid < NUM_THREADS; tid++) { | 291 | for (int tid = 0; tid < g_args.num_threads; tid++) { |
| 255 | // Summary to stderr | 292 | // Summary to stderr |
| 256 | fprintf(stderr, "%lu, %lu\n", ctx_times[tid][0] - smallest, ctx_times[tid][COPY_SIZE / PG_SZ - 1] - smallest); | 293 | fprintf(stderr, "%lu, %lu\n", ctx_times[tid][0] - smallest, ctx_times[tid][COPY_SIZE / PG_SZ - 1] - smallest); |
| 257 | // Full dataset to stdout | 294 | // Full dataset to stdout |
