mirror of https://github.com/GNOME/gimp.git
tools: in performance-log-viewer.py, add markers view
Add a "markers" page to the performance-log viewer, which lists the event markers contained in the log, and allows navigating between them. Update docs accordingly.
This commit is contained in:
parent
5a6548a4b6
commit
dafb63fd66
|
@ -18,16 +18,17 @@ report performance-related issues.
|
|||
- [4.1.1. Selecting Samples](#411-selecting-samples)
|
||||
- [4.2. Information Area](#42-information-area)
|
||||
- [4.2.1. Information Page](#421-information-page)
|
||||
- [4.2.2. Variables Page](#422-variables-page)
|
||||
- [4.2.3. Backtrace Page](#423-backtrace-page)
|
||||
- [4.2.3.1. Threads Pane](#4231-threads-pane)
|
||||
- [4.2.3.2. Stack Pane](#4232-stack-pane)
|
||||
- [4.2.4. Profile Page](#424-profile-page)
|
||||
- [4.2.4.1. Root Column](#4241-root-column)
|
||||
- [4.2.4.1.1. Thread Filter](#42411-thread-filter)
|
||||
- [4.2.4.1.2. Call-Graph Direction](#42412-call-graph-direction)
|
||||
- [4.2.4.2. Function Columns](#4242-function-columns)
|
||||
- [4.2.4.3. Source Columns](#4243-source-columns)
|
||||
- [4.2.2. Markers Page](#422-markers-page)
|
||||
- [4.2.3. Variables Page](#423-variables-page)
|
||||
- [4.2.4. Backtrace Page](#424-backtrace-page)
|
||||
- [4.2.4.1. Threads Pane](#4241-threads-pane)
|
||||
- [4.2.4.2. Stack Pane](#4242-stack-pane)
|
||||
- [4.2.5. Profile Page](#425-profile-page)
|
||||
- [4.2.5.1. Root Column](#4251-root-column)
|
||||
- [4.2.5.1.1. Thread Filter](#42511-thread-filter)
|
||||
- [4.2.5.1.2. Call-Graph Direction](#42512-call-graph-direction)
|
||||
- [4.2.5.2. Function Columns](#4252-function-columns)
|
||||
- [4.2.5.3. Source Columns](#4253-source-columns)
|
||||
- [4.3. Selection Modifiers](#43-selection-modifiers)
|
||||
- [4.3.1. Searching Samples](#431-searching-samples)
|
||||
- [4.4. History Navigation](#44-history-navigation)
|
||||
|
@ -249,7 +250,17 @@ associated with any sample, including:
|
|||
|
||||
The key/value lists are searchable by key name.
|
||||
|
||||
#### 4.2.2. Variables Page
|
||||
#### 4.2.4. Markers Page
|
||||
|
||||
The *markers page* lists the event markers contained in the log, displaying
|
||||
their number, relative time, and description.
|
||||
It is only present in logs containing event markers.
|
||||
|
||||
If the current selection contains samples corresponding to any markers, the
|
||||
markers are selected in the markers-page list. Conversely, if any markers are
|
||||
selected in the markers-page list, the corresponding samples are selected.
|
||||
|
||||
#### 4.2.3. Variables Page
|
||||
|
||||
The *variables page* shows instrumentation-variable statistics for the current
|
||||
selection.
|
||||
|
@ -267,13 +278,13 @@ standard deviation.
|
|||
The variable list is searchable by variable name, and its tooltip shows the
|
||||
variable descriptions.
|
||||
|
||||
#### 4.2.3. Backtrace Page
|
||||
#### 4.2.4. Backtrace Page
|
||||
|
||||
The *backtrace page* shows the program backtrace at the current sample.
|
||||
It is only available when a single sample is selected, in logs containing
|
||||
backtraces.
|
||||
|
||||
##### 4.2.3.1. Threads Pane
|
||||
##### 4.2.4.1. Threads Pane
|
||||
|
||||
The *threads pane*, on the left side of the page, lists all active threads at
|
||||
the time of the sample, displaying the following information:
|
||||
|
@ -306,7 +317,7 @@ The thread list is searchable by thread name.
|
|||
Double-clicking on a thread selects all samples at which the thread is in the
|
||||
running state.
|
||||
|
||||
##### 4.2.3.2. Stack Pane
|
||||
##### 4.2.4.2. Stack Pane
|
||||
|
||||
The *stack pane*, on the right side of the page, shows the selected thread's
|
||||
call stack at the time of the sample, displaying the following information:
|
||||
|
@ -350,7 +361,7 @@ The frame list is searchable by function name.
|
|||
Double-clicking on a frame selects all samples at which the corresponding
|
||||
function is present in the backtrace.
|
||||
|
||||
#### 4.2.4. Profile Page
|
||||
#### 4.2.5. Profile Page
|
||||
|
||||
The *profile page* shows a fully context-sensitive *call graph*, annotated with
|
||||
frequency information, for the current selection.
|
||||
|
@ -368,7 +379,7 @@ Each non-root column lists the direct *descendants* (*callers* or *callees*) of
|
|||
a given function; selecting a descendant opens a new column to the right of the
|
||||
current column, showing the descendants of the selected function, and so on.
|
||||
|
||||
##### 4.2.4.1. Root Column
|
||||
##### 4.2.5.1. Root Column
|
||||
|
||||
The *root column* of the call graph shows a list of all functions included in
|
||||
the graph.
|
||||
|
@ -398,14 +409,14 @@ Pressing *Escape* while the list has focus deselects the current item.
|
|||
The root-column header buttons allow controlling the structure of the call
|
||||
graph:
|
||||
|
||||
###### 4.2.4.1.1. Thread Filter
|
||||
###### 4.2.5.1.1. Thread Filter
|
||||
|
||||
The *Threads* button opens the *thread filter*, allowing control over which
|
||||
threads, and which states of each thread, are included in the graph.
|
||||
|
||||
The thread filter lists all threads included in the current selection.
|
||||
Each thread is identified by ID and name, as described in
|
||||
[section *4.2.3.1*](#4231-threads-pane).
|
||||
[section *4.2.4.1*](#4241-threads-pane).
|
||||
Next to each thread is a row of toggles, corresponding to the different thread
|
||||
states; only call stacks during which the thread was in one of the active
|
||||
states are included in the graph.
|
||||
|
@ -413,7 +424,7 @@ Clicking on a thread-state column title toggles the entire column.
|
|||
|
||||
The thread list can be searched by thread name.
|
||||
|
||||
###### 4.2.4.1.2. Call-Graph Direction
|
||||
###### 4.2.5.1.2. Call-Graph Direction
|
||||
|
||||
By default, the graph direction is *caller → callee*—the direct descendants of
|
||||
each function are its callees.
|
||||
|
@ -421,7 +432,7 @@ The *Call-Graph Direction* button allows toggling the graph between the *caller
|
|||
→ callee* direction, and the reverse *callee → caller* direction, in which the
|
||||
direct descendants of each function are its callers.
|
||||
|
||||
##### 4.2.4.2. Function Columns
|
||||
##### 4.2.5.2. Function Columns
|
||||
|
||||
When a function from the root column is selected, a new *function column* opens
|
||||
to the right of the root column, listing the direct descendants of the
|
||||
|
@ -472,7 +483,7 @@ corresponding to the current column, that is, all the samples whose call stacks
|
|||
contribute to column.
|
||||
The button's tooltip shows a textual description of the samples.
|
||||
|
||||
##### 4.2.4.3. Source Columns
|
||||
##### 4.2.5.3. Source Columns
|
||||
|
||||
When the *[Self]* item of a function column is selected, if the log contains
|
||||
source-location information for the function, and the corresponding source file
|
||||
|
@ -535,7 +546,7 @@ A number of sample-dependent variables and functions are provided:
|
|||
thread name.
|
||||
|
||||
The optional `state` argument, if not `None`, may specify a thread state
|
||||
(see [section *4.2.3.1*](#4231-threads-pane)).
|
||||
(see [section *4.2.4.1*](#4241-threads-pane)).
|
||||
Only samples at which the thread is in the given state are matched.
|
||||
The argument may be a regular expression, which should fully match the
|
||||
thread state.
|
||||
|
|
|
@ -288,15 +288,16 @@ Frame = namedtuple ("Frame", ("id", "address", "info"))
|
|||
Sample = namedtuple ("Sample", ("t", "vars", "markers", "backtrace"))
|
||||
Marker = namedtuple ("Marker", ("id", "t", "description"))
|
||||
|
||||
samples = []
|
||||
markers = []
|
||||
samples = []
|
||||
markers = []
|
||||
last_marker = 0
|
||||
|
||||
for element in log.find ("samples"):
|
||||
if element.tag == "sample":
|
||||
sample = Sample (
|
||||
t = int (element.get ("t")),
|
||||
vars = {},
|
||||
markers = markers,
|
||||
markers = markers[last_marker:],
|
||||
backtrace = []
|
||||
)
|
||||
|
||||
|
@ -347,7 +348,7 @@ for element in log.find ("samples"):
|
|||
|
||||
samples.append (sample)
|
||||
|
||||
markers = []
|
||||
last_marker = len (markers)
|
||||
elif element.tag == "marker":
|
||||
marker = Marker (
|
||||
id = int (element.get ("id")),
|
||||
|
@ -357,10 +358,8 @@ for element in log.find ("samples"):
|
|||
|
||||
markers.append (marker)
|
||||
|
||||
if samples and markers:
|
||||
samples[-1].markers += markers
|
||||
|
||||
markers = None
|
||||
if samples:
|
||||
samples[-1].markers.extend (markers[last_marker:])
|
||||
|
||||
DELTA_SAME = __builtins__.object ()
|
||||
|
||||
|
@ -1675,6 +1674,128 @@ class InformationViewer (Gtk.ScrolledWindow):
|
|||
for element in info:
|
||||
add_element (element)
|
||||
|
||||
class MarkersViewer (Gtk.ScrolledWindow):
|
||||
class Store (Gtk.ListStore):
|
||||
ID = 0
|
||||
TIME = 1
|
||||
DESC = 2
|
||||
|
||||
def __init__ (self):
|
||||
Gtk.ListStore.__init__ (self, int, int, str)
|
||||
|
||||
for marker in markers:
|
||||
self.append ((marker.id, marker.t, marker.description))
|
||||
|
||||
def __init__ (self, *args, **kwargs):
|
||||
Gtk.Box.__init__ (self,
|
||||
*args,
|
||||
hscrollbar_policy = Gtk.PolicyType.AUTOMATIC,
|
||||
vscrollbar_policy = Gtk.PolicyType.AUTOMATIC,
|
||||
**kwargs)
|
||||
|
||||
self.needs_update = True
|
||||
|
||||
store = self.Store ()
|
||||
self.store = store
|
||||
|
||||
tree = Gtk.TreeView (model = store)
|
||||
self.tree = tree
|
||||
self.add (tree)
|
||||
tree.show ()
|
||||
|
||||
tree.get_selection ().set_mode (Gtk.SelectionMode.MULTIPLE)
|
||||
|
||||
self.tree_selection_changed_handler = tree.get_selection ().connect (
|
||||
"changed", self.tree_selection_changed
|
||||
)
|
||||
|
||||
col = Gtk.TreeViewColumn (title = "#")
|
||||
tree.append_column (col)
|
||||
col.set_resizable (True)
|
||||
|
||||
cell = Gtk.CellRendererText (xalign = 1)
|
||||
col.pack_start (cell, False)
|
||||
col.add_attribute (cell, "text", store.ID)
|
||||
|
||||
def format_time_col (tree_col, cell, model, iter, col):
|
||||
time = model[iter][col]
|
||||
|
||||
cell.set_property ("text", format_duration (time / 1000000))
|
||||
|
||||
col = Gtk.TreeViewColumn (title = "Time")
|
||||
tree.append_column (col)
|
||||
col.set_resizable (True)
|
||||
col.set_alignment (0.5)
|
||||
|
||||
cell = Gtk.CellRendererText (xalign = 1)
|
||||
col.pack_start (cell, False)
|
||||
col.set_cell_data_func (cell, format_time_col, store.TIME)
|
||||
|
||||
col = Gtk.TreeViewColumn (title = "Description")
|
||||
tree.append_column (col)
|
||||
col.set_resizable (True)
|
||||
col.set_alignment (0.5)
|
||||
|
||||
cell = Gtk.CellRendererText ()
|
||||
col.pack_start (cell, False)
|
||||
col.add_attribute (cell, "text", store.DESC)
|
||||
|
||||
col = Gtk.TreeViewColumn ()
|
||||
tree.append_column (col)
|
||||
|
||||
selection.connect ("change-complete", self.selection_change_complete)
|
||||
|
||||
def update (self):
|
||||
markers = set ()
|
||||
|
||||
if not self.needs_update:
|
||||
return
|
||||
|
||||
self.needs_update = False
|
||||
|
||||
for i in selection.selection:
|
||||
markers.update (marker.id for marker in samples[i].markers)
|
||||
|
||||
tree_sel = self.tree.get_selection ()
|
||||
|
||||
GObject.signal_handler_block (tree_sel,
|
||||
self.tree_selection_changed_handler)
|
||||
|
||||
tree_sel.unselect_all ()
|
||||
|
||||
for row in self.store:
|
||||
if row[self.store.ID] in markers:
|
||||
tree_sel.select_iter (row.iter)
|
||||
|
||||
GObject.signal_handler_unblock (tree_sel,
|
||||
self.tree_selection_changed_handler)
|
||||
|
||||
def do_map (self):
|
||||
self.update ()
|
||||
|
||||
Gtk.ScrolledWindow.do_map (self)
|
||||
|
||||
def selection_change_complete (self, selection):
|
||||
self.needs_update = True
|
||||
|
||||
if self.get_mapped ():
|
||||
self.update ()
|
||||
|
||||
def tree_selection_changed (self, tree_sel):
|
||||
sel = set ()
|
||||
|
||||
for row in self.store:
|
||||
if tree_sel.iter_is_selected (row.iter):
|
||||
id = row[self.store.ID]
|
||||
|
||||
for i in range (len (samples)):
|
||||
if any (marker.id == id for marker in samples[i].markers):
|
||||
sel.add (i)
|
||||
|
||||
selection.select (sel)
|
||||
|
||||
selection.change_complete ()
|
||||
|
||||
class VariablesViewer (Gtk.ScrolledWindow):
|
||||
class Store (Gtk.ListStore):
|
||||
NAME = 0
|
||||
|
@ -3466,6 +3587,11 @@ class LogViewer (Gtk.Window):
|
|||
stack.add_titled (info_viewer, "information", "Information")
|
||||
info_viewer.show ()
|
||||
|
||||
if markers:
|
||||
markers_viewer = MarkersViewer ()
|
||||
stack.add_titled (markers_viewer, "markers", "Markers")
|
||||
markers_viewer.show ()
|
||||
|
||||
vars_viewer = VariablesViewer ()
|
||||
stack.add_titled (vars_viewer, "variables", "Variables")
|
||||
vars_viewer.show ()
|
||||
|
|
Loading…
Reference in New Issue