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