summaryrefslogtreecommitdiffstats
path: root/dis/random_walk.c
diff options
context:
space:
mode:
Diffstat (limited to 'dis/random_walk.c')
-rw-r--r--dis/random_walk.c550
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 */
19double 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 */
30double wctime(void)
31{
32 struct timeval tv;
33 gettimeofday(&tv, NULL);
34 return (tv.tv_sec + 1E-6 * tv.tv_usec);
35}
36
37void 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
51typedef struct cacheline
52{
53 int line[INTS_IN_CACHELINE];
54} __attribute__((aligned(CACHELINE_SIZE))) cacheline_t;
55
56static volatile cacheline_t* arena = NULL;
57
58#define UNCACHE_DEV "/dev/litmus/uncache"
59#define FAKE_DEV "/dev/litmus/fakedev0"
60
61static 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
93static 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
100static 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
119static 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.) */
151static 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
190volatile static cacheline_t* random_start(int wss)
191{
192 return arena + randrange(0, ((wss * 1024)/sizeof(cacheline_t)));
193}
194/*
195static 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
216static 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*/
243static volatile int dont_optimize_me = 0;
244
245#define RANDOM_WALK 1
246static 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
264int 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:"
331int 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(&param);
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(), &param);
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*/