convert from svn repository: remove tags directory
[lttv.git] / trunk / lttng-xenomai / LinuxTraceToolkitViewer-0.8.61-xenoltt / lttv / modules / gui / tutorial / tutorial.c
1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2005 Peter Ho
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 Each field of the interrupt viewer is summarized as follows:
20
21 - CPUID: processor ID
22
23 - IrqId: IRQ ID
24
25 - Frequency (Hz): the number of interrupts per second (Hz).
26 We compute the total number of interrupts. Then
27 we divide it by the time interval.
28
29 - Total Duration (nsec): the sum of each interrupt duration in nsec.
30 For a given Irq ID, we sum the duration of each interrupt
31 to give us the total duration
32
33
34 *******************************************************************/
35
36
37 #include <math.h>
38 #include <glib.h>
39 #include <gtk/gtk.h>
40 #include <gdk/gdk.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <ltt/ltt.h>
45 #include <ltt/event.h>
46 #include <ltt/type.h>
47 #include <ltt/trace.h>
48 #include <ltt/facility.h>
49 #include <lttv/module.h>
50 #include <lttv/hook.h>
51 #include <lttv/tracecontext.h>
52 #include <lttv/state.h>
53 #include <lttv/filter.h>
54 #include <lttvwindow/lttvwindow.h>
55 #include <lttvwindow/lttv_plugin_tab.h>
56 #include <ltt/time.h>
57
58 #include "hTutorialInsert.xpm"
59
60 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
61 #define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
62 #define NO_ITEMS 0
63
64 typedef struct
65 {
66 guint cpu_id;
67 guint id;
68 guint TotalNumberOfInterrupts;
69 LttTime total_duration;
70 }Irq;
71
72 typedef struct
73 {
74 guint id;
75 guint cpu_id;
76 LttTime event_time;
77 }irq_entry;
78
79 enum type_t
80 {
81 IRQ_ENTRY,
82 IRQ_EXIT
83 };
84
85 /** Array containing instanced objects. Used when module is unloaded */
86 static GSList *interrupt_data_list = NULL ;
87
88
89 #define TRACE_NUMBER 0
90
91 typedef struct _InterruptEventData
92 {
93
94 /* Graphical Widgets */
95 GtkWidget * ScrollWindow;
96 GtkListStore *ListStore;
97 GtkWidget *Hbox;
98 GtkWidget *TreeView;
99 GtkTreeSelection *SelectionTree;
100
101 Tab * tab; /* tab that contains this plug-in*/
102 LttvPluginTab * ptab;
103 LttvHooks * event_hooks;
104 LttvHooks * hooks_trace_after;
105 LttvHooks * hooks_trace_before;
106 TimeWindow time_window;
107 LttvHooksById * event_by_id_hooks;
108 GArray *IrqExit;
109 GArray *IrqEntry;
110 } InterruptEventData ;
111
112
113 /* Function prototypes */
114
115 static gboolean interrupt_update_time_window(void * hook_data, void * call_data);
116 static GtkWidget *interrupts(LttvPlugin *plugin);
117 static InterruptEventData *system_info(LttvPluginTab *ptab);
118 void interrupt_destructor(InterruptEventData *event_viewer_data);
119 static void request_event(InterruptEventData *event_data );
120 static guint64 get_interrupt_id(LttEvent *e);
121 static gboolean trace_header(void *hook_data, void *call_data);
122 static gboolean interrupt_display (void *hook_data, void *call_data);
123 static void calcul_duration(LttTime time_exit, guint cpu_id, InterruptEventData *event_data);
124 static void sum_interrupt_data(irq_entry *e, LttTime time_exit, GArray *interrupt_counters);
125 static gboolean irq_entry_callback(void *hook_data, void *call_data);
126 static gboolean irq_exit_callback(void *hook_data, void *call_data);
127 static void InterruptFree(InterruptEventData *event_viewer_data);
128 static int FrequencyInHZ(gint NumerofInterruptions, TimeWindow time_window);
129 /* Enumeration of the columns */
130 enum{
131 CPUID_COLUMN,
132 IRQ_ID_COLUMN,
133 FREQUENCY_COLUMN,
134 DURATION_COLUMN,
135 N_COLUMNS
136 };
137
138
139
140 /**
141 * init function
142 *
143 *
144 * This is the entry point of the viewer.
145 *
146 */
147 static void init()
148 {
149 g_info("interrupts: init()");
150
151 lttvwindow_register_constructor("tutorial",
152 "/",
153 "Insert Interrupts View",
154 hTutorialInsert_xpm,
155 "Insert Interrupts View",
156 interrupts);
157 }
158
159
160 /**
161 * Constructor hook
162 *
163 */
164 static GtkWidget *interrupts(LttvPlugin *plugin)
165 {
166 LttvPluginTab *ptab = LTTV_PLUGIN_TAB(plugin);
167 InterruptEventData* event_data = system_info(ptab) ;
168 if(event_data)
169 return event_data->Hbox;
170 else
171 return NULL;
172 }
173
174 /**
175 * This function initializes the Event Viewer functionnality through the
176 * GTK API.
177 */
178 InterruptEventData *system_info(LttvPluginTab *ptab)
179 {
180 LttTime end;
181 GtkTreeViewColumn *column;
182 GtkCellRenderer *renderer;
183 InterruptEventData* event_viewer_data = g_new(InterruptEventData,1) ;
184 Tab *tab = ptab->tab;
185
186 event_viewer_data->tab = tab;
187 event_viewer_data->ptab = ptab;
188
189 /*Get the current time frame from the main window */
190 event_viewer_data->time_window = lttvwindow_get_time_window(tab);
191 event_viewer_data->IrqExit = g_array_new(FALSE, FALSE, sizeof(Irq));
192 event_viewer_data->IrqEntry = g_array_new(FALSE, FALSE, sizeof(irq_entry));
193
194 /*Create tha main window for the viewer */
195 event_viewer_data->ScrollWindow = gtk_scrolled_window_new (NULL, NULL);
196 gtk_widget_show (event_viewer_data->ScrollWindow);
197 gtk_scrolled_window_set_policy(
198 GTK_SCROLLED_WINDOW(event_viewer_data->ScrollWindow),
199 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
200
201 /* Create a model for storing the data list */
202 event_viewer_data->ListStore = gtk_list_store_new (
203 N_COLUMNS, /* Total number of columns */
204 G_TYPE_INT, /* CPUID */
205 G_TYPE_INT, /* IRQ_ID */
206 G_TYPE_INT, /* Frequency */
207 G_TYPE_UINT64 /* Duration */
208 );
209
210 event_viewer_data->TreeView = gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data->ListStore));
211
212 g_object_unref (G_OBJECT (event_viewer_data->ListStore));
213
214 renderer = gtk_cell_renderer_text_new ();
215 column = gtk_tree_view_column_new_with_attributes ("CPU ID",
216 renderer,
217 "text", CPUID_COLUMN,
218 NULL);
219 gtk_tree_view_column_set_alignment (column, 0.0);
220 gtk_tree_view_column_set_fixed_width (column, 45);
221 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
222
223
224 renderer = gtk_cell_renderer_text_new ();
225 column = gtk_tree_view_column_new_with_attributes ("IRQ ID",
226 renderer,
227 "text", IRQ_ID_COLUMN,
228 NULL);
229 gtk_tree_view_column_set_alignment (column, 0.0);
230 gtk_tree_view_column_set_fixed_width (column, 220);
231 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
232
233 renderer = gtk_cell_renderer_text_new ();
234 column = gtk_tree_view_column_new_with_attributes ("Frequency (HZ)",
235 renderer,
236 "text", FREQUENCY_COLUMN,
237 NULL);
238 gtk_tree_view_column_set_alignment (column, 1.0);
239 gtk_tree_view_column_set_fixed_width (column, 220);
240 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
241
242 renderer = gtk_cell_renderer_text_new ();
243 column = gtk_tree_view_column_new_with_attributes ("Total Duration (nsec)",
244 renderer,
245 "text", DURATION_COLUMN,
246 NULL);
247 gtk_tree_view_column_set_alignment (column, 0.0);
248 gtk_tree_view_column_set_fixed_width (column, 145);
249 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
250
251 event_viewer_data->SelectionTree = gtk_tree_view_get_selection (GTK_TREE_VIEW (event_viewer_data->TreeView));
252 gtk_tree_selection_set_mode (event_viewer_data->SelectionTree, GTK_SELECTION_SINGLE);
253
254 gtk_container_add (GTK_CONTAINER (event_viewer_data->ScrollWindow), event_viewer_data->TreeView);
255
256 event_viewer_data->Hbox = gtk_hbox_new(0, 0);
257 gtk_box_pack_start(GTK_BOX(event_viewer_data->Hbox), event_viewer_data->ScrollWindow, TRUE, TRUE, 0);
258
259 gtk_widget_show(event_viewer_data->Hbox);
260 gtk_widget_show(event_viewer_data->TreeView);
261
262 interrupt_data_list = g_slist_append(interrupt_data_list, event_viewer_data);
263
264 /* Registration for time notification */
265 lttvwindow_register_time_window_notify(tab,
266 interrupt_update_time_window,
267 event_viewer_data);
268
269 g_object_set_data_full(G_OBJECT(event_viewer_data->Hbox),
270 "event_data",
271 event_viewer_data,
272 (GDestroyNotify) InterruptFree);
273
274
275 request_event(event_viewer_data );
276 return event_viewer_data;
277 }
278
279 /**
280 *
281 * For each trace in the traceset, this function:
282 * - registers a callback function to each hook
283 * - calls lttv_trace_find_hook() registers a hook function to event_by_id_hooks
284 * - calls lttvwindow_events_request() to request data in a specific
285 * time interval to the main window
286 *
287 */
288 static void request_event(InterruptEventData *event_data )
289 {
290 guint i, k, l, nb_trace;
291
292 LttvTraceHook *hook;
293
294 guint ret;
295
296 LttvTraceState *ts;
297
298 GArray *hooks;
299
300 EventsRequest *events_request;
301
302 LttvTraceHookByFacility *thf;
303
304 LttvTracesetContext *tsc = lttvwindow_get_traceset_context(event_data->tab);
305
306
307 /* Get the traceset */
308 LttvTraceset *traceset = tsc->ts;
309
310 nb_trace = lttv_traceset_number(traceset);
311
312 /* There are many traces in a traceset. Iteration for each trace. */
313 for(i = 0; i<MIN(TRACE_NUMBER+1, nb_trace);i++)
314 {
315 events_request = g_new(EventsRequest, 1);
316
317 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
318
319 hooks = g_array_set_size(hooks, 2);
320
321 event_data->hooks_trace_before = lttv_hooks_new();
322
323 /* Registers a hook function */
324 lttv_hooks_add(event_data->hooks_trace_before, trace_header, event_data, LTTV_PRIO_DEFAULT);
325
326 event_data->hooks_trace_after = lttv_hooks_new();
327 /* Registers a hook function */
328 lttv_hooks_add(event_data->hooks_trace_after, interrupt_display, event_data, LTTV_PRIO_DEFAULT);
329 /* Get a trace state */
330 ts = (LttvTraceState *)tsc->traces[i];
331 /* Create event_by_Id hooks */
332 event_data->event_by_id_hooks = lttv_hooks_by_id_new();
333
334 /*Register event_by_id_hooks with a callback function*/
335 ret = lttv_trace_find_hook(ts->parent.t,
336 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
337 LTT_FIELD_IRQ_ID, 0, 0,
338 irq_entry_callback,
339 events_request,
340 &g_array_index(hooks, LttvTraceHook, 0));
341
342 ret = lttv_trace_find_hook(ts->parent.t,
343 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
344 LTT_FIELD_IRQ_ID, 0, 0,
345 irq_exit_callback,
346 events_request,
347 &g_array_index(hooks, LttvTraceHook, 1));
348
349 g_assert(!ret);
350
351 /*iterate through the facility list*/
352 for(k = 0 ; k < hooks->len; k++)
353 {
354 hook = &g_array_index(hooks, LttvTraceHook, k);
355 for(l=0; l<hook->fac_list->len; l++)
356 {
357 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
358 lttv_hooks_add(lttv_hooks_by_id_find(event_data->event_by_id_hooks, thf->id),
359 thf->h,
360 event_data,
361 LTTV_PRIO_DEFAULT);
362
363 }
364 }
365
366 /* Initalize the EventsRequest structure */
367 events_request->owner = event_data;
368 events_request->viewer_data = event_data;
369 events_request->servicing = FALSE;
370 events_request->start_time = event_data->time_window.start_time;
371 events_request->start_position = NULL;
372 events_request->stop_flag = FALSE;
373 events_request->end_time = event_data->time_window.end_time;
374 events_request->num_events = G_MAXUINT;
375 events_request->end_position = NULL;
376 events_request->trace = i;
377
378 events_request->hooks = hooks;
379
380 events_request->before_chunk_traceset = NULL;
381 events_request->before_chunk_trace = event_data->hooks_trace_before;
382 events_request->before_chunk_tracefile= NULL;
383 events_request->event = NULL;
384 events_request->event_by_id = event_data->event_by_id_hooks;
385 events_request->after_chunk_tracefile = NULL;
386 events_request->after_chunk_trace = NULL;
387 events_request->after_chunk_traceset = NULL;
388 events_request->before_request = NULL;
389 events_request->after_request = event_data->hooks_trace_after;
390
391 lttvwindow_events_request(event_data->tab, events_request);
392 }
393
394 }
395
396 /**
397 * This function is called whenever an irq_entry event occurs.
398 *
399 */
400 static gboolean irq_entry_callback(void *hook_data, void *call_data)
401 {
402
403 LttTime event_time;
404 unsigned cpu_id;
405 irq_entry entry;
406 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
407 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
408 InterruptEventData *event_data = (InterruptEventData *)hook_data;
409 GArray* IrqEntry = event_data->IrqEntry;
410 LttEvent *e = ltt_tracefile_get_event(tfc->tf);
411 event_time = ltt_event_time(e);
412 cpu_id = ltt_event_cpu_id(e);
413
414 if ((ltt_time_compare(event_time,event_data->time_window.start_time) == TRUE) &&
415 (ltt_time_compare(event_data->time_window.end_time,event_time) == TRUE))
416 {
417 entry.id =get_interrupt_id(e);
418 entry.cpu_id = cpu_id;
419 entry.event_time = event_time;
420 g_array_append_val (IrqEntry, entry);
421 }
422 return FALSE;
423 }
424
425 /**
426 * This function gets the id of the interrupt. The id is stored in a dynamic structure.
427 * Refer to the print.c file for howto extract data from a dynamic structure.
428 */
429 static guint64 get_interrupt_id(LttEvent *e)
430 {
431 guint i, num_fields;
432 LttEventType *event_type;
433 LttField *element;
434 LttField *field;
435 guint64 irq_id;
436 event_type = ltt_event_eventtype(e);
437 num_fields = ltt_eventtype_num_fields(event_type);
438 for(i = 0 ; i < num_fields-1 ; i++)
439 {
440 field = ltt_eventtype_field(event_type, i);
441 irq_id = ltt_event_get_long_unsigned(e,field);
442 }
443 return irq_id;
444
445 }
446 /**
447 * This function is called whenever an irq_exit event occurs.
448 *
449 */
450 gboolean irq_exit_callback(void *hook_data, void *call_data)
451 {
452 LttTime event_time;
453 unsigned cpu_id;
454 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
455 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
456 InterruptEventData *event_data = (InterruptEventData *)hook_data;
457 LttEvent *e = ltt_tracefile_get_event(tfc->tf);
458 LttEventType *type = ltt_event_eventtype(e);
459 event_time = ltt_event_time(e);
460 cpu_id = ltt_event_cpu_id(e);
461 if ((ltt_time_compare(event_time,event_data->time_window.start_time) == TRUE) &&
462 (ltt_time_compare(event_data->time_window.end_time,event_time) == TRUE))
463 {
464 calcul_duration( event_time, cpu_id, event_data);
465
466 }
467 return FALSE;
468 }
469
470 /**
471 * This function calculates the duration of an interrupt.
472 *
473 */
474 static void calcul_duration(LttTime time_exit, guint cpu_id,InterruptEventData *event_data){
475
476 gint i, irq_id;
477 irq_entry *element;
478 LttTime duration;
479 GArray *IrqExit = event_data->IrqExit;
480 GArray *IrqEntry = event_data->IrqEntry;
481 for(i = 0; i < IrqEntry->len; i++){
482 element = &g_array_index(IrqEntry,irq_entry,i);
483 if(element->cpu_id == cpu_id)
484 {
485 sum_interrupt_data(element,time_exit, IrqExit);
486 g_array_remove_index(IrqEntry, i);
487 break;
488 }
489 }
490 }
491 /**
492 * This function calculates the total duration of an interrupt.
493 *
494 */
495 static void sum_interrupt_data(irq_entry *e, LttTime time_exit, GArray *IrqExit)
496 {
497 Irq irq;
498 Irq *element;
499 guint i;
500 LttTime duration;
501 gboolean notFound = FALSE;
502 memset ((void*)&irq, 0,sizeof(Irq));
503
504
505 if(IrqExit->len == NO_ITEMS)
506 {
507 irq.cpu_id = e->cpu_id;
508 irq.id = e->id;
509 irq.TotalNumberOfInterrupts++;
510 irq.total_duration = ltt_time_sub(time_exit, e->event_time);
511 g_array_append_val (IrqExit, irq);
512 }
513 else{
514 for(i = 0; i < IrqExit->len; i++)
515 {
516 element = &g_array_index(IrqExit, Irq, i);
517 if(element->id == e->id){
518 notFound = TRUE;
519 duration = ltt_time_sub(time_exit, e->event_time);
520 element->total_duration = ltt_time_add(element->total_duration, duration);
521 element->TotalNumberOfInterrupts++;
522 }
523 }
524
525 if(!notFound)
526 {
527 irq.cpu_id = e->cpu_id;
528 irq.id = e->id;
529 irq.TotalNumberOfInterrupts++;
530 irq.total_duration = ltt_time_sub(time_exit, e->event_time);
531 g_array_append_val (IrqExit, irq);
532 }
533 }
534 }
535
536 /**
537 * This function displays the result on the viewer
538 *
539 */
540 static gboolean interrupt_display(void *hook_data, void *call_data)
541 {
542
543 gint i;
544 Irq element;
545 LttTime average_duration;
546 GtkTreeIter iter;
547 guint64 real_data;
548 int FrequencyHZ = 0;
549
550 InterruptEventData *event_data = (InterruptEventData *)hook_data;
551 GArray *IrqExit = event_data->IrqExit;
552 gtk_list_store_clear(event_data->ListStore);
553 for(i = 0; i < IrqExit->len; i++)
554 {
555
556 element = g_array_index(IrqExit,Irq,i);
557 real_data = element.total_duration.tv_sec;
558 real_data *= NANOSECONDS_PER_SECOND;
559 real_data += element.total_duration.tv_nsec;
560
561 FrequencyHZ = FrequencyInHZ(element.TotalNumberOfInterrupts,event_data->time_window);
562
563 gtk_list_store_append (event_data->ListStore, &iter);
564
565 gtk_list_store_set (event_data->ListStore, &iter,
566 CPUID_COLUMN, element.cpu_id,
567 IRQ_ID_COLUMN, element.id,
568 FREQUENCY_COLUMN, FrequencyHZ,
569 DURATION_COLUMN, real_data,
570 -1);
571
572 }
573
574 if(event_data->IrqExit->len)
575 g_array_remove_range (event_data->IrqExit,0,event_data->IrqExit->len);
576
577 if(event_data->IrqEntry->len)
578 g_array_remove_range (event_data->IrqEntry,0,event_data->IrqEntry->len);
579 return FALSE;
580 }
581
582 /**
583 * This function converts the number of interrupts over a time window to
584 * frequency in HZ
585 */
586 static int FrequencyInHZ(gint NumerofInterruptions, TimeWindow time_window)
587 {
588 guint64 frequencyHz = 0;
589 double timeSec; // time in second
590 double result;
591 result = ltt_time_to_double(time_window.time_width);
592 timeSec = (result/NANOSECONDS_PER_SECOND); //time in second
593 frequencyHz = NumerofInterruptions / timeSec;
594 return frequencyHz;
595 }
596
597
598 /*
599 * This function is called by the main window
600 * when the time interval needs to be updated.
601 **/
602 gboolean interrupt_update_time_window(void * hook_data, void * call_data)
603 {
604 InterruptEventData *event_data = (InterruptEventData *) hook_data;
605 const TimeWindowNotifyData *time_window_nofify_data = ((const TimeWindowNotifyData *)call_data);
606 event_data->time_window = *time_window_nofify_data->new_time_window;
607 g_info("interrupts: interrupt_update_time_window()\n");
608 Tab *tab = event_data->tab;
609 lttvwindow_events_request_remove_all(tab, event_data);
610 request_event(event_data );
611 return FALSE;
612 }
613
614
615 gboolean trace_header(void *hook_data, void *call_data)
616 {
617
618 InterruptEventData *event_data = (InterruptEventData *)hook_data;
619 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
620 LttEvent *e;
621 LttTime event_time;
622 return FALSE;
623 }
624
625 void interrupt_destroy_walk(gpointer data, gpointer user_data)
626 {
627 g_info("interrupt_destroy_walk");
628 interrupt_destructor((InterruptEventData*)data);
629
630 }
631
632 void interrupt_destructor(InterruptEventData *event_viewer_data)
633 {
634 /* May already been done by GTK window closing */
635 g_info("enter interrupt_destructor \n");
636 if(GTK_IS_WIDGET(event_viewer_data->Hbox))
637 {
638 gtk_widget_destroy(event_viewer_data->Hbox);
639 }
640 }
641
642 /**
643 This function is called when the viewer is destroyed to free hooks and memory
644 */
645 static void InterruptFree(InterruptEventData *event_viewer_data)
646 {
647 Tab *tab = event_viewer_data->tab;
648 if(tab != NULL)
649 {
650 g_array_free(event_viewer_data->IrqExit, TRUE);
651
652 g_array_free(event_viewer_data->IrqEntry, TRUE);
653
654 lttvwindow_unregister_time_window_notify(tab, interrupt_update_time_window, event_viewer_data);
655
656 lttvwindow_events_request_remove_all(event_viewer_data->tab,
657 event_viewer_data);
658
659 interrupt_data_list = g_slist_remove(interrupt_data_list, event_viewer_data);
660
661 }
662
663 }
664
665 /**
666 * plugin's destroy function
667 *
668 * This function releases the memory reserved by the module and unregisters
669 * everything that has been registered in the gtkTraceSet API.
670 */
671 static void destroy() {
672 g_info("Destroy interrupts");
673 g_slist_foreach(interrupt_data_list, interrupt_destroy_walk, NULL );
674 g_slist_free(interrupt_data_list);
675 lttvwindow_unregister_constructor(interrupts);
676
677 }
678
679 LTTV_MODULE("tutorial", "interrupts info view", \
680 "Graphical module to display interrupts performance", \
681 init, destroy, "lttvwindow")
This page took 0.04393 seconds and 4 git commands to generate.