X-Git-Url: http://git.lttng.org./?a=blobdiff_plain;f=ltt%2Fbranches%2Fpoly%2Fdoc%2Fdeveloper%2Flttvwindow_events_delivery.txt;h=578abe0e67013d6085a4b8ed141316a49472c492;hb=4bcbbd42fd565e7ec9e32772dbb7839e05ccff5c;hp=f310dce9973ab29cb7ce1aa682775b83d059b890;hpb=3c502bdc69428da248713d503c511c71177092ef;p=lttv.git diff --git a/ltt/branches/poly/doc/developer/lttvwindow_events_delivery.txt b/ltt/branches/poly/doc/developer/lttvwindow_events_delivery.txt index f310dce9..578abe0e 100644 --- a/ltt/branches/poly/doc/developer/lttvwindow_events_delivery.txt +++ b/ltt/branches/poly/doc/developer/lttvwindow_events_delivery.txt @@ -144,12 +144,71 @@ void lttvwindow_events_request ( MainWindow *main_win, EventsRequest *events_request); +void lttvwindow_events_request +( MainWindow *main_win, + EventsRequest events_request); + +void lttvwindow_events_request_remove_all +( MainWindow *main_win, + gpointer viewer); + Internal functions : - lttvwindow_process_pending_requests +Events Requests Removal + +A new API function will be necessary to let viewers remove all event requests +they have made previously. By allowing this, no more out of bound requests will +be serviced : a viewer that sees its time interval changed before the first +servicing is completed can clear its previous events requests and make a new +one for the new interval needed, considering the finished chunks as completed +area. + +It is also very useful for dealing with the viewer destruction case : the viewer +just has to remove its events requests from the main window before it gets +destroyed. + + +Permitted GTK Events Between Chunks + +All GTK Events will be enabled between chunks. This is due to the fact that the +background processing and a high priority request are seen as the same case. +While a background processing is in progress, the whole graphical interface must +be enabled. + +We needed to deal with the coherence of background processing and diverse GTK +events anyway. This algorithm provides a generalized way to deal with any type +of request and any GTK events. + + +Background Computation Request + +The types of background computation that can be requested by a viewer : state +computation (main window scope) or viewer specific background computation. + +A background computation request is asked via lttvwindow_events_request, with a +priority field set with a low priority. + +If a lttvwindow_events_request_remove_all is done on the viewer pointer, it will +not affect the state computation as no viewer pointer will have been passed in +the initial request. This is the expected result. For the background processings +that call viewer's hooks, they will be removed. + + +A New "Redraw" Button + +It will be used to redraw the viewers entirely. It is useful to restart the +servicing after a "stop" action. + +A New "Continue" Button + +It will tell the viewers to send requests for damaged areas. It is useful to +complete the servicing after a "stop" action. + + Implementation @@ -166,30 +225,46 @@ each viewer through process traceset. - lttvwindow_events_request -It adds the a pointer to the EventsRequest struct to the array of time requests +It adds the an EventsRequest struct to the array of time requests pending and registers a pending request for the next g_idle if none is -registered. The viewer has to keep a reference to this structure in its own -instance data structure. Only the stop_flag can be changed by the viewer -through the event hooks. +registered. The viewer can access this structure during the read as its +hook_data. Only the stop_flag can be changed by the viewer through the +event hooks. + +typedef LttvEventsRequestPrio guint; typedef struct _EventsRequest { - LttTime start_time, /* Unset : { 0, 0 } */ - LttvTracesetContextPosition start_position, /* Unset : num_traces = 0 */ - gboolean stop_flag, /* Continue:TRUE Stop:FALSE */ - LttTime end_time, /* Unset : { 0, 0 } */ - guint num_events, /* Unset : G_MAXUINT */ - LttvTracesetContextPosition end_position, /* Unset : num_traces = 0 */ - LttvHooks *before_traceset, /* Unset : NULL */ - LttvHooks *before_trace, /* Unset : NULL */ - LttvHooks *before_tracefile, /* Unset : NULL */ - LttvHooks *event, /* Unset : NULL */ - LttvHooksById *event_by_id, /* Unset : NULL */ - LttvHooks *after_tracefile, /* Unset : NULL */ - LttvHooks *after_trace, /* Unset : NULL */ - LttvHooks *after_traceset /* Unset : NULL */ + gpointer viewer_data; + gboolean servicing; /* service in progress: TRUE */ + LttvEventsRequestPrio prio; /* Ev. Req. priority */ + LttTime start_time; /* Unset : { 0, 0 } */ + LttvTracesetContextPosition *start_position; /* Unset : num_traces = 0 */ + gboolean stop_flag; /* Continue:TRUE Stop:FALSE */ + LttTime end_time; /* Unset : { 0, 0 } */ + guint num_events; /* Unset : G_MAXUINT */ + LttvTracesetContextPosition *end_position; /* Unset : num_traces = 0 */ + LttvHooks *before_traceset; /* Unset : NULL */ + LttvHooks *before_trace; /* Unset : NULL */ + LttvHooks *before_tracefile;/* Unset : NULL */ + LttvHooks *event; /* Unset : NULL */ + LttvHooksById *event_by_id; /* Unset : NULL */ + LttvHooks *after_tracefile; /* Unset : NULL */ + LttvHooks *after_trace; /* Unset : NULL */ + LttvHooks *after_traceset; /* Unset : NULL */ + LttvHooks *before_chunk; /* Unset : NULL */ + LttvHooks *after_chunk /* Unset : NULL */ } EventsRequest; + +- lttvwindow_events_request_remove_all + +It removes all the events requests from the pool that has their "viewer" field +maching the viewer pointer given in argument. + +It calls the traceset/trace/tracefile end hooks for each request removed. + + - lttvwindow_process_pending_requests This internal function gets called by g_idle, taking care of the pending @@ -198,7 +273,18 @@ requests. It does it with the following algorithm organizing process traceset calls. Here is the detailed description of the way it works : -- Events Requests Servicing Algorithm + +- Revised Events Requests Servicing Algorithm (v2) + +The reads are splitted in chunks. After a chunk is over, we want to check if +there is a GTK Event pending and execute it. It can add or remove events +requests from the event requests list. If it happens, we want to start over +the algorithm from the beginning. + +Two levels of priority exists. High priority and low priority. High prio +requests are serviced first, even if lower priority requests has lower start +time or position. + Data structures necessary : @@ -211,64 +297,113 @@ list_in : empty list_out : many events requests -While list_in !empty and list_out !empty +A. While list_in !empty and list_out !empty and !GTK Event pending 1. If list_in is empty (need a seek) 1.1 Add requests to list_in - 1.1.1 Find all time requests with the lowest start time in list_out - (ltime) - 1.1.2 Find all position requests with the lowest position in list_out - (lpos) - 1.1.3 If lpos.start time < ltime + 1.1.1 Find all time requests with the highest priority and lowest start + time in list_out (ltime) + 1.1.2 Find all position requests with the highest priority and lowest + position in list_out (lpos) + 1.1.3 If lpos.prio > ltime.prio + || (lpos.prio == ltime.prio && lpos.start time < ltime) - Add lpos to list_in, remove them from list_out - 1.1.4 Else, (lpos.start time >= ltime) + 1.1.4 Else, (lpos.prio < ltime.prio + ||(lpos.prio == ltime.prio && lpos.start time >= ltime)) - Add ltime to list_in, remove them from list_out 1.2 Seek 1.2.1 If first request in list_in is a time request - 1.2.1.1 Seek to that time + - If first req in list_in start time != current time + - Seek to that time 1.2.2 Else, the first request in list_in is a position request - 1.2.2.1 Seek to that position - 1.3 Call begin for all list_in members - (1.3.1 begin hooks called) - (1.3.2 middle hooks added) + - If first req in list_in pos != current pos + - If the position is the same than the saved state, restore state + - Else, seek to that position + 1.3 Add hooks and call begin for all list_in members + 1.3.1 If !servicing + - begin hooks called + - servicing = TRUE + 1.3.2 call before_chunk + 1.3.3 events hooks added 2. Else, list_in is not empty, we continue a read 2.1 For each req of list_out - if req.start time == current context time - Add to list_in, remove from list_out - - Call begin + - If !servicing + - Call begin + - servicing = TRUE + - Call before_chunk + - events hooks added - if req.start position == current position - Add to list_in, remove from list_out - - Call begin + - If !servicing + - Call begin + - servicing = TRUE + - Call before_chunk + - events hooks added 3. Find end criterions 3.1 End time 3.1.1 Find lowest end time in list_in - 3.1.2 Find lowest start time in list_out + 3.1.2 Find lowest start time in list_out (>= than current time*) + * To eliminate lower prio requests 3.1.3 Use lowest of both as end time 3.2 Number of events 3.2.1 Find lowest number of events in list_in + 3.2.2 Use min(CHUNK_NUM_EVENTS, min num events in list_in) as num_events 3.3 End position 3.3.1 Find lowest end position in list_in - 3.3.2 Find lowest start position in list_out + 3.3.2 Find lowest start position in list_out (>= than current + position) 3.3.3 Use lowest of both as end position 4. Call process traceset middle 4.1 Call process traceset middle (Use end criterion found in 3) * note : end criterion can also be viewer's hook returning TRUE 5. After process traceset middle + - if current context time > traceset.end time + - For each req in list_in + - Call end for req + - Remove events hooks for req + - remove req from list_in 5.1 For each req in list_in - req.num -= count - if req.num == 0 - Call end for req + - Remove events hooks for req - remove req from list_in - if current context time > req.end time - Call end for req + - Remove events hooks for req - remove req from list_in - if req.end pos == current pos - Call end for req + - Remove events hooks for req - remove req from list_in - if req.stop_flag == TRUE - Call end for req + - Remove events hooks for req - remove req from list_in + - if exists one events requests in list_out that has + higher priority and time != current time + - Use current position as start position for req + - Remove start time from req + - Call after_chunk for req + - Remove event hooks for req + - Put req back in list_out, remove from list_in + - Save current state into saved_state. + +B. When interrupted + 1. for each request in list_in + 1.1. Use current postition as start position + 1.2. Remove start time + 1.3. Call after_chunk + 1.4. Remove event hooks + 1.5. Put it back in list_out + 2. Save current state into saved_state. + 2.1 Free old saved state. + 2.2 save current state. + + @@ -284,11 +419,25 @@ The >= for position is necessary to make ensure consistency between start time requests and positions requests that happens to be at the exact same start time and position. +We only keep one saved state in memory. If, for example, a low priority +servicing is interrupted, a high priority is serviced, then the low priority +will use the saved state to start back where it was instead of seeking to the +time. In the very specific case where a low priority servicing is interrupted, +and then a high priority servicing on top of it is also interrupted, well, the +low priority will loose its state and will have to seek back. It should not +occur often. The solution to it would be to save one state per priority. + + + + Weaknesses -- None (nearly?) :) +- There is a possibility that we must use seek if more than one interruption + occurs, i.e. low priority interrupted by addition of high priority, and then + high priority interrupted. The seek will be necessary for the low priority. + It could be a good idea to keep one saved_state per priority ? Strengths @@ -299,3 +448,6 @@ Strengths - Solves all the weaknesses idenfied in the actual boundaryless traceset reading. + +- Background processing available. +