[gimp] tools: in performance-log-viewer.py, add markers view
- From: Ell <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] tools: in performance-log-viewer.py, add markers view
- Date: Wed, 23 Jan 2019 21:34:24 +0000 (UTC)
commit dafb63fd661d02779b2e9011b5916fb26a8df4b9
Author: Ell <ell_se yahoo com>
Date: Wed Jan 23 16:29:10 2019 -0500
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.
devel-docs/performance-logs/performance-logs.md | 55 +++++----
tools/performance-log-viewer.py | 142 ++++++++++++++++++++++--
2 files changed, 167 insertions(+), 30 deletions(-)
---
diff --git a/devel-docs/performance-logs/performance-logs.md b/devel-docs/performance-logs/performance-logs.md
index efcf433be6..6efff2897e 100644
--- a/devel-docs/performance-logs/performance-logs.md
+++ b/devel-docs/performance-logs/performance-logs.md
@@ -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.
diff --git a/tools/performance-log-viewer.py b/tools/performance-log-viewer.py
index a0f78f2840..50cd7e8a7a 100755
--- a/tools/performance-log-viewer.py
+++ b/tools/performance-log-viewer.py
@@ -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 ()
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]