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