1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
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;
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.
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,
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>
35 /****************************************************************************************************************************/
36 gboolean
save_event(void *hook_data
, void *call_data
);
37 /****************************************************************************************************************************/
39 gboolean
sim_every_event(void *hook_data
, void *call_data
)
41 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
43 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.parent
.tf
);
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. */
52 lttv_attribute_find(tfcs
->current_event_types_tree
,
53 ltt_eventtype_name(ltt_event_eventtype(e
)),
59 // Hook wrapper. call_data is a traceset context.
60 gboolean
lttv_xenoltt_sim_hook_add_event_hooks(void *hook_data
, void *call_data
)
62 LttvTracesetStats
*tss
= (LttvTracesetStats
*)call_data
;
64 lttv_xenoltt_sim_add_event_hooks(tss
);
69 void lttv_xenoltt_sim_add_event_hooks(LttvTracesetStats
*self
)
71 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
73 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
77 LttvTracefileStats
*tfs
;
79 GArray
*hooks
, *before_hooks
;
83 LttvTraceHookByFacility
*thf
;
85 LttvAttributeValue val
;
90 nb_trace
= lttv_traceset_number(traceset
);
91 for(i
= 0 ; i
< nb_trace
; i
++) {
92 ts
= (LttvTraceStats
*)self
->parent
.parent
.traces
[i
];
94 /* Find the eventtype id for the following events and register the
95 associated by id hooks. */
97 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 16);
98 g_array_set_size(hooks
, 16);
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;
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,
126 &g_array_index(hooks
, LttvTraceHook
, hn
++));
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,
133 &g_array_index(hooks
, LttvTraceHook
, hn
++));
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,
140 &g_array_index(hooks
, LttvTraceHook
, hn
++));
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,
147 &g_array_index(hooks
, LttvTraceHook
, hn
++));
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,
154 &g_array_index(hooks
, LttvTraceHook
, hn
++));
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,
161 &g_array_index(hooks
, LttvTraceHook
, hn
++));
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,
168 &g_array_index(hooks
, LttvTraceHook
, hn
++));
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,
175 &g_array_index(hooks
, LttvTraceHook
, hn
++));
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,
182 &g_array_index(hooks
, LttvTraceHook
, hn
++));
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,
189 &g_array_index(hooks
, LttvTraceHook
, hn
++));
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,
196 &g_array_index(hooks
, LttvTraceHook
, hn
++));
199 g_array_set_size(hooks
, hn
);
201 before_hooks
= hooks
;
203 /* Add these hooks to each event_by_id hooks list */
205 nb_tracefile
= ts
->parent
.parent
.tracefiles
->len
;
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
,
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
);
218 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, thf
->id
),
226 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_BEFORE_HOOKS
,
228 *(val
.v_pointer
) = before_hooks
;
232 // Hook wrapper. call_data is a traceset context.
233 gboolean
lttv_xenoltt_sim_hook_remove_event_hooks(void *hook_data
, void *call_data
)
235 LttvTracesetStats
*tss
= (LttvTracesetStats
*)call_data
;
237 lttv_xenoltt_sim_remove_event_hooks(tss
);
242 void lttv_xenoltt_sim_remove_event_hooks(LttvTracesetStats
*self
)
244 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
246 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
250 LttvTracefileStats
*tfs
;
252 GArray
*before_hooks
;
256 LttvTraceHookByFacility
*thf
;
258 LttvAttributeValue val
;
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
,
265 before_hooks
= *(val
.v_pointer
);
267 /* Remove these hooks from each event_by_id hooks list */
269 nb_tracefile
= ts
->parent
.parent
.tracefiles
->len
;
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
,
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
),
288 g_debug("lttv_stats_remove_event_hooks()");
289 g_array_free(before_hooks
, TRUE
);
295 /****************************************************************************************************************************/
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.
303 ThreadEventData
* lookup_or_create_thread(gulong address
, guint prio
, LttTime creation_time
, GQuark name
){
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
*));
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
++;
324 g_array_insert_val(thread_event_list
,index
,temp_thread_2
);
326 return temp_thread_2
; // New inserted thread is returned
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
);
339 temp_thread
->new_event_list
= g_array_new(FALSE
, FALSE
, sizeof(EventData
*));
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
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
;
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
;
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
);
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
;
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
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);
375 first_thread_switch
= TRUE
;
376 preempt_time
= ltt_time_zero
;
377 preempt_begin
= ltt_time_zero
;
379 /************************************************************************
380 * Beginning of a new period
381 * We must check for thread_switching (preemption)
382 * new timer tick to create
384 * event missed_period to create
385 ************************************************************************/
387 while(new_event
->name
!= LTT_EVENT_XENOLTT_THREAD_WAIT_PERIOD
){ // Until the end of the period
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
;
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
);
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);
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);
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
){
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);
434 // Not the first thread switch, we will delete this event and the previous one that should be thread_suspend
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
440 // Thread is suspended and want to restart, delete the thread_switch and the following event that should be thread_resume
442 running
= TRUE
; // restart thread
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
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);
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
;
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);
472 // Period is finished
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);
485 // For other events, simply save them with new time
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);
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
500 // Iterate on the event_list and check for every thread_switch
501 gboolean not_running
= TRUE
;
503 wait_period_called
= TRUE
;
505 delay
= ltt_time_zero
;
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
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
);
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
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);
538 for(i
++;i
<temp_thread
->new_event_list
->len
;i
++){
539 event
= g_array_index(temp_thread
->new_event_list
, EventData
*, i
);
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
;
547 delay
= ltt_time_zero
;
549 // We are going in overrun
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
);
562 // All other events may be preempt by another task including the thread_switch
564 // insert the delay due to previous preemption in this period
565 event
->event_time
= ltt_time_add(event
->event_time
,delay
);
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
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
));
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
);
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
);
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);
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);
619 void simulate_high_priority_thread(ThreadEventData
* thread
){
621 gboolean running
= FALSE
;
622 RunningThread
*run_thread
= g_new(RunningThread
, 1);
623 RunningThread
*temp_thread
;
625 LttTime begin_time
= ltt_time_zero
;
626 LttTime end_time
= ltt_time_zero
;
629 for(i
=0;i
<thread
->event_list
->len
;i
++){
630 event
= g_array_index(thread
->event_list
, EventData
*, i
);
632 if(event
->name
== LTT_EVENT_XENOLTT_THREAD_SWITCH
){
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
;
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
);
650 if (!inserted
) g_array_append_val(running_thread
,run_thread
);
654 begin_time
= event
->event_time
;
658 thread
->new_event_list
= thread
->event_list
;
661 GArray
* get_thread_list(){
662 return thread_event_list
;
665 void compute_simulation(guint index
, guint period
, FILE *a_file
){
668 ThreadEventData
*temp_thread
;
669 RunningThread
*run_thread
;
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
;
677 running_thread
= g_array_new(FALSE
, FALSE
, sizeof(RunningThread
*));
679 fprintf(a_file
,"<EVENTS_LIST>\n");
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
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
);
694 fprintf(a_file
,"\t</TASK>\n");
697 for(i
=index
;i
<thread_event_list
->len
;i
++){
698 temp_thread
= g_array_index(thread_event_list
, ThreadEventData
*, i
);
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
);
707 fprintf(a_file
,"\t</TASK>\n");
711 fprintf(a_file
,"</EVENTS_LIST>\n");
713 fprintf(a_file
,"<RUNNING_TASK>\n");
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
);
721 fprintf(a_file
,"</RUNNING_TASK>\n");
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
;
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
);
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
);
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
);
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
);
761 /****************************************************************************************************************************/
766 static void module_init()
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
*));
773 static void module_destroy()
778 LTTV_MODULE("xenoltt_sim", "Compute Xenomai Tasks simulation", \
779 "Simulate a task execution with a different period", \
780 module_init
, module_destroy
, "state");