aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile13
-rw-r--r--bin/color.c2
-rw-r--r--bin/colorbench.c37
-rw-r--r--bin/colorspin.c99
-rw-r--r--bin/colortest.c1
-rw-r--r--bin/perfcounters.c27
-rw-r--r--bin/rtspin.c222
-rw-r--r--bin/singlepage.c158
-rw-r--r--include/perfcounters.h10
-rw-r--r--include/spin_common.h42
-rw-r--r--src/spin_common.c235
11 files changed, 614 insertions, 232 deletions
diff --git a/Makefile b/Makefile
index 5527862..b557ee3 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ host-arch := $(shell uname -m | \
12ARCH ?= ${host-arch} 12ARCH ?= ${host-arch}
13 13
14# LITMUS_KERNEL -- where to find the litmus kernel? 14# LITMUS_KERNEL -- where to find the litmus kernel?
15LITMUS_KERNEL ?= ../backup-litmus-rt 15LITMUS_KERNEL ?= ../litmus-rt
16 16
17 17
18# ############################################################################## 18# ##############################################################################
@@ -72,7 +72,8 @@ AR := ${CROSS_COMPILE}${AR}
72 72
73all = lib ${rt-apps} 73all = lib ${rt-apps}
74rt-apps = cycles base_task rt_launch rtspin release_ts measure_syscall \ 74rt-apps = cycles base_task rt_launch rtspin release_ts measure_syscall \
75 base_mt_task runtests colortest colorbench testcounters bespin 75 base_mt_task runtests colortest colorbench testcounters \
76 colorspin singlepage
76 77
77.PHONY: all lib clean dump-config TAGS tags cscope help 78.PHONY: all lib clean dump-config TAGS tags cscope help
78 79
@@ -213,6 +214,9 @@ lib-rt_launch = -lgsl -lgslcblas
213obj-rtspin = rtspin.o common.o 214obj-rtspin = rtspin.o common.o
214lib-rtspin = -lrt -lgsl -lgslcblas 215lib-rtspin = -lrt -lgsl -lgslcblas
215 216
217obj-colorspin = colorspin.o common.o
218lib-colorspin = -lrt -lgsl -lgslcblas
219
216obj-rtspin.ovh = rtspin.ovh.o common.o 220obj-rtspin.ovh = rtspin.ovh.o common.o
217lib-rtspin.ovh = -lrt -lgsl -lgslcblas 221lib-rtspin.ovh = -lrt -lgsl -lgslcblas
218 222
@@ -236,6 +240,9 @@ lib-colortest = -static
236obj-colorbench = colorbench.o color.o perfcounters.o common.o 240obj-colorbench = colorbench.o color.o perfcounters.o common.o
237lib-colorbench = -lpthread -lrt -lgsl -lgslcblas 241lib-colorbench = -lpthread -lrt -lgsl -lgslcblas
238 242
243obj-singlepage = singlepage.o color.o perfcounters.o common.o
244lib-singlepage = -lgsl -lgslcblas
245
239obj-testcounters = testcounters.o 246obj-testcounters = testcounters.o
240lib-testcounters = 247lib-testcounters =
241 248
@@ -244,7 +251,7 @@ lib-testcounters =
244 251
245.SECONDEXPANSION: 252.SECONDEXPANSION:
246${rt-apps}: $${obj-$$@} liblitmus.a 253${rt-apps}: $${obj-$$@} liblitmus.a
247 $(CC) -o $@ $(LDFLAGS) ${ldf-$@} $(filter-out liblitmus.a,$+) $(LOADLIBS) $(LDLIBS) ${liblitmus-flags} ${lib-$@} 254 $(CC) -o $@ $(LDFLAGS) ${ldf-$@} $(filter-out liblitmus.a,$+) $(LOADLIBS) $(LDLIBS) ${lib-$@} ${liblitmus-flags}
248 255
249# ############################################################################## 256# ##############################################################################
250# Dependency resolution. 257# Dependency resolution.
diff --git a/bin/color.c b/bin/color.c
index 2ec97a4..c1753a4 100644
--- a/bin/color.c
+++ b/bin/color.c
@@ -21,7 +21,7 @@ static int map_file(const char* filename, void **addr, size_t size)
21 if (fd >= 0) { 21 if (fd >= 0) {
22 *addr = mmap(NULL, size, 22 *addr = mmap(NULL, size,
23 PROT_READ | PROT_WRITE, 23 PROT_READ | PROT_WRITE,
24 MAP_PRIVATE, 24 MAP_SHARED,
25 fd, 0); 25 fd, 0);
26 if (*addr == MAP_FAILED) 26 if (*addr == MAP_FAILED)
27 error = -1; 27 error = -1;
diff --git a/bin/colorbench.c b/bin/colorbench.c
index c91b731..ac0c01a 100644
--- a/bin/colorbench.c
+++ b/bin/colorbench.c
@@ -18,17 +18,25 @@
18#define DEBUG 1 18#define DEBUG 1
19#define NR_LOOPS 10 19#define NR_LOOPS 10
20 20
21#if 0
21/* Pound */ 22/* Pound */
22#define NR_CPUS 4 23#define NR_CPUS 4
23#define CACHE_SIZE_MB 8 24#define CACHE_SIZE_MB 8
24#define ASSOC 16 25#define ASSOC 16
25#define LINE_SIZE 64 26#define LINE_SIZE 64
27#endif
28
29/* Flare */
30#define NR_CPUS 1
31#define CACHE_SIZE_MB 3
32#define ASSOC 12
33#define LINE_SIZE 64
26 34
27#define CACHE_SIZE (CACHE_SIZE_MB * 1024 * 1024) 35#define CACHE_SIZE (CACHE_SIZE_MB * 1024 * 1024)
28#define TOTAL_COLORS (CACHE_SIZE / ASSOC / PAGE_SIZE) 36#define TOTAL_COLORS (CACHE_SIZE / ASSOC / PAGE_SIZE)
29 37
30/* number of colors we actually use */ 38/* number of colors we actually use (cannot be zero) */
31#define USE_COLORS (TOTAL_COLORS >> color_shift) 39#define USE_COLORS ({int v = TOTAL_COLORS >> color_shift; (v) ? v : 1; })
32 40
33/* how many adjacent pages of the same color we need to allocate */ 41/* how many adjacent pages of the same color we need to allocate */
34#define CONTIG_COLORS (ARENA_PAGES / USE_COLORS) 42#define CONTIG_COLORS (ARENA_PAGES / USE_COLORS)
@@ -76,7 +84,7 @@ static pthread_barrier_t barrier;
76static int nr_threads; 84static int nr_threads;
77static int arena_size; 85static int arena_size;
78static int color_shift; 86static int color_shift;
79//static int *page_line_order; 87static int *page_line_order;
80static int *arena_line_order; 88static int *arena_line_order;
81static struct perf_counter perf_counters[NR_CPUS * NR_PERF_COUNTERS]; 89static struct perf_counter perf_counters[NR_CPUS * NR_PERF_COUNTERS];
82 90
@@ -138,7 +146,6 @@ void sattolo(int *items, const int len)
138 * Starting at position 0 in the page_line_order means the cycle ends with 0. 146 * Starting at position 0 in the page_line_order means the cycle ends with 0.
139 * We use 0 in the arena to signify that we are done reading. 147 * We use 0 in the arena to signify that we are done reading.
140 */ 148 */
141#if 0
142static void init_arena_page_line_order(int *arena) 149static void init_arena_page_line_order(int *arena)
143{ 150{
144 int cur_page; 151 int cur_page;
@@ -168,7 +175,8 @@ static void init_arena_page_line_order(int *arena)
168 } 175 }
169 } 176 }
170} 177}
171#endif 178
179#if 0
172static void init_arena_line_order(int *arena) 180static void init_arena_line_order(int *arena)
173{ 181{
174 int cur_line; 182 int cur_line;
@@ -184,6 +192,7 @@ static void init_arena_line_order(int *arena)
184 arena[idx] = next_idx; 192 arena[idx] = next_idx;
185 } 193 }
186} 194}
195#endif
187 196
188static void setup_colors(struct pthread_state *state) 197static void setup_colors(struct pthread_state *state)
189{ 198{
@@ -262,8 +271,8 @@ int thread_init(struct pthread_state *state)
262 goto out; 271 goto out;
263 } 272 }
264 273
265 //init_arena_page_line_order(state->arena); 274 init_arena_page_line_order(state->arena);
266 init_arena_line_order(state->arena); 275 //init_arena_line_order(state->arena);
267 276
268 err = mlockall(MCL_CURRENT|MCL_FUTURE); 277 err = mlockall(MCL_CURRENT|MCL_FUTURE);
269 if (err) 278 if (err)
@@ -405,7 +414,7 @@ int main(int argc, char **argv)
405 } 414 }
406 415
407 pthread_state = malloc(nr_threads * sizeof(*pthread_state)); 416 pthread_state = malloc(nr_threads * sizeof(*pthread_state));
408 //page_line_order = malloc(PAGE_LINES * sizeof(*page_line_order)); 417 page_line_order = malloc(PAGE_LINES * sizeof(*page_line_order));
409 arena_line_order = malloc(ARENA_LINES * sizeof(*arena_line_order)); 418 arena_line_order = malloc(ARENA_LINES * sizeof(*arena_line_order));
410 //if (!pthread_state || !page_line_order) { 419 //if (!pthread_state || !page_line_order) {
411 if (!pthread_state || !arena_line_order) { 420 if (!pthread_state || !arena_line_order) {
@@ -420,9 +429,10 @@ int main(int argc, char **argv)
420 CHECK(pthread_attr_setdetachstate, &attr, PTHREAD_CREATE_JOINABLE); 429 CHECK(pthread_attr_setdetachstate, &attr, PTHREAD_CREATE_JOINABLE);
421 CHECK(pthread_barrier_init, &barrier, NULL, nr_threads); 430 CHECK(pthread_barrier_init, &barrier, NULL, nr_threads);
422 431
423 //sattolo(page_line_order, PAGE_LINES); 432 sattolo(page_line_order, PAGE_LINES);
424 sattolo(arena_line_order, ARENA_LINES); 433 //sattolo(arena_line_order, ARENA_LINES);
425 //sequential(page_line_order, PAGE_LINES); 434 //sequential(page_line_order, PAGE_LINES);
435 //sequential(arena_line_order, PAGE_LINES);
426 436
427 for (i = 0; i < nr_threads; i++) { 437 for (i = 0; i < nr_threads; i++) {
428 pthread_state[i].tid = i; 438 pthread_state[i].tid = i;
@@ -447,12 +457,15 @@ int main(int argc, char **argv)
447 CHECK(pthread_barrier_destroy, &barrier); 457 CHECK(pthread_barrier_destroy, &barrier);
448 CHECK(pthread_attr_destroy, &attr); 458 CHECK(pthread_attr_destroy, &attr);
449 459
460 printf("page size: %d\n", PAGE_SIZE);
461 printf("cache size: %d\n", CACHE_SIZE);
462 printf("total colors: %d\n", TOTAL_COLORS);
463 printf("use colors: %d\n", USE_COLORS);
464 printf("contiguous colors: %d\n", CONTIG_COLORS);
450 printf("arena size: %d\n", arena_size); 465 printf("arena size: %d\n", arena_size);
451 printf("color shift: %d\n", color_shift); 466 printf("color shift: %d\n", color_shift);
452 printf("arena pages: %d\n", ARENA_PAGES); 467 printf("arena pages: %d\n", ARENA_PAGES);
453 printf("arena lines: %d\n", ARENA_LINES); 468 printf("arena lines: %d\n", ARENA_LINES);
454 printf("use colors: %d\n", USE_COLORS);
455 printf("contiguous colors: %d\n", CONTIG_COLORS);
456 //print_perf_counters(); 469 //print_perf_counters();
457 470
458out: 471out:
diff --git a/bin/colorspin.c b/bin/colorspin.c
new file mode 100644
index 0000000..83a7390
--- /dev/null
+++ b/bin/colorspin.c
@@ -0,0 +1,99 @@
1#include <stdlib.h>
2#include <unistd.h>
3#include <assert.h>
4#include "spin_common.h"
5#include "common.h"
6
7static void usage(char *error) {
8 fprintf(stderr, "Error: %s\n", error);
9 fprintf(stderr,
10 "Usage:\n"
11 " color_spin [COMMON-OPTS] WCET PERIOD DURATION\n"
12 " color_spin [COMMON-OPTS] -f FILE [-o COLUMN] WCET PERIOD\n"
13 "\n"
14 "COMMON-OPTS = [-w] [-p PARTITION] [-c CLASS] [-s SCALE]\n"
15 " [-x COLOR-FILE]\n"
16 "\n"
17 "WCET and PERIOD are milliseconds, DURATION is seconds.\n");
18 exit(EXIT_FAILURE);
19}
20
21static void get_page_colors(const char *file, int *num_colors,
22 int **colors, int **pages)
23{
24 FILE *fstream;
25 int ch, line;
26 *num_colors = 0;
27
28 fstream = fopen(file, "r");
29 if (!fstream)
30 bail_out("could not open page color file\n");
31
32 do {
33 skip_comments(fstream);
34 ch = skip_to_next_line(fstream);
35 if (ch != EOF)
36 ++(*num_colors);
37 } while (ch != EOF);
38
39 if (-1 == fseek(fstream, 0L, SEEK_SET))
40 bail_out("rewinding file failed");
41
42 *colors = calloc(*num_colors, sizeof(*colors));
43 *pages = calloc(*num_colors, sizeof(*pages));
44 if (!*pages || !*colors)
45 bail_out("couldn't allocate memory");
46
47 for (line = 0; line < *num_colors && !feof(fstream); ++line) {
48
49 skip_comments(fstream);
50
51 if (2 != fscanf(fstream, "%d,%d",
52 &(*colors)[line], &(*pages)[line])) {
53 fprintf(stderr, "invalid color pages near line %d\n",
54 line);
55 exit(EXIT_FAILURE);
56 }
57
58 skip_to_next_line(fstream);
59 }
60
61 assert(line == *num_colors);
62 fclose(fstream);
63}
64
65#define OPTSTR SPIN_OPTS "x:"
66
67int main(int argc, char** argv)
68{
69 const char* file = NULL;
70 int *pages, *colors, num_colors, opt, i;
71 struct spin_opts sopts;
72
73 init_spin_opts(&sopts, usage, NULL);
74
75 while ((opt = getopt(argc, argv, OPTSTR)) != -1) {
76 switch (opt) {
77 case 'x':
78 file = optarg;
79 break;
80 case ':':
81 usage("Argument missing.");
82 break;
83 case '?':
84 default:
85 if (!do_spin_opt(&sopts, opt, optarg))
86 usage("Bad argument.");
87 break;
88 }
89 }
90
91 if (file) {
92 get_page_colors(file, &num_colors, &colors, &pages);
93 for (i = 0; i < num_colors; i++)
94 printf("color %d has %d pages\n", colors[i], pages[i]);
95 }
96
97 /* setup_spin(&sopts, optind, argc, argv); */
98 return 0;
99}
diff --git a/bin/colortest.c b/bin/colortest.c
index 02a9169..bc66522 100644
--- a/bin/colortest.c
+++ b/bin/colortest.c
@@ -1,7 +1,6 @@
1#include <stdlib.h> 1#include <stdlib.h>
2#include <stdio.h> 2#include <stdio.h>
3#include <stdint.h> 3#include <stdint.h>
4
5#include <litmus/rt_param.h> 4#include <litmus/rt_param.h>
6 5
7#include "color.h" 6#include "color.h"
diff --git a/bin/perfcounters.c b/bin/perfcounters.c
index 6302164..975ee5b 100644
--- a/bin/perfcounters.c
+++ b/bin/perfcounters.c
@@ -39,7 +39,7 @@ struct perf_counter_setup {
39}; 39};
40 40
41#if 0 41#if 0
42/* these events are always zero */ 42/* on Pound, these events are always zero */
43static struct perf_fd perf_fds[] = { 43static struct perf_fd perf_fds[] = {
44 { 44 {
45 .fd = -1, 45 .fd = -1,
@@ -61,6 +61,8 @@ static struct perf_fd perf_fds[] = {
61}; 61};
62#endif 62#endif
63 63
64#if 0
65/* these are for Pound */
64static struct perf_counter_setup perf_setup[NR_PERF_COUNTERS] = { 66static struct perf_counter_setup perf_setup[NR_PERF_COUNTERS] = {
65#if 0 67#if 0
66 { 68 {
@@ -108,7 +110,30 @@ static struct perf_counter_setup perf_setup[NR_PERF_COUNTERS] = {
108#endif 110#endif
109 }, 111 },
110}; 112};
113#endif
111 114
115static struct perf_counter_setup perf_setup[NR_PERF_COUNTERS] = {
116 {
117 .name = "Linux LL Cache Read Miss",
118 .type = PERF_TYPE_HW_CACHE,
119 .config = ATTR_CONFIG_CACHE(LL, OP_READ, RESULT_MISS),
120#if 0
121 /* read misses */
122 .config = ATTR_CONFIG_CACHE(LL, OP_READ, RESULT_MISS),
123 /* write misses */
124 .config = ATTR_CONFIG_CACHE(LL, OP_WRITE, RESULT_MISS),
125 /* prefetch misses */
126 .config = ATTR_CONFIG_CACHE(LL, OP_PREFETCH, RESULT_MISS),
127#endif
128 },
129#if (2 == NR_PERF_COUNTERS)
130 {
131 .name = "Cycles",
132 .type = PERF_TYPE_HARDWARE,
133 .config = PERF_COUNT_HW_CPU_CYCLES,
134 },
135#endif
136};
112 137
113/* from kernel tools/perf/perf.h */ 138/* from kernel tools/perf/perf.h */
114int sys_perf_event_open(struct perf_event_attr *attr, pid_t pid, 139int sys_perf_event_open(struct perf_event_attr *attr, pid_t pid,
diff --git a/bin/rtspin.c b/bin/rtspin.c
index a19637c..d823edc 100644
--- a/bin/rtspin.c
+++ b/bin/rtspin.c
@@ -1,15 +1,7 @@
1#include <sys/time.h>
2
3#include <stdio.h>
4#include <stdlib.h> 1#include <stdlib.h>
5#include <unistd.h> 2#include <unistd.h>
6#include <time.h>
7#include <assert.h>
8#include <strings.h>
9#include <string.h>
10 3
11#include "litmus.h" 4#include "spin_common.h"
12#include "common.h"
13 5
14static void usage(char *error) { 6static void usage(char *error) {
15 fprintf(stderr, "Error: %s\n", error); 7 fprintf(stderr, "Error: %s\n", error);
@@ -20,80 +12,11 @@ static void usage(char *error) {
20 " rt_spin -l\n" 12 " rt_spin -l\n"
21 "\n" 13 "\n"
22 "COMMON-OPTS = [-w] [-p PARTITION] [-c CLASS] [-s SCALE]\n" 14 "COMMON-OPTS = [-w] [-p PARTITION] [-c CLASS] [-s SCALE]\n"
23 " [-h NUM-COLORS,AVG-WAYS]\n"
24 "\n" 15 "\n"
25 "WCET and PERIOD are milliseconds, DURATION is seconds.\n"); 16 "WCET and PERIOD are milliseconds, DURATION is seconds.\n");
26 exit(EXIT_FAILURE); 17 exit(EXIT_FAILURE);
27} 18}
28 19
29/*
30 * returns the character that made processing stop, newline or EOF
31 */
32static int skip_to_next_line(FILE *fstream)
33{
34 int ch;
35 for (ch = fgetc(fstream); ch != EOF && ch != '\n'; ch = fgetc(fstream));
36 return ch;
37}
38
39static void skip_comments(FILE *fstream)
40{
41 int ch;
42 for (ch = fgetc(fstream); ch == '#'; ch = fgetc(fstream))
43 skip_to_next_line(fstream);
44 ungetc(ch, fstream);
45}
46
47static void get_exec_times(const char *file, const int column,
48 int *num_jobs, double **exec_times)
49{
50 FILE *fstream;
51 int cur_job, cur_col, ch;
52 *num_jobs = 0;
53
54 fstream = fopen(file, "r");
55 if (!fstream)
56 bail_out("could not open execution time file");
57
58 /* figure out the number of jobs */
59 do {
60 skip_comments(fstream);
61 ch = skip_to_next_line(fstream);
62 if (ch != EOF)
63 ++(*num_jobs);
64 } while (ch != EOF);
65
66 if (-1 == fseek(fstream, 0L, SEEK_SET))
67 bail_out("rewinding file failed");
68
69 /* allocate space for exec times */
70 *exec_times = calloc(*num_jobs, sizeof(*exec_times));
71 if (!*exec_times)
72 bail_out("couldn't allocate memory");
73
74 for (cur_job = 0; cur_job < *num_jobs && !feof(fstream); ++cur_job) {
75
76 skip_comments(fstream);
77
78 for (cur_col = 1; cur_col < column; ++cur_col) {
79 /* discard input until we get to the column we want */
80 fscanf(fstream, "%*s,");
81 }
82
83 /* get the desired exec. time */
84 if (1 != fscanf(fstream, "%lf", (*exec_times)+cur_job)) {
85 fprintf(stderr, "invalid execution time near line %d\n",
86 cur_job);
87 exit(EXIT_FAILURE);
88 }
89
90 skip_to_next_line(fstream);
91 }
92
93 assert(cur_job == *num_jobs);
94 fclose(fstream);
95}
96
97#define NUMS 4096 20#define NUMS 4096
98static int num[NUMS]; 21static int num[NUMS];
99static char* progname; 22static char* progname;
@@ -161,70 +84,27 @@ static int job(double exec_time, double program_end)
161 } 84 }
162} 85}
163 86
164#define OPTSTR "p:c:wlveo:f:s:h:" 87#define OPTSTR SPIN_OPTS "l"
165 88
166int main(int argc, char** argv) 89int main(int argc, char** argv)
167{ 90{
168 int ret; 91 int opt, test_loop = 0;
169 lt_t wcet; 92 struct spin_opts sopts;
170 lt_t period;
171 double wcet_ms, period_ms;
172 int migrate = 0;
173 int cpu = 0;
174 int opt;
175 int wait = 0;
176 int test_loop = 0;
177 int column = 1;
178 const char *file = NULL;
179 int want_enforcement = 0;
180 double duration = 0, start;
181 double *exec_times = NULL;
182 double scale = 1.0;
183 task_class_t class = RT_CLASS_HARD;
184 int cur_job, num_jobs;
185 int task_colors = 0;
186 int avg_ways = 0;
187 93
188 progname = argv[0]; 94 init_spin_opts(&sopts, usage, job);
189 95
190 while ((opt = getopt(argc, argv, OPTSTR)) != -1) { 96 while ((opt = getopt(argc, argv, OPTSTR)) != -1) {
191 switch (opt) { 97 switch (opt) {
192 case 'w':
193 wait = 1;
194 break;
195 case 'p':
196 cpu = atoi(optarg);
197 migrate = 1;
198 break;
199 case 'c':
200 class = str2class(optarg);
201 if (class == -1)
202 usage("Unknown task class.");
203 break;
204 case 'e':
205 want_enforcement = 1;
206 break;
207 case 'l': 98 case 'l':
208 test_loop = 1; 99 test_loop = 1;
209 break; 100 break;
210 case 'o':
211 column = atoi(optarg);
212 break;
213 case 'f':
214 file = optarg;
215 break;
216 case 's':
217 scale = atof(optarg);
218 break;
219 case 'h':
220 sscanf(optarg, "%d,%d", &task_colors, &avg_ways);
221 break;
222 case ':': 101 case ':':
223 usage("Argument missing."); 102 usage("Argument missing.");
224 break; 103 break;
225 case '?': 104 case '?':
226 default: 105 default:
227 usage("Bad argument."); 106 if (!do_spin_opt(&sopts, opt, optarg))
107 usage("Bad argument.");
228 break; 108 break;
229 } 109 }
230 } 110 }
@@ -234,92 +114,8 @@ int main(int argc, char** argv)
234 return 0; 114 return 0;
235 } 115 }
236 116
237 if (file) { 117 setup_spin(&sopts, optind, argc, argv);
238 get_exec_times(file, column, &num_jobs, &exec_times); 118 run_spin(&sopts);
239
240 if (argc - optind < 2)
241 usage("Arguments missing.");
242
243 for (cur_job = 0; cur_job < num_jobs; ++cur_job) {
244 /* convert the execution time to seconds */
245 duration += exec_times[cur_job] * 0.001;
246 }
247 } else {
248 /*
249 * if we're not reading from the CSV file, then we need
250 * three parameters
251 */
252 if (argc - optind < 3)
253 usage("Arguments missing.");
254 }
255
256 wcet_ms = atof(argv[optind + 0]);
257 period_ms = atof(argv[optind + 1]);
258
259 wcet = wcet_ms * __NS_PER_MS;
260 period = period_ms * __NS_PER_MS;
261 if (wcet <= 0)
262 usage("The worst-case execution time must be a "
263 "positive number.");
264 if (period <= 0)
265 usage("The period must be a positive number.");
266 if (!file && wcet > period) {
267 usage("The worst-case execution time must not "
268 "exceed the period.");
269 }
270
271 if (!file)
272 duration = atof(argv[optind + 2]);
273 else if (file && num_jobs > 1)
274 duration += period_ms * 0.001 * (num_jobs - 1);
275
276 if (migrate) {
277 ret = be_migrate_to(cpu);
278 if (ret < 0)
279 bail_out("could not migrate to target partition");
280 }
281
282 ret = sporadic_task_ns(wcet, period, 0, cpu, class,
283 want_enforcement ? PRECISE_ENFORCEMENT
284 : NO_ENFORCEMENT,
285 migrate);
286 if (ret < 0)
287 bail_out("could not setup rt task params");
288
289 init_litmus();
290
291 request_resources(task_colors, avg_ways);
292
293 ret = task_mode(LITMUS_RT_TASK);
294 if (ret != 0)
295 bail_out("could not become RT task");
296
297 if (wait) {
298 ret = wait_for_ts_release();
299 if (ret != 0)
300 bail_out("wait_for_ts_release()");
301 }
302
303 start = wctime();
304
305 if (file) {
306 /* use times read from the CSV file */
307 for (cur_job = 0; cur_job < num_jobs; ++cur_job) {
308 /* convert job's length to seconds */
309 job(exec_times[cur_job] * 0.001 * scale,
310 start + duration);
311 }
312 } else {
313 /* conver to seconds and scale */
314 while (job(wcet_ms * 0.001 * scale, start + duration));
315 }
316
317 ret = task_mode(BACKGROUND_TASK);
318 if (ret != 0)
319 bail_out("could not become regular task (huh?)");
320
321 if (file)
322 free(exec_times);
323 119
324 return 0; 120 return 0;
325} 121}
diff --git a/bin/singlepage.c b/bin/singlepage.c
new file mode 100644
index 0000000..376f55d
--- /dev/null
+++ b/bin/singlepage.c
@@ -0,0 +1,158 @@
1#include <stdint.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <sys/ioctl.h>
5
6#include <litmus/rt_param.h>
7
8#include "perfcounters.h"
9#include "color.h"
10#include "litmus.h"
11
12#define CPU 0
13#define NR_PAGES 10
14#define NR_LOOPS 10
15
16struct page {
17 struct page *ptr;
18 char _unused[PAGE_SIZE - sizeof(struct page*)];
19};
20
21/*
22 * Get a random number in [0, max). Not really a good way to do this.
23 */
24static int randrange(const int max)
25{
26 return (rand() / (RAND_MAX / max + 1));
27}
28
29/*
30 * Sattolo's algorithm makes a random cycle that includes all the elements
31 * in the items array.
32 */
33static void sattolo(int *items, const int len)
34{
35 int i;
36 /* first set up 0, 1, ..., n - 1 */
37 for (i = 0; i < len; i++)
38 items[i] = i;
39 /* note: i is now n */
40 while (1 < i--) {
41 /* 0 <= j < i */
42 int t, j = randrange(i);
43 t = items[i];
44 items[i] = items[j];
45 items[j] = t;
46 }
47}
48static struct page * do_read(struct page* page)
49{
50 struct page *old;
51 do {
52 old = page;
53 page = page->ptr;
54 } while (page);
55 return old;
56}
57
58static inline void get_counters(const struct perf_counter *pc, uint64_t *vals)
59{
60 read_perf_counter(&pc[0], &vals[0]);
61#if (2 == NR_PERF_COUNTERS)
62 read_perf_counter(&pc[1], &vals[1]);
63#endif
64}
65
66static void print_counters(uint64_t *vals, double div)
67{
68 int i;
69 for (i = 0; i < NR_PERF_COUNTERS; i++) {
70 printf("counter %d: %12lu div: %8.3f\n", i, vals[i], vals[i] / div);
71 }
72 printf("\n");
73}
74
75#define quit_on_err(err, msg) do { \
76 if (err) { \
77 fprintf(stderr, "error: " msg); \
78 goto out; \
79 } \
80} while (0)
81
82int main(int argc, char **argv)
83{
84 static struct perf_counter perf_counters[NR_PERF_COUNTERS];
85 struct color_ctrl_page *color_ctrl;
86 struct page *pages[NR_PAGES];
87 struct page *page_ptr;
88 int read_order[NR_PAGES];
89 uint64_t counter_vals[NR_PERF_COUNTERS];
90 int i, err = 0;
91
92 err = be_migrate_to(CPU);
93 quit_on_err(err, "migrate to cpu\n");
94
95 err = setup_cpu_perf(CPU, -1, perf_counters);
96 quit_on_err(err, "setup perf\n");
97
98 ioctl(perf_counters[0].fd, PERF_EVENT_IOC_DISABLE);
99 ioctl(perf_counters[0].fd, PERF_EVENT_IOC_RESET);
100
101
102 err = map_color_ctrl((void**)&color_ctrl);
103 quit_on_err(err, "map color ctrl\n");
104
105 color_ctrl->colors[0] = 0;
106
107 for (i = 0; i < NR_PAGES; i++) {
108 pages[i] = color_malloc(sizeof(*pages[i]));
109 if (!pages[i]) {
110 fprintf(stderr, "could not color malloc\n");
111 err = -1;
112 goto out;
113 }
114 }
115
116 sattolo(read_order, NR_PAGES);
117
118 ioctl(perf_counters[0].fd, PERF_EVENT_IOC_ENABLE);
119
120 for (i = 0; i < NR_PAGES; i++) {
121 if (0 != read_order[i]) {
122 /* not the last element */
123 pages[i]->ptr = pages[read_order[i]];
124 } else {
125 /* last element should be NULL (terminate the cycle) */
126 pages[i]->ptr = NULL;
127 }
128 }
129
130 get_counters(perf_counters, counter_vals);
131 print_counters(counter_vals, NR_PAGES);
132 ioctl(perf_counters[0].fd, PERF_EVENT_IOC_RESET);
133
134 page_ptr = do_read(pages[0]);
135 get_counters(perf_counters, counter_vals);
136 print_counters(counter_vals, NR_PAGES);
137 ioctl(perf_counters[0].fd, PERF_EVENT_IOC_RESET);
138
139 page_ptr = do_read(pages[0]);
140 get_counters(perf_counters, counter_vals);
141 print_counters(counter_vals, NR_PAGES);
142 ioctl(perf_counters[0].fd, PERF_EVENT_IOC_RESET);
143
144 page_ptr = do_read(pages[0]);
145 get_counters(perf_counters, counter_vals);
146 print_counters(counter_vals, NR_PAGES);
147 ioctl(perf_counters[0].fd, PERF_EVENT_IOC_RESET);
148
149 for (i = 0; i < NR_LOOPS; i++) {
150 page_ptr = do_read(pages[0]);
151 }
152 get_counters(perf_counters, counter_vals);
153 print_counters(counter_vals, NR_PAGES * NR_LOOPS);
154 ioctl(perf_counters[0].fd, PERF_EVENT_IOC_DISABLE);
155
156out:
157 return err;
158}
diff --git a/include/perfcounters.h b/include/perfcounters.h
index 03f94fb..0329921 100644
--- a/include/perfcounters.h
+++ b/include/perfcounters.h
@@ -5,7 +5,15 @@
5 5
6#include "../../litmus-rt/include/linux/perf_event.h" 6#include "../../litmus-rt/include/linux/perf_event.h"
7 7
8#define NR_PERF_COUNTERS 4 8/* on Pound */
9//#define NR_PERF_COUNTERS 4
10
11/*
12 * Flare: 1 gets you the L2 read misses and 2 gets you that plus the
13 * CPU clock counter. However, accessing the CPU clock will add misses
14 * when you go to read the performance counters, so I don't use it.
15 */
16#define NR_PERF_COUNTERS 1
9 17
10/* 18/*
11 * Retain this information with a performance counter file descriptor. 19 * Retain this information with a performance counter file descriptor.
diff --git a/include/spin_common.h b/include/spin_common.h
new file mode 100644
index 0000000..977c201
--- /dev/null
+++ b/include/spin_common.h
@@ -0,0 +1,42 @@
1#ifndef SPIN_COMMON_H_
2#define SPIN_COMMON_H_
3
4#include <stdio.h>
5#include "litmus.h"
6
7#define SPIN_OPTS "p:c:weo:f:s:"
8
9typedef void (*usage_t)(char *error);
10typedef int (*job_t)(double exec, double end);
11
12struct spin_opts {
13 usage_t usage;
14 job_t job;
15
16 int wait;
17 int cpu;
18 int migrate;
19 int column;
20 int want_enforcement;
21 double scale;
22 task_class_t class;
23 const char* file;
24
25 int num_jobs;
26 double duration;
27 double *exec_times;
28 double wcet;
29 double period;
30};
31
32void init_spin_opts(struct spin_opts *sopts, usage_t usage, job_t job);
33
34int skip_to_next_line(FILE *fstream);
35void skip_comments(FILE *fstream);
36
37int do_spin_opt(struct spin_opts *sopts, int opt, const char *optarg);
38
39void setup_spin(struct spin_opts *sopts, int last, int argc, char** argv);
40void run_spin(struct spin_opts *sopts);
41
42#endif
diff --git a/src/spin_common.c b/src/spin_common.c
new file mode 100644
index 0000000..157a9bb
--- /dev/null
+++ b/src/spin_common.c
@@ -0,0 +1,235 @@
1#include <stdlib.h>
2#include <assert.h>
3
4#include "spin_common.h"
5#include "common.h"
6
7/*
8 * returns the character that made processing stop, newline or EOF
9 */
10int skip_to_next_line(FILE *fstream)
11{
12 int ch;
13 for (ch = fgetc(fstream); ch != EOF && ch != '\n'; ch = fgetc(fstream));
14 return ch;
15}
16
17void skip_comments(FILE *fstream)
18{
19 int ch;
20 for (ch = fgetc(fstream); ch == '#'; ch = fgetc(fstream))
21 skip_to_next_line(fstream);
22 ungetc(ch, fstream);
23}
24
25static void get_exec_times(const char *file, const int column,
26 int *num_jobs, double **exec_times)
27{
28 FILE *fstream;
29 int curr_job, cur_col, ch;
30 *num_jobs = 0;
31
32 fstream = fopen(file, "r");
33 if (!fstream)
34 bail_out("could not open execution time file");
35
36 /* figure out the number of jobs */
37 do {
38 skip_comments(fstream);
39 ch = skip_to_next_line(fstream);
40 if (ch != EOF)
41 ++(*num_jobs);
42 } while (ch != EOF);
43
44 if (-1 == fseek(fstream, 0L, SEEK_SET))
45 bail_out("rewinding file failed");
46
47 /* allocate space for exec times */
48 *exec_times = calloc(*num_jobs, sizeof(*exec_times));
49 if (!*exec_times)
50 bail_out("couldn't allocate memory");
51
52 for (curr_job = 0; curr_job < *num_jobs && !feof(fstream); ++curr_job) {
53
54 skip_comments(fstream);
55
56 for (cur_col = 1; cur_col < column; ++cur_col) {
57 /* discard input until we get to the column we want */
58 fscanf(fstream, "%*s,");
59 }
60
61 /* get the desired exec. time */
62 if (1 != fscanf(fstream, "%lf", (*exec_times)+curr_job)) {
63 fprintf(stderr, "invalid execution time near line %d\n",
64 curr_job);
65 exit(EXIT_FAILURE);
66 }
67
68 skip_to_next_line(fstream);
69 }
70
71 assert(curr_job == *num_jobs);
72 fclose(fstream);
73}
74
75
76
77int do_spin_opt(struct spin_opts *sopts, int opt, const char *optarg)
78{
79 int ret = 1;
80
81 switch (opt) {
82 case 'w':
83 sopts->wait = 1;
84 break;
85 case 'p':
86 sopts->cpu = atoi(optarg);
87 sopts->migrate = 1;
88 break;
89 case 'c':
90 sopts->class = str2class(optarg);
91 if (sopts->class == -1)
92 sopts->usage("Unknown task class.");
93 break;
94 case 'e':
95 sopts->want_enforcement = 1;
96 break;
97 case 'o':
98 sopts->column = atoi(optarg);
99 break;
100 case 'f':
101 sopts->file = optarg;
102 break;
103 case 's':
104 sopts->scale = atof(optarg);
105 break;
106 default:
107 ret = 0;
108 }
109
110 return ret;
111}
112
113void init_spin_opts(struct spin_opts *sopts, usage_t usage, job_t job)
114{
115 sopts->usage = usage;
116 sopts->job = job;
117
118 sopts->wait = 0;
119 sopts->cpu = 0;
120 sopts->migrate = 0;
121 sopts->column = 1;
122 sopts->want_enforcement = 0;
123 sopts->scale = 1.0;
124 sopts->class = RT_CLASS_HARD;
125 sopts->file = NULL;
126
127 sopts->num_jobs = 0;
128 sopts->duration = 0;
129 sopts->exec_times = NULL;
130
131 sopts->wcet = 0;
132 sopts->period = 0;
133}
134
135
136void setup_spin(struct spin_opts *sopts, int last, int argc, char** argv)
137{
138 int ret;
139 double wcet_ns, period_ns;
140 int curr_job;
141
142 if (sopts->file) {
143 get_exec_times(sopts->file, sopts->column,
144 &sopts->num_jobs, &sopts->exec_times);
145
146 if (argc - last < 2)
147 sopts->usage("Arguments missing.");
148
149 for (curr_job = 0; curr_job < sopts->num_jobs; ++curr_job) {
150 /* convert the execution time to seconds */
151 sopts->duration += sopts->exec_times[curr_job] * 0.001;
152 }
153 } else {
154 /*
155 * if we're not reading from the CSV file, then we need
156 * three parameters
157 */
158 if (argc - last < 3)
159 sopts->usage("Arguments missing.");
160 }
161
162 sopts->wcet = atof(argv[last + 0]);
163 sopts->period = atof(argv[last + 1]);
164
165 wcet_ns = sopts->wcet * __NS_PER_MS;
166 period_ns = sopts->period * __NS_PER_MS;
167 if (wcet_ns <= 0)
168 sopts->usage("The worst-case execution time must be a "
169 "positive number.");
170 if (period_ns <= 0)
171 sopts->usage("The period must be a positive number.");
172 if (!sopts->file && wcet_ns > period_ns) {
173 sopts->usage("The worst-case execution time must not "
174 "exceed the period.");
175 }
176
177 if (!sopts->file)
178 sopts->duration = atof(argv[last + 2]);
179 else if (sopts->file && sopts->num_jobs > 1)
180 sopts->duration += period_ns * 0.001 * (sopts->num_jobs - 1);
181
182 if (sopts->migrate) {
183 ret = be_migrate_to(sopts->cpu);
184 if (ret < 0)
185 bail_out("could not migrate to target partition");
186 }
187
188 ret = sporadic_task_ns(wcet_ns, period_ns, 0,
189 sopts->cpu, sopts->class,
190 sopts->want_enforcement ? PRECISE_ENFORCEMENT
191 : NO_ENFORCEMENT,
192 sopts->migrate);
193
194 if (ret < 0)
195 bail_out("could not setup rt task params");
196}
197
198void run_spin(struct spin_opts *sopts)
199{
200 double end, scale;
201 int ret, curr_job;
202
203 init_litmus();
204
205 ret = task_mode(LITMUS_RT_TASK);
206 if (ret != 0)
207 bail_out("could not become RT task");
208
209 if (sopts->wait) {
210 ret = wait_for_ts_release();
211 if (ret != 0)
212 bail_out("wait_for_ts_release()");
213 }
214
215 scale = .001 * sopts->scale;
216 end = wctime() + sopts->duration;
217
218 if (sopts->file) {
219 /* use times read from the CSV file */
220 for (curr_job = 0; curr_job < sopts->num_jobs; ++curr_job) {
221 /* convert job's length to seconds */
222 sopts->job(sopts->exec_times[curr_job] * scale, end);
223 }
224 } else {
225 /* conver to seconds and scale */
226 while (sopts->job(sopts->wcet * scale, end));
227 }
228
229 ret = task_mode(BACKGROUND_TASK);
230 if (ret != 0)
231 bail_out("could not become regular task (huh?)");
232
233 if (sopts->file)
234 free(sopts->exec_times);
235}