summaryrefslogtreecommitdiffstats
path: root/bin/pm_task.c
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-04-12 23:17:14 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-04-12 23:17:14 -0400
commit752ef77c1a70372bd2d2f7b349e2e25ac741c0c6 (patch)
treef5cdaa8e1f547a9ad8f71fd74d53ccc2931fb592 /bin/pm_task.c
parente1d76b979bace619aeaf4383f02b728ebb5558fd (diff)
Add main pm test program
- pm_task and architectural dependent memory access
Diffstat (limited to 'bin/pm_task.c')
-rw-r--r--bin/pm_task.c295
1 files changed, 295 insertions, 0 deletions
diff --git a/bin/pm_task.c b/bin/pm_task.c
new file mode 100644
index 0000000..40f3fb9
--- /dev/null
+++ b/bin/pm_task.c
@@ -0,0 +1,295 @@
1/*
2 * pm_task.c
3 *
4 * A real-time task that measures preemption and migration costs
5 * for a specific working set size.
6 *
7 * 2008 Original version and idea by John Calandrino
8 * (litmus2008, liblitmus2008)
9 *
10 * 2010 Porting of original program to litmus2010 and
11 * integration within liblitmus2010 by Andrea Bastoni
12 */
13
14/* common data structures and defines */
15#include "pm_common.h"
16
17#include "litmus.h"
18#include "asm.h"
19#include "cycles.h"
20
21/* architectural dependend code for pm measurement */
22#include "pm_arch.h"
23
24#include <sys/io.h>
25
26int mem_block[NUMWS][INTS_PER_WSS] __attribute__ ((aligned(CACHEALIGNMENT)));
27
28/* Setup flags, then enter loop to measure costs. */
29int main(int argc, char **argv)
30{
31 /* control_page to read data from kernel */
32 struct control_page *ctrl = NULL;
33#ifdef DEBUG
34 struct control_page *saved_ctrl_page_ptr = 0;
35#endif
36
37 unsigned long curr_job_count = 0;
38 unsigned long curr_sched_count = 0;
39 unsigned int curr_cpu = 0;
40 unsigned long curr_last_rt_task = 0;
41 unsigned long curr_ws = 0;
42
43 unsigned long long curr_preemption_length = 0;
44
45 unsigned long long start_time, end_time;
46
47 int *mem_ptr = NULL;
48 int *mem_ptr_end = NULL;
49
50 struct data_entry data_points[DATAPOINTS];
51 int data_count = 0;
52 int data_wrapped = 0;
53
54 int refcount;
55
56 int task_pid = gettid();
57 int task_period;
58 int read, *loc_ptr;
59 struct rt_task param;
60
61 char *filename;
62#ifdef DEBUG
63 int i;
64#endif
65
66 if (argc < 2) {
67 printf("pm_task: need a filename\n");
68 return -1;
69 }
70
71 filename = argv[1];
72#ifdef DEBUG
73 fprintf(stderr, "Saving on %s\n",filename);
74#endif
75
76 /* Initialize random library for read/write ratio enforcement. */
77 srandom(SEEDVAL);
78
79 /* this will lock all pages and will call init_kernel_iface */
80 init_litmus();
81
82 /* Ensure that the pages that we care about, either because they
83 * are shared with the kernel or they are performance-critical,
84 * are loaded and locked in memory before benchmarking begins.
85 */
86 memset(&param, 0, sizeof(struct rt_task));
87
88 memset(&mem_block, 0, sizeof(int) * NUMWS * INTS_PER_WSS);
89
90 memset(&mem_ptr, 0, sizeof(int*));
91 memset(&mem_ptr_end, 0, sizeof(int*));
92
93 /* Get task period. */
94 if (get_rt_task_param(task_pid, &param) < 0) {
95 perror("Cannot get task parameters\n");
96 return -1;
97 }
98
99 task_period = param.period / NS_PER_MS;
100
101 /* get the shared control page for this task */
102 if (!(ctrl = get_ctrl_page())) {
103 perror("Cannot get the shared control page\n");
104 return -1;
105 }
106#ifdef DEBUG
107 saved_ctrl_page_ptr = ctrl;
108#endif
109
110 /* Enter loop that measures preemption and migration costs. */
111 while (curr_job_count * task_period < SIMRUNTIME) {
112#ifdef DEBUG
113 /* try to understand if bad bad things happened */
114 if(ctrl != saved_ctrl_page_ptr) {
115 fprintf(stderr, "BAD BAD BAD!\n\nCtrl page changed! %p != %p\n",
116 saved_ctrl_page_ptr, ctrl);
117 return -1;
118 }
119#endif
120 if (curr_job_count != ctrl->job_count) {
121
122 /* ok, this is a new job. Get info from kernel */
123
124 curr_job_count = ctrl->job_count;
125 curr_sched_count = ctrl->sched_count;
126 curr_cpu = ctrl->cpu;
127 curr_last_rt_task = ctrl->last_rt_task;
128
129 barrier();
130
131 /* job's portion of the mem_block */
132 curr_ws = curr_job_count % NUMWS;
133
134 mem_ptr = &mem_block[curr_ws][0];
135 mem_ptr_end = mem_ptr + INTS_PER_WSS;
136
137 /* Access WS when cache cold, then immediately
138 * re-access to calculate "cache-hot" access time.
139 */
140
141 /* Cache-cold accesses. */
142 start_time = get_cycles();
143 for (; mem_ptr < mem_ptr_end; mem_ptr += 1024)
144 readwrite_one_thousand_ints(mem_ptr);
145 end_time = get_cycles();
146
147 data_points[data_count].timestamp = end_time;
148
149 /* Am I the same I was before? */
150 if (curr_job_count != ctrl->job_count ||
151 curr_sched_count != ctrl->sched_count ||
152 curr_cpu != ctrl->cpu)
153 /* fishiness */
154 data_points[data_count].access_type = 'c';
155 else
156 /* okay */
157 data_points[data_count].access_type = 'C';
158
159 data_points[data_count].access_time =
160 end_time - start_time;
161 data_points[data_count].cpu = curr_cpu;
162 data_points[data_count].job_count = curr_job_count;
163 data_points[data_count].sched_count = curr_sched_count;
164 data_points[data_count].last_rt_task = curr_last_rt_task;
165 data_points[data_count].preemption_length = 0;
166
167 data_wrapped = ((data_count+1) / DATAPOINTS > 0);
168 data_count = (data_count+1) % DATAPOINTS;
169
170 barrier();
171
172 /* "Best case". Read multiple times. */
173 for (refcount = 0; refcount < REFTOTAL; refcount++) {
174
175 mem_ptr = &mem_block[curr_ws][0];
176
177 start_time = get_cycles();
178 for (; mem_ptr < mem_ptr_end; mem_ptr += 1024)
179 readwrite_one_thousand_ints(mem_ptr);
180 end_time = get_cycles();
181
182 data_points[data_count].timestamp = end_time;
183
184 if (curr_job_count != ctrl->job_count ||
185 curr_sched_count != ctrl->sched_count ||
186 curr_cpu != ctrl->cpu)
187 /* fishiness */
188 data_points[data_count].
189 access_type = 'h';
190 else
191 /* okay */
192 data_points[data_count].
193 access_type = 'H';
194
195 data_points[data_count].access_time =
196 end_time - start_time;
197 data_points[data_count].cpu = curr_cpu;
198 data_points[data_count].job_count =
199 curr_job_count;
200 data_points[data_count].sched_count =
201 curr_sched_count;
202 data_points[data_count].last_rt_task =
203 curr_last_rt_task;
204 data_points[data_count].preemption_length = 0;
205
206 data_wrapped =
207 ((data_count+1) / DATAPOINTS > 0);
208 data_count = (data_count+1) % DATAPOINTS;
209 }
210
211 } else if (mem_ptr && mem_ptr_end &&
212 (curr_sched_count != ctrl->sched_count ||
213 curr_cpu != ctrl->cpu)) {
214
215 /* we have done at least one go in the "best case".
216 * job is the same => preempted / migrated
217 */
218 curr_preemption_length =
219 ctrl->preempt_end - ctrl->preempt_start;
220 curr_job_count = ctrl->job_count;
221 curr_sched_count = ctrl->sched_count;
222 curr_cpu = ctrl->cpu;
223 curr_last_rt_task = ctrl->last_rt_task;
224
225 barrier();
226
227 /* Measure preemption or migration cost. */
228 mem_ptr = &mem_block[curr_ws][0];
229
230 start_time = get_cycles();
231 for (; mem_ptr < mem_ptr_end; mem_ptr += 1024)
232 readwrite_one_thousand_ints(mem_ptr);
233 end_time = get_cycles();
234
235 data_points[data_count].timestamp = end_time;
236
237 /* just record pP, we tell the difference later */
238 if (curr_job_count != ctrl->job_count ||
239 curr_sched_count != ctrl->sched_count ||
240 curr_cpu != ctrl->cpu)
241 /* fishiness */
242 data_points[data_count].access_type = 'p';
243 else
244 /* okay */
245 data_points[data_count].access_type = 'P';
246
247 data_points[data_count].access_time =
248 end_time - start_time;
249 data_points[data_count].cpu = curr_cpu;
250 data_points[data_count].job_count = curr_job_count;
251 data_points[data_count].sched_count = curr_sched_count;
252 data_points[data_count].last_rt_task =
253 curr_last_rt_task;
254 data_points[data_count].preemption_length =
255 curr_preemption_length;
256
257 data_wrapped = ((data_count+1) / DATAPOINTS > 0);
258 data_count = (data_count+1) % DATAPOINTS;
259
260 } else if (mem_ptr && mem_ptr_end) {
261 /*
262 * Ok, we run (and we wait for a p/m event):
263 * Read or write some random location in the WS
264 * to keep the task "cache warm". We only do
265 * this if the pointers are valid, because we
266 * do not want to skew the "cold" read of the WS
267 * on the first job.
268 */
269 read = (random() % 100) < READRATIO;
270 loc_ptr = &mem_block[curr_ws][0];
271 loc_ptr += (random() % INTS_PER_WSS);
272
273 barrier();
274
275 if (read)
276 read_mem(loc_ptr);
277 else
278 write_mem(loc_ptr);
279 }
280 }
281
282#ifdef DEBUG
283 /* Print (most recent) results. */
284 for (i = 0; i < (data_wrapped ? DATAPOINTS : data_count) ; i++)
285 fprintf(stderr, "(%c) - ACC %llu, CPU %u, PLEN %llu\n",
286 data_points[i].access_type,
287 data_points[i].access_time, data_points[i].cpu,
288 data_points[i].preemption_length);
289#endif
290 serialize_data_entry(filename, data_points,
291 (data_wrapped ? DATAPOINTS : data_count));
292
293 return 0;
294}
295