aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile5
-rw-r--r--bin/rtspin.c6
-rw-r--r--bin/uncache.c381
-rw-r--r--tests/fdso.c4
-rw-r--r--tests/locks.c8
-rw-r--r--tests/pcp.c8
6 files changed, 398 insertions, 14 deletions
diff --git a/Makefile b/Makefile
index 8195752..5432edd 100644
--- a/Makefile
+++ b/Makefile
@@ -71,7 +71,7 @@ AR := ${CROSS_COMPILE}${AR}
71 71
72all = lib ${rt-apps} 72all = lib ${rt-apps}
73rt-apps = cycles base_task rt_launch rtspin release_ts measure_syscall \ 73rt-apps = cycles base_task rt_launch rtspin release_ts measure_syscall \
74 base_mt_task runtests 74 base_mt_task uncache runtests
75 75
76.PHONY: all lib clean dump-config TAGS tags cscope help 76.PHONY: all lib clean dump-config TAGS tags cscope help
77 77
@@ -215,6 +215,9 @@ obj-rt_launch = rt_launch.o common.o
215obj-rtspin = rtspin.o common.o 215obj-rtspin = rtspin.o common.o
216lib-rtspin = -lrt 216lib-rtspin = -lrt
217 217
218obj-uncache = uncache.o
219lib-uncache = -lrt
220
218obj-release_ts = release_ts.o 221obj-release_ts = release_ts.o
219 222
220obj-measure_syscall = null_call.o 223obj-measure_syscall = null_call.o
diff --git a/bin/rtspin.c b/bin/rtspin.c
index 5054d0b..657a94c 100644
--- a/bin/rtspin.c
+++ b/bin/rtspin.c
@@ -80,7 +80,7 @@ static void get_exec_times(const char *file, const int column,
80 80
81 for (cur_col = 1; cur_col < column; ++cur_col) { 81 for (cur_col = 1; cur_col < column; ++cur_col) {
82 /* discard input until we get to the column we want */ 82 /* discard input until we get to the column we want */
83 fscanf(fstream, "%*s,"); 83 int unused __attribute__ ((unused)) = fscanf(fstream, "%*s,");
84 } 84 }
85 85
86 /* get the desired exec. time */ 86 /* get the desired exec. time */
@@ -200,11 +200,11 @@ int main(int argc, char** argv)
200 int column = 1; 200 int column = 1;
201 const char *file = NULL; 201 const char *file = NULL;
202 int want_enforcement = 0; 202 int want_enforcement = 0;
203 double duration = 0, start; 203 double duration = 0, start = 0;
204 double *exec_times = NULL; 204 double *exec_times = NULL;
205 double scale = 1.0; 205 double scale = 1.0;
206 task_class_t class = RT_CLASS_HARD; 206 task_class_t class = RT_CLASS_HARD;
207 int cur_job, num_jobs; 207 int cur_job = 0, num_jobs = 0;
208 208
209 /* locking */ 209 /* locking */
210 int lock_od = -1; 210 int lock_od = -1;
diff --git a/bin/uncache.c b/bin/uncache.c
new file mode 100644
index 0000000..b6f6913
--- /dev/null
+++ b/bin/uncache.c
@@ -0,0 +1,381 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <time.h>
5#include <sched.h>
6#include <assert.h>
7#include <string.h>
8#include <stdint.h>
9#include <sys/fcntl.h>
10#include <sys/mman.h>
11
12/* Test tool for validating Litmus's uncache device. */
13/* Tool also capable basic cache vs. sysmem statistics. */
14/* Compile with '-O2' for significaintly greater margins */
15/* in performance between cache and sysmem: */
16/* (Intel Xeon X5650) */
17/* -g -> uncache is 30x slower */
18/* -O2 -> uncache is >100x slower */
19
20int PAGE_SIZE;
21#define NR_PAGES 16
22
23#define UNCACHE_DEV "/dev/litmus/uncache"
24
25/* volatile forces a read from memory (or cache) on every reference. Note
26 that volatile does not keep data out of the cache! */
27typedef volatile char* pbuf_t;
28
29/* hit the first byte in each page.
30 addr must be page aligned. */
31inline int linear_write(pbuf_t addr, int size, char val)
32{
33 pbuf_t end = addr + size;
34 pbuf_t step;
35 int nr_pages = (unsigned long)(end - addr)/PAGE_SIZE;
36 int times = nr_pages * PAGE_SIZE;
37 int i;
38
39 for (i = 0; i < times; ++i)
40 for(step = addr; step < end; step += PAGE_SIZE)
41 *step = val;
42 return 0;
43}
44inline int linear_read(pbuf_t addr, int size, char val)
45{
46 pbuf_t end = addr + size;
47 pbuf_t step;
48 int nr_pages = (unsigned long)(end - addr)/PAGE_SIZE;
49 int times = nr_pages * PAGE_SIZE;
50 int i;
51
52 for (i = 0; i < times; ++i)
53 for(step = addr; step < end; step += PAGE_SIZE) {
54 if (*step != val)
55 return -1;
56 }
57 return 0;
58}
59
60/* write to *data nr times. */
61inline int hammer_write(pbuf_t data, char val, int nr)
62{
63 int i;
64 for (i = 0; i < nr; ++i)
65 *data = val;
66 return 0;
67}
68
69/* read from *data nr times. */
70inline int hammer_read(pbuf_t data, char val, int nr)
71{
72 int i;
73 for (i = 0; i < nr; ++i) {
74 if (*data != val)
75 return -1;
76 }
77 return 0;
78}
79
80inline int test(pbuf_t data, int size, int trials)
81{
82 int HAMMER_TIME = 10000; /* can't cache this! */
83 char VAL = 0x55;
84 int t;
85 for(t = 0; t < trials; ++t) {
86
87#if 0
88 if (linear_write(data, size, VAL) != 0) {
89 printf("failed linear_write()\n");
90 return -1;
91 }
92 if (linear_read(data, size, VAL) != 0) {
93 printf("failed linear_read()\n");
94 return -1;
95 }
96#endif
97
98 /* hammer at the first byte in the array */
99 if (hammer_write(data, VAL, HAMMER_TIME) != 0) {
100 printf("failed hammer_write()\n");
101 return -1;
102 }
103 if (hammer_read(data, VAL, HAMMER_TIME) != 0) {
104 printf("failed hammer_read()\n");
105 return -1;
106 }
107 }
108 return 0;
109}
110
111inline void timespec_normalize(struct timespec* ts, time_t sec, int64_t nsec)
112{
113 while(nsec > 1000000000LL) {
114 asm("" : "+rm"(nsec));
115 nsec -= 1000000000LL;
116 ++sec;
117 }
118 while(nsec < 0) {
119 asm("" : "+rm"(nsec));
120 nsec += 1000000000LL;
121 --sec;
122 }
123
124 ts->tv_sec = sec;
125 ts->tv_nsec = nsec;
126}
127
128inline struct timespec timespec_sub(struct timespec lhs, struct timespec rhs)
129{
130 struct timespec delta;
131 timespec_normalize(&delta, lhs.tv_sec - rhs.tv_sec, lhs.tv_nsec - rhs.tv_nsec);
132 return delta;
133}
134
135inline struct timespec timespec_add(struct timespec lhs, struct timespec rhs)
136{
137 struct timespec delta;
138 timespec_normalize(&delta, lhs.tv_sec + rhs.tv_sec, lhs.tv_nsec + rhs.tv_nsec);
139 return delta;
140}
141
142inline int64_t timespec_to_us(struct timespec ts)
143{
144 int64_t t;
145 t = ts.tv_sec * 1000000LL;
146 t += ts.tv_nsec / 1000LL;
147 return t;
148}
149
150/* hammers away at the first byte in each mmaped page and
151 times how long it took. */
152int do_data(int do_uncache, int64_t* time)
153{
154 int size;
155 int prot = PROT_READ | PROT_WRITE;
156 int flags = MAP_PRIVATE;
157
158 pbuf_t data;
159
160 struct sched_param fifo_params;
161
162 struct timespec start, end;
163 int64_t elapsed;
164 int trials = 1000;
165
166 printf("Running data access test.\n");
167
168 mlockall(MCL_CURRENT | MCL_FUTURE);
169
170 memset(&fifo_params, 0, sizeof(fifo_params));
171 fifo_params.sched_priority = sched_get_priority_max(SCHED_FIFO);
172
173 size = PAGE_SIZE*NR_PAGES;
174
175 printf("Allocating %d %s pages.\n", NR_PAGES, (do_uncache) ?
176 "uncacheable" : "cacheable");
177 if (do_uncache) {
178 int fd = open(UNCACHE_DEV, O_RDWR);
179 data = mmap(NULL, size, prot, flags, fd, 0);
180 close(fd);
181 }
182 else {
183 /* Accessed data will probably fit in L1, so this will go VERY fast.
184 Code should also have little-to-no pipeline stalls. */
185 flags |= MAP_ANONYMOUS;
186 data = mmap(NULL, size, prot, flags, -1, 0);
187 }
188 if (data == MAP_FAILED) {
189 printf("Failed to alloc data! "
190 "Are you running Litmus? "
191 "Is Litmus broken?\n");
192 return -1;
193 }
194 else {
195 printf("Data allocated at %p.\n", data);
196 }
197
198 printf("Beginning tests...\n");
199 if (sched_setscheduler(getpid(), SCHED_FIFO, &fifo_params)) {
200 printf("(Could not become SCHED_FIFO task.) Are you running as root?\n");
201 }
202
203 /* observations suggest that no warmup phase is needed. */
204 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start);
205 if (test(data, size, trials) != 0) {
206 printf("Test failed!\n");
207 munmap((char*)data, size);
208 return -1;
209 }
210 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
211 elapsed = timespec_to_us(timespec_sub(end, start));
212 printf("%s Time: %ldus\n", (do_uncache) ?
213 "Uncache" : "Cache", elapsed);
214
215 munmap((char*)data, size);
216
217 if(time)
218 *time = elapsed;
219
220 return 0;
221}
222
223/* compares runtime of cached vs. uncached */
224int do_data_compare()
225{
226 const double thresh = 1.3;
227 int ret = 0;
228 double ratio;
229 int64_t cache_time = 0, uncache_time = 0;
230
231 printf("Timing cached pages...\n");
232 ret = do_data(0, &cache_time);
233 if (ret != 0)
234 goto out;
235
236 printf("Timing uncached pages...\n");
237 ret = do_data(1, &uncache_time);
238 if (ret != 0)
239 goto out;
240
241 ratio = (double)uncache_time/(double)cache_time;
242 printf("Uncached/Cached Ratio: %f\n", ratio);
243
244 if (ratio < thresh) {
245 printf("Ratio is unexpectedly small (< %f)! "
246 " Uncache broken? Are you on kvm?\n", thresh);
247 ret = -1;
248 }
249
250out:
251 return ret;
252}
253
254/* tries to max out uncache allocations.
255 under normal conditions (non-mlock),
256 pages should spill into swap. uncache
257 pages are not locked in memory. */
258int do_max_alloc(void)
259{
260 int fd;
261 int good = 1;
262 int count = 0;
263 uint64_t mmap_size = PAGE_SIZE; /* start at one page per mmap */
264
265 /* half of default limit on ubuntu. (see /proc/sys/vm/max_map_count) */
266 int max_mmaps = 32765;
267 volatile char** maps = calloc(max_mmaps, sizeof(pbuf_t));
268
269 if (!maps) {
270 printf("failed to alloc pointers for pages\n");
271 return -1;
272 }
273
274 printf("Testing max amount of uncache data. System may get wonkie (OOM Killer)!\n");
275
276 fd = open(UNCACHE_DEV, O_RDWR);
277 do {
278 int i;
279 int nr_pages = mmap_size/PAGE_SIZE;
280 printf("Testing mmaps of %d pages.\n", nr_pages);
281
282 count = 0;
283 for (i = 0; (i < max_mmaps) && good; ++i) {
284 pbuf_t data = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_POPULATE, fd, 0);
285
286 if (data != MAP_FAILED) {
287 maps[i] = data;
288 ++count;
289 }
290 else {
291 perror(NULL);
292 good = 0;
293 }
294 }
295 for (i = 0; i < count; ++i) {
296 if (maps[i])
297 munmap((char*)(maps[i]), mmap_size);
298 }
299 memset(maps, 0, sizeof(maps[0])*max_mmaps);
300
301 mmap_size *= 2; /* let's do it again with bigger allocations */
302 }while(good);
303
304 free(maps);
305 close(fd);
306
307 printf("Maxed out allocs with %d mmaps of %lu pages in size.\n",
308 count, mmap_size/PAGE_SIZE);
309
310 return 0;
311}
312
313typedef enum
314{
315 UNCACHE,
316 CACHE,
317 COMPARE,
318 MAX_ALLOC
319} test_t;
320
321#define OPTSTR "ucxa"
322int main(int argc, char** argv)
323{
324 int ret;
325 test_t test = UNCACHE;
326 int opt;
327 PAGE_SIZE = sysconf(_SC_PAGE_SIZE);
328
329 while((opt = getopt(argc, argv, OPTSTR)) != -1) {
330 switch(opt) {
331 case 'c':
332 test = CACHE;
333 break;
334 case 'u':
335 test = UNCACHE;
336 break;
337 case 'x':
338 test = COMPARE;
339 break;
340 case 'a':
341 test = MAX_ALLOC;
342 break;
343 case ':':
344 printf("missing option\n");
345 exit(-1);
346 case '?':
347 default:
348 printf("bad argument\n");
349 exit(-1);
350 }
351 }
352
353
354 printf("Page Size: %d\n", PAGE_SIZE);
355
356 switch(test)
357 {
358 case CACHE:
359 ret = do_data(0, NULL);
360 break;
361 case UNCACHE:
362 ret = do_data(1, NULL);
363 break;
364 case COMPARE:
365 ret = do_data_compare();
366 break;
367 case MAX_ALLOC:
368 ret = do_max_alloc();
369 break;
370 default:
371 printf("invalid test\n");
372 ret = -1;
373 break;
374 }
375
376 if (ret != 0) {
377 printf("Test failed.\n");
378 }
379
380 return ret;
381}
diff --git a/tests/fdso.c b/tests/fdso.c
index 8a2a0d0..fda343f 100644
--- a/tests/fdso.c
+++ b/tests/fdso.c
@@ -16,7 +16,7 @@ TESTCASE(fmlp_not_active, C_EDF | PFAIR | LINUX,
16{ 16{
17 int fd; 17 int fd;
18 18
19 SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT) ); 19 SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT, S_IRUSR) );
20 20
21 ASSERT(fd != -1); 21 ASSERT(fd != -1);
22 22
@@ -57,7 +57,7 @@ TESTCASE(not_inherit_od, GSN_EDF | PSN_EDF,
57{ 57{
58 int fd, od, pid, status; 58 int fd, od, pid, status;
59 59
60 SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT) ); 60 SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT, S_IRUSR) );
61 61
62 SYSCALL( od = open_fmlp_sem(fd, 0) ); 62 SYSCALL( od = open_fmlp_sem(fd, 0) );
63 63
diff --git a/tests/locks.c b/tests/locks.c
index d7ebfe2..9a928b3 100644
--- a/tests/locks.c
+++ b/tests/locks.c
@@ -11,7 +11,7 @@ TESTCASE(not_lock_fmlp_be, GSN_EDF | PSN_EDF | P_FP,
11{ 11{
12 int fd, od; 12 int fd, od;
13 13
14 SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT) ); 14 SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT, S_IRUSR) );
15 15
16 SYSCALL( od = open_fmlp_sem(fd, 0) ); 16 SYSCALL( od = open_fmlp_sem(fd, 0) );
17 17
@@ -34,7 +34,7 @@ TESTCASE(not_lock_srp_be, PSN_EDF | P_FP,
34{ 34{
35 int fd, od; 35 int fd, od;
36 36
37 SYSCALL( fd = open(".srp_locks", O_RDONLY | O_CREAT) ); 37 SYSCALL( fd = open(".srp_locks", O_RDONLY | O_CREAT, S_IRUSR) );
38 38
39 /* BE tasks may not open SRP semaphores */ 39 /* BE tasks may not open SRP semaphores */
40 40
@@ -51,7 +51,7 @@ TESTCASE(lock_srp, PSN_EDF | P_FP,
51{ 51{
52 int fd, od; 52 int fd, od;
53 53
54 SYSCALL( fd = open(".srp_locks", O_RDONLY | O_CREAT) ); 54 SYSCALL( fd = open(".srp_locks", O_RDONLY | O_CREAT, S_IRUSR) );
55 55
56 SYSCALL( sporadic_partitioned(10, 100, 0) ); 56 SYSCALL( sporadic_partitioned(10, 100, 0) );
57 SYSCALL( task_mode(LITMUS_RT_TASK) ); 57 SYSCALL( task_mode(LITMUS_RT_TASK) );
@@ -83,7 +83,7 @@ TESTCASE(lock_fmlp, PSN_EDF | GSN_EDF | P_FP,
83{ 83{
84 int fd, od; 84 int fd, od;
85 85
86 SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT) ); 86 SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT, S_IRUSR) );
87 87
88 SYSCALL( sporadic_partitioned(10, 100, 0) ); 88 SYSCALL( sporadic_partitioned(10, 100, 0) );
89 SYSCALL( task_mode(LITMUS_RT_TASK) ); 89 SYSCALL( task_mode(LITMUS_RT_TASK) );
diff --git a/tests/pcp.c b/tests/pcp.c
index 52ee959..ff4259c 100644
--- a/tests/pcp.c
+++ b/tests/pcp.c
@@ -13,7 +13,7 @@ TESTCASE(lock_pcp, P_FP,
13{ 13{
14 int fd, od, cpu = 0; 14 int fd, od, cpu = 0;
15 15
16 SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT) ); 16 SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT, S_IRUSR) );
17 17
18 SYSCALL( sporadic_partitioned(10, 100, cpu) ); 18 SYSCALL( sporadic_partitioned(10, 100, cpu) );
19 SYSCALL( task_mode(LITMUS_RT_TASK) ); 19 SYSCALL( task_mode(LITMUS_RT_TASK) );
@@ -250,7 +250,7 @@ TESTCASE(lock_dpcp, P_FP,
250{ 250{
251 int fd, od, cpu = 1; 251 int fd, od, cpu = 1;
252 252
253 SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT) ); 253 SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT, S_IRUSR) );
254 254
255 SYSCALL( sporadic_partitioned(10, 100, 0) ); 255 SYSCALL( sporadic_partitioned(10, 100, 0) );
256 SYSCALL( task_mode(LITMUS_RT_TASK) ); 256 SYSCALL( task_mode(LITMUS_RT_TASK) );
@@ -281,7 +281,7 @@ TESTCASE(not_lock_pcp_be, P_FP,
281{ 281{
282 int fd, od; 282 int fd, od;
283 283
284 SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT) ); 284 SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT, S_IRUSR) );
285 285
286 /* BE tasks are not even allowed to open a PCP semaphore */ 286 /* BE tasks are not even allowed to open a PCP semaphore */
287 SYSCALL_FAILS(EPERM, od = open_pcp_sem(fd, 0, 1) ); 287 SYSCALL_FAILS(EPERM, od = open_pcp_sem(fd, 0, 1) );
@@ -303,7 +303,7 @@ TESTCASE(lock_mpcp, P_FP,
303{ 303{
304 int fd, od; 304 int fd, od;
305 305
306 SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT) ); 306 SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT, S_IRUSR) );
307 307
308 SYSCALL( sporadic_partitioned(10, 100, 0) ); 308 SYSCALL( sporadic_partitioned(10, 100, 0) );
309 SYSCALL( task_mode(LITMUS_RT_TASK) ); 309 SYSCALL( task_mode(LITMUS_RT_TASK) );