aboutsummaryrefslogtreecommitdiffstats
path: root/bin/dglspin.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/dglspin.c')
-rw-r--r--bin/dglspin.c335
1 files changed, 335 insertions, 0 deletions
diff --git a/bin/dglspin.c b/bin/dglspin.c
new file mode 100644
index 0000000..805fd85
--- /dev/null
+++ b/bin/dglspin.c
@@ -0,0 +1,335 @@
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 <fcntl.h>
9
10
11#include "litmus.h"
12#include "common.h"
13
14
15
16static void usage(char *error) {
17 fprintf(stderr, "Error: %s\n", error);
18 fprintf(stderr,
19 "Usage:\n"
20 " rt_spin [COMMON-OPTS] WCET PERIOD DURATION\n"
21 " rt_spin [COMMON-OPTS] -f FILE [-o COLUMN] WCET PERIOD\n"
22 " rt_spin -l\n"
23 "\n"
24 "COMMON-OPTS = [-w] [-p PARTITION] [-c CLASS] [-s SCALE]\n"
25 "\n"
26 "WCET and PERIOD are milliseconds, DURATION is seconds.\n");
27 exit(EXIT_FAILURE);
28}
29
30/*
31 * returns the character that made processing stop, newline or EOF
32 */
33static int skip_to_next_line(FILE *fstream)
34{
35 int ch;
36 for (ch = fgetc(fstream); ch != EOF && ch != '\n'; ch = fgetc(fstream));
37 return ch;
38}
39
40static void skip_comments(FILE *fstream)
41{
42 int ch;
43 for (ch = fgetc(fstream); ch == '#'; ch = fgetc(fstream))
44 skip_to_next_line(fstream);
45 ungetc(ch, fstream);
46}
47
48static void get_exec_times(const char *file, const int column,
49 int *num_jobs, double **exec_times)
50{
51 FILE *fstream;
52 int cur_job, cur_col, ch;
53 *num_jobs = 0;
54
55 fstream = fopen(file, "r");
56 if (!fstream)
57 bail_out("could not open execution time file");
58
59 /* figure out the number of jobs */
60 do {
61 skip_comments(fstream);
62 ch = skip_to_next_line(fstream);
63 if (ch != EOF)
64 ++(*num_jobs);
65 } while (ch != EOF);
66
67 if (-1 == fseek(fstream, 0L, SEEK_SET))
68 bail_out("rewinding file failed");
69
70 /* allocate space for exec times */
71 *exec_times = calloc(*num_jobs, sizeof(*exec_times));
72 if (!*exec_times)
73 bail_out("couldn't allocate memory");
74
75 for (cur_job = 0; cur_job < *num_jobs && !feof(fstream); ++cur_job) {
76
77 skip_comments(fstream);
78
79 for (cur_col = 1; cur_col < column; ++cur_col) {
80 /* discard input until we get to the column we want */
81 fscanf(fstream, "%*s,");
82 }
83
84 /* get the desired exec. time */
85 if (1 != fscanf(fstream, "%lf", (*exec_times)+cur_job)) {
86 fprintf(stderr, "invalid execution time near line %d\n",
87 cur_job);
88 exit(EXIT_FAILURE);
89 }
90
91 skip_to_next_line(fstream);
92 }
93
94 assert(cur_job == *num_jobs);
95 fclose(fstream);
96}
97
98#define NUMS 4096
99static int num[NUMS];
100static char* progname;
101
102static int loop_once(void)
103{
104 int i, j = 0;
105 for (i = 0; i < NUMS; i++)
106 j += num[i]++;
107 return j;
108}
109
110static int loop_for(double exec_time, double emergency_exit, int mask)
111{
112 double last_loop = 0, loop_start;
113 int tmp = 0;
114
115 double start = cputime();
116 double now = cputime();
117
118 while (now + last_loop < start + exec_time) {
119 loop_start = now;
120 dynamic_group_lock(mask);
121 tmp += loop_once();
122 dynamic_group_unlock(mask);
123 now = cputime();
124 last_loop = now - loop_start;
125 if (emergency_exit && wctime() > emergency_exit) {
126 /* Oops --- this should only be possible if the execution time tracking
127 * is broken in the LITMUS^RT kernel. */
128 fprintf(stderr, "!!! rtspin/%d emergency exit!\n", getpid());
129 fprintf(stderr, "Something is seriously wrong! Do not ignore this.\n");
130 break;
131 }
132 }
133
134 return tmp;
135}
136
137
138static void debug_delay_loop(void)
139{
140 double start, end, delay;
141
142 while (1) {
143 for (delay = 0.5; delay > 0.01; delay -= 0.01) {
144 start = wctime();
145 loop_for(delay, 0, 1);
146 end = wctime();
147 printf("%6.4fs: looped for %10.8fs, delta=%11.8fs, error=%7.4f%%\n",
148 delay,
149 end - start,
150 end - start - delay,
151 100 * (end - start - delay) / delay);
152 }
153 }
154}
155
156static int job(double exec_time, double program_end, int mask)
157{
158 if (wctime() > program_end)
159 return 0;
160 else {
161 loop_for(exec_time, program_end + 1, mask);
162 sleep_next_period();
163 return 1;
164 }
165}
166
167#define OPTSTR "p:c:wlveo:f:s:q:"
168
169int main(int argc, char** argv)
170{
171 int ret;
172 lt_t wcet;
173 lt_t period;
174 double wcet_ms, period_ms;
175 unsigned int priority = LITMUS_LOWEST_PRIORITY;
176 int migrate = 0;
177 int cpu = 0;
178 int opt;
179 int wait = 0;
180 int test_loop = 0;
181 int column = 1;
182 const char *file = NULL;
183 int want_enforcement = 0;
184 double duration = 0, start;
185 double *exec_times = NULL;
186 double scale = 1.0;
187 task_class_t class = RT_CLASS_HARD;
188 int cur_job, num_jobs;
189
190 int fd, od_org, od_new, mask;
191
192 progname = argv[0];
193
194 while ((opt = getopt(argc, argv, OPTSTR)) != -1) {
195 switch (opt) {
196 case 'w':
197 wait = 1;
198 break;
199 case 'p':
200 cpu = atoi(optarg);
201 migrate = 1;
202 break;
203 case 'q':
204 priority = atoi(optarg);
205 if (!litmus_is_valid_fixed_prio(priority))
206 usage("Invalid priority.");
207 break;
208 case 'c':
209 class = str2class(optarg);
210 if (class == -1)
211 usage("Unknown task class.");
212 break;
213 case 'e':
214 want_enforcement = 1;
215 break;
216 case 'l':
217 test_loop = 1;
218 break;
219 case 'o':
220 column = atoi(optarg);
221 break;
222 case 'f':
223 file = optarg;
224 break;
225 case 's':
226 scale = atof(optarg);
227 break;
228 case ':':
229 usage("Argument missing.");
230 break;
231 case '?':
232 default:
233 usage("Bad argument.");
234 break;
235 }
236 }
237
238 if (test_loop) {
239 debug_delay_loop();
240 return 0;
241 }
242
243 if (file) {
244 get_exec_times(file, column, &num_jobs, &exec_times);
245
246 if (argc - optind < 2)
247 usage("Arguments missing.");
248
249 for (cur_job = 0; cur_job < num_jobs; ++cur_job) {
250 /* convert the execution time to seconds */
251 duration += exec_times[cur_job] * 0.001;
252 }
253 } else {
254 /*
255 * if we're not reading from the CSV file, then we need
256 * three parameters
257 */
258 if (argc - optind < 3)
259 usage("Arguments missing.");
260 }
261
262 wcet_ms = atof(argv[optind + 0]);
263 period_ms = atof(argv[optind + 1]);
264
265 wcet = wcet_ms * __NS_PER_MS;
266 period = period_ms * __NS_PER_MS;
267 if (wcet <= 0)
268 usage("The worst-case execution time must be a "
269 "positive number.");
270 if (period <= 0)
271 usage("The period must be a positive number.");
272 if (!file && wcet > period) {
273 usage("The worst-case execution time must not "
274 "exceed the period.");
275 }
276
277 if (!file)
278 duration = atof(argv[optind + 2]);
279 else if (file && num_jobs > 1)
280 duration += period_ms * 0.001 * (num_jobs - 1);
281
282 if (migrate) {
283 ret = be_migrate_to(cpu);
284 if (ret < 0)
285 bail_out("could not migrate to target partition");
286 }
287
288 ret = sporadic_task_ns(wcet, period, 0, cpu, priority, class,
289 want_enforcement ? PRECISE_ENFORCEMENT
290 : NO_ENFORCEMENT,
291 migrate);
292 if (ret < 0)
293 bail_out("could not setup rt task params");
294
295 fd = open(".dgl_locks", O_RDONLY | O_CREAT);
296
297 init_litmus();
298
299 ret = task_mode(LITMUS_RT_TASK);
300 if (ret != 0)
301 bail_out("could not become RT task");
302
303 if (wait) {
304 ret = wait_for_ts_release();
305 if (ret != 0)
306 bail_out("wait_for_ts_release()");
307 }
308
309 od_org = open_new_dgl_sem(fd, 0);
310 od_new = attach_dgl_sem(fd, 1, od_org);
311 mask = (1<<od_org) & (1<<od_new);
312
313 start = wctime();
314
315 if (file) {
316 /* use times read from the CSV file */
317 for (cur_job = 0; cur_job < num_jobs; ++cur_job) {
318 /* convert job's length to seconds */
319 job(exec_times[cur_job] * 0.001 * scale,
320 start + duration, mask);
321 }
322 } else {
323 /* conver to seconds and scale */
324 while (job(wcet_ms * 0.001 * scale, start + duration, mask));
325 }
326
327 ret = task_mode(BACKGROUND_TASK);
328 if (ret != 0)
329 bail_out("could not become regular task (huh?)");
330
331 if (file)
332 free(exec_times);
333
334 return 0;
335}