X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=ltt%2Fbranches%2Fpoly%2Flttv%2Fmodules%2Fgui%2Finterrupts%2Finterrupts.c;h=2818875f650edc6553354be2bb7ef0db7994c6a9;hb=d9ba814de610e2d38a49e8daf71b185242102c00;hp=f9b199e81b05fc9d6f2b9456f78a9326214b7953;hpb=b3e7b1253402ebc65d65e7753f29d406347c83a2;p=lttv.git diff --git a/ltt/branches/poly/lttv/modules/gui/interrupts/interrupts.c b/ltt/branches/poly/lttv/modules/gui/interrupts/interrupts.c index f9b199e8..2818875f 100644 --- a/ltt/branches/poly/lttv/modules/gui/interrupts/interrupts.c +++ b/ltt/branches/poly/lttv/modules/gui/interrupts/interrupts.c @@ -15,6 +15,51 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. */ + + /****************************************************************** + +Each field of the interrupt viewer is summarized as follows: + +- CPUID: processor ID + +- IrqId: IRQ ID + +- Frequency (Hz): the number of interrupts per second (Hz). + We compute the total number of interrupts. Then + we divide it by the time interval. + +- Total Duration (nsec): the sum of each interrupt duration in nsec. + For a given Irq ID, we sum the duration of each interrupt + to give us the total duration + +- Duration Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2)) where + N: number of interrupts + xi: duration of an interrupt (nsec) + Xa: average duration (nsec) + The formula is taken from wikipedia: http://en.wikipedia.org/wiki/Standard_deviation. + To calculate the duration standard deviation, we make two EventsRequest passes to the main window. + In the first EventsRequest pass, we calculate the total number of interrupts to compute for + the average Xa. In the second EventsRequest pass, calculate the standard deviation. + + +- Max IRQ handler duration (nsec) [time interval]: the longest IRQ handler duration in nsec. + +- Min IRQ handler duration (nsec) [time interval]: the shortest IRQ handler duration in nsec. + +- Average period (nsec): 1/Frequency(in HZ). The frequency is computed above. + +-Period Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2)) where +N: number of interrupts +xi: duration of an interrupt +Xa: Period = 1/Frequency (in Hz) + +-Frequency Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2)) +N: number of interrupts +xi: duration of an interrupt +Xa: Frequency (Hz) + + +*******************************************************************/ @@ -24,6 +69,7 @@ #include #include #include +#include #include #include #include @@ -44,11 +90,21 @@ #define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format) #define NO_ITEMS 0 +typedef struct +{ + LttTime duration; + LttTime start_time; + LttTime end_time; +}IrqDuration; + typedef struct { guint cpu_id; guint id; - guint frequency; + guint TotalNumberOfInterrupts; LttTime total_duration; + guint average_duration; + IrqDuration max_irq_handler; + IrqDuration min_irq_handler; }Irq; typedef struct { @@ -57,6 +113,17 @@ typedef struct { LttTime event_time; }irq_entry; + +typedef struct +{ + guint irqId; + guint TotalNumberOfInterrupts;//frequency;// + guint64 sumOfDurations; // to store the Sum ((xi -Xa)^2) of the duration Standard deviation + guint64 sumOfPeriods; // to store the Sum ((xi -Xa)^2) of the period Standard deviation + guint64 sumOfFrequencies;// to store the Sum ((xi -Xa)^2) of the frequency Standard deviation + +}SumId; + enum type_t { IRQ_ENTRY, IRQ_EXIT @@ -66,6 +133,8 @@ enum type_t { static GSList *interrupt_data_list = NULL ; +#define TRACE_NUMBER 0 + typedef struct _InterruptEventData { /*Graphical Widgets */ @@ -80,45 +149,86 @@ typedef struct _InterruptEventData { LttvHooks * hooks_trace_after; LttvHooks * hooks_trace_before; TimeWindow time_window; + LttvHooksById * event_by_id_hooks; + GArray *FirstRequestIrqExit; + GArray *FirstRequestIrqEntry; + GArray *SecondRequestIrqEntry; + GArray *SecondRequestIrqExit; + GArray *SumArray; - GArray *interrupt_counters; - GArray *active_irq_entry ; } InterruptEventData ; + /* Function prototypes */ static gboolean interrupt_update_time_window(void * hook_data, void * call_data); -GtkWidget *interrupts(Tab *tab); -// Plug-in's constructor -InterruptEventData *system_info(Tab *tab); -// Plug-in's destructor +static GtkWidget *interrupts(Tab *tab); +static InterruptEventData *system_info(Tab *tab); void interrupt_destructor(InterruptEventData *event_viewer_data); - -static void request_event( InterruptEventData *event_data); -static guint64 get_event_detail(LttEvent *e, LttField *f); +static void FirstRequest(InterruptEventData *event_data ); +static guint64 get_interrupt_id(LttEvent *e); static gboolean trace_header(void *hook_data, void *call_data); -static gboolean parse_event(void *hook_data, void *call_data); -static gboolean interrupt_show(void *hook_data, void *call_data); -static void calcul_duration(LttTime time_exit, guint cpu_id, InterruptEventData *event_data); -static void sum_interrupt_data(irq_entry *e, LttTime time_exit, GArray *interrupt_counters); +static gboolean DisplayViewer (void *hook_data, void *call_data); +static void CalculateData(LttTime time_exit, guint cpu_id, InterruptEventData *event_data); +static void CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(irq_entry *e, LttTime time_exit, GArray *FirstRequestIrqExit); +static gboolean FirstRequestIrqEntryCallback(void *hook_data, void *call_data); +static gboolean FirstRequestIrqExitCallback(void *hook_data, void *call_data); +static gboolean SecondRequest(void *hook_data, void *call_data); +static void CalculateAverageDurationForEachIrqId(InterruptEventData *event_data); +static gboolean SecondRequestIrqEntryCallback(void *hook_data, void *call_data); +static gboolean SecondRequestIrqExitCallback(void *hook_data, void *call_data); +static void CalculateXi(LttEvent *event, InterruptEventData *event_data); +static void SumItems(gint irq_id, LttTime Xi, InterruptEventData *event_data); +static int CalculateDurationStandardDeviation(gint id, InterruptEventData *event_data); +static int CalculatePeriodStandardDeviation(gint id, InterruptEventData *event_data); +static int FrequencyInHZ(gint NumberOfInterruptions, TimeWindow time_window); +static guint64 CalculatePeriodInnerPart(guint Xi, guint FrequencyHZ); +static guint64 CalculateFrequencyInnerPart(guint Xi_in_ns, guint FrequencyHZ); +static void InterruptFree(InterruptEventData *event_viewer_data); +static int CalculateFrequencyStandardDeviation(gint id, InterruptEventData *event_data); + /* Enumeration of the columns */ enum{ CPUID_COLUMN, IRQ_ID_COLUMN, FREQUENCY_COLUMN, DURATION_COLUMN, + DURATION_STANDARD_DEV_COLUMN, + MAX_IRQ_HANDLER_COLUMN, + MIN_IRQ_HANDLER_COLUMN, + AVERAGE_PERIOD, + PERIOD_STANDARD_DEV_COLUMN, + FREQUENCY_STANDARD_DEV_COLUMN, N_COLUMNS }; + + + +/** + * init function + * + * + * This is the entry point of the viewer. + * + */ +static void init() { + g_info("interrupts: init()"); + lttvwindow_register_constructor("interrupts", + "/", + "Insert Interrupts View", + hInterruptsInsert_xpm, + "Insert Interrupts View", + interrupts); + +} + /** - * constructor hook + * Constructor hook * - * This constructor is given as a parameter to the menuitem and toolbar button - * registration. It creates the list. - * @param parent_window A pointer to the parent window. - * @return The widget created. */ -GtkWidget *interrupts(Tab * tab){ +static GtkWidget *interrupts(Tab * tab) +{ InterruptEventData* event_data = system_info(tab) ; if(event_data) @@ -127,19 +237,33 @@ GtkWidget *interrupts(Tab * tab){ return NULL; } +/** + * This function initializes the Event Viewer functionnality through the + * GTK API. + */ InterruptEventData *system_info(Tab *tab) { + LttTime end; GtkTreeViewColumn *column; GtkCellRenderer *renderer; InterruptEventData* event_viewer_data = g_new(InterruptEventData,1) ; - g_info("system_info \n"); - + event_viewer_data->tab = tab; + + /*Get the current time frame from the main window */ event_viewer_data->time_window = lttvwindow_get_time_window(tab); - event_viewer_data->interrupt_counters = g_array_new(FALSE, FALSE, sizeof(Irq)); - event_viewer_data->active_irq_entry = g_array_new(FALSE, FALSE, sizeof(irq_entry)); - + + event_viewer_data->FirstRequestIrqExit = g_array_new(FALSE, FALSE, sizeof(Irq)); + event_viewer_data->FirstRequestIrqEntry = g_array_new(FALSE, FALSE, sizeof(irq_entry)); + + event_viewer_data->SecondRequestIrqEntry = g_array_new(FALSE, FALSE, sizeof(irq_entry)); + event_viewer_data->SecondRequestIrqExit = g_array_new(FALSE, FALSE, sizeof(Irq)); + + event_viewer_data->SumArray = g_array_new(FALSE, FALSE, sizeof(SumId)); + + + /*Create tha main window for the viewer */ event_viewer_data->ScrollWindow = gtk_scrolled_window_new (NULL, NULL); gtk_widget_show (event_viewer_data->ScrollWindow); gtk_scrolled_window_set_policy( @@ -152,7 +276,14 @@ InterruptEventData *system_info(Tab *tab) G_TYPE_INT, /* CPUID */ G_TYPE_INT, /* IRQ_ID */ G_TYPE_INT, /* Frequency */ - G_TYPE_UINT64 /* Duration */ + G_TYPE_UINT64, /* Duration */ + G_TYPE_INT, /* standard deviation */ + G_TYPE_STRING, /* Max IRQ handler */ + G_TYPE_STRING, /* Min IRQ handler */ + G_TYPE_INT, /* Average period */ + G_TYPE_INT, /* period standard deviation */ + G_TYPE_INT /* frequency standard deviation */ + ); event_viewer_data->TreeView = gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data->ListStore)); @@ -160,7 +291,7 @@ InterruptEventData *system_info(Tab *tab) g_object_unref (G_OBJECT (event_viewer_data->ListStore)); renderer = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes ("CPUID", + column = gtk_tree_view_column_new_with_attributes ("CPU ID", renderer, "text", CPUID_COLUMN, NULL); @@ -170,7 +301,7 @@ InterruptEventData *system_info(Tab *tab) renderer = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes ("IrqId", + column = gtk_tree_view_column_new_with_attributes ("IRQ ID", renderer, "text", IRQ_ID_COLUMN, NULL); @@ -179,7 +310,7 @@ InterruptEventData *system_info(Tab *tab) gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); renderer = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes ("Frequency", + column = gtk_tree_view_column_new_with_attributes ("Frequency (Hz)", renderer, "text", FREQUENCY_COLUMN, NULL); @@ -188,7 +319,7 @@ InterruptEventData *system_info(Tab *tab) gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); renderer = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes ("Duration (nsec)", + column = gtk_tree_view_column_new_with_attributes ("Total Duration (nsec)", renderer, "text", DURATION_COLUMN, NULL); @@ -196,6 +327,62 @@ InterruptEventData *system_info(Tab *tab) gtk_tree_view_column_set_fixed_width (column, 145); gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Duration standard deviation (nsec)", + renderer, + "text", DURATION_STANDARD_DEV_COLUMN, + NULL); + gtk_tree_view_column_set_alignment (column, 0.0); + gtk_tree_view_column_set_fixed_width (column, 200); + gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Max IRQ handler duration (nsec) [time interval]", + renderer, + "text", MAX_IRQ_HANDLER_COLUMN, + NULL); + gtk_tree_view_column_set_alignment (column, 0.0); + gtk_tree_view_column_set_fixed_width (column, 250); + gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Min IRQ handler duration (nsec) [time interval]", + renderer, + "text", MIN_IRQ_HANDLER_COLUMN, + NULL); + gtk_tree_view_column_set_alignment (column, 0.0); + gtk_tree_view_column_set_fixed_width (column, 250); + gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (" Average period (nsec)", + renderer, + "text", AVERAGE_PERIOD, + NULL); + gtk_tree_view_column_set_alignment (column, 0.0); + gtk_tree_view_column_set_fixed_width (column, 200); + gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Period standard deviation (nsec)", + renderer, + "text", PERIOD_STANDARD_DEV_COLUMN, + NULL); + gtk_tree_view_column_set_alignment (column, 0.0); + gtk_tree_view_column_set_fixed_width (column, 200); + gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Frequency standard deviation (Hz)", + renderer, + "text", FREQUENCY_STANDARD_DEV_COLUMN, + NULL); + gtk_tree_view_column_set_alignment (column, 0.0); + gtk_tree_view_column_set_fixed_width (column, 200); + gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); + + event_viewer_data->SelectionTree = gtk_tree_view_get_selection (GTK_TREE_VIEW (event_viewer_data->TreeView)); gtk_tree_selection_set_mode (event_viewer_data->SelectionTree, GTK_SELECTION_SINGLE); @@ -208,167 +395,237 @@ InterruptEventData *system_info(Tab *tab) gtk_widget_show(event_viewer_data->TreeView); interrupt_data_list = g_slist_append(interrupt_data_list, event_viewer_data); - + /* Registration for time notification */ lttvwindow_register_time_window_notify(tab, interrupt_update_time_window, event_viewer_data); - request_event(event_viewer_data); + + g_object_set_data_full(G_OBJECT(event_viewer_data->Hbox), + "event_data", + event_viewer_data, + (GDestroyNotify) InterruptFree); + + FirstRequest(event_viewer_data ); return event_viewer_data; } -static void request_event( InterruptEventData *event_data){ - - event_data->hooks_trace_before = lttv_hooks_new(); - lttv_hooks_add(event_data->hooks_trace_before, trace_header, event_data, LTTV_PRIO_DEFAULT); +/** + * + * For each trace in the traceset, this function: + * - registers a callback function to each hook + * - calls lttv_trace_find_hook() registers a hook function to event_by_id_hooks + * - calls lttvwindow_events_request() to request data in a specific + * time interval to the main window + * + */ +static void FirstRequest(InterruptEventData *event_data ) +{ + guint i, k, l, nb_trace; + + LttvTraceHook *hook; + + guint ret; - event_data->event_hooks = lttv_hooks_new(); - lttv_hooks_add(event_data->event_hooks, parse_event, event_data, LTTV_PRIO_DEFAULT); + LttvTraceState *ts; + + GArray *hooks; + + EventsRequest *events_request; + + LttvTraceHookByFacility *thf; + + LttvTracesetContext *tsc = lttvwindow_get_traceset_context(event_data->tab); + + + /* Get the traceset */ + LttvTraceset *traceset = tsc->ts; - event_data->hooks_trace_after = lttv_hooks_new(); - lttv_hooks_add(event_data->hooks_trace_after, interrupt_show, event_data, LTTV_PRIO_DEFAULT); + nb_trace = lttv_traceset_number(traceset); + + /* There are many traces in a traceset. Iteration for each trace. */ + for(i = 0; iowner = event_data; - events_request->viewer_data = event_data; - events_request->servicing = FALSE; - events_request->start_time = event_data->time_window.start_time; - events_request->start_position = NULL; - events_request->stop_flag = FALSE; - events_request->end_time = event_data->time_window.end_time; - events_request->num_events = G_MAXUINT; - events_request->end_position = NULL; - events_request->trace = 0; - events_request->hooks = NULL; - events_request->before_chunk_traceset = NULL; - events_request->before_chunk_trace = event_data->hooks_trace_before; - events_request->before_chunk_tracefile= NULL; - events_request->event = event_data->event_hooks; - events_request->event_by_id = NULL; - events_request->after_chunk_tracefile = NULL; - events_request->after_chunk_trace = NULL; - events_request->after_chunk_traceset = NULL; - events_request->before_request = NULL; - events_request->after_request = event_data->hooks_trace_after; - - lttvwindow_events_request(event_data->tab, events_request); -} + event_data->hooks_trace_before = lttv_hooks_new(); + + /* Registers a hook function */ + lttv_hooks_add(event_data->hooks_trace_before, trace_header, event_data, LTTV_PRIO_DEFAULT); -gboolean parse_event(void *hook_data, void *call_data){ + event_data->hooks_trace_after = lttv_hooks_new(); + + /* Registers a hook function */ + lttv_hooks_add(event_data->hooks_trace_after, SecondRequest, event_data, LTTV_PRIO_DEFAULT); + /* Get a trace state */ + ts = (LttvTraceState *)tsc->traces[i]; + /* Create event_by_Id hooks */ + event_data->event_by_id_hooks = lttv_hooks_by_id_new(); + + /*Register event_by_id_hooks with a callback function*/ + ret = lttv_trace_find_hook(ts->parent.t, + LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY, + LTT_FIELD_IRQ_ID, 0, 0, + FirstRequestIrqEntryCallback, + events_request, + &g_array_index(hooks, LttvTraceHook, 0)); + + ret = lttv_trace_find_hook(ts->parent.t, + LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT, + LTT_FIELD_IRQ_ID, 0, 0, + FirstRequestIrqExitCallback, + events_request, + &g_array_index(hooks, LttvTraceHook, 1)); + + g_assert(!ret); + /*iterate through the facility list*/ + for(k = 0 ; k < hooks->len; k++) + { + hook = &g_array_index(hooks, LttvTraceHook, k); + for(l=0; lfac_list->len; l++) + { + thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l); + lttv_hooks_add(lttv_hooks_by_id_find(event_data->event_by_id_hooks, thf->id), + thf->h, + event_data, + LTTV_PRIO_DEFAULT); + + } + } + /* Initalize the EventsRequest structure */ + events_request->owner = event_data; + events_request->viewer_data = event_data; + events_request->servicing = FALSE; + events_request->start_time = event_data->time_window.start_time; + events_request->start_position = NULL; + events_request->stop_flag = FALSE; + events_request->end_time = event_data->time_window.end_time; + events_request->num_events = G_MAXUINT; + events_request->end_position = NULL; + events_request->trace = i; + + events_request->hooks = hooks; + + events_request->before_chunk_traceset = NULL; + events_request->before_chunk_trace = event_data->hooks_trace_before; + events_request->before_chunk_tracefile= NULL; + events_request->event = NULL; + events_request->event_by_id = event_data->event_by_id_hooks; + events_request->after_chunk_tracefile = NULL; + events_request->after_chunk_trace = NULL; + events_request->after_chunk_traceset = NULL; + events_request->before_request = NULL; + events_request->after_request = event_data->hooks_trace_after; + + lttvwindow_events_request(event_data->tab, events_request); + } + +} +/** + * This function is called whenever an irq_entry event occurs. + * + */ +static gboolean FirstRequestIrqEntryCallback(void *hook_data, void *call_data) +{ + LttTime event_time; - LttEvent *e; - LttField *field; - LttEventType *event_type; unsigned cpu_id; irq_entry entry; - irq_entry *element; - guint i; - // g_info("interrupts: parse_event() \n"); - InterruptEventData *event_data = (InterruptEventData *)hook_data; - GArray* active_irq_entry = event_data->active_irq_entry; LttvTracefileContext *tfc = (LttvTracefileContext *)call_data; LttvTracefileState *tfs = (LttvTracefileState *)call_data; - //e = tfc->e; - e = ltt_tracefile_get_event(tfc->tf); - - field = ltt_event_field(e); + InterruptEventData *event_data = (InterruptEventData *)hook_data; + GArray* FirstRequestIrqEntry = event_data->FirstRequestIrqEntry; + LttEvent *e = ltt_tracefile_get_event(tfc->tf); event_time = ltt_event_time(e); - event_type = ltt_event_eventtype(e); cpu_id = ltt_event_cpu_id(e); - GString * detail_event = g_string_new(""); - if ((ltt_time_compare(event_time,event_data->time_window.start_time) == TRUE) && - (ltt_time_compare(event_data->time_window.end_time,event_time) == TRUE)){ - if (strcmp( g_quark_to_string(ltt_eventtype_name(event_type)),"irq_entry") == 0) { - entry.id = get_event_detail(e, field); - entry.cpu_id = cpu_id; - entry.event_time = event_time; - g_array_append_val (active_irq_entry, entry); - - } - if(strcmp( g_quark_to_string(ltt_eventtype_name(event_type)),"irq_exit") == 0) { - //printf("event_time: %ld.%ld\n",event_time.tv_sec,event_time.tv_nsec); - calcul_duration( event_time, cpu_id, event_data); - } - } - g_string_free(detail_event, TRUE); - return FALSE; + + + entry.id =get_interrupt_id(e); + entry.cpu_id = cpu_id; + entry.event_time = event_time; + g_array_append_val (FirstRequestIrqEntry, entry); + + return FALSE; } - -void interrupt_destructor(InterruptEventData *event_viewer_data) +/** + * This function gets the id of the interrupt. The id is stored in a dynamic structure. + * Refer to the print.c file for how to extract data from a dynamic structure. + */ +static guint64 get_interrupt_id(LttEvent *e) { - /* May already been done by GTK window closing */ - g_info("enter interrupt_destructor \n"); - if(GTK_IS_WIDGET(event_viewer_data->Hbox)){ - gtk_widget_destroy(event_viewer_data->Hbox); - } -} - -static guint64 get_event_detail(LttEvent *e, LttField *f){ - - LttType *type; - LttField *element; - GQuark name; - int nb, i; - guint64 irq_id; - type = ltt_field_type(f); - nb = ltt_type_member_number(type); - for(i = 0 ; i < nb-1 ; i++) { - element = ltt_field_member(f,i); - ltt_type_member_type(type, i, &name); - irq_id = ltt_event_get_long_unsigned(e,element); + guint i, num_fields; + LttEventType *event_type; + LttField *element; + LttField *field; + guint64 irq_id; + event_type = ltt_event_eventtype(e); + num_fields = ltt_eventtype_num_fields(event_type); + for(i = 0 ; i < num_fields-1 ; i++) + { + field = ltt_eventtype_field(event_type, i); + irq_id = ltt_event_get_long_unsigned(e,field); } return irq_id; -} - - - -gboolean trace_header(void *hook_data, void *call_data){ - - InterruptEventData *event_data = (InterruptEventData *)hook_data; +} +/** + * This function is called whenever an irq_exit event occurs. + * + */ +gboolean FirstRequestIrqExitCallback(void *hook_data, void *call_data) +{ + LttTime event_time; + unsigned cpu_id; LttvTracefileContext *tfc = (LttvTracefileContext *)call_data; - LttEvent *e; - LttTime event_time; - return FALSE; -} - -static gboolean interrupt_show(void *hook_data, void *call_data){ - - gint i; - Irq element; - LttTime average_duration; - GtkTreeIter iter; - guint64 real_data; + LttvTracefileState *tfs = (LttvTracefileState *)call_data; InterruptEventData *event_data = (InterruptEventData *)hook_data; - GArray *interrupt_counters = event_data->interrupt_counters; - g_info("interrupts: interrupt_show() \n"); - gtk_list_store_clear(event_data->ListStore); - for(i = 0; i < interrupt_counters->len; i++){ - element = g_array_index(interrupt_counters,Irq,i); - real_data = element.total_duration.tv_sec; - real_data *= NANOSECONDS_PER_SECOND; - real_data += element.total_duration.tv_nsec; - //printf("total_duration:%ld\n", element.total_duration.tv_nsec); - gtk_list_store_append (event_data->ListStore, &iter); - gtk_list_store_set (event_data->ListStore, &iter, - CPUID_COLUMN, element.cpu_id, - IRQ_ID_COLUMN, element.id, - FREQUENCY_COLUMN, element.frequency, - DURATION_COLUMN, real_data, - -1); - } + LttEvent *e = ltt_tracefile_get_event(tfc->tf); + LttEventType *type = ltt_event_eventtype(e); + event_time = ltt_event_time(e); + cpu_id = ltt_event_cpu_id(e); - if(event_data->interrupt_counters->len) - g_array_remove_range (event_data->interrupt_counters,0,event_data->interrupt_counters->len); + CalculateData( event_time, cpu_id, event_data); - if(event_data->active_irq_entry->len) - g_array_remove_range (event_data->active_irq_entry,0,event_data->active_irq_entry->len); return FALSE; } -static void sum_interrupt_data(irq_entry *e, LttTime time_exit, GArray *interrupt_counters){ +/** + * This function calculates the duration of an interrupt. + * + */ +static void CalculateData(LttTime time_exit, guint cpu_id,InterruptEventData *event_data) +{ + + gint i, irq_id; + irq_entry *element; + LttTime duration; + GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit; + GArray *FirstRequestIrqEntry = event_data->FirstRequestIrqEntry; + for(i = 0; i < FirstRequestIrqEntry->len; i++) + { + element = &g_array_index(FirstRequestIrqEntry,irq_entry,i); + if(element->cpu_id == cpu_id) + { + CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(element,time_exit, FirstRequestIrqExit); + g_array_remove_index(FirstRequestIrqEntry, i); + break; + } + } +} + + +/** + * This function calculates the total duration of an interrupt and the longest & shortest Irq handlers. + * + */ +static void CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(irq_entry *e, LttTime time_exit, GArray *FirstRequestIrqExit) +{ Irq irq; Irq *element; guint i; @@ -376,88 +633,675 @@ static void sum_interrupt_data(irq_entry *e, LttTime time_exit, GArray *interrup gboolean notFound = FALSE; memset ((void*)&irq, 0,sizeof(Irq)); - //printf("time_exit: %ld.%ld\n",time_exit.tv_sec,time_exit.tv_nsec); - if(interrupt_counters->len == NO_ITEMS){ + /*first time*/ + if(FirstRequestIrqExit->len == NO_ITEMS) + { irq.cpu_id = e->cpu_id; irq.id = e->id; - irq.frequency++; + irq.TotalNumberOfInterrupts++; irq.total_duration = ltt_time_sub(time_exit, e->event_time); - g_array_append_val (interrupt_counters, irq); + + irq.max_irq_handler.start_time = e->event_time; + irq.max_irq_handler.end_time = time_exit; + irq.max_irq_handler.duration = ltt_time_sub(time_exit, e->event_time); + + irq.min_irq_handler.start_time = e->event_time; + irq.min_irq_handler.end_time = time_exit; + irq.min_irq_handler.duration = ltt_time_sub(time_exit, e->event_time); + + g_array_append_val (FirstRequestIrqExit, irq); } - else{ - for(i = 0; i < interrupt_counters->len; i++){ - element = &g_array_index(interrupt_counters,Irq,i); - if(element->id == e->id){ + else + { + for(i = 0; i < FirstRequestIrqExit->len; i++) + { + element = &g_array_index(FirstRequestIrqExit,Irq,i); + if(element->id == e->id) + { notFound = TRUE; duration = ltt_time_sub(time_exit, e->event_time); element->total_duration = ltt_time_add(element->total_duration, duration); - element->frequency++; + element->TotalNumberOfInterrupts++; + // Max irq handler + if(ltt_time_compare(duration,element->max_irq_handler.duration) > 0) + { + element->max_irq_handler.duration = duration; + element->max_irq_handler.start_time = e->event_time; + element->max_irq_handler.end_time = time_exit; + } + // Min irq handler + if(ltt_time_compare(duration,element->min_irq_handler.duration) < 0) + { + element->min_irq_handler.duration = duration; + element->min_irq_handler.start_time = e->event_time; + element->min_irq_handler.end_time = time_exit; + } } } - if(!notFound){ + if(!notFound) + { irq.cpu_id = e->cpu_id; irq.id = e->id; - irq.frequency++; + irq.TotalNumberOfInterrupts++; irq.total_duration = ltt_time_sub(time_exit, e->event_time); - g_array_append_val (interrupt_counters, irq); + // Max irq handler + irq.max_irq_handler.start_time = e->event_time; + irq.max_irq_handler.end_time = time_exit; + irq.max_irq_handler.duration = ltt_time_sub(time_exit, e->event_time); + // Min irq handler + irq.min_irq_handler.start_time = e->event_time; + irq.min_irq_handler.end_time = time_exit; + irq.min_irq_handler.duration = ltt_time_sub(time_exit, e->event_time); + + g_array_append_val (FirstRequestIrqExit, irq); } } } + +/** + * This function passes the second EventsRequest to LTTV + * + */ +static gboolean SecondRequest(void *hook_data, void *call_data) +{ + + guint i, k, l, nb_trace; -static void calcul_duration(LttTime time_exit, guint cpu_id,InterruptEventData *event_data){ + LttvTraceHook *hook; + + guint ret; + + LttvTraceState *ts; + + GArray *hooks; + + EventsRequest *events_request; + + LttvTraceHookByFacility *thf; + InterruptEventData *event_data = (InterruptEventData *)hook_data; + + LttvTracesetContext *tsc = lttvwindow_get_traceset_context(event_data->tab); + + CalculateAverageDurationForEachIrqId(event_data); + + /* Get the traceset */ + LttvTraceset *traceset = tsc->ts; + + nb_trace = lttv_traceset_number(traceset); + + /* There are many traces in a traceset. Iteration for each trace. */ + for(i = 0; ihooks_trace_after = lttv_hooks_new(); + + /* Registers a hook function */ + lttv_hooks_add(event_data->hooks_trace_after, DisplayViewer, event_data, LTTV_PRIO_DEFAULT); + + /* Get a trace state */ + ts = (LttvTraceState *)tsc->traces[i]; + /* Create event_by_Id hooks */ + event_data->event_by_id_hooks = lttv_hooks_by_id_new(); + + /*Register event_by_id_hooks with a callback function*/ + ret = lttv_trace_find_hook(ts->parent.t, + LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY, + LTT_FIELD_IRQ_ID, 0, 0, + SecondRequestIrqEntryCallback, + events_request, + &g_array_index(hooks, LttvTraceHook, 0)); + + ret = lttv_trace_find_hook(ts->parent.t, + LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT, + LTT_FIELD_IRQ_ID, 0, 0, + SecondRequestIrqExitCallback, + events_request, + &g_array_index(hooks, LttvTraceHook, 1)); + + g_assert(!ret); + + /* iterate through the facility list */ + for(k = 0 ; k < hooks->len; k++) + { + hook = &g_array_index(hooks, LttvTraceHook, k); + for(l=0; lfac_list->len; l++) + { + thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l); + lttv_hooks_add(lttv_hooks_by_id_find(event_data->event_by_id_hooks, thf->id), + thf->h, + event_data, + LTTV_PRIO_DEFAULT); + + } + } + /* Initalize the EventsRequest structure */ + events_request->owner = event_data; + events_request->viewer_data = event_data; + events_request->servicing = FALSE; + events_request->start_time = event_data->time_window.start_time; + events_request->start_position = NULL; + events_request->stop_flag = FALSE; + events_request->end_time = event_data->time_window.end_time; + events_request->num_events = G_MAXUINT; + events_request->end_position = NULL; + events_request->trace = i; + + events_request->hooks = hooks; + + events_request->before_chunk_traceset = NULL; + events_request->before_chunk_trace = NULL; + events_request->before_chunk_tracefile= NULL; + events_request->event = NULL; + events_request->event_by_id = event_data->event_by_id_hooks; + events_request->after_chunk_tracefile = NULL; + events_request->after_chunk_trace = NULL; + events_request->after_chunk_traceset = NULL; + events_request->before_request = NULL; + events_request->after_request = event_data->hooks_trace_after; + + lttvwindow_events_request(event_data->tab, events_request); + } + return FALSE; +} + +/** + * This function calculates the average duration for each Irq Id + * + */ +static void CalculateAverageDurationForEachIrqId(InterruptEventData *event_data) +{ + guint64 real_data; + Irq *element; + gint i; + GArray* FirstRequestIrqExit = event_data->FirstRequestIrqExit; + for(i = 0; i < FirstRequestIrqExit->len; i++) + { + element = &g_array_index(FirstRequestIrqExit,Irq,i); + real_data = element->total_duration.tv_sec; + real_data *= NANOSECONDS_PER_SECOND; + real_data += element->total_duration.tv_nsec; + if(element->TotalNumberOfInterrupts != 0) + element->average_duration = real_data / element->TotalNumberOfInterrupts; + else + element->average_duration = 0; + } + +} + +/** + * This function is called whenever an irq_entry event occurs. Use in the second request + * + */ +static gboolean SecondRequestIrqEntryCallback(void *hook_data, void *call_data) +{ + + LttTime event_time; + unsigned cpu_id; + irq_entry entry; + LttvTracefileContext *tfc = (LttvTracefileContext *)call_data; + LttvTracefileState *tfs = (LttvTracefileState *)call_data; + InterruptEventData *event_data = (InterruptEventData *)hook_data; + GArray* SecondRequestIrqEntry = event_data->SecondRequestIrqEntry; + LttEvent *e = ltt_tracefile_get_event(tfc->tf); + event_time = ltt_event_time(e); + cpu_id = ltt_event_cpu_id(e); + + + entry.id =get_interrupt_id(e); + entry.cpu_id = cpu_id; + entry.event_time = event_time; + g_array_append_val (SecondRequestIrqEntry, entry); + + return FALSE; +} + +/** + * This function is called whenever an irq_exit event occurs in the second request. + * + */ +static gboolean SecondRequestIrqExitCallback(void *hook_data, void *call_data) +{ + + LttvTracefileContext *tfc = (LttvTracefileContext *)call_data; + LttvTracefileState *tfs = (LttvTracefileState *)call_data; + InterruptEventData *event_data = (InterruptEventData *)hook_data; + LttEvent *event = ltt_tracefile_get_event(tfc->tf); + + CalculateXi(event, event_data); + return FALSE; +} + + +/** + * This function is called whenever an irq_exit event occurs in the second request. + * + */ +static void CalculateXi(LttEvent *event_irq_exit, InterruptEventData *event_data) +{ gint i, irq_id; irq_entry *element; - LttTime duration; - GArray *interrupt_counters = event_data->interrupt_counters; - GArray *active_irq_entry = event_data->active_irq_entry; - for(i = 0; i < active_irq_entry->len; i++){ - element = &g_array_index(active_irq_entry,irq_entry,i); - if(element->cpu_id == cpu_id){ - sum_interrupt_data(element,time_exit, interrupt_counters); - g_array_remove_index(active_irq_entry, i); - // printf("array length:%d\n",active_irq_entry->len); + LttTime Xi; + LttTime exit_time; + unsigned cpu_id; + + GArray *SecondRequestIrqExit = event_data->SecondRequestIrqExit; + GArray *SecondRequestIrqEntry = event_data->SecondRequestIrqEntry; + cpu_id = ltt_event_cpu_id(event_irq_exit); + for(i = 0; i < SecondRequestIrqEntry->len; i++) + { + element = &g_array_index(SecondRequestIrqEntry,irq_entry,i); + if(element->cpu_id == cpu_id) + { + + /* time calculation */ + exit_time = ltt_event_time(event_irq_exit); + Xi = ltt_time_sub(exit_time, element->event_time); + irq_id = element->id; + + SumItems(irq_id, Xi,event_data); + g_array_remove_index(SecondRequestIrqEntry, i); break; } } } -gboolean interrupt_update_time_window(void * hook_data, void * call_data){ +/** + * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray + * + */ +static void SumItems(gint irq_id, LttTime Xi, InterruptEventData *event_data) +{ + gint i; + guint Xi_in_ns; + + gint duration_inner_part; + guint64 period_inner_part; + guint64 frequency_inner_part; + + Irq *average; + SumId *sumItem; + SumId sum; + int FrequencyHZ = 0; + gboolean notFound = FALSE; + GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit; + GArray *SumArray = event_data->SumArray; + Xi_in_ns = Xi.tv_sec; + Xi_in_ns *= NANOSECONDS_PER_SECOND; + Xi_in_ns += Xi.tv_nsec; + + for(i = 0; i < FirstRequestIrqExit->len; i++) + { + average = &g_array_index(FirstRequestIrqExit,Irq,i); + if(irq_id == average->id) + { + duration_inner_part = Xi_in_ns - average->average_duration; + FrequencyHZ = FrequencyInHZ(average->TotalNumberOfInterrupts, event_data->time_window); + sum.irqId = irq_id; + // compute (xi -Xa)^2 of the duration Standard deviation + sum.TotalNumberOfInterrupts = average->TotalNumberOfInterrupts; + sum.sumOfDurations = pow (duration_inner_part , 2); + + // compute (xi -Xa)^2 of the period Standard deviation + period_inner_part = CalculatePeriodInnerPart(Xi_in_ns, FrequencyHZ); + + // compute (xi -Xa)^2 of the frequency Standard deviation + frequency_inner_part = CalculateFrequencyInnerPart(Xi_in_ns, FrequencyHZ); + + sum.sumOfPeriods = period_inner_part; + + sum.sumOfFrequencies = frequency_inner_part; + + if(event_data->SumArray->len == NO_ITEMS) + { + g_array_append_val (SumArray, sum); + } + else + { + for(i = 0; i < SumArray->len; i++) + { + sumItem = &g_array_index(SumArray, SumId, i); + if(sumItem->irqId == irq_id) + { + notFound = TRUE; + sumItem->sumOfDurations += sum.sumOfDurations; + sumItem->sumOfPeriods += sum.sumOfPeriods; + sumItem->sumOfFrequencies += sum.sumOfFrequencies; + } + } + if(!notFound) + { + g_array_append_val (SumArray, sum); + } + + } + + } + } +} + +/** + * This function computes the inner part of the period standard deviation = sqrt(1/N Sum ((xi -Xa)^2)) + * The inner part is: (xi -Xa)^2 + */ +static guint64 CalculatePeriodInnerPart(guint Xi, guint FrequencyHZ) +{ + + double periodInSec; /*period in sec*/ + int periodInNSec; + gint difference; + guint64 result; + periodInSec = (double)1/FrequencyHZ; + periodInSec *= NANOSECONDS_PER_SECOND; + periodInNSec = (int)periodInSec; + + difference = Xi - periodInNSec; + result = pow (difference , 2); + return result; +} + +/** + * This function computes the inner part of the frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2)) + * The inner part is: (xi -Xa)^2 + */ +static guint64 CalculateFrequencyInnerPart(guint Xi_in_ns, guint FrequencyHZ) +{ + guint64 result; + gint difference; + + difference = Xi_in_ns - FrequencyHZ; + result = pow (difference , 2); + return result; +} +/** + * This function displays the result on the viewer + * + */ +static gboolean DisplayViewer(void *hook_data, void *call_data) +{ + + guint average; + gint i; + Irq element; + LttTime average_duration; + GtkTreeIter iter; + guint64 real_data; + guint maxIRQduration; + guint minIRQduration; + double periodInSec; + int periodInNsec; + char maxIrqHandler[80]; + char minIrqHandler[80]; + InterruptEventData *event_data = (InterruptEventData *)hook_data; + GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit; + int FrequencyHZ = 0; + periodInSec = 0; + gtk_list_store_clear(event_data->ListStore); + for(i = 0; i < FirstRequestIrqExit->len; i++) + { + element = g_array_index(FirstRequestIrqExit,Irq,i); + real_data = element.total_duration.tv_sec; + real_data *= NANOSECONDS_PER_SECOND; + real_data += element.total_duration.tv_nsec; + + + maxIRQduration = element.max_irq_handler.duration.tv_sec; + maxIRQduration *= NANOSECONDS_PER_SECOND; + maxIRQduration += element.max_irq_handler.duration.tv_nsec; + + sprintf(maxIrqHandler, "%d [%d.%d - %d.%d]",maxIRQduration, element.max_irq_handler.start_time.tv_sec, \ + element.max_irq_handler.start_time.tv_nsec, element.max_irq_handler.end_time.tv_sec, \ + element.max_irq_handler.end_time.tv_nsec) ; + + minIRQduration = element.min_irq_handler.duration.tv_sec; + minIRQduration *= NANOSECONDS_PER_SECOND; + minIRQduration += element.min_irq_handler.duration.tv_nsec; + sprintf(minIrqHandler, "%d [%d.%d - %d.%d]",minIRQduration, element.min_irq_handler.start_time.tv_sec, \ + element.min_irq_handler.start_time.tv_nsec, element.min_irq_handler.end_time.tv_sec, \ + element.min_irq_handler.end_time.tv_nsec) ; + + + FrequencyHZ = FrequencyInHZ(element.TotalNumberOfInterrupts,event_data->time_window); + + if(FrequencyHZ != 0) + { + periodInSec = (double)1/FrequencyHZ; + periodInSec *= NANOSECONDS_PER_SECOND; + periodInNsec = (int)periodInSec; + + } + + gtk_list_store_append (event_data->ListStore, &iter); + gtk_list_store_set (event_data->ListStore, &iter, + CPUID_COLUMN, element.cpu_id, + IRQ_ID_COLUMN, element.id, + FREQUENCY_COLUMN, FrequencyHZ, + DURATION_COLUMN, real_data, + DURATION_STANDARD_DEV_COLUMN, CalculateDurationStandardDeviation(element.id, event_data), + MAX_IRQ_HANDLER_COLUMN, maxIrqHandler, + MIN_IRQ_HANDLER_COLUMN, minIrqHandler, + AVERAGE_PERIOD , periodInNsec, + PERIOD_STANDARD_DEV_COLUMN, CalculatePeriodStandardDeviation(element.id, event_data), + FREQUENCY_STANDARD_DEV_COLUMN, CalculateFrequencyStandardDeviation(element.id, event_data), + -1); + } + + + if(event_data->FirstRequestIrqExit->len) + { + g_array_remove_range (event_data->FirstRequestIrqExit,0,event_data->FirstRequestIrqExit->len); + } + + if(event_data->FirstRequestIrqEntry->len) + { + g_array_remove_range (event_data->FirstRequestIrqEntry,0,event_data->FirstRequestIrqEntry->len); + } + + if(event_data->SecondRequestIrqEntry->len) + { + g_array_remove_range (event_data->SecondRequestIrqEntry,0,event_data->SecondRequestIrqEntry->len); + } + + if(event_data->SecondRequestIrqExit->len) + { + g_array_remove_range (event_data->SecondRequestIrqExit,0, event_data->SecondRequestIrqExit->len); + } + + if(event_data->SumArray->len) + { + g_array_remove_range (event_data->SumArray,0, event_data->SumArray->len); + } + + return FALSE; +} + + +/** + * This function converts the number of interrupts over a time window to + * frequency in HZ + */ +static int FrequencyInHZ(gint NumerofInterruptions, TimeWindow time_window) +{ + guint64 frequencyHz = 0; + double timeSec; // time in second + double result; + result = ltt_time_to_double(time_window.time_width); + timeSec = (result/NANOSECONDS_PER_SECOND); //time in second + frequencyHz = NumerofInterruptions / timeSec; + return frequencyHz; +} + +/** + * This function calculates the duration standard deviation + * Duration standard deviation = sqrt(1/N Sum ((xi -Xa)^2)) + * Where: + * sumId.sumOfDurations -> Sum ((xi -Xa)^2) + * inner_component -> 1/N Sum ((xi -Xa)^2) + * deviation-> sqrt(1/N Sum ((xi -Xa)^2)) + */ +static int CalculateDurationStandardDeviation(gint id, InterruptEventData *event_data) +{ + int i; + SumId sumId; + double inner_component; + int deviation = 0; + for(i = 0; i < event_data->SumArray->len; i++) + { + sumId = g_array_index(event_data->SumArray, SumId, i); + if(id == sumId.irqId) + { + if(sumId.TotalNumberOfInterrupts != 0) + inner_component = sumId.sumOfDurations/ sumId.TotalNumberOfInterrupts; + else + inner_component = 0.0; + deviation = sqrt(inner_component); + return deviation; + } + } + return deviation; +} + + +/** + * This function calculates the period standard deviation + * Period standard deviation = sqrt(1/N Sum ((xi -Xa)^2)) + * Where: + * sumId.sumOfPeriods -> Sum ((xi -Xa)^2) + * inner_component -> 1/N Sum ((xi -Xa)^2) + * period_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2)) + * + */ +static int CalculatePeriodStandardDeviation(gint id, InterruptEventData *event_data) +{ + int i; + SumId sumId; + guint64 inner_component; + guint64 period_standard_deviation = 0; + + for(i = 0; i < event_data->SumArray->len; i++) + { + sumId = g_array_index(event_data->SumArray, SumId, i); + if(id == sumId.irqId) + { + if(sumId.TotalNumberOfInterrupts != 0) + inner_component = sumId.sumOfPeriods / sumId.TotalNumberOfInterrupts; + else + inner_component = 0; + + period_standard_deviation = sqrt(inner_component); + } + } + + return period_standard_deviation; +} + +/** + * This function calculates the frequency standard deviation + * Frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2)) + * Where: + * sumId.sumOfFrequencies -> Sum ((xi -Xa)^2) + * inner_component -> 1/N Sum ((xi -Xa)^2) + * frequency_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2)) + * + */ +static int CalculateFrequencyStandardDeviation(gint id, InterruptEventData *event_data) +{ + int i; + SumId sumId; + guint64 inner_component; + guint64 frequency_standard_deviation = 0; + for(i = 0; i < event_data->SumArray->len; i++) + { + sumId = g_array_index(event_data->SumArray, SumId, i); + if(id == sumId.irqId) + { + if(sumId.TotalNumberOfInterrupts != 0) + inner_component = sumId.sumOfFrequencies / sumId.TotalNumberOfInterrupts; + else + inner_component = 0; + + frequency_standard_deviation = sqrt(inner_component); + } + } + return frequency_standard_deviation; +} + +/* + * This function is called by the main window + * when the time interval needs to be updated. + **/ +gboolean interrupt_update_time_window(void * hook_data, void * call_data) +{ InterruptEventData *event_data = (InterruptEventData *) hook_data; const TimeWindowNotifyData *time_window_nofify_data = ((const TimeWindowNotifyData *)call_data); event_data->time_window = *time_window_nofify_data->new_time_window; g_info("interrupts: interrupt_update_time_window()\n"); Tab *tab = event_data->tab; lttvwindow_events_request_remove_all(tab, event_data); - request_event(event_data); - - - return FALSE; + FirstRequest(event_data ); + return FALSE; } -/** - * plugin's init function - * - * This function initializes the Event Viewer functionnality through the - * gtkTraceSet API. - */ -static void init() { - g_info("interrupts: init()"); - lttvwindow_register_constructor("interrupts", - "/", - "Insert Interrupts View", - hInterruptsInsert_xpm, - "Insert Interrupts View", - interrupts); - + +gboolean trace_header(void *hook_data, void *call_data) +{ + + InterruptEventData *event_data = (InterruptEventData *)hook_data; + LttvTracefileContext *tfc = (LttvTracefileContext *)call_data; + LttEvent *e; + LttTime event_time; + return FALSE; } -void interrupt_destroy_walk(gpointer data, gpointer user_data){ +void interrupt_destroy_walk(gpointer data, gpointer user_data) +{ g_info("interrupt_destroy_walk"); + InterruptEventData *event_data = (InterruptEventData*) data; interrupt_destructor((InterruptEventData*)data); +} + + +void interrupt_destructor(InterruptEventData *event_viewer_data) +{ + /* May already been done by GTK window closing */ + g_info("enter interrupt_destructor \n"); + if(GTK_IS_WIDGET(event_viewer_data->Hbox)) + { + gtk_widget_destroy(event_viewer_data->Hbox); + } +} +/** + This function is called when the viewer is destroyed to free hooks and memory +*/ +static void InterruptFree(InterruptEventData *event_viewer_data) +{ + Tab *tab = event_viewer_data->tab; + if(tab != NULL) + { + + g_array_free(event_viewer_data->FirstRequestIrqExit, TRUE); + g_array_free(event_viewer_data->FirstRequestIrqEntry, TRUE); + g_array_free(event_viewer_data->SecondRequestIrqEntry, TRUE); + g_array_free(event_viewer_data->SecondRequestIrqExit, TRUE); + g_array_free(event_viewer_data->SumArray, TRUE); + + lttvwindow_unregister_time_window_notify(tab, interrupt_update_time_window, event_viewer_data); + + lttvwindow_events_request_remove_all(event_viewer_data->tab, + event_viewer_data); + + interrupt_data_list = g_slist_remove(interrupt_data_list, event_viewer_data); + + } + } /** @@ -466,7 +1310,9 @@ void interrupt_destroy_walk(gpointer data, gpointer user_data){ * This function releases the memory reserved by the module and unregisters * everything that has been registered in the gtkTraceSet API. */ -static void destroy() { +static void destroy() +{ + g_info("Destroy interrupts"); g_slist_foreach(interrupt_data_list, interrupt_destroy_walk, NULL ); g_slist_free(interrupt_data_list);