diff options
author | Christopher Kenna <cjk@cs.unc.edu> | 2011-10-12 20:03:26 -0400 |
---|---|---|
committer | Christopher Kenna <cjk@cs.unc.edu> | 2011-10-12 20:03:26 -0400 |
commit | de112da123054cb6f3eb8d8278e0547a0030264c (patch) | |
tree | f903fe1cdac5b36f6527c2f870942c0d0dd81faa | |
parent | 732d9db4c95a4dc81ad2d200dce6ef8a585c00ad (diff) |
Add RTSpin that uses beta distributions.
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | bin/rtspin.beta.c | 270 |
2 files changed, 275 insertions, 2 deletions
@@ -70,8 +70,8 @@ AR := ${CROSS_COMPILE}${AR} | |||
70 | # Targets | 70 | # Targets |
71 | 71 | ||
72 | all = lib ${rt-apps} | 72 | all = lib ${rt-apps} |
73 | rt-apps = cycles base_task rt_launch rtspin rtspin.ovh release_ts measure_syscall \ | 73 | rt-apps = cycles base_task rt_launch rtspin rtspin.ovh rtspin.beta release_ts \ |
74 | base_mt_task runtests | 74 | measure_syscall base_mt_task 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 | ||
@@ -214,6 +214,9 @@ lib-rtspin = -lrt | |||
214 | obj-rtspin.ovh = rtspin.ovh.o common.o | 214 | obj-rtspin.ovh = rtspin.ovh.o common.o |
215 | lib-rtspin.ovh = -lrt | 215 | lib-rtspin.ovh = -lrt |
216 | 216 | ||
217 | obj-rtspin.beta = rtspin.beta.o common.o | ||
218 | lib-rtspin.beta = -lrt $(shell gsl-config --libs) | ||
219 | |||
217 | obj-release_ts = release_ts.o | 220 | obj-release_ts = release_ts.o |
218 | 221 | ||
219 | obj-measure_syscall = null_call.o | 222 | obj-measure_syscall = null_call.o |
diff --git a/bin/rtspin.beta.c b/bin/rtspin.beta.c new file mode 100644 index 0000000..9dbe845 --- /dev/null +++ b/bin/rtspin.beta.c | |||
@@ -0,0 +1,270 @@ | |||
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 <strings.h> | ||
9 | |||
10 | #include <gsl/gsl_rng.h> | ||
11 | #include <gsl/gsl_randist.h> | ||
12 | |||
13 | #include "litmus.h" | ||
14 | #include "common.h" | ||
15 | |||
16 | #include <litmus/sched_mc.h> | ||
17 | |||
18 | |||
19 | static void usage(char *error) { | ||
20 | fprintf(stderr, "Error: %s\n", error); | ||
21 | fprintf(stderr, | ||
22 | "Usage:\n" | ||
23 | " rt_spin [COMMON-OPTS] WCET PERIOD DURATION\n" | ||
24 | " rt_spin -l\n" | ||
25 | "\n" | ||
26 | "COMMON-OPTS = [-w] [-p PARTITION] [-c CLASS] [-s SCALE]\n" | ||
27 | " [-r CRITICALITY = [a|b|c|d]] [-i MC-LVL-A-ID]\n" | ||
28 | " [-a ALPHA] [-b BETA] [-d SEED]\n" | ||
29 | "\n" | ||
30 | "WCET and PERIOD are nanoseconds, DURATION is seconds.\n"); | ||
31 | exit(EXIT_FAILURE); | ||
32 | } | ||
33 | |||
34 | #define NUMS 4096 | ||
35 | static int num[NUMS]; | ||
36 | static char* progname; | ||
37 | |||
38 | static gsl_rng *beta_rng; | ||
39 | |||
40 | static void setup_rng(unsigned long seed) | ||
41 | { | ||
42 | beta_rng = gsl_rng_alloc(gsl_rng_taus); | ||
43 | if (!beta_rng) | ||
44 | bail_out("Could not initialize RNG"); | ||
45 | gsl_rng_set(beta_rng, seed); | ||
46 | } | ||
47 | |||
48 | static int loop_once(void) | ||
49 | { | ||
50 | int i, j = 0; | ||
51 | for (i = 0; i < NUMS; i++) | ||
52 | j += num[i]++; | ||
53 | return j; | ||
54 | } | ||
55 | |||
56 | static int loop_for(double exec_time, double emergency_exit) | ||
57 | { | ||
58 | double last_loop = 0, loop_start; | ||
59 | int tmp = 0; | ||
60 | |||
61 | double start = cputime(); | ||
62 | double now = cputime(); | ||
63 | |||
64 | while (now + last_loop < start + exec_time) { | ||
65 | loop_start = now; | ||
66 | tmp += loop_once(); | ||
67 | now = cputime(); | ||
68 | last_loop = now - loop_start; | ||
69 | if (emergency_exit && wctime() > emergency_exit) { | ||
70 | /* Oops --- this should only be possible if the execution time tracking | ||
71 | * is broken in the LITMUS^RT kernel. */ | ||
72 | fprintf(stderr, "!!! rtspin/%d emergency exit!\n", getpid()); | ||
73 | fprintf(stderr, "Something is seriously wrong! Do not ignore this.\n"); | ||
74 | break; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | return tmp; | ||
79 | } | ||
80 | |||
81 | |||
82 | static void debug_delay_loop(void) | ||
83 | { | ||
84 | double start, end, delay; | ||
85 | |||
86 | while (1) { | ||
87 | for (delay = 0.5; delay > 0.01; delay -= 0.01) { | ||
88 | start = wctime(); | ||
89 | loop_for(delay, 0); | ||
90 | end = wctime(); | ||
91 | printf("%6.4fs: looped for %10.8fs, delta=%11.8fs, error=%7.4f%%\n", | ||
92 | delay, | ||
93 | end - start, | ||
94 | end - start - delay, | ||
95 | 100 * (end - start - delay) / delay); | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | |||
100 | static int job(double exec_time, double program_end) | ||
101 | { | ||
102 | if (wctime() > program_end) | ||
103 | return 0; | ||
104 | else { | ||
105 | loop_for(exec_time, program_end + 1); | ||
106 | sleep_next_period(); | ||
107 | return 1; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | enum crit_level str2crit(const char* str) | ||
112 | { | ||
113 | if (0 == strncasecmp("a", str, 1)) | ||
114 | return CRIT_LEVEL_A; | ||
115 | else if (0 == strncasecmp("b", str, 1)) | ||
116 | return CRIT_LEVEL_B; | ||
117 | else if (0 == strncasecmp("c", str, 1)) | ||
118 | return CRIT_LEVEL_C; | ||
119 | /* failure */ | ||
120 | return NUM_CRIT_LEVELS; | ||
121 | } | ||
122 | |||
123 | #define OPTSTR "a:b:d:p:c:wlves:r:i:" | ||
124 | |||
125 | int main(int argc, char** argv) | ||
126 | { | ||
127 | int ret; | ||
128 | lt_t wcet; | ||
129 | lt_t period; | ||
130 | int migrate = 0; | ||
131 | int cpu = 0; | ||
132 | int opt; | ||
133 | int wait = 0; | ||
134 | int test_loop = 0; | ||
135 | int want_enforcement = 0; | ||
136 | unsigned long seed = 1; | ||
137 | double duration = 0, start; | ||
138 | double scale = 1.0; | ||
139 | double alpha = -1, beta = -1, beta_sample, exec_time; | ||
140 | task_class_t class = RT_CLASS_HARD; | ||
141 | struct mc_task mc_task = { .crit = NUM_CRIT_LEVELS, .lvl_a_id = -1 }; | ||
142 | |||
143 | progname = argv[0]; | ||
144 | |||
145 | while ((opt = getopt(argc, argv, OPTSTR)) != -1) { | ||
146 | switch (opt) { | ||
147 | case 'a': | ||
148 | alpha = atof(optarg); | ||
149 | break; | ||
150 | case 'b': | ||
151 | beta = atof(optarg); | ||
152 | break; | ||
153 | case 'd': | ||
154 | seed = atoi(optarg); | ||
155 | break; | ||
156 | case 'w': | ||
157 | wait = 1; | ||
158 | break; | ||
159 | case 'p': | ||
160 | cpu = atoi(optarg); | ||
161 | migrate = 1; | ||
162 | break; | ||
163 | case 'c': | ||
164 | class = str2class(optarg); | ||
165 | if (class == -1) | ||
166 | usage("Unknown task class."); | ||
167 | break; | ||
168 | case 'e': | ||
169 | want_enforcement = 1; | ||
170 | break; | ||
171 | case 'l': | ||
172 | test_loop = 1; | ||
173 | break; | ||
174 | case 's': | ||
175 | scale = atof(optarg); | ||
176 | break; | ||
177 | case 'r': | ||
178 | mc_task.crit = str2crit(optarg); | ||
179 | if (NUM_CRIT_LEVELS == mc_task.crit) | ||
180 | usage("Bad crit level."); | ||
181 | break; | ||
182 | case 'i': | ||
183 | mc_task.lvl_a_id = atoi(optarg); | ||
184 | break; | ||
185 | case ':': | ||
186 | usage("Argument missing."); | ||
187 | break; | ||
188 | case '?': | ||
189 | default: | ||
190 | usage("Bad argument."); | ||
191 | break; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | if (test_loop) { | ||
196 | debug_delay_loop(); | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | if (argc - optind < 3) | ||
201 | usage("Arguments missing."); | ||
202 | |||
203 | wcet = atoi(argv[optind + 0]); | ||
204 | period = atoi(argv[optind + 1]); | ||
205 | |||
206 | if (seed < 1) | ||
207 | usage("Seed < 1 not allowed."); | ||
208 | if (alpha <= 0 || beta <= 0) | ||
209 | usage("Need positive alpha and beta."); | ||
210 | if (wcet <= 0) | ||
211 | usage("The worst-case execution time must be a " | ||
212 | "positive number."); | ||
213 | if (period <= 0) | ||
214 | usage("The period must be a positive number."); | ||
215 | if (wcet > period) { | ||
216 | usage("The worst-case execution time must not " | ||
217 | "exceed the period."); | ||
218 | } | ||
219 | |||
220 | duration = atof(argv[optind + 2]); | ||
221 | |||
222 | setup_rng(seed); | ||
223 | |||
224 | if (migrate) { | ||
225 | ret = be_migrate_to(cpu); | ||
226 | if (ret < 0) | ||
227 | bail_out("could not migrate to target partition"); | ||
228 | } | ||
229 | |||
230 | ret = sporadic_task_ns(wcet, period, 0, cpu, class, | ||
231 | want_enforcement ? PRECISE_ENFORCEMENT | ||
232 | : NO_ENFORCEMENT, | ||
233 | migrate); | ||
234 | if (ret < 0) | ||
235 | bail_out("could not setup rt task params"); | ||
236 | |||
237 | if (NUM_CRIT_LEVELS != mc_task.crit) { | ||
238 | ret = set_rt_task_mc_param(gettid(), &mc_task); | ||
239 | if (ret < 0) | ||
240 | bail_out("could not setup rt mixed criticality params"); | ||
241 | } | ||
242 | |||
243 | init_litmus(); | ||
244 | |||
245 | ret = task_mode(LITMUS_RT_TASK); | ||
246 | if (ret != 0) | ||
247 | bail_out("could not become RT task"); | ||
248 | |||
249 | if (wait) { | ||
250 | ret = wait_for_ts_release(); | ||
251 | if (ret != 0) | ||
252 | bail_out("wait_for_ts_release()"); | ||
253 | } | ||
254 | |||
255 | start = wctime(); | ||
256 | |||
257 | do { | ||
258 | beta_sample = gsl_ran_beta(beta_rng, alpha, beta); | ||
259 | /* convert to seconds and scale */ | ||
260 | exec_time = wcet * beta_sample * 0.000000001 * scale; | ||
261 | } while(job(exec_time, start + duration)); | ||
262 | |||
263 | ret = task_mode(BACKGROUND_TASK); | ||
264 | if (ret != 0) | ||
265 | bail_out("could not become regular task (huh?)"); | ||
266 | |||
267 | gsl_rng_free(beta_rng); | ||
268 | |||
269 | return 0; | ||
270 | } | ||