aboutsummaryrefslogtreecommitdiffstats
path: root/bin/rtspin.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/rtspin.c')
-rw-r--r--bin/rtspin.c261
1 files changed, 161 insertions, 100 deletions
diff --git a/bin/rtspin.c b/bin/rtspin.c
index 20ce734..28c4a4e 100644
--- a/bin/rtspin.c
+++ b/bin/rtspin.c
@@ -4,40 +4,98 @@
4#include <stdlib.h> 4#include <stdlib.h>
5#include <unistd.h> 5#include <unistd.h>
6#include <time.h> 6#include <time.h>
7#include <assert.h>
7 8
8 9
9#include "litmus.h" 10#include "litmus.h"
10#include "common.h" 11#include "common.h"
11 12
12 13
13static double cputime() 14
15static void usage(char *error) {
16 fprintf(stderr, "Error: %s\n", error);
17 fprintf(stderr,
18 "Usage:\n"
19 " rt_spin [COMMON-OPTS] WCET PERIOD DURATION\n"
20 " rt_spin [COMMON-OPTS] -f FILE [-o COLUMN] WCET PERIOD\n"
21 " rt_spin -l\n"
22 "\n"
23 "COMMON-OPTS = [-w] [-p PARTITION] [-c CLASS] [-s SCALE]\n"
24 "\n"
25 "WCET and PERIOD are milliseconds, DURATION is seconds.\n");
26 exit(EXIT_FAILURE);
27}
28
29/*
30 * returns the character that made processing stop, newline or EOF
31 */
32static int skip_to_next_line(FILE *fstream)
14{ 33{
15 struct timespec ts; 34 int ch;
16 int err; 35 for (ch = fgetc(fstream); ch != EOF && ch != '\n'; ch = fgetc(fstream));
17 err = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); 36 return ch;
18 if (err != 0)
19 perror("clock_gettime");
20 return (ts.tv_sec + 1E-9 * ts.tv_nsec);
21} 37}
22 38
23static double wctime() 39static void skip_comments(FILE *fstream)
24{ 40{
25 struct timeval tv; 41 int ch;
26 gettimeofday(&tv, NULL); 42 for (ch = fgetc(fstream); ch == '#'; ch = fgetc(fstream))
27 return (tv.tv_sec + 1E-6 * tv.tv_usec); 43 skip_to_next_line(fstream);
44 ungetc(ch, fstream);
28} 45}
29 46
30void usage(char *error) { 47static void get_exec_times(const char *file, const int column,
31 fprintf(stderr, "Error: %s\n", error); 48 int *num_jobs, double **exec_times)
32 fprintf(stderr, 49{
33 "Usage: rt_spin [-w] [-p PARTITION] [-c CLASS] WCET PERIOD DURATION\n" 50 FILE *fstream;
34 " rt_spin -l\n"); 51 int cur_job, cur_col, ch;
35 exit(1); 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);
36} 95}
37 96
38#define NUMS 4096 97#define NUMS 4096
39static int num[NUMS]; 98static int num[NUMS];
40static double loop_length = 1.0;
41static char* progname; 99static char* progname;
42 100
43static int loop_once(void) 101static int loop_once(void)
@@ -48,74 +106,40 @@ static int loop_once(void)
48 return j; 106 return j;
49} 107}
50 108
51static int loop_for(double exec_time) 109static int loop_for(double exec_time, double emergency_exit)
52{ 110{
53 double t = 0; 111 double last_loop = 0, loop_start;
54 int tmp = 0; 112 int tmp = 0;
55/* while (t + loop_length < exec_time) { 113
56 tmp += loop_once();
57 t += loop_length;
58 }
59*/
60 double start = cputime(); 114 double start = cputime();
61 double now = cputime(); 115 double now = cputime();
62 while (now + loop_length < start + exec_time) { 116
117 while (now + last_loop < start + exec_time) {
118 loop_start = now;
63 tmp += loop_once(); 119 tmp += loop_once();
64 t += loop_length;
65 now = cputime(); 120 now = cputime();
121 last_loop = now - loop_start;
122 if (emergency_exit && wctime() > emergency_exit) {
123 /* Oops --- this should only be possible if the execution time tracking
124 * is broken in the LITMUS^RT kernel. */
125 fprintf(stderr, "!!! rtspin/%d emergency exit!\n", getpid());
126 fprintf(stderr, "Something is seriously wrong! Do not ignore this.\n");
127 break;
128 }
66 } 129 }
67 130
68 return tmp; 131 return tmp;
69} 132}
70 133
71static void fine_tune(double interval)
72{
73 double start, end, delta;
74
75 start = wctime();
76 loop_for(interval);
77 end = wctime();
78 delta = (end - start - interval) / interval;
79 if (delta != 0)
80 loop_length = loop_length / (1 - delta);
81}
82
83static void configure_loop(void)
84{
85 double start;
86
87 /* prime cache */
88 loop_once();
89 loop_once();
90 loop_once();
91
92 /* measure */
93 start = wctime();
94 loop_once(); /* hope we didn't get preempted */
95 loop_length = wctime();
96 loop_length -= start;
97
98 /* fine tune */
99 fine_tune(0.1);
100 fine_tune(0.1);
101 fine_tune(0.1);
102}
103
104static void show_loop_length(void)
105{
106 printf("%s/%d: loop_length=%f (%ldus)\n",
107 progname, getpid(), loop_length,
108 (long) (loop_length * 1000000));
109}
110 134
111static void debug_delay_loop(void) 135static void debug_delay_loop(void)
112{ 136{
113 double start, end, delay; 137 double start, end, delay;
114 show_loop_length(); 138
115 while (1) { 139 while (1) {
116 for (delay = 0.5; delay > 0.01; delay -= 0.01) { 140 for (delay = 0.5; delay > 0.01; delay -= 0.01) {
117 start = wctime(); 141 start = wctime();
118 loop_for(delay); 142 loop_for(delay, 0);
119 end = wctime(); 143 end = wctime();
120 printf("%6.4fs: looped for %10.8fs, delta=%11.8fs, error=%7.4f%%\n", 144 printf("%6.4fs: looped for %10.8fs, delta=%11.8fs, error=%7.4f%%\n",
121 delay, 145 delay,
@@ -126,16 +150,20 @@ static void debug_delay_loop(void)
126 } 150 }
127} 151}
128 152
129static int job(double exec_time) 153static int job(double exec_time, double program_end)
130{ 154{
131 loop_for(exec_time); 155 if (wctime() > program_end)
132 sleep_next_period(); 156 return 0;
133 return 0; 157 else {
158 loop_for(exec_time, program_end + 1);
159 sleep_next_period();
160 return 1;
161 }
134} 162}
135 163
136#define OPTSTR "p:c:m:wld:ve" 164#define OPTSTR "p:c:wldveo:f:s:m:"
137 165
138int main(int argc, char** argv) 166int main(int argc, char** argv)
139{ 167{
140 int ret; 168 int ret;
141 lt_t wcet; 169 lt_t wcet;
@@ -146,11 +174,14 @@ int main(int argc, char** argv)
146 int opt; 174 int opt;
147 int wait = 0; 175 int wait = 0;
148 int test_loop = 0; 176 int test_loop = 0;
149 int skip_config = 0; 177 int column = 1;
150 int verbose = 0; 178 const char *file = NULL;
151 int want_enforcement = 0; 179 int want_enforcement = 0;
152 double duration, start; 180 double duration = 0, start;
181 double *exec_times = NULL;
182 double scale = 1.0;
153 task_class_t class = RT_CLASS_HARD; 183 task_class_t class = RT_CLASS_HARD;
184 int cur_job, num_jobs;
154 crit_level_t crit = CRIT_LEVEL_C; 185 crit_level_t crit = CRIT_LEVEL_C;
155 186
156 progname = argv[0]; 187 progname = argv[0];
@@ -179,14 +210,14 @@ int main(int argc, char** argv)
179 case 'l': 210 case 'l':
180 test_loop = 1; 211 test_loop = 1;
181 break; 212 break;
182 case 'd': 213 case 'o':
183 /* manually configure delay per loop iteration 214 column = atoi(optarg);
184 * unit: microseconds */ 215 break;
185 loop_length = atof(optarg) / 1000000; 216 case 'f':
186 skip_config = 1; 217 file = optarg;
187 break; 218 break;
188 case 'v': 219 case 's':
189 verbose = 1; 220 scale = atof(optarg);
190 break; 221 break;
191 case ':': 222 case ':':
192 usage("Argument missing."); 223 usage("Argument missing.");
@@ -198,32 +229,50 @@ int main(int argc, char** argv)
198 } 229 }
199 } 230 }
200 231
201
202 if (!skip_config)
203 configure_loop();
204
205 if (test_loop) { 232 if (test_loop) {
206 debug_delay_loop(); 233 debug_delay_loop();
207 return 0; 234 return 0;
208 } 235 }
209 236
210 if (argc - optind < 3) 237 if (file) {
211 usage("Arguments missing."); 238 get_exec_times(file, column, &num_jobs, &exec_times);
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
212 wcet_ms = atof(argv[optind + 0]); 256 wcet_ms = atof(argv[optind + 0]);
213 period_ms = atof(argv[optind + 1]); 257 period_ms = atof(argv[optind + 1]);
214 duration = atof(argv[optind + 2]); 258
215 wcet = wcet_ms * __NS_PER_MS; 259 wcet = wcet_ms * __NS_PER_MS;
216 period = period_ms * __NS_PER_MS; 260 period = period_ms * __NS_PER_MS;
217 if (wcet <= 0) 261 if (wcet <= 0)
218 usage("The worst-case execution time must be a " 262 usage("The worst-case execution time must be a "
219 "positive number."); 263 "positive number.");
220 if (period <= 0) 264 if (period <= 0)
221 usage("The period must be a positive number."); 265 usage("The period must be a positive number.");
222 if (wcet > period) { 266 if (!file && wcet > period) {
223 usage("The worst-case execution time must not " 267 usage("The worst-case execution time must not "
224 "exceed the period."); 268 "exceed the period.");
225 } 269 }
226 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
227 if (migrate) { 276 if (migrate) {
228 ret = be_migrate_to(cpu); 277 ret = be_migrate_to(cpu);
229 if (ret < 0) 278 if (ret < 0)
@@ -238,9 +287,6 @@ int main(int argc, char** argv)
238 if (ret < 0) 287 if (ret < 0)
239 bail_out("could not setup rt task params"); 288 bail_out("could not setup rt task params");
240 289
241 if (verbose)
242 show_loop_length();
243
244 init_litmus(); 290 init_litmus();
245 291
246 ret = task_mode(LITMUS_RT_TASK); 292 ret = task_mode(LITMUS_RT_TASK);
@@ -255,9 +301,24 @@ int main(int argc, char** argv)
255 301
256 start = wctime(); 302 start = wctime();
257 303
258 while (start + duration > wctime()) { 304 if (file) {
259 job(wcet_ms * 0.0009); /* 90% wcet, in seconds */ 305 /* use times read from the CSV file */
306 for (cur_job = 0; cur_job < num_jobs; ++cur_job) {
307 /* convert job's length to seconds */
308 job(exec_times[cur_job] * 0.001 * scale,
309 start + duration);
310 }
311 } else {
312 /* conver to seconds and scale */
313 while (job(wcet_ms * 0.001 * scale, start + duration));
260 } 314 }
261 315
316 ret = task_mode(BACKGROUND_TASK);
317 if (ret != 0)
318 bail_out("could not become regular task (huh?)");
319
320 if (file)
321 free(exec_times);
322
262 return 0; 323 return 0;
263} 324}