diff options
author | Joshua Bakita <jbakita@cs.unc.edu> | 2020-10-16 16:55:14 -0400 |
---|---|---|
committer | Joshua Bakita <jbakita@cs.unc.edu> | 2020-10-16 16:55:14 -0400 |
commit | 6ea9939e0610a809f6f47d13ec68df00d1ca0afc (patch) | |
tree | fe4a2eee3ddcf77e2367309dcd75a232b76dcd62 /dis/random_walk.c | |
parent | e9285d0cdea756a2830f0ace378e4197b36869aa (diff) |
Move the DIS benchmarks up a directory and update hardcoded paths
Note that this repo does not attempt to keep a copy of the original
DIS benchmark distributions. UNC real-time has another repo for that.
Diffstat (limited to 'dis/random_walk.c')
-rw-r--r-- | dis/random_walk.c | 550 |
1 files changed, 550 insertions, 0 deletions
diff --git a/dis/random_walk.c b/dis/random_walk.c new file mode 100644 index 0000000..9f907bb --- /dev/null +++ b/dis/random_walk.c | |||
@@ -0,0 +1,550 @@ | |||
1 | #include <sys/time.h> | ||
2 | #include <sys/mman.h> | ||
3 | |||
4 | #include <stdio.h> | ||
5 | #include <stdlib.h> | ||
6 | #include <unistd.h> | ||
7 | #include <time.h> | ||
8 | #include <string.h> | ||
9 | #include <inttypes.h> | ||
10 | #include <assert.h> | ||
11 | #include <limits.h> | ||
12 | #include <fcntl.h> | ||
13 | #include <errno.h> | ||
14 | /* | ||
15 | #include "litmus.h" | ||
16 | #include "common.h" | ||
17 | */ | ||
18 | /* CPU time consumed so far in seconds */ | ||
19 | double cputime(void) | ||
20 | { | ||
21 | struct timespec ts; | ||
22 | int err; | ||
23 | err = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); | ||
24 | if (err != 0) | ||
25 | perror("clock_gettime"); | ||
26 | return (ts.tv_sec + 1E-9 * ts.tv_nsec); | ||
27 | } | ||
28 | |||
29 | /* wall-clock time in seconds */ | ||
30 | double wctime(void) | ||
31 | { | ||
32 | struct timeval tv; | ||
33 | gettimeofday(&tv, NULL); | ||
34 | return (tv.tv_sec + 1E-6 * tv.tv_usec); | ||
35 | } | ||
36 | |||
37 | void bail_out(const char* msg) | ||
38 | { | ||
39 | perror(msg); | ||
40 | exit(-1 * errno); | ||
41 | } | ||
42 | |||
43 | #include "extra.h" | ||
44 | |||
45 | #define PAGE_SIZE (4096) | ||
46 | #define CACHELINE_SIZE 64 | ||
47 | #define INTS_IN_CACHELINE (CACHELINE_SIZE/sizeof(int)) | ||
48 | #define CACHELINES_IN_1KB (1024 / sizeof(cacheline_t)) | ||
49 | #define INTS_IN_1KB (1024 / sizeof(int)) | ||
50 | |||
51 | typedef struct cacheline | ||
52 | { | ||
53 | int line[INTS_IN_CACHELINE]; | ||
54 | } __attribute__((aligned(CACHELINE_SIZE))) cacheline_t; | ||
55 | |||
56 | static volatile cacheline_t* arena = NULL; | ||
57 | |||
58 | #define UNCACHE_DEV "/dev/litmus/uncache" | ||
59 | #define FAKE_DEV "/dev/litmus/fakedev0" | ||
60 | |||
61 | static cacheline_t* alloc_arena(size_t size, int use_huge_pages, int use_uncache_pages) | ||
62 | { | ||
63 | int flags = MAP_PRIVATE | MAP_POPULATE; | ||
64 | cacheline_t* arena = NULL; | ||
65 | int fd; | ||
66 | |||
67 | if(use_huge_pages) | ||
68 | flags |= MAP_HUGETLB; | ||
69 | |||
70 | if(use_uncache_pages == 1) { | ||
71 | fd = open(UNCACHE_DEV, O_RDWR|O_SYNC); | ||
72 | if (fd == -1) | ||
73 | bail_out("Failed to open uncache device. Are you running the LITMUS^RT kernel?"); | ||
74 | } else if (use_uncache_pages == 2) { | ||
75 | fd = open(FAKE_DEV, O_RDWR|O_SYNC); | ||
76 | if (fd == -1) | ||
77 | bail_out("Failed to open fake device. Are you running the LITMUS^RT kernel?"); | ||
78 | } else { | ||
79 | fd = -1; | ||
80 | flags |= MAP_ANONYMOUS; | ||
81 | } | ||
82 | |||
83 | arena = (cacheline_t*)mmap(0, size, PROT_READ | PROT_WRITE, flags, fd, 0); | ||
84 | |||
85 | if(use_uncache_pages) | ||
86 | close(fd); | ||
87 | |||
88 | assert(arena); | ||
89 | |||
90 | return arena; | ||
91 | } | ||
92 | |||
93 | static void dealloc_arena(cacheline_t* arena, size_t size) | ||
94 | { | ||
95 | int ret = munmap((void*)arena, size); | ||
96 | if(ret != 0) | ||
97 | bail_out("munmap() error"); | ||
98 | } | ||
99 | |||
100 | static int randrange(int min, int max) | ||
101 | { | ||
102 | // Range is [min, max) | ||
103 | assert(max - min - 1 <= RAND_MAX); | ||
104 | return rand() % (max - min) + min; | ||
105 | //return (rand() % (max - min + 1)) + min; | ||
106 | /* generate a random number on the range [min, max) w/o skew */ | ||
107 | /*int limit = max - min; | ||
108 | int devisor = RAND_MAX/limit; | ||
109 | int retval; | ||
110 | |||
111 | do { | ||
112 | retval = rand() / devisor; | ||
113 | } while(retval == limit); | ||
114 | retval += min; | ||
115 | |||
116 | return retval;*/ | ||
117 | } | ||
118 | |||
119 | static void init_arena(volatile cacheline_t* arena, size_t size) | ||
120 | { | ||
121 | int i; | ||
122 | size_t num_arena_elem = size / sizeof(cacheline_t); | ||
123 | |||
124 | /* Generate a cycle among the cache lines using Sattolo's algorithm. | ||
125 | Every int in the cache line points to the same cache line. | ||
126 | Note: Sequential walk doesn't care about these values. */ | ||
127 | for (i = 0; i < num_arena_elem; i++) { | ||
128 | int j; | ||
129 | for(j = 0; j < INTS_IN_CACHELINE; j++) | ||
130 | arena[i].line[j] = i; | ||
131 | arena[i].line[1] = 0; | ||
132 | } | ||
133 | /*while(1 < i--) { | ||
134 | int j = randrange(0, i); | ||
135 | cacheline_t temp = arena[j]; | ||
136 | arena[j] = arena[i]; | ||
137 | arena[i] = temp; | ||
138 | }*/ | ||
139 | for (int j = 0; j < num_arena_elem-1; j++) { | ||
140 | int k = randrange(j+1, num_arena_elem); | ||
141 | cacheline_t temp = arena[j]; | ||
142 | arena[j] = arena[k]; | ||
143 | arena[k] = temp; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | /* Random walk around the arena in cacheline-sized chunks. | ||
148 | Cacheline-sized chucks ensures the same utilization of each | ||
149 | hit line as sequential read. (Otherwise, our utilization | ||
150 | would only be 1/INTS_IN_CACHELINE.) */ | ||
151 | static int random_walk(volatile cacheline_t *mem, int wss, int write_cycle) | ||
152 | { | ||
153 | /* a random cycle among the cache lines was set up by init_arena(). */ | ||
154 | int sum, i, next; | ||
155 | |||
156 | // Always do the same number of hops | ||
157 | int numlines = 33554432 / CACHELINE_SIZE;//wss * CACHELINES_IN_1KB; | ||
158 | |||
159 | sum = 0; | ||
160 | |||
161 | /* contents of arena is structured s.t. offsets are all | ||
162 | w.r.t. to start of arena, so compute the initial offset */ | ||
163 | next = mem - arena; | ||
164 | |||
165 | if (write_cycle == 0) { | ||
166 | for (i = 0; i < numlines; i++) { | ||
167 | next = arena[next].line[0]; | ||
168 | arena[next].line[1] = 1; // Record that we touched this line | ||
169 | sum += next; | ||
170 | for (int j = 2; j < INTS_IN_CACHELINE; j++) | ||
171 | arena[next].line[j]++; | ||
172 | } | ||
173 | } else { | ||
174 | int w, which_line; | ||
175 | for (i = 0, w = 0; i < numlines; i++) { | ||
176 | which_line = next; | ||
177 | next = arena[next].line[0]; | ||
178 | if((w % write_cycle) != (write_cycle - 1)) { // This is equivalent to 1 % 1 != 1 - 1 which is always false | ||
179 | sum += next; | ||
180 | } | ||
181 | else { | ||
182 | // I /think/ that this just writes back to the address it read from | ||
183 | arena[which_line].line[0] = next; | ||
184 | } | ||
185 | } | ||
186 | } | ||
187 | return sum; | ||
188 | } | ||
189 | |||
190 | volatile static cacheline_t* random_start(int wss) | ||
191 | { | ||
192 | return arena + randrange(0, ((wss * 1024)/sizeof(cacheline_t))); | ||
193 | } | ||
194 | /* | ||
195 | static int sequential_walk(cacheline_t *_mem, int wss, int write_cycle) | ||
196 | { | ||
197 | int sum = 0, i; | ||
198 | int* mem = (int*)_mem; // treat as raw buffer of ints | ||
199 | int num_ints = wss * INTS_IN_1KB; | ||
200 | |||
201 | if (write_cycle > 0) { | ||
202 | for (i = 0; i < num_ints; i++) { | ||
203 | if (i % write_cycle == (write_cycle - 1)) | ||
204 | mem[i]++; | ||
205 | else | ||
206 | sum += mem[i]; | ||
207 | } | ||
208 | } else { | ||
209 | // sequential access, pure read | ||
210 | for (i = 0; i < num_ints; i++) | ||
211 | sum += mem[i]; | ||
212 | } | ||
213 | return sum; | ||
214 | } | ||
215 | |||
216 | static cacheline_t* sequential_start(int wss) | ||
217 | { | ||
218 | static int pos = 0; | ||
219 | |||
220 | int num_cachelines = wss * CACHELINES_IN_1KB; | ||
221 | |||
222 | cacheline_t *mem; | ||
223 | |||
224 | * Don't allow re-use between allocations. | ||
225 | * At most half of the arena may be used | ||
226 | * at any one time. | ||
227 | * | ||
228 | if (num_cachelines * 2 > ((wss * 1024)/sizeof(cacheline_t))) | ||
229 | ;//bail_out("static memory arena too small"); | ||
230 | |||
231 | if (pos + num_cachelines > ((wss * 1024)/sizeof(cacheline_t))) { | ||
232 | // wrap to beginning | ||
233 | mem = arena; | ||
234 | pos = num_cachelines; | ||
235 | } else { | ||
236 | mem = arena + pos; | ||
237 | pos += num_cachelines; | ||
238 | } | ||
239 | |||
240 | return mem; | ||
241 | } | ||
242 | */ | ||
243 | static volatile int dont_optimize_me = 0; | ||
244 | |||
245 | #define RANDOM_WALK 1 | ||
246 | static int loop_once(int wss, int write) | ||
247 | { | ||
248 | volatile cacheline_t *mem; | ||
249 | int temp; | ||
250 | |||
251 | #ifdef RANDOM_WALK | ||
252 | mem = random_start(wss); | ||
253 | // printf("Using start offset %ld. Data here is %d. data size: %ld\n", mem-arena, mem->line[0], sizeof(mem->line[0])); | ||
254 | temp = random_walk(mem, wss, write); | ||
255 | #else | ||
256 | mem = sequential_start(wss); | ||
257 | temp = sequential_walk(mem, wss, write); | ||
258 | #endif | ||
259 | dont_optimize_me = temp; | ||
260 | // printf("%d", dont_optimize_me); | ||
261 | return dont_optimize_me; | ||
262 | } | ||
263 | |||
264 | int main(int argc, char** argv) { | ||
265 | SET_UP | ||
266 | int write; | ||
267 | long wss; | ||
268 | double duration; | ||
269 | double program_end; | ||
270 | // Reads in benchmark params from stdin | ||
271 | // <long: wss in bytes> <float: duration in seconds> <bool: if we should also write> | ||
272 | if (scanf("%ld %lf %d", &wss, &duration, &write) != 3) { | ||
273 | fprintf(stderr, "Bad input, please enter 3 parameters: <WSS (Int)> <Duration (Double)> <Write (Bool)>.\n"); | ||
274 | exit(1); | ||
275 | } | ||
276 | printf("random_walk: Using parameters: %ld, %lf, %d\n", wss, duration, write); | ||
277 | wss /= 1024; | ||
278 | program_end = duration + wctime(); | ||
279 | // Initialize memory | ||
280 | size_t arena_sz = wss*1024; | ||
281 | arena = alloc_arena(arena_sz*2, 0, 0); | ||
282 | init_arena(arena, arena_sz); | ||
283 | loop_once(wss, write); | ||
284 | // This loop contains the original content of job(int wss, int write, double exec_time, double program_end) | ||
285 | while (1) { | ||
286 | double emergency_exit = program_end + 1; | ||
287 | |||
288 | if (wctime() > program_end) { | ||
289 | break; | ||
290 | } else { | ||
291 | double last_loop = 0, loop_start; | ||
292 | int tmp = 0; | ||
293 | |||
294 | double start = cputime(); | ||
295 | double now = cputime(); | ||
296 | |||
297 | //while (now + last_loop < start) {// + exec_time) { | ||
298 | loop_start = now; | ||
299 | START_LOOP | ||
300 | tmp += loop_once(wss, write); | ||
301 | STOP_LOOP | ||
302 | now = cputime(); | ||
303 | last_loop = now - loop_start; | ||
304 | if (emergency_exit && wctime() > emergency_exit) { | ||
305 | /* Oops --- this should only be possible if the execution time tracking | ||
306 | * is broken in the LITMUS^RT kernel. */ | ||
307 | fprintf(stderr, "!!! rtspin/%d emergency exit!\n", getpid()); | ||
308 | fprintf(stderr, "Something is seriously wrong! Do not ignore this.\n"); | ||
309 | break; | ||
310 | } | ||
311 | long sum = 0; | ||
312 | // Verify that we actually traversed the whole wss | ||
313 | for (volatile cacheline_t* loc = arena; loc < arena + (wss*1024)/sizeof(cacheline_t); loc++) { | ||
314 | sum += loc->line[1]; | ||
315 | } | ||
316 | if (sum != wss * CACHELINES_IN_1KB) { | ||
317 | fprintf(stderr, "We hopped the wrong number of times! Hops: %ld, should have been: %ld\n", sum, wss * CACHELINES_IN_1KB); | ||
318 | } | ||
319 | //} | ||
320 | |||
321 | //sleep_next_period(); | ||
322 | continue; | ||
323 | } | ||
324 | } | ||
325 | WRITE_TO_FILE | ||
326 | printf("random_walk: done walking %ldKiB.\n", wss); | ||
327 | return 0; | ||
328 | } | ||
329 | /* | ||
330 | #define OPTSTR "p:wl:m:i:b:k:u:r:" | ||
331 | int main(int argc, char** argv) | ||
332 | { | ||
333 | int ret; | ||
334 | lt_t wcet, period, budget; | ||
335 | double wcet_ms, period_ms, budget_ms; | ||
336 | unsigned int priority = LITMUS_NO_PRIORITY; | ||
337 | int migrate = 0; | ||
338 | int cluster = 0; | ||
339 | int opt; | ||
340 | int wait = 0; | ||
341 | double duration = 0, start = 0; | ||
342 | struct rt_task param; | ||
343 | struct mc2_task mc2_param; | ||
344 | struct reservation_config config; | ||
345 | int res_type = PERIODIC_POLLING; | ||
346 | size_t arena_sz; | ||
347 | int wss; | ||
348 | int uncacheable = 0; | ||
349 | int read_access = 0, write; | ||
350 | int verbose = 0; | ||
351 | unsigned int job_no; | ||
352 | struct control_page* cp; | ||
353 | |||
354 | * default for reservation * | ||
355 | config.id = 0; | ||
356 | config.cpu = -1; | ||
357 | |||
358 | mc2_param.crit = CRIT_LEVEL_C; | ||
359 | |||
360 | budget_ms = 1000; | ||
361 | wss = 32; | ||
362 | |||
363 | while ((opt = getopt(argc, argv, OPTSTR)) != -1) { | ||
364 | switch (opt) { | ||
365 | case 'w': | ||
366 | wait = 1; | ||
367 | break; | ||
368 | case 'p': | ||
369 | cluster = atoi(optarg); | ||
370 | migrate = 1; | ||
371 | config.cpu = cluster; | ||
372 | break; | ||
373 | case 'k': | ||
374 | wss = atoi(optarg); | ||
375 | break; | ||
376 | case 'm': | ||
377 | mc2_param.crit = atoi(optarg); | ||
378 | if ((mc2_param.crit >= CRIT_LEVEL_A) && (mc2_param.crit <= CRIT_LEVEL_C)) { | ||
379 | res_type = PERIODIC_POLLING; | ||
380 | } | ||
381 | else | ||
382 | usage("Invalid criticality level."); | ||
383 | break; | ||
384 | case 'b': | ||
385 | budget_ms = atof(optarg); | ||
386 | break; | ||
387 | case 'r': | ||
388 | read_access = atoi(optarg); | ||
389 | break; | ||
390 | case 'q': | ||
391 | priority = want_non_negative_int(optarg, "-q"); | ||
392 | if (!litmus_is_valid_fixed_prio(priority)) | ||
393 | usage("Invalid priority"); | ||
394 | config.priority = atoi(optarg); | ||
395 | break; | ||
396 | case 'u': | ||
397 | uncacheable = atoi(optarg); | ||
398 | break; | ||
399 | case 'v': | ||
400 | verbose = 1; | ||
401 | break; | ||
402 | case ':': | ||
403 | usage("Argument missing."); | ||
404 | break; | ||
405 | case '?': | ||
406 | default: | ||
407 | usage("Bad argument."); | ||
408 | break; | ||
409 | } | ||
410 | } | ||
411 | srand(getpid()); | ||
412 | if (read_access == 1) | ||
413 | write = 0; | ||
414 | else | ||
415 | write = 1; | ||
416 | * | ||
417 | * We need three parameters | ||
418 | * | ||
419 | if (argc - optind < 3) | ||
420 | usage("Arguments missing."); | ||
421 | |||
422 | wcet_ms = atof(argv[optind + 0]); | ||
423 | period_ms = atof(argv[optind + 1]); | ||
424 | |||
425 | wcet = ms2ns(wcet_ms); | ||
426 | period = ms2ns(period_ms); | ||
427 | budget = ms2ns(budget_ms); | ||
428 | if (wcet <= 0) | ||
429 | usage("The worst-case execution time must be a " | ||
430 | "positive number."); | ||
431 | if (period <= 0) | ||
432 | usage("The period must be a positive number."); | ||
433 | if (wcet > period) { | ||
434 | usage("The worst-case execution time must not " | ||
435 | "exceed the period."); | ||
436 | } | ||
437 | |||
438 | duration = atof(argv[optind + 2]); | ||
439 | |||
440 | if (migrate) { | ||
441 | ret = be_migrate_to_domain(cluster); | ||
442 | if (ret < 0) | ||
443 | bail_out("could not migrate to target partition or cluster."); | ||
444 | } | ||
445 | |||
446 | * reservation config * | ||
447 | config.id = gettid(); | ||
448 | config.priority = priority; | ||
449 | config.polling_params.budget = budget; | ||
450 | config.polling_params.period = period; | ||
451 | config.polling_params.offset = 0; | ||
452 | config.polling_params.relative_deadline = 0; | ||
453 | |||
454 | if (config.polling_params.budget > config.polling_params.period) { | ||
455 | usage("The budget must not exceed the period."); | ||
456 | } | ||
457 | |||
458 | * create a reservation * | ||
459 | ret = reservation_create(res_type, &config); | ||
460 | if (ret < 0) { | ||
461 | bail_out("failed to create reservation."); | ||
462 | } | ||
463 | |||
464 | init_rt_task_param(¶m); | ||
465 | param.exec_cost = wcet; | ||
466 | param.period = period; | ||
467 | param.phase = 0; | ||
468 | param.relative_deadline = 0; | ||
469 | param.priority = priority == LITMUS_NO_PRIORITY ? LITMUS_LOWEST_PRIORITY : priority; | ||
470 | param.cls = RT_CLASS_HARD; | ||
471 | param.budget_policy = NO_ENFORCEMENT; | ||
472 | param.release_policy = TASK_PERIODIC; | ||
473 | if (migrate) { | ||
474 | param.cpu = gettid(); | ||
475 | } | ||
476 | ret = set_rt_task_param(gettid(), ¶m); | ||
477 | if (ret < 0) | ||
478 | bail_out("could not setup rt task params"); | ||
479 | |||
480 | mc2_param.res_id = gettid(); | ||
481 | ret = set_mc2_task_param(gettid(), &mc2_param); | ||
482 | if (ret < 0) | ||
483 | bail_out("could not setup mc2 task params"); | ||
484 | |||
485 | arena_sz = wss*1024; | ||
486 | arena = alloc_arena(arena_sz*2, 0, uncacheable); | ||
487 | init_arena(arena, arena_sz); | ||
488 | loop_once(wss, write); | ||
489 | |||
490 | ret = init_litmus(); | ||
491 | if (ret != 0) | ||
492 | bail_out("init_litmus() failed\n"); | ||
493 | |||
494 | mlockall(MCL_CURRENT | MCL_FUTURE); | ||
495 | |||
496 | if (mc2_param.crit == CRIT_LEVEL_C) | ||
497 | set_page_color(-1); | ||
498 | else | ||
499 | set_page_color(config.cpu); | ||
500 | |||
501 | start = wctime(); | ||
502 | ret = task_mode(LITMUS_RT_TASK); | ||
503 | if (ret != 0) | ||
504 | bail_out("could not become RT task"); | ||
505 | |||
506 | if (wait) { | ||
507 | ret = wait_for_ts_release(); | ||
508 | if (ret != 0) | ||
509 | bail_out("wait_for_ts_release()"); | ||
510 | start = wctime(); | ||
511 | } | ||
512 | cp = get_ctrl_page(); | ||
513 | |||
514 | while (job(wss, write, wcet_ms * 0.001, start + duration)) { | ||
515 | if (verbose) { | ||
516 | get_job_no(&job_no); | ||
517 | fprintf(stderr, "rtspin/%d:%u @ %.4fms\n", gettid(), | ||
518 | job_no, (wctime() - start) * 1000); | ||
519 | if (cp) { | ||
520 | double deadline, current, release; | ||
521 | lt_t now = litmus_clock(); | ||
522 | deadline = ns2s((double) cp->deadline); | ||
523 | current = ns2s((double) now); | ||
524 | release = ns2s((double) cp->release); | ||
525 | fprintf(stderr, | ||
526 | "\trelease: %" PRIu64 "ns (=%.2fs)\n", | ||
527 | (uint64_t) cp->release, release); | ||
528 | fprintf(stderr, | ||
529 | "\tdeadline: %" PRIu64 "ns (=%.2fs)\n", | ||
530 | (uint64_t) cp->deadline, deadline); | ||
531 | fprintf(stderr, | ||
532 | "\tcur time: %" PRIu64 "ns (=%.2fs)\n", | ||
533 | (uint64_t) now, current); | ||
534 | fprintf(stderr, | ||
535 | "\ttime until deadline: %.2fms\n", | ||
536 | (deadline - current) * 1000); | ||
537 | } | ||
538 | } | ||
539 | }; | ||
540 | |||
541 | ret = task_mode(BACKGROUND_TASK); | ||
542 | if (ret != 0) | ||
543 | bail_out("could not become regular task (huh?)"); | ||
544 | |||
545 | reservation_destroy(gettid(), config.cpu); | ||
546 | dealloc_arena(arena, arena_sz*2); | ||
547 | printf("%s finished.\n", argv[0]); | ||
548 | return 0; | ||
549 | } | ||
550 | */ | ||