03d7fdf3 |
1 | /* This file is part of the Linux Trace Toolkit viewer |
2 | * Copyright (C) 2003-2004 Michel Dagenais |
3 | * |
4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License Version 2 as |
6 | * published by the Free Software Foundation; |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License |
14 | * along with this program; if not, write to the Free Software |
15 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
16 | * MA 02111-1307, USA. |
17 | */ |
18 | |
19 | #ifdef HAVE_CONFIG_H |
20 | #include <config.h> |
21 | #endif |
22 | |
23 | #include <stdio.h> |
24 | #include <lttv/module.h> |
25 | #include <lttv/xenoltt_sim.h> |
26 | #include <lttv/stats.h> |
27 | #include <lttv/lttv.h> |
28 | #include <lttv/attribute.h> |
29 | #include <ltt/facility.h> |
30 | #include <ltt/trace.h> |
31 | #include <ltt/event.h> |
32 | #include <ltt/type.h> |
33 | |
34 | |
35 | /****************************************************************************************************************************/ |
36 | gboolean save_event(void *hook_data, void *call_data); |
37 | /****************************************************************************************************************************/ |
38 | |
39 | gboolean sim_every_event(void *hook_data, void *call_data) |
40 | { |
41 | LttvTracefileStats *tfcs = (LttvTracefileStats *)call_data; |
42 | |
43 | LttEvent *e = ltt_tracefile_get_event(tfcs->parent.parent.tf); |
44 | |
45 | LttvAttributeValue v; |
46 | |
47 | /* The current branch corresponds to the tracefile/process/interrupt state. |
48 | Statistics are added within it, to count the number of events of this |
49 | type occuring in this context. A quark has been pre-allocated for each |
50 | event type and is used as name. */ |
51 | |
52 | lttv_attribute_find(tfcs->current_event_types_tree, |
53 | ltt_eventtype_name(ltt_event_eventtype(e)), |
54 | LTTV_UINT, &v); |
55 | (*(v.v_uint))++; |
56 | return FALSE; |
57 | } |
58 | |
59 | // Hook wrapper. call_data is a traceset context. |
60 | gboolean lttv_xenoltt_sim_hook_add_event_hooks(void *hook_data, void *call_data) |
61 | { |
62 | LttvTracesetStats *tss = (LttvTracesetStats*)call_data; |
63 | |
64 | thread_event_list = g_array_new(FALSE, FALSE, sizeof(ThreadEventData*)); |
65 | running_thread = g_array_new(FALSE, FALSE, sizeof(RunningThread*)); |
66 | |
67 | lttv_xenoltt_sim_add_event_hooks(tss); |
68 | |
69 | return 0; |
70 | } |
71 | |
72 | void lttv_xenoltt_sim_add_event_hooks(LttvTracesetStats *self) |
73 | { |
74 | LttvTraceset *traceset = self->parent.parent.ts; |
75 | |
76 | guint i, j, k, l, nb_trace, nb_tracefile; |
77 | |
78 | LttvTraceStats *ts; |
79 | |
80 | LttvTracefileStats *tfs; |
81 | |
82 | GArray *hooks, *before_hooks; |
83 | |
84 | LttvTraceHook *hook; |
85 | |
86 | LttvTraceHookByFacility *thf; |
87 | |
88 | LttvAttributeValue val; |
89 | |
90 | gint ret; |
91 | gint hn; |
92 | |
93 | nb_trace = lttv_traceset_number(traceset); |
94 | for(i = 0 ; i < nb_trace ; i++) { |
95 | ts = (LttvTraceStats *)self->parent.parent.traces[i]; |
96 | |
97 | /* Find the eventtype id for the following events and register the |
98 | associated by id hooks. */ |
99 | |
100 | hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 16); |
101 | g_array_set_size(hooks, 16); |
102 | hn=0; |
103 | /* |
104 | LTT_EVENT_XENOLTT_THREAD_INIT, |
105 | LTT_EVENT_XENOLTT_THREAD_SET_PERIOD, |
106 | LTT_EVENT_XENOLTT_THREAD_WAIT_PERIOD, |
107 | LTT_EVENT_XENOLTT_THREAD_MISSED_PERIOD, |
108 | LTT_EVENT_XENOLTT_THREAD_SUSPEND, |
109 | LTT_EVENT_XENOLTT_THREAD_START, |
110 | LTT_EVENT_XENOLTT_THREAD_RESUME, |
111 | LTT_EVENT_XENOLTT_THREAD_DELETE, |
112 | LTT_EVENT_XENOLTT_THREAD_UNBLOCK, |
113 | LTT_EVENT_XENOLTT_THREAD_RENICE, |
114 | LTT_EVENT_XENOLTT_TIMER_TICK, |
115 | LTT_EVENT_XENOLTT_SYNCH_SET_OWNER, |
116 | LTT_EVENT_XENOLTT_SYNCH_UNLOCK, |
117 | LTT_EVENT_XENOLTT_SYNCH_WAKEUP1, |
118 | LTT_EVENT_XENOLTT_SYNCH_WAKEUPX, |
119 | LTT_EVENT_XENOLTT_SYNCH_SLEEP_ON, |
120 | LTT_EVENT_XENOLTT_SYNCH_FLUSH, |
121 | LTT_EVENT_XENOLTT_SYNCH_FORGET, |
122 | LTT_EVENT_XENOLTT_THREAD_SWITCH; |
123 | */ |
124 | |
125 | ret = lttv_trace_find_hook(ts->parent.parent.t, |
126 | LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_INIT, |
127 | LTT_FIELD_XENOLTT_ADDRESS, 0, 0, |
128 | save_event, NULL, |
129 | &g_array_index(hooks, LttvTraceHook, hn++)); |
130 | if(ret) hn--; |
131 | |
132 | ret = lttv_trace_find_hook(ts->parent.parent.t, |
133 | LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_SET_PERIOD, |
134 | LTT_FIELD_XENOLTT_ADDRESS, 0, 0, |
135 | save_event, NULL, |
136 | &g_array_index(hooks, LttvTraceHook, hn++)); |
137 | if(ret) hn--; |
138 | |
139 | ret = lttv_trace_find_hook(ts->parent.parent.t, |
140 | LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_WAIT_PERIOD, |
141 | LTT_FIELD_XENOLTT_ADDRESS, 0, 0, |
142 | save_event, NULL, |
143 | &g_array_index(hooks, LttvTraceHook, hn++)); |
144 | if(ret) hn--; |
145 | |
146 | ret = lttv_trace_find_hook(ts->parent.parent.t, |
147 | LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_MISSED_PERIOD, |
148 | LTT_FIELD_XENOLTT_ADDRESS, 0, 0, |
149 | save_event, NULL, |
150 | &g_array_index(hooks, LttvTraceHook, hn++)); |
151 | if(ret) hn--; |
152 | |
153 | ret = lttv_trace_find_hook(ts->parent.parent.t, |
154 | LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_SUSPEND, |
155 | LTT_FIELD_XENOLTT_ADDRESS, 0, 0, |
156 | save_event, NULL, |
157 | &g_array_index(hooks, LttvTraceHook, hn++)); |
158 | if(ret) hn--; |
159 | |
160 | ret = lttv_trace_find_hook(ts->parent.parent.t, |
161 | LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_START, |
162 | LTT_FIELD_XENOLTT_ADDRESS, 0, 0, |
163 | save_event, NULL, |
164 | &g_array_index(hooks, LttvTraceHook, hn++)); |
165 | if(ret) hn--; |
166 | |
167 | ret = lttv_trace_find_hook(ts->parent.parent.t, |
168 | LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_RESUME, |
169 | LTT_FIELD_XENOLTT_ADDRESS, 0, 0, |
170 | save_event, NULL, |
171 | &g_array_index(hooks, LttvTraceHook, hn++)); |
172 | if(ret) hn--; |
173 | |
174 | ret = lttv_trace_find_hook(ts->parent.parent.t, |
175 | LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_DELETE, |
176 | LTT_FIELD_XENOLTT_ADDRESS, 0, 0, |
177 | save_event, NULL, |
178 | &g_array_index(hooks, LttvTraceHook, hn++)); |
179 | if(ret) hn--; |
180 | |
181 | ret = lttv_trace_find_hook(ts->parent.parent.t, |
182 | LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_SWITCH, |
183 | LTT_FIELD_XENOLTT_ADDRESS, 0, 0, |
184 | save_event, NULL, |
185 | &g_array_index(hooks, LttvTraceHook, hn++)); |
186 | if(ret) hn--; |
187 | |
188 | ret = lttv_trace_find_hook(ts->parent.parent.t, |
189 | LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_SWITCH, |
190 | LTT_FIELD_XENOLTT_ADDRESS_OUT, 0, 0, |
191 | save_event, NULL, |
192 | &g_array_index(hooks, LttvTraceHook, hn++)); |
193 | if(ret) hn--; |
194 | |
195 | ret = lttv_trace_find_hook(ts->parent.parent.t, |
196 | LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_TIMER_TICK, |
197 | LTT_FIELD_XENOLTT_ADDRESS, 0, 0, |
198 | save_event, NULL, |
199 | &g_array_index(hooks, LttvTraceHook, hn++)); |
200 | if(ret) hn--; |
201 | |
202 | g_array_set_size(hooks, hn); |
203 | |
204 | before_hooks = hooks; |
205 | |
206 | /* Add these hooks to each event_by_id hooks list */ |
207 | |
208 | nb_tracefile = ts->parent.parent.tracefiles->len; |
209 | |
210 | for(j = 0 ; j < nb_tracefile ; j++) { |
211 | tfs = LTTV_TRACEFILE_STATS(g_array_index(ts->parent.parent.tracefiles, |
212 | LttvTracefileContext*, j)); |
213 | lttv_hooks_add(tfs->parent.parent.event, sim_every_event, NULL, |
214 | LTTV_PRIO_DEFAULT); |
215 | |
216 | for(k = 0 ; k < before_hooks->len ; k++) { |
217 | hook = &g_array_index(before_hooks, LttvTraceHook, k); |
218 | for(l = 0; l<hook->fac_list->len;l++) { |
219 | thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l); |
220 | lttv_hooks_add( |
221 | lttv_hooks_by_id_find(tfs->parent.parent.event_by_id, thf->id), |
222 | thf->h, |
223 | thf, |
224 | LTTV_PRIO_DEFAULT); |
225 | } |
226 | } |
227 | |
228 | } |
229 | lttv_attribute_find(self->parent.parent.a, LTTV_STATS_BEFORE_HOOKS, |
230 | LTTV_POINTER, &val); |
231 | *(val.v_pointer) = before_hooks; |
232 | } |
233 | } |
234 | |
235 | // Hook wrapper. call_data is a traceset context. |
236 | gboolean lttv_xenoltt_sim_hook_remove_event_hooks(void *hook_data, void *call_data) |
237 | { |
238 | LttvTracesetStats *tss = (LttvTracesetStats*)call_data; |
239 | |
240 | lttv_xenoltt_sim_remove_event_hooks(tss); |
241 | |
242 | return 0; |
243 | } |
244 | |
245 | void lttv_xenoltt_sim_remove_event_hooks(LttvTracesetStats *self) |
246 | { |
247 | LttvTraceset *traceset = self->parent.parent.ts; |
248 | |
249 | guint i, j, k, l, nb_trace, nb_tracefile; |
250 | |
251 | LttvTraceStats *ts; |
252 | |
253 | LttvTracefileStats *tfs; |
254 | |
255 | GArray *before_hooks; |
256 | |
257 | LttvTraceHook *hook; |
258 | |
259 | LttvTraceHookByFacility *thf; |
260 | |
261 | LttvAttributeValue val; |
262 | |
263 | nb_trace = lttv_traceset_number(traceset); |
264 | for(i = 0 ; i < nb_trace ; i++) { |
265 | ts = (LttvTraceStats*)self->parent.parent.traces[i]; |
266 | lttv_attribute_find(self->parent.parent.a, LTTV_STATS_BEFORE_HOOKS, |
267 | LTTV_POINTER, &val); |
268 | before_hooks = *(val.v_pointer); |
269 | |
270 | /* Remove these hooks from each event_by_id hooks list */ |
271 | |
272 | nb_tracefile = ts->parent.parent.tracefiles->len; |
273 | |
274 | for(j = 0 ; j < nb_tracefile ; j++) { |
275 | tfs = LTTV_TRACEFILE_STATS(g_array_index(ts->parent.parent.tracefiles, |
276 | LttvTracefileContext*, j)); |
277 | lttv_hooks_remove_data(tfs->parent.parent.event, sim_every_event, |
278 | NULL); |
279 | |
280 | for(k = 0 ; k < before_hooks->len ; k++) { |
281 | hook = &g_array_index(before_hooks, LttvTraceHook, k); |
282 | for(l = 0 ; l < hook->fac_list->len ; l++) { |
283 | thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l); |
284 | lttv_hooks_remove_data( |
285 | lttv_hooks_by_id_find(tfs->parent.parent.event_by_id, thf->id), |
286 | thf->h, |
287 | thf); |
288 | } |
289 | } |
290 | } |
291 | g_debug("lttv_stats_remove_event_hooks()"); |
292 | g_array_free(before_hooks, TRUE); |
293 | } |
294 | } |
295 | |
296 | |
297 | |
298 | /****************************************************************************************************************************/ |
299 | |
300 | |
301 | |
302 | /* |
303 | This function will look into the thread list to find the corresponding thread and returns it |
304 | This way we will be able to add a new event to this thread events list. |
305 | */ |
306 | ThreadEventData* lookup_or_create_thread(gulong address, guint prio, LttTime creation_time, GQuark name){ |
307 | printf("lookup_or_create\n"); |
308 | int i, index = 0; |
309 | ThreadEventData *temp_thread; |
310 | ThreadEventData *temp_thread_2 = g_new(ThreadEventData, 1); |
311 | temp_thread_2->address = address; |
312 | temp_thread_2->prio = prio; |
313 | temp_thread_2->creation_time = creation_time; |
314 | temp_thread_2->name = name; |
315 | temp_thread_2->event_list = g_array_new(FALSE, FALSE, sizeof(EventData*)); |
316 | |
317 | |
318 | for(i=0;i<thread_event_list->len;i++){ |
319 | temp_thread = g_array_index(thread_event_list, ThreadEventData*, i); |
320 | if (temp_thread->address == temp_thread_2->address && |
321 | ltt_time_compare(temp_thread->creation_time,temp_thread_2->creation_time) == 0) |
322 | return temp_thread; // Thread is found we return it |
323 | /* Otherwise we check for the priority, this will help us to defined the |
324 | index where to insert the thread. This way we don't to sort the thread list */ |
325 | else if(temp_thread_2->prio <= temp_thread->prio) index++; |
326 | } |
327 | |
328 | g_array_insert_val(thread_event_list,index,temp_thread_2); |
329 | |
330 | return temp_thread_2; // New inserted thread is returned |
331 | } |
332 | |
333 | void calculate_event_time(guint index, ThreadEventData *temp_thread){ |
334 | LttTime next_tick = ltt_time_zero, delay, preempt_begin, preempt_time, |
335 | last_write_event_time, last_read_event_time, original_event_time; |
336 | EventData *new_event, *event; |
337 | int i,j, overruns = 0; |
338 | gboolean wait_period_called = FALSE; |
339 | RunningThread *temp_running_thread; |
340 | GArray* new_event_list = g_array_new(FALSE, FALSE, sizeof(EventData*)); |
341 | gboolean first_thread_switch, running = FALSE; |
342 | LttTime new_period = { 0, temp_thread->period }; |
343 | |
344 | // We will iterate on all event of this thread |
345 | for(i=0;i<temp_thread->event_list->len;i++){ |
346 | // for the first event read |
347 | if (i == 0){ |
348 | new_event = g_array_index(temp_thread->event_list, EventData*, i); |
349 | last_write_event_time = new_event->event_time; |
350 | last_read_event_time = new_event->event_time; |
351 | original_event_time = new_event->event_time; |
352 | } |
353 | else{ |
354 | last_write_event_time = new_event->event_time; |
355 | last_read_event_time = original_event_time; |
356 | new_event = g_array_index(temp_thread->event_list, EventData*, i); |
357 | original_event_time = new_event->event_time; |
358 | } |
359 | |
360 | // Calculate the delay between to following events |
361 | delay = ltt_time_sub(original_event_time,last_read_event_time); |
362 | |
363 | // We need to save all events from the timer_tick until the wait_period event |
364 | // At the same time we can calculate the new time of the event |
365 | if (new_event->name == LTT_EVENT_XENOLTT_TIMER_TICK){ |
366 | printf("NEW PERIOD\n"); |
367 | // The first tick will be unchanged |
368 | if(ltt_time_compare(ltt_time_zero,next_tick) != 0){ |
369 | new_event->event_time = next_tick; |
370 | } |
371 | next_tick = ltt_time_add(new_event->event_time,new_period); |
372 | wait_period_called = FALSE; // We prepare for next period that should begin now |
373 | |
374 | g_array_append_val(new_event_list,new_event); // insert the new timer_tick |
375 | printf("\tTIMER_TICK - TIME: %lu.%lu - %lu.%lu\n", original_event_time.tv_sec,original_event_time.tv_nsec, |
376 | new_event->event_time.tv_sec,new_event->event_time.tv_nsec); |
377 | |
378 | first_thread_switch = TRUE; |
379 | preempt_time = ltt_time_zero; |
380 | preempt_begin = ltt_time_zero; |
381 | |
382 | /************************************************************************ |
383 | * Beginning of a new period |
384 | * We must check for thread_switching (preemption) |
385 | * new timer tick to create |
386 | * overrun to create |
387 | * event missed_period to create |
388 | ************************************************************************/ |
389 | |
390 | while(new_event->name != LTT_EVENT_XENOLTT_THREAD_WAIT_PERIOD){ // Until the end of the period |
391 | i++; |
392 | last_write_event_time = new_event->event_time; |
393 | last_read_event_time = original_event_time; |
394 | new_event = g_array_index(temp_thread->event_list, EventData*, i); |
395 | original_event_time = new_event->event_time; |
396 | |
397 | // Calculate the delay between to following events |
398 | delay = ltt_time_sub(original_event_time,last_read_event_time); |
399 | delay = ltt_time_sub(delay,preempt_time); |
400 | |
401 | // Need to test if we have exceeded the new period |
402 | if(new_event->name != LTT_EVENT_XENOLTT_TIMER_TICK){ |
403 | if (ltt_time_compare(ltt_time_add(last_write_event_time,delay),next_tick) > 0){ |
404 | EventData *tick_event = g_new(EventData, 1); |
405 | tick_event->event_time = next_tick; |
406 | tick_event->name = LTT_EVENT_XENOLTT_TIMER_TICK; |
407 | g_array_append_val(new_event_list,tick_event); |
408 | next_tick = ltt_time_add(tick_event->event_time,new_period); |
409 | printf("\t%s - TIME: \t%lu.%lu\n", g_quark_to_string(tick_event->name),tick_event->event_time.tv_sec,tick_event->event_time.tv_nsec); |
410 | overruns++; |
411 | } |
412 | } |
413 | |
414 | if(new_event->name == LTT_EVENT_XENOLTT_THREAD_INIT || |
415 | new_event->name == LTT_EVENT_XENOLTT_THREAD_SET_PERIOD || |
416 | new_event->name == LTT_EVENT_XENOLTT_THREAD_START || |
417 | new_event->name == LTT_EVENT_XENOLTT_THREAD_RESUME || |
418 | new_event->name == LTT_EVENT_XENOLTT_THREAD_RENICE || |
419 | new_event->name == LTT_EVENT_XENOLTT_THREAD_SUSPEND){ |
420 | new_event->event_time = ltt_time_add(last_write_event_time,delay); // New time of the event |
421 | // Insert event in the period list |
422 | g_array_append_val(new_event_list,new_event); |
423 | printf("\t%s - TIME: %lu.%lu - %lu.%lu\n", g_quark_to_string(new_event->name),original_event_time.tv_sec,original_event_time.tv_nsec, |
424 | new_event->event_time.tv_sec,new_event->event_time.tv_nsec); |
425 | } |
426 | // the first Thread_Switch indicate that the thread is now running |
427 | else if(new_event->name == LTT_EVENT_XENOLTT_THREAD_SWITCH){ |
428 | if (first_thread_switch){ |
429 | running = TRUE; |
430 | first_thread_switch = FALSE; |
431 | new_event->event_time = ltt_time_add(last_write_event_time,delay); // New time of the event |
432 | // Insert event in the period list |
433 | g_array_append_val(new_event_list,new_event); |
434 | printf("\t%s - TIME: %lu.%lu - %lu.%lu\n", g_quark_to_string(new_event->name),original_event_time.tv_sec,original_event_time.tv_nsec, |
435 | new_event->event_time.tv_sec,new_event->event_time.tv_nsec); |
436 | } |
437 | // Not the first thread switch, we will delete this event and the previous one that should be thread_suspend |
438 | else if(running){ |
439 | running = FALSE; // Stop the thread |
440 | new_event = g_array_index(temp_thread->event_list, EventData*, (i-1)); |
441 | preempt_begin = new_event->event_time;// Save the time of the preemption (time of the suspend event |
442 | } |
443 | // Thread is suspended and want to restart, delete the thread_switch and the following event that should be thread_resume |
444 | else{ |
445 | running = TRUE; // restart thread |
446 | i++; |
447 | new_event = g_array_index(temp_thread->event_list, EventData*, i); |
448 | preempt_time = ltt_time_add(preempt_time,ltt_time_sub(new_event->event_time,preempt_begin));// ignore the time spent in ready state |
449 | } |
450 | } |
451 | // Thread going in overrun |
452 | else if(new_event->name == LTT_EVENT_XENOLTT_TIMER_TICK){ |
453 | new_event->event_time = next_tick; |
454 | next_tick = ltt_time_add(new_event->event_time,new_period); |
455 | overruns++; // If wait_period has not been called, this means we are going in overrun |
456 | // Insert event in the period list |
457 | g_array_append_val(new_event_list,new_event); |
458 | printf("\t%s - TIME: %lu.%lu - %lu.%lu\n", g_quark_to_string(new_event->name),original_event_time.tv_sec,original_event_time.tv_nsec, |
459 | new_event->event_time.tv_sec,new_event->event_time.tv_nsec); |
460 | } |
461 | |
462 | if(new_event->name == LTT_EVENT_XENOLTT_THREAD_WAIT_PERIOD){ |
463 | new_event->event_time = ltt_time_add(last_write_event_time,delay); // New time of the event |
464 | g_array_append_val(new_event_list,new_event); |
465 | printf("\t%s - TIME: %lu.%lu - %lu.%lu\n", g_quark_to_string(new_event->name),original_event_time.tv_sec,original_event_time.tv_nsec, |
466 | new_event->event_time.tv_sec,new_event->event_time.tv_nsec); |
467 | printf("END PERIOD\n"); |
468 | wait_period_called = TRUE; |
469 | if(overruns > 0){ |
470 | EventData *missed_period_event = g_new(EventData, 1); |
471 | missed_period_event->event_time = new_event->event_time; // Same time ?? |
472 | missed_period_event->name = LTT_EVENT_XENOLTT_THREAD_MISSED_PERIOD; |
473 | g_array_append_val(new_event_list,missed_period_event); |
474 | printf("\t%s - TIME: %lu.%lu\n", g_quark_to_string(missed_period_event->name), |
475 | missed_period_event->event_time.tv_sec,missed_period_event->event_time.tv_nsec); |
476 | } |
477 | overruns = 0; |
478 | // Period is finished |
479 | running = FALSE; |
480 | } |
481 | |
482 | if(new_event->name == LTT_EVENT_XENOLTT_THREAD_DELETE){ |
483 | // Insert event in the period list |
484 | new_event->event_time = ltt_time_add(last_write_event_time,delay); // New time of the event |
485 | g_array_append_val(new_event_list,new_event); |
486 | printf("\t%s - TIME: %lu.%lu - %lu.%lu\n", g_quark_to_string(new_event->name),original_event_time.tv_sec,original_event_time.tv_nsec, |
487 | new_event->event_time.tv_sec,new_event->event_time.tv_nsec); |
488 | break; |
489 | } |
490 | } |
491 | } |
492 | // For other events, simply save them with new time |
493 | else{ |
494 | if (new_event->name != LTT_EVENT_XENOLTT_THREAD_MISSED_PERIOD){ |
495 | new_event->event_time = ltt_time_add(last_write_event_time,delay); // New time of the event |
496 | g_array_append_val(new_event_list,new_event); |
497 | printf("NO_PERIOD %s - TIME: %lu.%lu - %lu.%lu\n", g_quark_to_string(new_event->name),original_event_time.tv_sec,original_event_time.tv_nsec, |
498 | new_event->event_time.tv_sec,new_event->event_time.tv_nsec); |
499 | } |
500 | } |
501 | } |
502 | |
503 | // Now we have a full list of events representing the simulation of the current task |
504 | // Last step consist of checking if this thread will be preempted by others |
505 | // To see that, we will check in the running_thread list to find some free time space |
506 | |
507 | // Iterate on the event_list and check for every thread_switch |
508 | // We will iterate on all event of this thread |
509 | gboolean not_running = TRUE; |
510 | |
511 | for(i=0;i<new_event_list->len;i++){ |
512 | event = g_array_index(new_event_list, EventData*, i); |
513 | if (event->name == LTT_EVENT_XENOLTT_THREAD_SWITCH){ |
514 | if (not_running){ |
515 | not_running = FALSE; |
516 | for(j=0;j<running_thread->len;j++){ |
517 | temp_running_thread = g_array_index(running_thread, RunningThread*, j); |
518 | // First we need to get the thread running at the closest time before the current time |
519 | if (ltt_time_compare(temp_running_thread->begin_time,event->event_time) > 0){ |
520 | // If thread finishes after current time, we must delay the task |
521 | // We will check the previous thread in the running list |
522 | temp_running_thread = g_array_index(running_thread, RunningThread*, (j-1)); |
523 | if (ltt_time_compare(temp_running_thread->end_time,event->event_time) <= 0){ |
524 | event->event_time = temp_running_thread->end_time; |
525 | } |
526 | else{ // Time is good |
527 | break; |
528 | } |
529 | } |
530 | } |
531 | |
532 | |
533 | // At this time we should have found a free starting position |
534 | RunningThread *new_running = g_new(RunningThread,1); |
535 | new_running->thread = temp_thread; |
536 | new_running->begin_time = event->event_time; |
537 | |
538 | j--; |
539 | |
540 | delay = ltt_time_zero; |
541 | // Next step is to chek before all event, if we must preempt the thread because a higher priority task is already running |
542 | // Preemption will cause the creation of 2 events thread_switch |
543 | for(i++;i<new_event_list->len;i++){ |
544 | event = g_array_index(new_event_list, EventData*, i); |
545 | // Don't delay Timer_Tick |
546 | if (event->name == LTT_EVENT_XENOLTT_TIMER_TICK){ |
547 | if (wait_period_called) wait_period_called = FALSE; |
548 | } |
549 | // If event is a thread_switch, this means we have finish the period |
550 | else if (event->name == LTT_EVENT_XENOLTT_THREAD_SWITCH){ |
551 | event->event_time = ltt_time_add(event->event_time,delay); |
552 | new_running->end_time = event->event_time; |
553 | // Add the thread in the running thread list |
554 | // j is the index where we found a free time space |
555 | g_array_insert_val(running_thread,j,new_running); |
556 | not_running = TRUE; |
557 | break; |
558 | } |
559 | else{ |
560 | event->event_time = ltt_time_add(event->event_time,delay); |
561 | |
562 | // We must check the if the next running thread is beginning before the event_time |
563 | temp_running_thread = g_array_index(running_thread, RunningThread*, j); |
564 | |
565 | if(ltt_time_compare(event->event_time,temp_running_thread->begin_time) >= 0){ |
566 | // if so, we must preempt the task and delay all event of the period |
567 | delay = ltt_time_add(delay,ltt_time_sub(event->event_time,temp_running_thread->begin_time)); |
568 | |
569 | // Insert a thread switch out |
570 | new_event = g_new(EventData, 1); |
571 | new_event->event_time = temp_running_thread->begin_time; |
572 | new_event->name = LTT_EVENT_XENOLTT_THREAD_SWITCH; |
573 | g_array_insert_val(new_event_list,i,new_event); |
574 | |
575 | // Insert a thread switch in that will be check at next iteration |
576 | new_event = g_new(EventData, 1); |
577 | new_event->event_time = temp_running_thread->end_time; |
578 | new_event->name = LTT_EVENT_XENOLTT_THREAD_SWITCH; |
579 | g_array_insert_val(new_event_list,(i+1),new_event); |
580 | |
581 | // Insert the thread in the running thread |
582 | new_running->end_time = temp_running_thread->begin_time; |
583 | g_array_insert_val(running_thread,j,new_running); |
584 | not_running = TRUE; |
585 | |
586 | break; |
587 | } |
588 | } |
589 | } |
590 | } |
591 | } |
592 | } |
593 | |
594 | /* |
595 | //Print the new thread simulation |
596 | for(j=0;j<new_event_list->len;j++){ |
597 | event = g_array_index(new_event_list, EventData*, j); |
598 | printf("%s - TIME: %lu.%lu\n", g_quark_to_string(event->name),event->event_time.tv_sec,event->event_time.tv_nsec); |
599 | } |
600 | */ |
601 | } |
602 | |
603 | void simulater_high_priority_thread(ThreadEventData* thread){ |
604 | EventData *event; |
605 | gboolean running = FALSE; |
606 | RunningThread *run_thread = g_new(RunningThread, 1); |
607 | RunningThread *temp_thread; |
608 | int i,j; |
609 | LttTime begin_time = ltt_time_zero; |
610 | LttTime end_time = ltt_time_zero; |
611 | gboolean inserted; |
612 | |
613 | for(i=0;i<thread->event_list->len;i++){ |
614 | event = g_array_index(thread->event_list, EventData*, i); |
615 | |
616 | if(event->name == LTT_EVENT_XENOLTT_THREAD_SWITCH){ |
617 | if(running){ |
618 | running = FALSE; |
619 | end_time = event->event_time; |
620 | run_thread = g_new(RunningThread, 1); |
621 | run_thread->thread = thread; |
622 | run_thread->begin_time = begin_time; |
623 | run_thread->end_time = end_time; |
624 | |
625 | inserted = FALSE; |
626 | for(j=0;j<running_thread->len;j++){ |
627 | temp_thread = g_array_index(running_thread, RunningThread*, j); |
628 | if (ltt_time_compare(temp_thread->begin_time,run_thread->begin_time) > 0){ |
629 | g_array_insert_val(running_thread,j,run_thread); |
630 | inserted = TRUE; |
631 | break; |
632 | } |
633 | } |
634 | if (!inserted) g_array_append_val(running_thread,run_thread); |
635 | } |
636 | else{ |
637 | running = TRUE; |
638 | begin_time = event->event_time; |
639 | } |
640 | } |
641 | |
642 | |
643 | } |
644 | } |
645 | |
646 | gint sort_running_thread(gconstpointer a,gconstpointer b){ |
647 | const RunningThread *pa = (const RunningThread*)a; |
648 | const RunningThread *pb = (const RunningThread*)b; |
649 | |
650 | return ltt_time_compare(pa->begin_time,pb->begin_time); |
651 | } |
652 | |
653 | void compute_simulation(guint index,guint period){ |
654 | |
655 | int i; |
656 | ThreadEventData *temp_thread; |
657 | RunningThread *run_thread; |
658 | |
659 | printf("---\n"); |
660 | |
661 | printf("-> %u\n",thread_event_list->len); |
662 | // First, set the new period of the thread |
663 | temp_thread = g_array_index(thread_event_list, ThreadEventData*, index); |
664 | // We will double the simulation only if period has changed |
665 | if (period != temp_thread->period) temp_thread->period = period; |
666 | else{ |
667 | printf("Period is the same, no need to simulate\n"); |
668 | return; |
669 | } |
670 | |
671 | /* |
672 | First, we need to ignore all task with higher priority |
673 | than the task we want to simulate that's why we begin the simulation |
674 | from the thread index which we will modify the period |
675 | */ |
676 | printf("simulater_high_priority_thread\n"); |
677 | for(i=0;i<index;i++){ |
678 | temp_thread = g_array_index(thread_event_list, ThreadEventData*, i); |
679 | simulater_high_priority_thread(temp_thread); |
680 | } |
681 | |
682 | for(i=index;i<thread_event_list->len;i++){ |
683 | temp_thread = g_array_index(thread_event_list, ThreadEventData*, i); |
684 | printf("%s - %u\n",g_quark_to_string(temp_thread->name), temp_thread->prio); |
685 | |
686 | |
687 | // temp_thread->period = period; |
688 | temp_thread->period = 20000; |
689 | |
690 | |
691 | // We will simulate this thread considering all higher priority threads |
692 | printf("calculate_event_time\n"); |
693 | calculate_event_time(index, temp_thread); |
694 | } |
695 | |
696 | |
697 | printf("print run_thread\n"); |
698 | for(i=0;i<running_thread->len;i++){ |
699 | run_thread = g_array_index(running_thread, RunningThread*, i); |
700 | printf("%s\tFROM:%lu.%lu\tTO:%lu.%lu\n",g_quark_to_string(run_thread->thread->name),run_thread->begin_time.tv_sec,run_thread->begin_time.tv_nsec, |
701 | run_thread->end_time.tv_sec,run_thread->end_time.tv_nsec); |
702 | } |
703 | } |
704 | |
705 | gboolean save_event(void *hook_data, void *call_data){ |
706 | LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data; |
707 | LttvTracefileStats *tfcs = (LttvTracefileStats *)call_data; |
708 | LttvTraceState *ts = (LttvTraceState*)tfcs->parent.parent.t_context; |
709 | guint cpu = tfcs->parent.cpu; |
710 | LttvXenoThreadState *thread_info; |
711 | |
712 | LttvTracefileContext *tfc = (LttvTracefileContext *)call_data; |
713 | LttEvent *e = ltt_tracefile_get_event(tfc->tf); |
714 | GQuark event_name = ltt_eventtype_name(ltt_event_eventtype(e)); |
715 | LttTime evtime = ltt_event_time(e); |
716 | |
717 | if (event_name == LTT_EVENT_XENOLTT_TIMER_TICK){ |
718 | gulong timer_address = ltt_event_get_long_unsigned(e, thf->f1); |
719 | thread_info = lttv_xeno_state_find_thread_from_timer(ts,cpu,timer_address); |
720 | } |
721 | else{ |
722 | gulong address = ltt_event_get_long_unsigned(e, thf->f1); |
723 | // First we need to lookup for the current thread in the list |
724 | thread_info = lttv_xeno_state_find_thread(ts,cpu,address); |
725 | } |
726 | |
727 | if (thread_info != NULL){ |
728 | ThreadEventData *thread = lookup_or_create_thread(thread_info->address, thread_info->prio, thread_info->creation_time, thread_info->name); |
729 | // printf("%s - %lu.%lu\n",g_quark_to_string(event_name), evtime.tv_sec, evtime.tv_nsec); |
730 | if (event_name == LTT_EVENT_XENOLTT_THREAD_SET_PERIOD) thread->period = thread_info->period; |
731 | //Thread is found in the table, we can insert the new event in the list |
732 | EventData *new_event = g_new(EventData, 1); |
733 | new_event->event_time = evtime; |
734 | new_event->name = event_name; |
735 | new_event->event = e; |
736 | g_array_append_val(thread->event_list,new_event); |
737 | } |
738 | |
739 | return FALSE; |
740 | } |
741 | |
742 | /****************************************************************************************************************************/ |
743 | |
744 | |
745 | |
746 | |
747 | static void module_init() |
748 | { |
749 | } |
750 | |
751 | static void module_destroy() |
752 | { |
753 | } |
754 | |
755 | |
756 | LTTV_MODULE("xenoltt_sim", "Compute Xenomai Tasks simulation", \ |
757 | "Simulate a task execution with a different period", \ |
758 | module_init, module_destroy, "state"); |