aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2012-04-08 15:08:50 -0400
committerJonathan Herman <hermanjl@cs.unc.edu>2012-04-08 15:08:50 -0400
commit7bcc57e302810ba4ad9f77588fbacc3e02385b45 (patch)
treebadb53d366e1484872b05ca8ff3a560c2d91ddde
parent4fe84175df26830e9450a5d583ffc1d979c3f24f (diff)
Added bespin
-rw-r--r--Makefile6
-rw-r--r--bin/bespin.c379
2 files changed, 384 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 25f863d..c5a8c0a 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 locktest rtspin rtspin.ovh rtspin.beta release_ts \ 73rt-apps = cycles base_task rt_launch locktest rtspin rtspin.ovh rtspin.beta release_ts \
74 measure_syscall base_mt_task runtests 74 measure_syscall base_mt_task runtests bespin
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
@@ -219,7 +219,11 @@ lib-rtspin.ovh = -lrt
219obj-rtspin.beta = rtspin.beta.o common.o 219obj-rtspin.beta = rtspin.beta.o common.o
220lib-rtspin.beta = -lrt $(shell gsl-config --libs) 220lib-rtspin.beta = -lrt $(shell gsl-config --libs)
221 221
222obj-bespin = bespin.o common.o
223lib-bespin = -lrt -lgsl -lgslcblas
224
222obj-release_ts = release_ts.o 225obj-release_ts = release_ts.o
226
223obj-locktest = locktest.o 227obj-locktest = locktest.o
224lib-locktest = -lrt -pthread 228lib-locktest = -lrt -pthread
225 229
diff --git a/bin/bespin.c b/bin/bespin.c
new file mode 100644
index 0000000..f3b7e20
--- /dev/null
+++ b/bin/bespin.c
@@ -0,0 +1,379 @@
1#include <sys/time.h>
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <unistd.h>
6#include <time.h>
7#include <assert.h>
8#include <string.h>
9#include <limits.h>
10
11#include <sched.h>
12#include <sys/time.h>
13#include <sys/resource.h>
14
15#include <gsl/gsl_rng.h>
16#include <gsl/gsl_randist.h>
17
18#include "litmus.h"
19#include "common.h"
20
21#define UINT_WANT 4294967295
22#if UINT_MAX < UINT_WANT
23#error Unsigned int not big enough.
24#endif
25
26/*
27 * Limit the execution times.
28 */
29#define EXEC_MIN (2 * __NS_PER_MS)
30#define EXEC_MAX (100 * __NS_PER_MS)
31
32/*
33 * Limit interarrival times.
34 */
35#define IA_MIN (0 * __NS_PER_MS)
36#define IA_MAX (200 * __NS_PER_MS)
37
38
39static void usage(char *error) {
40 fprintf(stderr, "Error: %s\n", error);
41 fprintf(stderr,
42 "Usage:\n"
43 " bespin [-w] [-o] [-n] [-s seed] [-f res-time file] OS_TYPE DURATION\n"
44 "OS_TYPE is litmus or linux\n"
45 "DURATION is milliseconds.\n");
46 exit(EXIT_FAILURE);
47}
48
49#define NUMS 4096
50static int num[NUMS];
51static char* progname;
52
53static gsl_rng *exec_rng;
54static gsl_rng *ia_rng;
55static struct timespec sleep_ts = { .tv_sec = 0 };
56
57static void setup_rng(unsigned long seed)
58{
59 exec_rng = gsl_rng_alloc(gsl_rng_taus);
60 ia_rng = gsl_rng_alloc(gsl_rng_taus);
61 if (!exec_rng || !ia_rng)
62 bail_out("Could not initialize RNG");
63 gsl_rng_set(exec_rng, seed);
64 gsl_rng_set(ia_rng, seed + 1);
65}
66
67static lt_t round_double_lt(const double d)
68{
69 /* if needed, add one so round up */
70 if (d - ((lt_t)d) > 0.0)
71 return ((lt_t)(d + 1.0));
72 else
73 return ((lt_t)d);
74}
75
76static lt_t get_exec_time(const lt_t exec_mean)
77{
78 double e = gsl_ran_exponential(exec_rng, exec_mean);
79 e = (e < EXEC_MIN) ? EXEC_MIN : e;
80 e = (e > EXEC_MAX) ? EXEC_MAX : e;
81 return (round_double_lt(e));
82}
83
84static lt_t get_ia_time(const lt_t ia_mean)
85{
86 double ia = gsl_ran_exponential(ia_rng, ia_mean);
87 ia = (ia < IA_MIN) ? IA_MIN : ia;
88 ia = (ia > IA_MAX) ? IA_MAX : ia;
89 return (round_double_lt(ia));
90}
91
92#define LITMUS_STR "litmus"
93#define LINUX_STR "linux"
94static int using_os(const char *const os, const char *const test)
95{
96 /* LITMUS_STR > LINUX_STR */
97 return (0 == strncasecmp(os, test, sizeof(LITMUS_STR)));
98}
99
100static int valid_os(char *os)
101{
102 return (using_os(LITMUS_STR, os) || using_os(LINUX_STR, os));
103}
104
105static inline lt_t ts_to_ns(const struct timespec *ts)
106{
107 return ( (((lt_t)ts->tv_sec) * 1e9) + ts->tv_nsec );
108}
109
110static void mono_time_ts(struct timespec *ts)
111{
112 int ret = clock_gettime(CLOCK_MONOTONIC, ts);
113 if (ret)
114 bail_out("could not get monotonic time");
115}
116
117static lt_t mono_time(void)
118{
119 struct timespec ts;
120 mono_time_ts(&ts);
121 return (ts_to_ns(&ts));
122}
123
124static void add_to_ts(struct timespec *ts, const lt_t t)
125{
126 /* convert the lt_t to seconds and nanoseconds */
127 const lt_t sec = t / 1e9;
128 long nsec = t - sec;
129
130 /* figure out carry for nsec field */
131 const long nsec_sum_large = ts->tv_nsec + nsec;
132 const time_t sec_carry = nsec_sum_large / 1e9;
133
134 ts->tv_sec += sec + sec_carry;
135 ts->tv_nsec = nsec_sum_large - sec_carry * 1e9;
136 assert(ts->tv_nsec < 1e9);
137}
138
139static lt_t etime(void)
140{
141 struct timespec ts;
142 int err;
143 err = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
144 if (err)
145 bail_out("could not get thread CPU time");
146 return (ts_to_ns(&ts));
147}
148
149static int loop_once(void)
150{
151 int i, j = 0;
152 for (i = 0; i < NUMS; i++)
153 j += num[i]++;
154 return j;
155}
156
157static int loop_for(lt_t exec_time, lt_t emergency_exit)
158{
159 double last_loop = 0, loop_start;
160 int job_finished = 1;
161 int tmp = 0;
162
163 lt_t start = etime();
164 lt_t now = etime();
165
166 while (now + last_loop < start + exec_time) {
167 loop_start = now;
168 tmp += loop_once();
169 now = etime();
170 last_loop = now - loop_start;
171 if (emergency_exit && mono_time() > emergency_exit)
172 job_finished = 0;
173 }
174
175 return job_finished;
176}
177
178static void do_sleep(const lt_t ia_mean)
179{
180 const lt_t ia = get_ia_time(ia_mean);
181 int err;
182
183 add_to_ts(&sleep_ts, ia);
184 err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
185 &sleep_ts, NULL);
186
187 /*
188 * For some reason, nanosleep returns non-zero even when things are
189 * okay the last time. */
190 if (err)
191 bail_out("could not nanosleep!");
192}
193
194static int job(const lt_t exec_mean, const lt_t ia_mean, FILE *out_f,
195 const lt_t program_end)
196{
197 const lt_t now = mono_time();
198 const lt_t exec = get_exec_time(exec_mean);
199 int job_finished;
200 lt_t end_time;
201
202 if (now > program_end || now + exec > program_end)
203 {
204 /* this job is either after we want to stop, or would be,
205 * so just quit now */
206 return 0;
207 } else {
208 /* add NS per MS as an error margin */
209 job_finished = loop_for(exec, program_end + __NS_PER_MS);
210 end_time = mono_time();
211
212 /* record response time if wanted and the job finished */
213 if (out_f && job_finished)
214 {
215 /* print start time, end time, exec time */
216 fprintf(out_f, "%llu, %llu, %llu\n",
217 ts_to_ns(&sleep_ts), end_time, exec);
218 }
219
220 if (end_time < program_end) {
221 /* we can go to sleep some time */
222 do_sleep(ia_mean);
223 return 1;
224 } else {
225 /* that was the last job */
226 return 0;
227 }
228 }
229}
230
231static void setup_litmus_task(const double phase_ms)
232{
233 const lt_t phase = phase_ms * __NS_PER_MS;
234 int ret;
235
236 /* Best-Effort task has no WCET or period, just use one */
237 ret = sporadic_task_ns(1, 1, phase, 0, RT_CLASS_BEST_EFFORT,
238 NO_ENFORCEMENT, 0);
239 if (ret < 0)
240 bail_out("could not setup rt task params");
241
242 init_litmus();
243
244 ret = task_mode(LITMUS_RT_TASK);
245 if (ret != 0)
246 bail_out("could not become RT task");
247}
248
249#define OPTSTR "wnos:f:"
250
251int main(int argc, char** argv)
252{
253 unsigned long seed = 1;
254 double duration_ms;
255 double exec_mean_ms = 10.0, ia_mean_ms = 100.0, phase_ms = 0.0;
256 lt_t duration, start, exec_mean, ia_mean;
257 char *os_type, *out_fname = NULL;
258 FILE *out_f = NULL;
259 int opt;
260 int ret;
261 int wait = 0;
262 int nice = 0;
263 int fifo = 0;
264 struct sched_param param;
265
266 progname = argv[0];
267
268 while ((opt = getopt(argc, argv, OPTSTR)) != -1) {
269 switch (opt) {
270 case 'w':
271 wait = 1;
272 break;
273 case 'n':
274 nice = 1;
275 break;
276 case 'o':
277 fifo = 1;
278 break;
279 case 's':
280 seed = atoi(optarg);
281 break;
282 case 'h':
283 phase_ms = atof(optarg);
284 break;
285 case 'e':
286 exec_mean_ms = atof(optarg);
287 break;
288 case 'i':
289 ia_mean_ms = atof(optarg);
290 break;
291 case 'f':
292 out_fname = optarg;
293 break;
294 case ':':
295 usage("Argument missing.");
296 break;
297 case '?':
298 default:
299 usage("Bad argument.");
300 break;
301 }
302 }
303
304 if (argc - optind != 2)
305 usage("Arguments missing.");
306
307 os_type = argv[optind + 0];
308 duration_ms = atof(argv[optind + 1]);
309
310 if (!valid_os(os_type))
311 bail_out("Invalid OS type");
312
313 if (duration_ms < 0)
314 bail_out("duration < 0 not allowed");
315
316 if (exec_mean_ms < 0)
317 bail_out("execution time mean < 0 not allowed");
318
319 if (ia_mean_ms < 0)
320 bail_out("IA time mean < 0 not allowed");
321
322 if (exec_mean_ms * __NS_PER_MS > UINT_MAX >> 1)
323 bail_out("Exec time too big");
324
325 if (seed < 1)
326 bail_out("seed < 1 not allowed");
327
328 if (phase_ms < 0)
329 bail_out("phase < 0 not allowed");
330
331 if (wait && using_os(LINUX_STR, os_type))
332 bail_out("Linux cannot use the wait flag");
333
334 duration = duration_ms * __NS_PER_MS;
335 exec_mean = exec_mean_ms * __NS_PER_MS;
336 ia_mean = ia_mean_ms * __NS_PER_MS;
337
338 if (out_fname)
339 {
340 out_f = fopen(out_fname, "w");
341 if (!out_f)
342 bail_out("Could not open response-time file");
343 }
344
345 setup_rng(seed);
346
347 if (using_os(LITMUS_STR, os_type)) {
348 setup_litmus_task(phase_ms);
349
350 if (wait) {
351 ret = wait_for_ts_release();
352 if (ret != 0)
353 bail_out("wait_for_ts_release()");
354 }
355 } else if (fifo) {
356 param.sched_priority = sched_get_priority_max(SCHED_FIFO) - 2;
357 ret = sched_setscheduler(0, SCHED_FIFO, &param);
358 if (ret)
359 bail_out("Could not switch to FIFO scheduler");
360 } else if (nice) {
361 ret = setpriority(PRIO_PROCESS, 0, 5);
362 if (ret)
363 bail_out("Could not set task priority");
364 }
365
366 /* initialize the start time */
367 mono_time_ts(&sleep_ts);
368 start = ts_to_ns(&sleep_ts);
369
370 while (job(exec_mean, ia_mean, out_f, start + duration));
371
372 if (using_os(LITMUS_STR, os_type)) {
373 ret = task_mode(BACKGROUND_TASK);
374 if (ret != 0)
375 bail_out("could not become regular task (huh?)");
376 }
377
378 return 0;
379}