rev |
line source |
gdunlap@0
|
1 #include <stdlib.h>
|
gdunlap@0
|
2 #include <stdio.h>
|
gdunlap@0
|
3 #include <assert.h>
|
gdunlap@0
|
4
|
gdunlap@0
|
5 #define ASSERT assert
|
gdunlap@0
|
6
|
gdunlap@0
|
7 #include "stats.h"
|
gdunlap@0
|
8 #include "list.h"
|
gdunlap@0
|
9 #include "sim.h"
|
gdunlap@0
|
10 #include "workload.h"
|
gdunlap@2
|
11 #include "sched.h"
|
gdunlap@2
|
12 #include "options.h"
|
gdunlap@0
|
13
|
gdunlap@0
|
14 FILE *warn;
|
gdunlap@0
|
15
|
gdunlap@0
|
16 enum event_type {
|
gdunlap@0
|
17 EVT_BLOCK,
|
gdunlap@0
|
18 EVT_WAKE,
|
gdunlap@0
|
19 EVT_TIMER,
|
gdunlap@0
|
20 EVT_MAX
|
gdunlap@0
|
21 };
|
gdunlap@0
|
22
|
gdunlap@0
|
23 char *event_name[EVT_MAX] = {
|
gdunlap@0
|
24 [EVT_BLOCK]="block",
|
gdunlap@0
|
25 [EVT_WAKE] ="wake ",
|
gdunlap@0
|
26 [EVT_TIMER]="timer"
|
gdunlap@0
|
27 };
|
gdunlap@0
|
28
|
gdunlap@0
|
29 struct event {
|
gdunlap@0
|
30 struct list_head event_list;
|
gdunlap@0
|
31 enum event_type type;
|
gdunlap@0
|
32 int time;
|
gdunlap@0
|
33 int param; /* Usually VM ID */
|
gdunlap@0
|
34 };
|
gdunlap@0
|
35
|
gdunlap@0
|
36 char * state_name[STATE_MAX] = {
|
gdunlap@0
|
37 [STATE_RUN]= "run ",
|
gdunlap@0
|
38 [STATE_PREEMPT]="preempt",
|
gdunlap@0
|
39 [STATE_WAKE]= "wake ",
|
gdunlap@0
|
40 [STATE_BLOCK]= "block ",
|
gdunlap@0
|
41 };
|
gdunlap@0
|
42
|
gdunlap@0
|
43 struct {
|
gdunlap@0
|
44 int now;
|
gdunlap@0
|
45 struct list_head events;
|
gdunlap@0
|
46 struct list_head *timer;
|
gdunlap@0
|
47 const struct sched_ops *sched_ops;
|
gdunlap@0
|
48 } sim;
|
gdunlap@0
|
49
|
gdunlap@0
|
50
|
gdunlap@1
|
51 #ifndef VM_DATA_PUBLIC
|
gdunlap@1
|
52 struct global_vm_data {
|
gdunlap@0
|
53 int count;
|
gdunlap@0
|
54 struct vm vms[MAX_VMS];
|
gdunlap@1
|
55 };
|
gdunlap@1
|
56 #endif
|
gdunlap@1
|
57 struct global_vm_data V;
|
gdunlap@0
|
58
|
gdunlap@0
|
59 extern struct scheduler sched_rr;
|
gdunlap@5
|
60 extern struct scheduler sched_credit01;
|
gdunlap@11
|
61 extern struct scheduler sched_credit02;
|
george@14
|
62 extern struct scheduler sched_credit03;
|
gdunlap@0
|
63 int default_scheduler = 0;
|
gdunlap@0
|
64 struct scheduler *schedulers[] =
|
gdunlap@0
|
65 {
|
gdunlap@0
|
66 &sched_rr,
|
gdunlap@5
|
67 &sched_credit01,
|
gdunlap@11
|
68 &sched_credit02,
|
george@14
|
69 &sched_credit03,
|
gdunlap@2
|
70 NULL
|
gdunlap@0
|
71 };
|
gdunlap@0
|
72
|
gdunlap@0
|
73 /* Options */
|
gdunlap@0
|
74
|
gdunlap@0
|
75 struct global_pcpu_data P;
|
gdunlap@0
|
76
|
gdunlap@0
|
77 /* Sim list interface */
|
gdunlap@0
|
78 /* NB: Caller must free if they're not going to use it! */
|
gdunlap@0
|
79 #define list_event(_l) (list_entry((_l), struct event, event_list))
|
gdunlap@0
|
80
|
gdunlap@0
|
81 struct event* sim_remove_event(int type, int param)
|
gdunlap@0
|
82 {
|
gdunlap@0
|
83 struct event* ret = NULL;
|
gdunlap@0
|
84 struct list_head *pos, *tmp;
|
gdunlap@0
|
85
|
gdunlap@0
|
86 /* Look for an event that matches this one and remove it */
|
gdunlap@0
|
87 list_for_each_safe(pos, tmp, &sim.events)
|
gdunlap@0
|
88 {
|
gdunlap@0
|
89 struct event *tevt = list_event(pos);
|
gdunlap@0
|
90 if ( tevt->type == type
|
gdunlap@0
|
91 && tevt->param == param )
|
gdunlap@0
|
92 {
|
gdunlap@0
|
93 list_del(pos);
|
gdunlap@0
|
94 ret = tevt;
|
gdunlap@0
|
95 break;
|
gdunlap@0
|
96 }
|
gdunlap@0
|
97 }
|
gdunlap@0
|
98
|
gdunlap@0
|
99 return ret;
|
gdunlap@0
|
100 }
|
gdunlap@0
|
101
|
gdunlap@0
|
102 void sim_insert_event(int time, int type, int param, int reset)
|
gdunlap@0
|
103 {
|
gdunlap@0
|
104 struct list_head *pos = NULL;
|
gdunlap@0
|
105 struct event *evt=NULL;
|
gdunlap@0
|
106
|
gdunlap@0
|
107 ASSERT(time >= sim.now);
|
gdunlap@0
|
108
|
gdunlap@0
|
109 if ( reset )
|
gdunlap@0
|
110 evt=sim_remove_event(type, param);
|
gdunlap@0
|
111
|
gdunlap@0
|
112 if ( !evt )
|
gdunlap@0
|
113 evt = (struct event *)malloc(sizeof(*evt));
|
gdunlap@0
|
114
|
gdunlap@0
|
115 evt->time = time;
|
gdunlap@0
|
116 evt->type = type;
|
gdunlap@0
|
117 evt->param = param;
|
gdunlap@0
|
118
|
gdunlap@1
|
119 printf(" [insert t%d %s param%d]\n",
|
gdunlap@1
|
120 evt->time, event_name[evt->type], evt->param);
|
gdunlap@1
|
121
|
gdunlap@0
|
122 INIT_LIST_HEAD(&evt->event_list);
|
gdunlap@0
|
123
|
gdunlap@0
|
124 list_for_each(pos, &sim.events)
|
gdunlap@0
|
125 {
|
gdunlap@0
|
126 if ( list_event(pos)->time > evt->time )
|
gdunlap@0
|
127 break;
|
gdunlap@0
|
128 }
|
gdunlap@0
|
129 list_add_tail(&evt->event_list, pos);
|
gdunlap@0
|
130 }
|
gdunlap@0
|
131
|
gdunlap@0
|
132 struct event sim_next_event(void)
|
gdunlap@0
|
133 {
|
gdunlap@0
|
134 struct event *evt;
|
gdunlap@0
|
135 struct list_head *next;
|
gdunlap@0
|
136
|
gdunlap@0
|
137 ASSERT(!list_empty(&sim.events));
|
gdunlap@0
|
138
|
gdunlap@0
|
139 next=sim.events.next;
|
gdunlap@0
|
140
|
gdunlap@0
|
141 list_del(next);
|
gdunlap@0
|
142
|
gdunlap@0
|
143 evt=list_event(next);
|
gdunlap@0
|
144
|
gdunlap@0
|
145 printf("%d: evt %s param%d\n",
|
gdunlap@0
|
146 evt->time, event_name[evt->type], evt->param);
|
gdunlap@0
|
147
|
gdunlap@0
|
148 free(evt);
|
gdunlap@0
|
149
|
gdunlap@0
|
150 /* XXX */
|
gdunlap@0
|
151 return *evt;
|
gdunlap@0
|
152 }
|
gdunlap@0
|
153
|
gdunlap@0
|
154 /*
|
gdunlap@0
|
155 * VM simulation
|
gdunlap@0
|
156 */
|
gdunlap@0
|
157 void vm_next_event(struct vm *v)
|
gdunlap@0
|
158 {
|
gdunlap@0
|
159 v->phase_index = ( v->phase_index + 1 ) % v->workload->phase_count;
|
gdunlap@0
|
160
|
gdunlap@0
|
161 v->e = v->workload->list + v->phase_index;
|
gdunlap@0
|
162 }
|
gdunlap@0
|
163
|
gdunlap@0
|
164 struct vm* vm_from_vid(int vid)
|
gdunlap@0
|
165 {
|
gdunlap@1
|
166 if ( vid >= V.count )
|
gdunlap@1
|
167 {
|
gdunlap@1
|
168 fprintf(stderr, "%s: v%d >= V.count %d!\n",
|
gdunlap@1
|
169 __func__, vid, V.count);
|
gdunlap@1
|
170 exit(1);
|
gdunlap@1
|
171 }
|
gdunlap@0
|
172
|
gdunlap@0
|
173 return V.vms + vid;
|
gdunlap@0
|
174 }
|
gdunlap@0
|
175
|
gdunlap@0
|
176 void vm_block(int now, struct vm *v)
|
gdunlap@0
|
177 {
|
gdunlap@0
|
178 ASSERT(v->e->type == PHASE_RUN);
|
gdunlap@0
|
179 v->time_this_phase += now - v->state_start_time;
|
gdunlap@3
|
180 printf("%s: v%d time_this_phase %d (evt %d)\n",
|
gdunlap@3
|
181 __func__, v->vid, v->time_this_phase, v->e->time);
|
gdunlap@0
|
182
|
gdunlap@0
|
183 ASSERT(v->time_this_phase == v->e->time);
|
gdunlap@0
|
184
|
gdunlap@0
|
185 vm_next_event(v);
|
gdunlap@0
|
186
|
gdunlap@0
|
187 ASSERT(v->e->type == PHASE_BLOCK);
|
gdunlap@0
|
188
|
gdunlap@0
|
189 sim_insert_event(now + v->e->time, EVT_WAKE, v->vid, 0);
|
gdunlap@0
|
190 v->time_this_phase = 0;
|
gdunlap@0
|
191 v->was_preempted = 0;
|
gdunlap@0
|
192 }
|
gdunlap@0
|
193
|
gdunlap@0
|
194 /* Called when wake event happens; increment timer and reset state */
|
gdunlap@0
|
195 void vm_wake(int now, struct vm *v)
|
gdunlap@0
|
196 {
|
gdunlap@0
|
197 ASSERT(v->e->type == PHASE_BLOCK);
|
gdunlap@0
|
198 ASSERT(v->time_this_phase == 0);
|
gdunlap@0
|
199
|
gdunlap@0
|
200 v->time_this_phase = now - v->state_start_time;
|
gdunlap@0
|
201
|
gdunlap@0
|
202 if ( now != 0 )
|
gdunlap@0
|
203 ASSERT(v->time_this_phase == v->e->time);
|
gdunlap@0
|
204
|
gdunlap@0
|
205 vm_next_event(v);
|
gdunlap@0
|
206
|
gdunlap@0
|
207 v->time_this_phase = 0;
|
gdunlap@0
|
208 }
|
gdunlap@0
|
209
|
gdunlap@0
|
210 /* Called when actually starting to run; make block event and set state */
|
gdunlap@0
|
211 void vm_run(int now, struct vm *v)
|
gdunlap@0
|
212 {
|
gdunlap@0
|
213 ASSERT(v->e->type == PHASE_RUN);
|
gdunlap@3
|
214 ASSERT(v->time_this_phase <= v->e->time);
|
gdunlap@0
|
215
|
gdunlap@0
|
216 sim_insert_event(now + v->e->time - v->time_this_phase, EVT_BLOCK, v->vid, 0);
|
gdunlap@0
|
217 v->state_start_time = now;
|
gdunlap@0
|
218 }
|
gdunlap@0
|
219
|
gdunlap@0
|
220 /* Preempt: Remove block event, update amount of runtime (so that when it runs again we can accurately
|
gdunlap@0
|
221 * generate a new block event) */
|
gdunlap@0
|
222 void vm_preempt(int now, struct vm *v)
|
gdunlap@0
|
223 {
|
gdunlap@0
|
224 struct event* evt;
|
gdunlap@0
|
225
|
gdunlap@3
|
226 v->time_this_phase += now - v->state_start_time;
|
gdunlap@3
|
227 printf("%s: v%d time_this_phase %d (evt %d)\n",
|
gdunlap@3
|
228 __func__, v->vid, v->time_this_phase, v->e->time);
|
gdunlap@3
|
229
|
gdunlap@3
|
230 ASSERT( v->time_this_phase <= v->e->time );
|
gdunlap@3
|
231
|
gdunlap@3
|
232 /* Only remove block event if we still have more runtime left */
|
gdunlap@0
|
233 if ( ( evt = sim_remove_event(EVT_BLOCK, v->vid) ) )
|
gdunlap@0
|
234 free(evt);
|
gdunlap@0
|
235
|
gdunlap@0
|
236 v->was_preempted = 1;
|
gdunlap@0
|
237 }
|
gdunlap@0
|
238
|
gdunlap@0
|
239
|
gdunlap@0
|
240 /* Callbacks the scheduler may make */
|
gdunlap@0
|
241 void sim_sched_timer(int time, int pid)
|
gdunlap@0
|
242 {
|
gdunlap@3
|
243 if ( time < 0 )
|
gdunlap@3
|
244 {
|
gdunlap@3
|
245 fprintf(stderr, "%s: Time %d < 0!\n",
|
gdunlap@3
|
246 __func__, time);
|
gdunlap@3
|
247 abort();
|
gdunlap@3
|
248 }
|
gdunlap@3
|
249
|
gdunlap@1
|
250 if ( pid >= P.count )
|
gdunlap@1
|
251 {
|
gdunlap@1
|
252 fprintf(stderr, "%s: p%d >= P.count %d\n",
|
gdunlap@1
|
253 __func__, pid, P.count);
|
gdunlap@1
|
254 exit(1);
|
gdunlap@1
|
255 }
|
gdunlap@1
|
256
|
gdunlap@1
|
257 if ( P.pcpus[pid].idle )
|
gdunlap@1
|
258 {
|
gdunlap@1
|
259 P.pcpus[pid].idle = 0;
|
gdunlap@1
|
260 P.idle--;
|
gdunlap@1
|
261 }
|
gdunlap@0
|
262 sim_insert_event(sim.now + time, EVT_TIMER, pid, 1);
|
gdunlap@0
|
263 }
|
gdunlap@0
|
264
|
gdunlap@6
|
265 void dump_running(int now, struct vm *v)
|
gdunlap@6
|
266 {
|
gdunlap@6
|
267 printf("runtime v%d %d %llu\n",
|
gdunlap@6
|
268 v->vid,
|
gdunlap@6
|
269 now,
|
gdunlap@6
|
270 v->stats.state[RUNSTATE_RUNNING].cycles);
|
gdunlap@6
|
271 }
|
gdunlap@6
|
272
|
gdunlap@0
|
273 void sim_runstate_change(int now, struct vm *v, int new_runstate)
|
gdunlap@0
|
274 {
|
gdunlap@0
|
275 int ostate, nstate;
|
gdunlap@0
|
276 int stime = now - v->state_start_time;
|
gdunlap@0
|
277
|
gdunlap@0
|
278 /* Valid transitions:
|
gdunlap@0
|
279 * + R->A (preemption): remove block event
|
gdunlap@0
|
280 * + R->B (block) : Insert wake event
|
gdunlap@0
|
281 * + A->R (run) : Insert block event
|
gdunlap@0
|
282 * + B->A (wake) : No action necessary
|
gdunlap@0
|
283 */
|
gdunlap@0
|
284
|
gdunlap@0
|
285 switch ( v->runstate )
|
gdunlap@0
|
286 {
|
gdunlap@0
|
287 case RUNSTATE_RUNNING:
|
gdunlap@0
|
288 ostate = STATE_RUN;
|
gdunlap@0
|
289 break;
|
gdunlap@0
|
290 case RUNSTATE_RUNNABLE:
|
gdunlap@0
|
291 if ( v->was_preempted )
|
gdunlap@0
|
292 ostate = STATE_PREEMPT;
|
gdunlap@0
|
293 else
|
gdunlap@0
|
294 ostate = STATE_WAKE;
|
gdunlap@0
|
295 break;
|
gdunlap@0
|
296 case RUNSTATE_BLOCKED:
|
gdunlap@0
|
297 ostate = STATE_BLOCK;
|
gdunlap@0
|
298 break;
|
gdunlap@0
|
299 }
|
gdunlap@0
|
300
|
gdunlap@0
|
301 update_cycles(&v->stats.state[ostate], stime);
|
gdunlap@0
|
302
|
gdunlap@6
|
303 if ( v->runstate == RUNSTATE_RUNNING
|
gdunlap@6
|
304 || new_runstate == RUNSTATE_RUNNING )
|
gdunlap@6
|
305 dump_running(now, v);
|
gdunlap@6
|
306
|
gdunlap@0
|
307
|
gdunlap@0
|
308 if ( v->runstate == RUNSTATE_RUNNING
|
gdunlap@0
|
309 && new_runstate == RUNSTATE_RUNNABLE )
|
gdunlap@0
|
310 {
|
gdunlap@0
|
311 nstate = STATE_PREEMPT;
|
gdunlap@0
|
312 vm_preempt(now, v);
|
gdunlap@0
|
313 }
|
gdunlap@0
|
314 else if ( v->runstate == RUNSTATE_RUNNING
|
gdunlap@0
|
315 && new_runstate == RUNSTATE_BLOCKED )
|
gdunlap@0
|
316 {
|
gdunlap@0
|
317 nstate = STATE_BLOCK;
|
gdunlap@0
|
318 vm_block(now, v);
|
gdunlap@0
|
319 }
|
gdunlap@0
|
320 else if ( v->runstate == RUNSTATE_RUNNABLE
|
gdunlap@0
|
321 && new_runstate == RUNSTATE_RUNNING )
|
gdunlap@0
|
322 {
|
gdunlap@0
|
323 nstate = STATE_RUN;
|
gdunlap@0
|
324 vm_run(now, v);
|
gdunlap@0
|
325 }
|
gdunlap@0
|
326 else if ( v->runstate == RUNSTATE_BLOCKED
|
gdunlap@0
|
327 && new_runstate == RUNSTATE_RUNNABLE )
|
gdunlap@0
|
328 {
|
gdunlap@0
|
329 nstate = STATE_WAKE;
|
gdunlap@0
|
330 vm_wake(now, v);
|
gdunlap@0
|
331 }
|
gdunlap@0
|
332 else
|
gdunlap@0
|
333 goto unexpected_transition;
|
gdunlap@0
|
334
|
gdunlap@0
|
335 printf("%d: v%d %s %d -> %s\n",
|
gdunlap@0
|
336 now, v->vid, state_name[ostate], stime, state_name[nstate]);
|
gdunlap@0
|
337
|
gdunlap@0
|
338 v->runstate = new_runstate;
|
gdunlap@0
|
339 v->state_start_time = now;
|
gdunlap@0
|
340
|
gdunlap@0
|
341 return;
|
gdunlap@0
|
342
|
gdunlap@0
|
343 unexpected_transition:
|
gdunlap@0
|
344 fprintf(stderr, "Unexpected transition for vm %d: %d->%d\n",
|
gdunlap@0
|
345 v->vid,
|
gdunlap@0
|
346 v->runstate,
|
gdunlap@0
|
347 new_runstate);
|
gdunlap@0
|
348 exit(1);
|
gdunlap@0
|
349 }
|
gdunlap@0
|
350
|
gdunlap@0
|
351 /*
|
gdunlap@0
|
352 * Main loop
|
gdunlap@0
|
353 */
|
gdunlap@0
|
354 void simulate(void)
|
gdunlap@0
|
355 {
|
gdunlap@0
|
356 while ( sim.now < opt.time_limit )
|
gdunlap@0
|
357 {
|
gdunlap@0
|
358 /* Take next event off list */
|
gdunlap@0
|
359 struct event evt;
|
gdunlap@0
|
360
|
gdunlap@0
|
361 evt = sim_next_event();
|
gdunlap@0
|
362
|
gdunlap@0
|
363 sim.now = evt.time;
|
gdunlap@0
|
364
|
gdunlap@0
|
365 switch(evt.type)
|
gdunlap@0
|
366 {
|
gdunlap@0
|
367 case EVT_WAKE:
|
gdunlap@0
|
368 {
|
gdunlap@0
|
369 struct vm *v = vm_from_vid(evt.param);
|
gdunlap@0
|
370 ASSERT(v->processor == -1);
|
gdunlap@0
|
371 sim_runstate_change(sim.now, v, RUNSTATE_RUNNABLE);
|
gdunlap@2
|
372 sim.sched_ops->wake(sim.now, v->vid);
|
gdunlap@0
|
373 }
|
gdunlap@0
|
374 break;
|
gdunlap@0
|
375 case EVT_BLOCK:
|
gdunlap@0
|
376 {
|
gdunlap@0
|
377 struct vm *v = vm_from_vid(evt.param);
|
gdunlap@0
|
378
|
gdunlap@0
|
379 ASSERT(v->processor != -1);
|
gdunlap@0
|
380 ASSERT(v->processor <= P.count);
|
gdunlap@0
|
381
|
gdunlap@0
|
382 sim_runstate_change(sim.now, v, RUNSTATE_BLOCKED);
|
gdunlap@0
|
383
|
gdunlap@0
|
384 evt.param = v->processor; /* FIXME */
|
gdunlap@0
|
385 }
|
gdunlap@0
|
386 /* FALL-THRU */
|
gdunlap@0
|
387 case EVT_TIMER:
|
gdunlap@0
|
388 {
|
gdunlap@0
|
389 struct vm *prev, *next;
|
gdunlap@0
|
390 int pid = evt.param;
|
gdunlap@0
|
391
|
gdunlap@0
|
392 ASSERT(pid < P.count);
|
gdunlap@0
|
393
|
gdunlap@0
|
394 prev = P.pcpus[pid].current;
|
gdunlap@0
|
395
|
gdunlap@0
|
396 next = sim.sched_ops->schedule(sim.now, pid);
|
gdunlap@0
|
397
|
gdunlap@0
|
398 if ( prev && prev != next )
|
gdunlap@0
|
399 {
|
gdunlap@0
|
400 prev->processor = -1;
|
gdunlap@0
|
401 if( prev->runstate != RUNSTATE_BLOCKED )
|
gdunlap@0
|
402 sim_runstate_change(sim.now, prev, RUNSTATE_RUNNABLE);
|
gdunlap@0
|
403 }
|
gdunlap@0
|
404
|
gdunlap@1
|
405
|
gdunlap@0
|
406 P.pcpus[pid].current = next;
|
gdunlap@1
|
407 if ( next )
|
gdunlap@1
|
408 {
|
gdunlap@1
|
409 if ( next != prev )
|
gdunlap@1
|
410 {
|
gdunlap@1
|
411 sim_runstate_change(sim.now, next, RUNSTATE_RUNNING);
|
gdunlap@1
|
412 next->processor = pid;
|
gdunlap@1
|
413 }
|
gdunlap@1
|
414 }
|
gdunlap@3
|
415 else
|
gdunlap@1
|
416 {
|
gdunlap@3
|
417 if ( P.pcpus[pid].idle )
|
gdunlap@3
|
418 {
|
gdunlap@3
|
419 fprintf(stderr, "Strange, pid %d already idle!\n",
|
gdunlap@3
|
420 pid);
|
gdunlap@3
|
421 abort();
|
gdunlap@3
|
422 }
|
gdunlap@3
|
423
|
gdunlap@3
|
424 /* If the pcpu is going idle, clear all timers from it */
|
gdunlap@3
|
425 sim_remove_event(EVT_TIMER, pid);
|
gdunlap@3
|
426
|
gdunlap@1
|
427 P.pcpus[pid].idle = 1;
|
gdunlap@1
|
428 P.idle++;
|
gdunlap@1
|
429 }
|
gdunlap@0
|
430 }
|
gdunlap@0
|
431 break;
|
gdunlap@0
|
432 default:
|
gdunlap@0
|
433 fprintf(stderr, "Unexpected event type: %d\n", evt.type);
|
gdunlap@0
|
434 exit(1);
|
gdunlap@0
|
435 break;
|
gdunlap@0
|
436 }
|
gdunlap@0
|
437 }
|
gdunlap@0
|
438 }
|
gdunlap@0
|
439
|
gdunlap@0
|
440 void init(void)
|
gdunlap@0
|
441 {
|
gdunlap@0
|
442 int vid, i;
|
gdunlap@0
|
443 const struct workload *w;
|
gdunlap@0
|
444
|
gdunlap@0
|
445 /* Initialize simulation variables */
|
gdunlap@0
|
446 sim.now=0;
|
gdunlap@0
|
447 sim.timer=NULL;
|
gdunlap@0
|
448 INIT_LIST_HEAD(&sim.events);
|
gdunlap@0
|
449 sim.sched_ops = &opt.scheduler->ops;
|
gdunlap@0
|
450
|
gdunlap@0
|
451 /* Initialize pcpus */
|
gdunlap@0
|
452 P.count = opt.pcpu_count;
|
gdunlap@1
|
453 P.idle = 0;
|
gdunlap@0
|
454 for ( i=0; i<P.count; i++ )
|
gdunlap@0
|
455 {
|
gdunlap@0
|
456 P.pcpus[i].pid = i;
|
gdunlap@1
|
457 P.pcpus[i].idle = 1;
|
gdunlap@1
|
458 P.idle++;
|
gdunlap@0
|
459 P.pcpus[i].current = NULL;
|
gdunlap@0
|
460 }
|
gdunlap@0
|
461
|
gdunlap@0
|
462 /* Initialize scheduler */
|
gdunlap@0
|
463 sim.sched_ops->sched_init();
|
gdunlap@0
|
464
|
gdunlap@0
|
465 /* Initialize vms */
|
gdunlap@0
|
466 w=opt.workload;
|
gdunlap@1
|
467 V.count = 0;
|
gdunlap@0
|
468 for ( vid=0; vid<w->vm_count; vid++)
|
gdunlap@0
|
469 {
|
gdunlap@0
|
470 struct vm *v = V.vms+vid;
|
gdunlap@0
|
471
|
gdunlap@0
|
472 v->vid = vid;
|
gdunlap@0
|
473 v->runstate = RUNSTATE_BLOCKED;
|
gdunlap@0
|
474 v->processor = -1;
|
gdunlap@0
|
475 v->private = NULL;
|
gdunlap@0
|
476
|
gdunlap@0
|
477 v->state_start_time = 0;
|
gdunlap@0
|
478 v->time_this_phase = 0;
|
gdunlap@0
|
479
|
gdunlap@0
|
480
|
gdunlap@0
|
481 v->phase_index = -1;
|
gdunlap@0
|
482 v->e = NULL;
|
gdunlap@0
|
483 v->workload = w->vm_workloads+vid;
|
gdunlap@0
|
484
|
gdunlap@0
|
485 V.count++;
|
gdunlap@0
|
486
|
gdunlap@0
|
487 sim.sched_ops->vm_init(vid);
|
gdunlap@0
|
488 }
|
gdunlap@0
|
489
|
gdunlap@0
|
490 /* Set VM starting conditions */
|
gdunlap@0
|
491 for ( vid=0; vid<V.count; vid++)
|
gdunlap@0
|
492 {
|
gdunlap@0
|
493 struct vm *v = V.vms+vid;
|
gdunlap@0
|
494
|
gdunlap@0
|
495 switch(v->workload->list[0].type)
|
gdunlap@0
|
496 {
|
gdunlap@0
|
497 case PHASE_RUN:
|
gdunlap@0
|
498 v->phase_index = v->workload->phase_count - 1;
|
gdunlap@0
|
499 v->e = v->workload->list + v->phase_index;
|
gdunlap@0
|
500
|
gdunlap@0
|
501 sim_insert_event(sim.now, EVT_WAKE, v->vid, 0);
|
gdunlap@0
|
502 v->state_start_time = sim.now;
|
gdunlap@0
|
503 v->time_this_phase = 0;
|
gdunlap@0
|
504 break;
|
gdunlap@0
|
505 case PHASE_BLOCK:
|
gdunlap@0
|
506 v->phase_index = 0;
|
gdunlap@0
|
507 v->e = v->workload->list;
|
gdunlap@0
|
508
|
gdunlap@0
|
509 sim_insert_event(sim.now + v->e->time, EVT_WAKE, v->vid, 0);
|
gdunlap@0
|
510 v->state_start_time = sim.now;
|
gdunlap@0
|
511 v->time_this_phase = 0;
|
gdunlap@0
|
512 break;
|
gdunlap@0
|
513 }
|
gdunlap@0
|
514 }
|
gdunlap@0
|
515 }
|
gdunlap@0
|
516
|
gdunlap@0
|
517 void report(void)
|
gdunlap@0
|
518 {
|
gdunlap@0
|
519 int i, j;
|
gdunlap@0
|
520
|
gdunlap@0
|
521 for ( i=0; i<V.count; i++ )
|
gdunlap@0
|
522 {
|
gdunlap@0
|
523 struct vm *v = V.vms + i;
|
gdunlap@0
|
524
|
gdunlap@0
|
525 printf("VM %d\n", i);
|
gdunlap@0
|
526 for ( j = 0; j < STATE_MAX ; j++ )
|
gdunlap@0
|
527 {
|
gdunlap@0
|
528 char s[128];
|
gdunlap@0
|
529 snprintf(s, 128, " %s", state_name[j]);
|
gdunlap@0
|
530 print_cycle_summary(&v->stats.state[j], sim.now, s);
|
gdunlap@0
|
531 }
|
gdunlap@0
|
532 }
|
gdunlap@0
|
533 }
|
gdunlap@0
|
534
|
gdunlap@0
|
535 int main(int argc, char * argv[])
|
gdunlap@0
|
536 {
|
gdunlap@0
|
537 warn = stdout;
|
gdunlap@0
|
538
|
gdunlap@2
|
539 parse_options(argc, argv);
|
gdunlap@0
|
540
|
gdunlap@0
|
541 /* Setup simulation */
|
gdunlap@0
|
542 init();
|
gdunlap@0
|
543
|
gdunlap@0
|
544 /* Run simulation */
|
gdunlap@0
|
545 simulate();
|
gdunlap@0
|
546 /* Report statistics */
|
gdunlap@0
|
547 report();
|
gdunlap@0
|
548 }
|