aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-06-24 19:50:19 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-06-24 19:50:19 -0400
commitc176d77f446a9f218e0bd413bfad949b286e8326 (patch)
treee55aad93dd3a4fa410e54c01d97f687cf2669dbc
parent623b61db6649c1fd60791df965f38a06acb3ea93 (diff)
[NPS-F] Add rtspin and utility to add notional processors
- add syscall to add notional processors (servers) - add rtspin_npsf program to run on specified (npsf_id, cpu) - add npsf_add_server as wrapper on the syscall
-rw-r--r--SConstruct2
-rw-r--r--bin/npsf_add_server.c45
-rw-r--r--bin/rtspin_npsf.c252
-rw-r--r--include/litmus.h25
-rw-r--r--src/litmus.c21
-rw-r--r--src/syscalls.c5
6 files changed, 350 insertions, 0 deletions
diff --git a/SConstruct b/SConstruct
index c0a5f6e..0888e90 100644
--- a/SConstruct
+++ b/SConstruct
@@ -209,6 +209,8 @@ mtrt.Program('base_mt_task', 'bin/base_mt_task.c')
209rt.Program('rt_launch', ['bin/rt_launch.c', 'bin/common.c']) 209rt.Program('rt_launch', ['bin/rt_launch.c', 'bin/common.c'])
210rt.Program('rtspin', ['bin/rtspin.c', 'bin/common.c']) 210rt.Program('rtspin', ['bin/rtspin.c', 'bin/common.c'])
211rt.Program('rtspin_edffm', ['bin/rtspin_edffm.c', 'bin/common.c']) 211rt.Program('rtspin_edffm', ['bin/rtspin_edffm.c', 'bin/common.c'])
212rt.Program('rtspin_npsf', ['bin/rtspin_npsf.c', 'bin/common.c'])
213rt.Program('npsf_add_server', ['bin/npsf_add_server.c', 'bin/common.c'])
212rt.Program('rt_launch_edffm', ['bin/rt_launch_edffm.c', 'bin/common.c']) 214rt.Program('rt_launch_edffm', ['bin/rt_launch_edffm.c', 'bin/common.c'])
213rt.Program('release_ts', 'bin/release_ts.c') 215rt.Program('release_ts', 'bin/release_ts.c')
214rtm.Program('measure_syscall', 'bin/null_call.c') 216rtm.Program('measure_syscall', 'bin/null_call.c')
diff --git a/bin/npsf_add_server.c b/bin/npsf_add_server.c
new file mode 100644
index 0000000..3983e77
--- /dev/null
+++ b/bin/npsf_add_server.c
@@ -0,0 +1,45 @@
1/* wrapper for sys_add_server */
2#include <stdio.h>
3#include <stdlib.h>
4#include <unistd.h>
5
6#include "litmus.h"
7#include "common.h"
8
9void usage(char *error) {
10 fprintf(stderr, "Error: %s\n", error);
11 fprintf(stderr,
12 "Usage: npsf_add_server NPSF-ID UTIL SLOT-SIZE(ms) CPU \n");
13 exit(1);
14}
15
16int main(int argc, char** argv)
17{
18 int ret;
19 int cpu = 0;
20 int npsf_id = 0;
21 double util = 0;
22 int slot_ms = 0;
23 lt_t budget_ns = 0;
24
25 if (argc < 5)
26 usage("Arguments missing.");
27 npsf_id = atoi(argv[1]);
28 util = atof(argv[2]);
29 slot_ms = atoi(argv[3]);
30 cpu = atoi(argv[4]);
31
32 if (util > 1)
33 usage("Utilization > 1");
34
35 budget_ns = (lt_t)((__NS_PER_MS * util) * slot_ms);
36
37 printf("Trying to add NP(%d): budget = %f\n", npsf_id, (double)(budget_ns) / __NS_PER_MS);
38
39 ret = add_server(&npsf_id, &budget_ns, &cpu);
40
41 if (ret < 0)
42 bail_out("Cannot add Notional Processor: ");
43
44 return 0;
45}
diff --git a/bin/rtspin_npsf.c b/bin/rtspin_npsf.c
new file mode 100644
index 0000000..87eb52f
--- /dev/null
+++ b/bin/rtspin_npsf.c
@@ -0,0 +1,252 @@
1#include <sys/time.h>
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <unistd.h>
6#include <time.h>
7
8
9#include "litmus.h"
10#include "common.h"
11
12
13static double cputime()
14{
15 struct timespec ts;
16 int err;
17 err = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
18 if (err != 0)
19 perror("clock_gettime");
20 return (ts.tv_sec + 1E-9 * ts.tv_nsec);
21}
22
23static double wctime()
24{
25 struct timeval tv;
26 gettimeofday(&tv, NULL);
27 return (tv.tv_sec + 1E-6 * tv.tv_usec);
28}
29
30void usage(char *error) {
31 fprintf(stderr, "Error: %s\n", error);
32 fprintf(stderr,
33 "Usage: rt_spin [-w] WCET PERIOD DURATION CPU NPSF-ID\n"
34 " rt_spin -l\n");
35 exit(1);
36}
37
38#define NUMS 4096
39static int num[NUMS];
40static double loop_length = 1.0;
41static char* progname;
42
43static int loop_once(void)
44{
45 int i, j = 0;
46 for (i = 0; i < NUMS; i++)
47 j += num[i]++;
48 return j;
49}
50
51static int loop_for(double exec_time)
52{
53 double t = 0;
54 int tmp = 0;
55/* while (t + loop_length < exec_time) {
56 tmp += loop_once();
57 t += loop_length;
58 }
59*/
60 double start = cputime();
61 double now = cputime();
62 while (now + loop_length < start + exec_time) {
63 tmp += loop_once();
64 t += loop_length;
65 now = cputime();
66 }
67
68 return tmp;
69}
70
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
111static void debug_delay_loop(void)
112{
113 double start, end, delay;
114 show_loop_length();
115 while (1) {
116 for (delay = 0.5; delay > 0.01; delay -= 0.01) {
117 start = wctime();
118 loop_for(delay);
119 end = wctime();
120 printf("%6.4fs: looped for %10.8fs, delta=%11.8fs, error=%7.4f%%\n",
121 delay,
122 end - start,
123 end - start - delay,
124 100 * (end - start - delay) / delay);
125 }
126 }
127}
128
129static int job(double exec_time)
130{
131 loop_for(exec_time);
132 sleep_next_period();
133 return 0;
134}
135
136#define OPTSTR "c:wld:v"
137
138int main(int argc, char** argv)
139{
140 int ret;
141 lt_t wcet;
142 lt_t period;
143 double wcet_ms, period_ms;
144 int migrate = 0;
145 int cpu = 0;
146 int npsf_id = 0;
147 int opt;
148 int wait = 0;
149 int test_loop = 0;
150 int skip_config = 0;
151 int verbose = 0;
152 double duration, start;
153 task_class_t class = RT_CLASS_HARD;
154
155 progname = argv[0];
156
157 while ((opt = getopt(argc, argv, OPTSTR)) != -1) {
158 switch (opt) {
159 case 'w':
160 wait = 1;
161 break;
162 case 'c':
163 class = str2class(optarg);
164 if (class == -1)
165 usage("Unknown task class.");
166 break;
167 case 'l':
168 test_loop = 1;
169 break;
170 case 'd':
171 /* manually configure delay per loop iteration
172 * unit: microseconds */
173 loop_length = atof(optarg) / 1000000;
174 skip_config = 1;
175 break;
176 case 'v':
177 verbose = 1;
178 break;
179 case ':':
180 usage("Argument missing.");
181 break;
182 case '?':
183 default:
184 usage("Bad argument.");
185 break;
186 }
187 }
188
189
190 if (!skip_config)
191 configure_loop();
192
193 if (test_loop) {
194 debug_delay_loop();
195 return 0;
196 }
197
198 if (argc - optind < 3)
199 usage("Arguments missing.");
200 wcet_ms = atof(argv[optind + 0]);
201 period_ms = atof(argv[optind + 1]);
202 duration = atof(argv[optind + 2]);
203 cpu = atoi(argv[optind + 3]);
204 migrate = 1;
205 npsf_id = atoi(argv[optind + 4]);
206 wcet = wcet_ms * __NS_PER_MS;
207 period = period_ms * __NS_PER_MS;
208 if (wcet <= 0)
209 usage("The worst-case execution time must be a "
210 "positive number.");
211 if (period <= 0)
212 usage("The period must be a positive number.");
213 if (wcet > period) {
214 usage("The worst-case execution time must not "
215 "exceed the period.");
216 }
217
218 if (migrate) {
219 ret = be_migrate_to(cpu);
220 if (ret < 0)
221 bail_out("could not migrate to target partition");
222 }
223
224 ret = sporadic_task_ns_npsf(wcet, period, 0, cpu, class, npsf_id,
225 NO_ENFORCEMENT, migrate);
226
227 if (ret < 0)
228 bail_out("could not setup rt task params");
229
230 if (verbose)
231 show_loop_length();
232
233 init_litmus();
234
235 ret = task_mode(LITMUS_RT_TASK);
236 if (ret != 0)
237 bail_out("could not become RT task");
238
239 if (wait) {
240 ret = wait_for_ts_release();
241 if (ret != 0)
242 bail_out("wait_for_ts_release()");
243 }
244
245 start = wctime();
246
247 while (start + duration > wctime()) {
248 job(wcet_ms * 0.0009); /* 90% wcet, in seconds */
249 }
250
251 return 0;
252}
diff --git a/include/litmus.h b/include/litmus.h
index 3aa790f..d7f7b99 100644
--- a/include/litmus.h
+++ b/include/litmus.h
@@ -45,6 +45,11 @@ int sporadic_task_ns_edffm(lt_t e, lt_t p, lt_t phase, int cpu,
45 task_class_t cls, budget_policy_t budget_policy, 45 task_class_t cls, budget_policy_t budget_policy,
46 int set_cpu_set); 46 int set_cpu_set);
47 47
48int sporadic_task_ns_npsf(
49 lt_t e, lt_t p, lt_t phase,
50 int cpu, task_class_t cls, int npsf_id,
51 budget_policy_t budget_policy, int set_cpu_set);
52
48/* budget enforcement off by default in these macros */ 53/* budget enforcement off by default in these macros */
49#define sporadic_global(e, p) \ 54#define sporadic_global(e, p) \
50 sporadic_task(e, p, 0, 0, RT_CLASS_SOFT, NO_ENFORCEMENT, 0) 55 sporadic_task(e, p, 0, 0, RT_CLASS_SOFT, NO_ENFORCEMENT, 0)
@@ -142,6 +147,26 @@ int null_call(cycles_t *timestamp);
142 */ 147 */
143struct control_page* get_ctrl_page(void); 148struct control_page* get_ctrl_page(void);
144 149
150/* NPS-F syscall to add a notional processor (a server) to a cpu.
151 * A notional processor may span across multiple cpu. If the NP.
152 * spans multiple cpus, each "segment" must be initialized indipendently
153 * with the proper fraction of budget of the original NP. For example:
154 *
155 * NP1 = 0.75 = inflated utilization; it spans on CPU0 and CPU1:
156 * NP1_0 = 0.2; NP1_1 = 0.55
157 *
158 * So, we have to initialize a segment (0.2 * slot_length) on CPU0
159 * and a segment (0.55 * slot_length) on CPU1 (both should have
160 * the same npsf_id).
161 *
162 * @npsf_id: a "unique" identifier for the notional processor.
163 * @budget: the length of the segment for this NP. on this CPU (in ns).
164 * @cpu: the cpu that holds this NP segment.
165 *
166 * Currently implemented on x86_64 only.
167 */
168int add_server(int *npsf_id, lt_t *budget, int *cpu);
169
145#ifdef __cplusplus 170#ifdef __cplusplus
146} 171}
147#endif 172#endif
diff --git a/src/litmus.c b/src/litmus.c
index d253368..65f711a 100644
--- a/src/litmus.c
+++ b/src/litmus.c
@@ -101,6 +101,27 @@ int sporadic_task_ns_edffm(lt_t e, lt_t p, lt_t phase, int cpu,
101 return set_rt_task_param(gettid(), &param); 101 return set_rt_task_param(gettid(), &param);
102} 102}
103 103
104int sporadic_task_ns_npsf(lt_t e, lt_t p, lt_t phase,
105 int cpu, task_class_t cls, int npsf_id,
106 budget_policy_t budget_policy, int set_cpu_set)
107{
108 struct rt_task param;
109 int ret;
110 param.exec_cost = e;
111 param.period = p;
112 param.cpu = cpu;
113 param.cls = cls;
114 param.phase = phase;
115 param.budget_policy = budget_policy;
116 param.npsf_id = npsf_id;
117
118 if (set_cpu_set) {
119 ret = be_migrate_to(cpu);
120 check("migrate to cpu");
121 }
122 return set_rt_task_param(gettid(), &param);
123}
124
104int init_kernel_iface(void); 125int init_kernel_iface(void);
105 126
106int init_litmus(void) 127int init_litmus(void)
diff --git a/src/syscalls.c b/src/syscalls.c
index 77a6277..58d7151 100644
--- a/src/syscalls.c
+++ b/src/syscalls.c
@@ -95,3 +95,8 @@ int null_call(cycles_t *timestamp)
95{ 95{
96 return syscall(__NR_null_call, timestamp); 96 return syscall(__NR_null_call, timestamp);
97} 97}
98
99int add_server(int *npsf_id, lt_t *budget, int *cpu)
100{
101 return syscall(__NR_add_server, npsf_id, budget, cpu);
102}