* [PATCH 0/6] perf scripts python: exported-sql-viewer.py: Minor improvements
@ 2019-05-03 12:08 Adrian Hunter
2019-05-03 12:08 ` [PATCH 1/6] perf scripts python: exported-sql-viewer.py: Fix error when shrinking / enlarging font Adrian Hunter
` (5 more replies)
0 siblings, 6 replies; 17+ messages in thread
From: Adrian Hunter @ 2019-05-03 12:08 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: Jiri Olsa, linux-kernel
Hi
Here are a some minor improvememnts to exported-sql-viewer.py
The patches go on top of the pyside2 support patches, here:
https://lore.kernel.org/lkml/20190412113830.4126-1-adrian.hunter@intel.com
Adrian Hunter (6):
perf scripts python: exported-sql-viewer.py: Fix error when shrinking / enlarging font
perf scripts python: exported-sql-viewer.py: Move view creation
perf scripts python: exported-sql-viewer.py: Add tree level
perf scripts python: exported-sql-viewer.py: Add copy to clipboard
perf scripts python: exported-sql-viewer.py: Add context menu
perf scripts python: exported-sql-viewer.py: Add 'About' dialog box
tools/perf/scripts/python/exported-sql-viewer.py | 340 ++++++++++++++++++++++-
1 file changed, 333 insertions(+), 7 deletions(-)
Regards
Adrian
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 1/6] perf scripts python: exported-sql-viewer.py: Fix error when shrinking / enlarging font
2019-05-03 12:08 [PATCH 0/6] perf scripts python: exported-sql-viewer.py: Minor improvements Adrian Hunter
@ 2019-05-03 12:08 ` Adrian Hunter
2019-05-13 19:57 ` Arnaldo Carvalho de Melo
2019-05-18 8:55 ` [tip:perf/core] " tip-bot for Adrian Hunter
2019-05-03 12:08 ` [PATCH 2/6] perf scripts python: exported-sql-viewer.py: Move view creation Adrian Hunter
` (4 subsequent siblings)
5 siblings, 2 replies; 17+ messages in thread
From: Adrian Hunter @ 2019-05-03 12:08 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: Jiri Olsa, linux-kernel
Fix the following error if shrink / enlarge font is used with the help
window.
Traceback (most recent call last):
File "tools/perf/scripts/python/exported-sql-viewer.py", line 2791, in ShrinkFont
ShrinkFont(win.view)
AttributeError: 'HelpWindow' object has no attribute 'view'
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
tools/perf/scripts/python/exported-sql-viewer.py | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
index c586abfb2b46..289e8dbd1444 100755
--- a/tools/perf/scripts/python/exported-sql-viewer.py
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -2770,6 +2770,14 @@ class MainWindow(QMainWindow):
help_menu = menu.addMenu("&Help")
help_menu.addAction(CreateAction("&Exported SQL Viewer Help", "Helpful information", self.Help, self, QKeySequence.HelpContents))
+ def Try(self, fn):
+ win = self.mdi_area.activeSubWindow()
+ if win:
+ try:
+ fn(win.view)
+ except:
+ pass
+
def Find(self):
win = self.mdi_area.activeSubWindow()
if win:
@@ -2787,12 +2795,10 @@ class MainWindow(QMainWindow):
pass
def ShrinkFont(self):
- win = self.mdi_area.activeSubWindow()
- ShrinkFont(win.view)
+ self.Try(ShrinkFont)
def EnlargeFont(self):
- win = self.mdi_area.activeSubWindow()
- EnlargeFont(win.view)
+ self.Try(EnlargeFont)
def EventMenu(self, events, reports_menu):
branches_events = 0
--
2.17.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 2/6] perf scripts python: exported-sql-viewer.py: Move view creation
2019-05-03 12:08 [PATCH 0/6] perf scripts python: exported-sql-viewer.py: Minor improvements Adrian Hunter
2019-05-03 12:08 ` [PATCH 1/6] perf scripts python: exported-sql-viewer.py: Fix error when shrinking / enlarging font Adrian Hunter
@ 2019-05-03 12:08 ` Adrian Hunter
2019-05-18 8:54 ` [tip:perf/core] " tip-bot for Adrian Hunter
2019-05-03 12:08 ` [PATCH 3/6] perf scripts python: exported-sql-viewer.py: Add tree level Adrian Hunter
` (3 subsequent siblings)
5 siblings, 1 reply; 17+ messages in thread
From: Adrian Hunter @ 2019-05-03 12:08 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: Jiri Olsa, linux-kernel
As preparation for adding support for copying to clipboard, create view in
TreeWindowBase instead of derived classes.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
tools/perf/scripts/python/exported-sql-viewer.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
index 289e8dbd1444..73fc02d6d1e4 100755
--- a/tools/perf/scripts/python/exported-sql-viewer.py
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -891,9 +891,10 @@ class TreeWindowBase(QMdiSubWindow):
super(TreeWindowBase, self).__init__(parent)
self.model = None
- self.view = None
self.find_bar = None
+ self.view = QTreeView()
+
def DisplayFound(self, ids):
if not len(ids):
return False
@@ -935,7 +936,6 @@ class CallGraphWindow(TreeWindowBase):
self.model = LookupCreateModel("Context-Sensitive Call Graph", lambda x=glb: CallGraphModel(x))
- self.view = QTreeView()
self.view.setModel(self.model)
for c, w in ((0, 250), (1, 100), (2, 60), (3, 70), (4, 70), (5, 100)):
@@ -958,7 +958,6 @@ class CallTreeWindow(TreeWindowBase):
self.model = LookupCreateModel("Call Tree", lambda x=glb: CallTreeModel(x))
- self.view = QTreeView()
self.view.setModel(self.model)
for c, w in ((0, 230), (1, 100), (2, 100), (3, 70), (4, 70), (5, 100)):
--
2.17.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 3/6] perf scripts python: exported-sql-viewer.py: Add tree level
2019-05-03 12:08 [PATCH 0/6] perf scripts python: exported-sql-viewer.py: Minor improvements Adrian Hunter
2019-05-03 12:08 ` [PATCH 1/6] perf scripts python: exported-sql-viewer.py: Fix error when shrinking / enlarging font Adrian Hunter
2019-05-03 12:08 ` [PATCH 2/6] perf scripts python: exported-sql-viewer.py: Move view creation Adrian Hunter
@ 2019-05-03 12:08 ` Adrian Hunter
2019-05-18 8:55 ` [tip:perf/core] " tip-bot for Adrian Hunter
2019-05-03 12:08 ` [PATCH 4/6] perf scripts python: exported-sql-viewer.py: Add copy to clipboard Adrian Hunter
` (2 subsequent siblings)
5 siblings, 1 reply; 17+ messages in thread
From: Adrian Hunter @ 2019-05-03 12:08 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: Jiri Olsa, linux-kernel
As preparation for adding support for copying to clipboard, keep track of
what level each item is in tree items.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
tools/perf/scripts/python/exported-sql-viewer.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
index 73fc02d6d1e4..c0fb88d440ba 100755
--- a/tools/perf/scripts/python/exported-sql-viewer.py
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -470,6 +470,10 @@ class CallGraphLevelItemBase(object):
self.query_done = False;
self.child_count = 0
self.child_items = []
+ if parent_item:
+ self.level = parent_item.level + 1
+ else:
+ self.level = 0
def getChildItem(self, row):
return self.child_items[row]
--
2.17.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 4/6] perf scripts python: exported-sql-viewer.py: Add copy to clipboard
2019-05-03 12:08 [PATCH 0/6] perf scripts python: exported-sql-viewer.py: Minor improvements Adrian Hunter
` (2 preceding siblings ...)
2019-05-03 12:08 ` [PATCH 3/6] perf scripts python: exported-sql-viewer.py: Add tree level Adrian Hunter
@ 2019-05-03 12:08 ` Adrian Hunter
2019-05-13 20:03 ` Arnaldo Carvalho de Melo
2019-05-18 8:56 ` [tip:perf/core] " tip-bot for Adrian Hunter
2019-05-03 12:08 ` [PATCH 5/6] perf scripts python: exported-sql-viewer.py: Add context menu Adrian Hunter
2019-05-03 12:08 ` [PATCH 6/6] perf scripts python: exported-sql-viewer.py: Add 'About' dialog box Adrian Hunter
5 siblings, 2 replies; 17+ messages in thread
From: Adrian Hunter @ 2019-05-03 12:08 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: Jiri Olsa, linux-kernel
Add support for copying to clipboard. Two menu options are added to copy the
selected rows / columns with normal spacing, or as comma-separated-values.
In the case of trees, only entire rows can be copied.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
.../scripts/python/exported-sql-viewer.py | 217 ++++++++++++++++++
1 file changed, 217 insertions(+)
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
index c0fb88d440ba..5804d9705ab7 100755
--- a/tools/perf/scripts/python/exported-sql-viewer.py
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -898,6 +898,8 @@ class TreeWindowBase(QMdiSubWindow):
self.find_bar = None
self.view = QTreeView()
+ self.view.setSelectionMode(QAbstractItemView.ContiguousSelection)
+ self.view.CopyCellsToClipboard = CopyTreeCellsToClipboard
def DisplayFound(self, ids):
if not len(ids):
@@ -1666,6 +1668,8 @@ class BranchWindow(QMdiSubWindow):
self.view = QTreeView()
self.view.setUniformRowHeights(True)
+ self.view.setSelectionMode(QAbstractItemView.ContiguousSelection)
+ self.view.CopyCellsToClipboard = CopyTreeCellsToClipboard
self.view.setModel(self.model)
self.ResizeColumnsToContents()
@@ -2278,6 +2282,207 @@ class ResizeColumnsToContentsBase(QObject):
self.data_model.rowsInserted.disconnect(self.UpdateColumnWidths)
self.ResizeColumnsToContents()
+# Convert value to CSV
+
+def ToCSValue(val):
+ if '"' in val:
+ val = val.replace('"', '""')
+ if "," in val or '"' in val:
+ val = '"' + val + '"'
+ return val
+
+# Key to sort table model indexes by row / column, assuming fewer than 1000 columns
+
+glb_max_cols = 1000
+
+def RowColumnKey(a):
+ return a.row() * glb_max_cols + a.column()
+
+# Copy selected table cells to clipboard
+
+def CopyTableCellsToClipboard(view, as_csv=False, with_hdr=False):
+ indexes = sorted(view.selectedIndexes(), key=RowColumnKey)
+ idx_cnt = len(indexes)
+ if not idx_cnt:
+ return
+ if idx_cnt == 1:
+ with_hdr=False
+ min_row = indexes[0].row()
+ max_row = indexes[0].row()
+ min_col = indexes[0].column()
+ max_col = indexes[0].column()
+ for i in indexes:
+ min_row = min(min_row, i.row())
+ max_row = max(max_row, i.row())
+ min_col = min(min_col, i.column())
+ max_col = max(max_col, i.column())
+ if max_col > glb_max_cols:
+ raise RuntimeError("glb_max_cols is too low")
+ max_width = [0] * (1 + max_col - min_col)
+ for i in indexes:
+ c = i.column() - min_col
+ max_width[c] = max(max_width[c], len(str(i.data())))
+ text = ""
+ pad = ""
+ sep = ""
+ if with_hdr:
+ model = indexes[0].model()
+ for col in range(min_col, max_col + 1):
+ val = model.headerData(col, Qt.Horizontal)
+ if as_csv:
+ text += sep + ToCSValue(val)
+ sep = ","
+ else:
+ c = col - min_col
+ max_width[c] = max(max_width[c], len(val))
+ width = max_width[c]
+ align = model.headerData(col, Qt.Horizontal, Qt.TextAlignmentRole)
+ if align & Qt.AlignRight:
+ val = val.rjust(width)
+ text += pad + sep + val
+ pad = " " * (width - len(val))
+ sep = " "
+ text += "\n"
+ pad = ""
+ sep = ""
+ last_row = min_row
+ for i in indexes:
+ if i.row() > last_row:
+ last_row = i.row()
+ text += "\n"
+ pad = ""
+ sep = ""
+ if as_csv:
+ text += sep + ToCSValue(str(i.data()))
+ sep = ","
+ else:
+ width = max_width[i.column() - min_col]
+ if i.data(Qt.TextAlignmentRole) & Qt.AlignRight:
+ val = str(i.data()).rjust(width)
+ else:
+ val = str(i.data())
+ text += pad + sep + val
+ pad = " " * (width - len(val))
+ sep = " "
+ QApplication.clipboard().setText(text)
+
+def CopyTreeCellsToClipboard(view, as_csv=False, with_hdr=False):
+ indexes = view.selectedIndexes()
+ if not len(indexes):
+ return
+
+ selection = view.selectionModel()
+
+ first = None
+ for i in indexes:
+ above = view.indexAbove(i)
+ if not selection.isSelected(above):
+ first = i
+ break
+
+ if first is None:
+ raise RuntimeError("CopyTreeCellsToClipboard internal error")
+
+ model = first.model()
+ row_cnt = 0
+ col_cnt = model.columnCount(first)
+ max_width = [0] * col_cnt
+
+ indent_sz = 2
+ indent_str = " " * indent_sz
+
+ expanded_mark_sz = 2
+ if sys.version_info[0] == 3:
+ expanded_mark = "\u25BC "
+ not_expanded_mark = "\u25B6 "
+ else:
+ expanded_mark = unicode(chr(0xE2) + chr(0x96) + chr(0xBC) + " ", "utf-8")
+ not_expanded_mark = unicode(chr(0xE2) + chr(0x96) + chr(0xB6) + " ", "utf-8")
+ leaf_mark = " "
+
+ if not as_csv:
+ pos = first
+ while True:
+ row_cnt += 1
+ row = pos.row()
+ for c in range(col_cnt):
+ i = pos.sibling(row, c)
+ if c:
+ n = len(str(i.data()))
+ else:
+ n = len(str(i.data()).strip())
+ n += (i.internalPointer().level - 1) * indent_sz
+ n += expanded_mark_sz
+ max_width[c] = max(max_width[c], n)
+ pos = view.indexBelow(pos)
+ if not selection.isSelected(pos):
+ break
+
+ text = ""
+ pad = ""
+ sep = ""
+ if with_hdr:
+ for c in range(col_cnt):
+ val = model.headerData(c, Qt.Horizontal, Qt.DisplayRole).strip()
+ if as_csv:
+ text += sep + ToCSValue(val)
+ sep = ","
+ else:
+ max_width[c] = max(max_width[c], len(val))
+ width = max_width[c]
+ align = model.headerData(c, Qt.Horizontal, Qt.TextAlignmentRole)
+ if align & Qt.AlignRight:
+ val = val.rjust(width)
+ text += pad + sep + val
+ pad = " " * (width - len(val))
+ sep = " "
+ text += "\n"
+ pad = ""
+ sep = ""
+
+ pos = first
+ while True:
+ row = pos.row()
+ for c in range(col_cnt):
+ i = pos.sibling(row, c)
+ val = str(i.data())
+ if not c:
+ if model.hasChildren(i):
+ if view.isExpanded(i):
+ mark = expanded_mark
+ else:
+ mark = not_expanded_mark
+ else:
+ mark = leaf_mark
+ val = indent_str * (i.internalPointer().level - 1) + mark + val.strip()
+ if as_csv:
+ text += sep + ToCSValue(val)
+ sep = ","
+ else:
+ width = max_width[c]
+ if c and i.data(Qt.TextAlignmentRole) & Qt.AlignRight:
+ val = val.rjust(width)
+ text += pad + sep + val
+ pad = " " * (width - len(val))
+ sep = " "
+ pos = view.indexBelow(pos)
+ if not selection.isSelected(pos):
+ break
+ text = text.rstrip() + "\n"
+ pad = ""
+ sep = ""
+
+ QApplication.clipboard().setText(text)
+
+def CopyCellsToClipboard(view, as_csv=False, with_hdr=False):
+ view.CopyCellsToClipboard(view, as_csv, with_hdr)
+
+def CopyCellsToClipboardHdr(view):
+ CopyCellsToClipboard(view, False, True)
+
+def CopyCellsToClipboardCSV(view):
+ CopyCellsToClipboard(view, True, True)
+
# Table window
class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
@@ -2296,6 +2501,8 @@ class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
self.view.verticalHeader().setVisible(False)
self.view.sortByColumn(-1, Qt.AscendingOrder)
self.view.setSortingEnabled(True)
+ self.view.setSelectionMode(QAbstractItemView.ContiguousSelection)
+ self.view.CopyCellsToClipboard = CopyTableCellsToClipboard
self.ResizeColumnsToContents()
@@ -2412,6 +2619,8 @@ class TopCallsWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
self.view.setModel(self.model)
self.view.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.view.verticalHeader().setVisible(False)
+ self.view.setSelectionMode(QAbstractItemView.ContiguousSelection)
+ self.view.CopyCellsToClipboard = CopyTableCellsToClipboard
self.ResizeColumnsToContents()
@@ -2749,6 +2958,8 @@ class MainWindow(QMainWindow):
file_menu.addAction(CreateExitAction(glb.app, self))
edit_menu = menu.addMenu("&Edit")
+ edit_menu.addAction(CreateAction("&Copy", "Copy to clipboard", self.CopyToClipboard, self, QKeySequence.Copy))
+ edit_menu.addAction(CreateAction("Copy as CS&V", "Copy to clipboard as CSV", self.CopyToClipboardCSV, self))
edit_menu.addAction(CreateAction("&Find...", "Find items", self.Find, self, QKeySequence.Find))
edit_menu.addAction(CreateAction("Fetch &more records...", "Fetch more records", self.FetchMoreRecords, self, [QKeySequence(Qt.Key_F8)]))
edit_menu.addAction(CreateAction("&Shrink Font", "Make text smaller", self.ShrinkFont, self, [QKeySequence("Ctrl+-")]))
@@ -2781,6 +2992,12 @@ class MainWindow(QMainWindow):
except:
pass
+ def CopyToClipboard(self):
+ self.Try(CopyCellsToClipboardHdr)
+
+ def CopyToClipboardCSV(self):
+ self.Try(CopyCellsToClipboardCSV)
+
def Find(self):
win = self.mdi_area.activeSubWindow()
if win:
--
2.17.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 5/6] perf scripts python: exported-sql-viewer.py: Add context menu
2019-05-03 12:08 [PATCH 0/6] perf scripts python: exported-sql-viewer.py: Minor improvements Adrian Hunter
` (3 preceding siblings ...)
2019-05-03 12:08 ` [PATCH 4/6] perf scripts python: exported-sql-viewer.py: Add copy to clipboard Adrian Hunter
@ 2019-05-03 12:08 ` Adrian Hunter
2019-05-13 20:09 ` Arnaldo Carvalho de Melo
2019-05-18 8:57 ` [tip:perf/core] " tip-bot for Adrian Hunter
2019-05-03 12:08 ` [PATCH 6/6] perf scripts python: exported-sql-viewer.py: Add 'About' dialog box Adrian Hunter
5 siblings, 2 replies; 17+ messages in thread
From: Adrian Hunter @ 2019-05-03 12:08 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: Jiri Olsa, linux-kernel
Add a context menu (right-click) that provides options for copying to
clipboard, including, for trees, the ability to copy only the cell under
the mouse pointer.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
.../scripts/python/exported-sql-viewer.py | 41 +++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
index 5804d9705ab7..421f3828ea43 100755
--- a/tools/perf/scripts/python/exported-sql-viewer.py
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -901,6 +901,8 @@ class TreeWindowBase(QMdiSubWindow):
self.view.setSelectionMode(QAbstractItemView.ContiguousSelection)
self.view.CopyCellsToClipboard = CopyTreeCellsToClipboard
+ self.context_menu = TreeContextMenu(self.view)
+
def DisplayFound(self, ids):
if not len(ids):
return False
@@ -1674,6 +1676,8 @@ class BranchWindow(QMdiSubWindow):
self.ResizeColumnsToContents()
+ self.context_menu = TreeContextMenu(self.view)
+
self.find_bar = FindBar(self, self, True)
self.finder = ChildDataItemFinder(self.model.root)
@@ -2483,6 +2487,39 @@ def CopyCellsToClipboardHdr(view):
def CopyCellsToClipboardCSV(view):
CopyCellsToClipboard(view, True, True)
+# Context menu
+
+class ContextMenu(object):
+
+ def __init__(self, view):
+ self.view = view
+ self.view.setContextMenuPolicy(Qt.CustomContextMenu)
+ self.view.customContextMenuRequested.connect(self.ShowContextMenu)
+
+ def ShowContextMenu(self, pos):
+ menu = QMenu(self.view)
+ self.AddActions(menu)
+ menu.exec_(self.view.mapToGlobal(pos))
+
+ def AddCopy(self, menu):
+ menu.addAction(CreateAction("&Copy selection", "Copy to clipboard", lambda: CopyCellsToClipboardHdr(self.view), self.view))
+ menu.addAction(CreateAction("Copy selection as CS&V", "Copy to clipboard as CSV", lambda: CopyCellsToClipboardCSV(self.view), self.view))
+
+ def AddActions(self, menu):
+ self.AddCopy(menu)
+
+class TreeContextMenu(ContextMenu):
+
+ def __init__(self, view):
+ super(TreeContextMenu, self).__init__(view)
+
+ def AddActions(self, menu):
+ i = self.view.currentIndex()
+ text = str(i.data()).strip()
+ if len(text):
+ menu.addAction(CreateAction('Copy "' + text + '"', "Copy to clipboard", lambda: QApplication.clipboard().setText(text), self.view))
+ self.AddCopy(menu)
+
# Table window
class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
@@ -2506,6 +2543,8 @@ class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
self.ResizeColumnsToContents()
+ self.context_menu = ContextMenu(self.view)
+
self.find_bar = FindBar(self, self, True)
self.finder = ChildDataItemFinder(self.data_model)
@@ -2622,6 +2661,8 @@ class TopCallsWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
self.view.setSelectionMode(QAbstractItemView.ContiguousSelection)
self.view.CopyCellsToClipboard = CopyTableCellsToClipboard
+ self.context_menu = ContextMenu(self.view)
+
self.ResizeColumnsToContents()
self.find_bar = FindBar(self, self, True)
--
2.17.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 6/6] perf scripts python: exported-sql-viewer.py: Add 'About' dialog box
2019-05-03 12:08 [PATCH 0/6] perf scripts python: exported-sql-viewer.py: Minor improvements Adrian Hunter
` (4 preceding siblings ...)
2019-05-03 12:08 ` [PATCH 5/6] perf scripts python: exported-sql-viewer.py: Add context menu Adrian Hunter
@ 2019-05-03 12:08 ` Adrian Hunter
2019-05-13 20:12 ` Arnaldo Carvalho de Melo
2019-05-18 8:58 ` [tip:perf/core] " tip-bot for Adrian Hunter
5 siblings, 2 replies; 17+ messages in thread
From: Adrian Hunter @ 2019-05-03 12:08 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: Jiri Olsa, linux-kernel
With support for Python 2 or 3 and PySide 1 or 2 (Qt 4 or 5), it is useful
to see what versions are in use. Add an 'About' dialog box that displays
Python, PySide, Qt and database server (SQLite or PostgreSQL) version
numbers.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
.../scripts/python/exported-sql-viewer.py | 59 +++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
index 421f3828ea43..6fe553258ce5 100755
--- a/tools/perf/scripts/python/exported-sql-viewer.py
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -2927,6 +2927,60 @@ class HelpOnlyWindow(QMainWindow):
self.setCentralWidget(self.text)
+# PostqreSQL server version
+
+def PostqreSQLServerVersion(db):
+ query = QSqlQuery(db)
+ QueryExec(query, "SELECT VERSION()")
+ if query.next():
+ v_str = query.value(0)
+ v_list = v_str.strip().split(" ")
+ if v_list[0] == "PostgreSQL" and v_list[2] == "on":
+ return v_list[1]
+ return v_str
+ return "Unknown"
+
+# SQLite version
+
+def SQLiteVersion(db):
+ query = QSqlQuery(db)
+ QueryExec(query, "SELECT sqlite_version()")
+ if query.next():
+ return query.value(0)
+ return "Unknown"
+
+# About dialog
+
+class AboutDialog(QDialog):
+
+ def __init__(self, glb, parent=None):
+ super(AboutDialog, self).__init__(parent)
+
+ self.setWindowTitle("About Exported SQL Viewer")
+ self.setMinimumWidth(300)
+
+ pyside_version = "1" if pyside_version_1 else "2"
+
+ text = "<pre>"
+ text += "Python version: " + sys.version.split(" ")[0] + "\n"
+ text += "PySide version: " + pyside_version + "\n"
+ text += "Qt version: " + qVersion() + "\n"
+ if glb.dbref.is_sqlite3:
+ text += "SQLite version: " + SQLiteVersion(glb.db) + "\n"
+ else:
+ text += "PostqreSQL version: " + PostqreSQLServerVersion(glb.db) + "\n"
+ text += "</pre>"
+
+ self.text = QTextBrowser()
+ self.text.setHtml(text)
+ self.text.setReadOnly(True)
+ self.text.setOpenExternalLinks(True)
+
+ self.vbox = QVBoxLayout()
+ self.vbox.addWidget(self.text)
+
+ self.setLayout(self.vbox);
+
# Font resize
def ResizeFont(widget, diff):
@@ -3024,6 +3078,7 @@ class MainWindow(QMainWindow):
help_menu = menu.addMenu("&Help")
help_menu.addAction(CreateAction("&Exported SQL Viewer Help", "Helpful information", self.Help, self, QKeySequence.HelpContents))
+ help_menu.addAction(CreateAction("&About Exported SQL Viewer", "About this application", self.About, self))
def Try(self, fn):
win = self.mdi_area.activeSubWindow()
@@ -3109,6 +3164,10 @@ class MainWindow(QMainWindow):
def Help(self):
HelpWindow(self.glb, self)
+ def About(self):
+ dialog = AboutDialog(self.glb, self)
+ dialog.exec_()
+
# XED Disassembler
class xed_state_t(Structure):
--
2.17.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 1/6] perf scripts python: exported-sql-viewer.py: Fix error when shrinking / enlarging font
2019-05-03 12:08 ` [PATCH 1/6] perf scripts python: exported-sql-viewer.py: Fix error when shrinking / enlarging font Adrian Hunter
@ 2019-05-13 19:57 ` Arnaldo Carvalho de Melo
2019-05-18 8:55 ` [tip:perf/core] " tip-bot for Adrian Hunter
1 sibling, 0 replies; 17+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-05-13 19:57 UTC (permalink / raw)
To: Adrian Hunter; +Cc: Jiri Olsa, linux-kernel
Em Fri, May 03, 2019 at 03:08:23PM +0300, Adrian Hunter escreveu:
> Fix the following error if shrink / enlarge font is used with the help
> window.
>
> Traceback (most recent call last):
> File "tools/perf/scripts/python/exported-sql-viewer.py", line 2791, in ShrinkFont
> ShrinkFont(win.view)
> AttributeError: 'HelpWindow' object has no attribute 'view'
Humm, this is kinda frustrating, I tried it and expected it to either
enlarge/shrink or tell me that that is not possible, and why :-\
Anyway, if you think this is the best approach, applied.
- Arnaldo
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> tools/perf/scripts/python/exported-sql-viewer.py | 14 ++++++++++----
> 1 file changed, 10 insertions(+), 4 deletions(-)
>
> diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
> index c586abfb2b46..289e8dbd1444 100755
> --- a/tools/perf/scripts/python/exported-sql-viewer.py
> +++ b/tools/perf/scripts/python/exported-sql-viewer.py
> @@ -2770,6 +2770,14 @@ class MainWindow(QMainWindow):
> help_menu = menu.addMenu("&Help")
> help_menu.addAction(CreateAction("&Exported SQL Viewer Help", "Helpful information", self.Help, self, QKeySequence.HelpContents))
>
> + def Try(self, fn):
> + win = self.mdi_area.activeSubWindow()
> + if win:
> + try:
> + fn(win.view)
> + except:
> + pass
> +
> def Find(self):
> win = self.mdi_area.activeSubWindow()
> if win:
> @@ -2787,12 +2795,10 @@ class MainWindow(QMainWindow):
> pass
>
> def ShrinkFont(self):
> - win = self.mdi_area.activeSubWindow()
> - ShrinkFont(win.view)
> + self.Try(ShrinkFont)
>
> def EnlargeFont(self):
> - win = self.mdi_area.activeSubWindow()
> - EnlargeFont(win.view)
> + self.Try(EnlargeFont)
>
> def EventMenu(self, events, reports_menu):
> branches_events = 0
> --
> 2.17.1
--
- Arnaldo
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 4/6] perf scripts python: exported-sql-viewer.py: Add copy to clipboard
2019-05-03 12:08 ` [PATCH 4/6] perf scripts python: exported-sql-viewer.py: Add copy to clipboard Adrian Hunter
@ 2019-05-13 20:03 ` Arnaldo Carvalho de Melo
2019-05-18 8:56 ` [tip:perf/core] " tip-bot for Adrian Hunter
1 sibling, 0 replies; 17+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-05-13 20:03 UTC (permalink / raw)
To: Adrian Hunter; +Cc: Jiri Olsa, linux-kernel, linux-perf-users
Em Fri, May 03, 2019 at 03:08:26PM +0300, Adrian Hunter escreveu:
> Add support for copying to clipboard. Two menu options are added to copy the
> selected rows / columns with normal spacing, or as comma-separated-values.
> In the case of trees, only entire rows can be copied.
Cool, it works:
Comitter testing:
$ python ~acme/libexec/perf-core/scripts/python/exported-sql-viewer.py ~/c/adrian.hunter/simple-retpoline.db
Select the lines, press control+C and on the same terminal,
press control+shift+V and voilà:
Call Path Object Count Time (ns) Time (%) Branch Count Branch Count (%)
▼ 14503:14503
▼ _start ld-2.28.so 1 156267 100.0 10602 100.0
unknown unknown 1 2276 1.5 1 0.0
▼ _dl_start ld-2.28.so 1 137047 87.7 10088 95.2
▶ unknown unknown 4 4127 3.0 4 0.0
_dl_setup_hash ld-2.28.so 1 0 0.0 1 0.0
▶ _dl_sysdep_start ld-2.28.so 1 131342 95.8 9981 98.9
▼ _dl_init ld-2.28.so 1 9142 5.9 326 3.1
▼ call_init.part.0 ld-2.28.so 3 9133 99.9 319 97.9
▶ _init libc-2.28.so 1 6877 75.3 110 34.5
▶ check_stdfiles_vtables libc-2.28.so 1 76 0.8 2 0.6
▶ init_cacheinfo libc-2.28.so 1 1991 21.8 197 61.8
▶ _start simple-retpoline 1 7457 4.8 182 1.7
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> .../scripts/python/exported-sql-viewer.py | 217 ++++++++++++++++++
> 1 file changed, 217 insertions(+)
>
> diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
> index c0fb88d440ba..5804d9705ab7 100755
> --- a/tools/perf/scripts/python/exported-sql-viewer.py
> +++ b/tools/perf/scripts/python/exported-sql-viewer.py
> @@ -898,6 +898,8 @@ class TreeWindowBase(QMdiSubWindow):
> self.find_bar = None
>
> self.view = QTreeView()
> + self.view.setSelectionMode(QAbstractItemView.ContiguousSelection)
> + self.view.CopyCellsToClipboard = CopyTreeCellsToClipboard
>
> def DisplayFound(self, ids):
> if not len(ids):
> @@ -1666,6 +1668,8 @@ class BranchWindow(QMdiSubWindow):
>
> self.view = QTreeView()
> self.view.setUniformRowHeights(True)
> + self.view.setSelectionMode(QAbstractItemView.ContiguousSelection)
> + self.view.CopyCellsToClipboard = CopyTreeCellsToClipboard
> self.view.setModel(self.model)
>
> self.ResizeColumnsToContents()
> @@ -2278,6 +2282,207 @@ class ResizeColumnsToContentsBase(QObject):
> self.data_model.rowsInserted.disconnect(self.UpdateColumnWidths)
> self.ResizeColumnsToContents()
>
> +# Convert value to CSV
> +
> +def ToCSValue(val):
> + if '"' in val:
> + val = val.replace('"', '""')
> + if "," in val or '"' in val:
> + val = '"' + val + '"'
> + return val
> +
> +# Key to sort table model indexes by row / column, assuming fewer than 1000 columns
> +
> +glb_max_cols = 1000
> +
> +def RowColumnKey(a):
> + return a.row() * glb_max_cols + a.column()
> +
> +# Copy selected table cells to clipboard
> +
> +def CopyTableCellsToClipboard(view, as_csv=False, with_hdr=False):
> + indexes = sorted(view.selectedIndexes(), key=RowColumnKey)
> + idx_cnt = len(indexes)
> + if not idx_cnt:
> + return
> + if idx_cnt == 1:
> + with_hdr=False
> + min_row = indexes[0].row()
> + max_row = indexes[0].row()
> + min_col = indexes[0].column()
> + max_col = indexes[0].column()
> + for i in indexes:
> + min_row = min(min_row, i.row())
> + max_row = max(max_row, i.row())
> + min_col = min(min_col, i.column())
> + max_col = max(max_col, i.column())
> + if max_col > glb_max_cols:
> + raise RuntimeError("glb_max_cols is too low")
> + max_width = [0] * (1 + max_col - min_col)
> + for i in indexes:
> + c = i.column() - min_col
> + max_width[c] = max(max_width[c], len(str(i.data())))
> + text = ""
> + pad = ""
> + sep = ""
> + if with_hdr:
> + model = indexes[0].model()
> + for col in range(min_col, max_col + 1):
> + val = model.headerData(col, Qt.Horizontal)
> + if as_csv:
> + text += sep + ToCSValue(val)
> + sep = ","
> + else:
> + c = col - min_col
> + max_width[c] = max(max_width[c], len(val))
> + width = max_width[c]
> + align = model.headerData(col, Qt.Horizontal, Qt.TextAlignmentRole)
> + if align & Qt.AlignRight:
> + val = val.rjust(width)
> + text += pad + sep + val
> + pad = " " * (width - len(val))
> + sep = " "
> + text += "\n"
> + pad = ""
> + sep = ""
> + last_row = min_row
> + for i in indexes:
> + if i.row() > last_row:
> + last_row = i.row()
> + text += "\n"
> + pad = ""
> + sep = ""
> + if as_csv:
> + text += sep + ToCSValue(str(i.data()))
> + sep = ","
> + else:
> + width = max_width[i.column() - min_col]
> + if i.data(Qt.TextAlignmentRole) & Qt.AlignRight:
> + val = str(i.data()).rjust(width)
> + else:
> + val = str(i.data())
> + text += pad + sep + val
> + pad = " " * (width - len(val))
> + sep = " "
> + QApplication.clipboard().setText(text)
> +
> +def CopyTreeCellsToClipboard(view, as_csv=False, with_hdr=False):
> + indexes = view.selectedIndexes()
> + if not len(indexes):
> + return
> +
> + selection = view.selectionModel()
> +
> + first = None
> + for i in indexes:
> + above = view.indexAbove(i)
> + if not selection.isSelected(above):
> + first = i
> + break
> +
> + if first is None:
> + raise RuntimeError("CopyTreeCellsToClipboard internal error")
> +
> + model = first.model()
> + row_cnt = 0
> + col_cnt = model.columnCount(first)
> + max_width = [0] * col_cnt
> +
> + indent_sz = 2
> + indent_str = " " * indent_sz
> +
> + expanded_mark_sz = 2
> + if sys.version_info[0] == 3:
> + expanded_mark = "\u25BC "
> + not_expanded_mark = "\u25B6 "
> + else:
> + expanded_mark = unicode(chr(0xE2) + chr(0x96) + chr(0xBC) + " ", "utf-8")
> + not_expanded_mark = unicode(chr(0xE2) + chr(0x96) + chr(0xB6) + " ", "utf-8")
> + leaf_mark = " "
> +
> + if not as_csv:
> + pos = first
> + while True:
> + row_cnt += 1
> + row = pos.row()
> + for c in range(col_cnt):
> + i = pos.sibling(row, c)
> + if c:
> + n = len(str(i.data()))
> + else:
> + n = len(str(i.data()).strip())
> + n += (i.internalPointer().level - 1) * indent_sz
> + n += expanded_mark_sz
> + max_width[c] = max(max_width[c], n)
> + pos = view.indexBelow(pos)
> + if not selection.isSelected(pos):
> + break
> +
> + text = ""
> + pad = ""
> + sep = ""
> + if with_hdr:
> + for c in range(col_cnt):
> + val = model.headerData(c, Qt.Horizontal, Qt.DisplayRole).strip()
> + if as_csv:
> + text += sep + ToCSValue(val)
> + sep = ","
> + else:
> + max_width[c] = max(max_width[c], len(val))
> + width = max_width[c]
> + align = model.headerData(c, Qt.Horizontal, Qt.TextAlignmentRole)
> + if align & Qt.AlignRight:
> + val = val.rjust(width)
> + text += pad + sep + val
> + pad = " " * (width - len(val))
> + sep = " "
> + text += "\n"
> + pad = ""
> + sep = ""
> +
> + pos = first
> + while True:
> + row = pos.row()
> + for c in range(col_cnt):
> + i = pos.sibling(row, c)
> + val = str(i.data())
> + if not c:
> + if model.hasChildren(i):
> + if view.isExpanded(i):
> + mark = expanded_mark
> + else:
> + mark = not_expanded_mark
> + else:
> + mark = leaf_mark
> + val = indent_str * (i.internalPointer().level - 1) + mark + val.strip()
> + if as_csv:
> + text += sep + ToCSValue(val)
> + sep = ","
> + else:
> + width = max_width[c]
> + if c and i.data(Qt.TextAlignmentRole) & Qt.AlignRight:
> + val = val.rjust(width)
> + text += pad + sep + val
> + pad = " " * (width - len(val))
> + sep = " "
> + pos = view.indexBelow(pos)
> + if not selection.isSelected(pos):
> + break
> + text = text.rstrip() + "\n"
> + pad = ""
> + sep = ""
> +
> + QApplication.clipboard().setText(text)
> +
> +def CopyCellsToClipboard(view, as_csv=False, with_hdr=False):
> + view.CopyCellsToClipboard(view, as_csv, with_hdr)
> +
> +def CopyCellsToClipboardHdr(view):
> + CopyCellsToClipboard(view, False, True)
> +
> +def CopyCellsToClipboardCSV(view):
> + CopyCellsToClipboard(view, True, True)
> +
> # Table window
>
> class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
> @@ -2296,6 +2501,8 @@ class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
> self.view.verticalHeader().setVisible(False)
> self.view.sortByColumn(-1, Qt.AscendingOrder)
> self.view.setSortingEnabled(True)
> + self.view.setSelectionMode(QAbstractItemView.ContiguousSelection)
> + self.view.CopyCellsToClipboard = CopyTableCellsToClipboard
>
> self.ResizeColumnsToContents()
>
> @@ -2412,6 +2619,8 @@ class TopCallsWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
> self.view.setModel(self.model)
> self.view.setEditTriggers(QAbstractItemView.NoEditTriggers)
> self.view.verticalHeader().setVisible(False)
> + self.view.setSelectionMode(QAbstractItemView.ContiguousSelection)
> + self.view.CopyCellsToClipboard = CopyTableCellsToClipboard
>
> self.ResizeColumnsToContents()
>
> @@ -2749,6 +2958,8 @@ class MainWindow(QMainWindow):
> file_menu.addAction(CreateExitAction(glb.app, self))
>
> edit_menu = menu.addMenu("&Edit")
> + edit_menu.addAction(CreateAction("&Copy", "Copy to clipboard", self.CopyToClipboard, self, QKeySequence.Copy))
> + edit_menu.addAction(CreateAction("Copy as CS&V", "Copy to clipboard as CSV", self.CopyToClipboardCSV, self))
> edit_menu.addAction(CreateAction("&Find...", "Find items", self.Find, self, QKeySequence.Find))
> edit_menu.addAction(CreateAction("Fetch &more records...", "Fetch more records", self.FetchMoreRecords, self, [QKeySequence(Qt.Key_F8)]))
> edit_menu.addAction(CreateAction("&Shrink Font", "Make text smaller", self.ShrinkFont, self, [QKeySequence("Ctrl+-")]))
> @@ -2781,6 +2992,12 @@ class MainWindow(QMainWindow):
> except:
> pass
>
> + def CopyToClipboard(self):
> + self.Try(CopyCellsToClipboardHdr)
> +
> + def CopyToClipboardCSV(self):
> + self.Try(CopyCellsToClipboardCSV)
> +
> def Find(self):
> win = self.mdi_area.activeSubWindow()
> if win:
> --
> 2.17.1
--
- Arnaldo
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 5/6] perf scripts python: exported-sql-viewer.py: Add context menu
2019-05-03 12:08 ` [PATCH 5/6] perf scripts python: exported-sql-viewer.py: Add context menu Adrian Hunter
@ 2019-05-13 20:09 ` Arnaldo Carvalho de Melo
2019-05-18 8:57 ` [tip:perf/core] " tip-bot for Adrian Hunter
1 sibling, 0 replies; 17+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-05-13 20:09 UTC (permalink / raw)
To: Adrian Hunter; +Cc: Jiri Olsa, linux-kernel
Em Fri, May 03, 2019 at 03:08:27PM +0300, Adrian Hunter escreveu:
> Add a context menu (right-click) that provides options for copying to
> clipboard, including, for trees, the ability to copy only the cell under
> the mouse pointer.
Works as well:
Committer testing:
$ python ~acme/libexec/perf-core/scripts/python/exported-sql-viewer.py ~/c/adrian.hunter/simple-retpoline.db
Simply right click and pick "Copy selection", that at this point has
just the first line, not expanded, then see what was copied by pressing
shift+control+v on a terminal:
Call Path,Object,Count,Time (ns),Time (%),Branch Count,Branch Count (%)
▶ simple-retpolin,,,,,,
Ditto after expanding, i.e. the selection continues to be just one
line:
Call Path Object Count Time (ns) Time (%) Branch Count Branch Count (%)
▼ simple-retpolin
Now select all the lines with the mouse and control+shift+v again:
Call Path Object Count Time (ns) Time (%) Branch Count Branch Count (%)
▼ 14503:14503
▼ _start ld-2.28.so 1 156267 100.0 10602 100.0
▶ unknown unknown 1 2276 1.5 1 0.0
▶ _dl_start ld-2.28.so 1 137047 87.7 10088 95.2
▶ _dl_init ld-2.28.so 1 9142 5.9 326 3.1
▼ _start simple-retpoline 1 7457 4.8 182 1.7
▶ unknown unknown 1 805 10.8 1 0.5
▶ __libc_start_main libc-2.28.so 1 6347 85.1 179 98.4
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> .../scripts/python/exported-sql-viewer.py | 41 +++++++++++++++++++
> 1 file changed, 41 insertions(+)
>
> diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
> index 5804d9705ab7..421f3828ea43 100755
> --- a/tools/perf/scripts/python/exported-sql-viewer.py
> +++ b/tools/perf/scripts/python/exported-sql-viewer.py
> @@ -901,6 +901,8 @@ class TreeWindowBase(QMdiSubWindow):
> self.view.setSelectionMode(QAbstractItemView.ContiguousSelection)
> self.view.CopyCellsToClipboard = CopyTreeCellsToClipboard
>
> + self.context_menu = TreeContextMenu(self.view)
> +
> def DisplayFound(self, ids):
> if not len(ids):
> return False
> @@ -1674,6 +1676,8 @@ class BranchWindow(QMdiSubWindow):
>
> self.ResizeColumnsToContents()
>
> + self.context_menu = TreeContextMenu(self.view)
> +
> self.find_bar = FindBar(self, self, True)
>
> self.finder = ChildDataItemFinder(self.model.root)
> @@ -2483,6 +2487,39 @@ def CopyCellsToClipboardHdr(view):
> def CopyCellsToClipboardCSV(view):
> CopyCellsToClipboard(view, True, True)
>
> +# Context menu
> +
> +class ContextMenu(object):
> +
> + def __init__(self, view):
> + self.view = view
> + self.view.setContextMenuPolicy(Qt.CustomContextMenu)
> + self.view.customContextMenuRequested.connect(self.ShowContextMenu)
> +
> + def ShowContextMenu(self, pos):
> + menu = QMenu(self.view)
> + self.AddActions(menu)
> + menu.exec_(self.view.mapToGlobal(pos))
> +
> + def AddCopy(self, menu):
> + menu.addAction(CreateAction("&Copy selection", "Copy to clipboard", lambda: CopyCellsToClipboardHdr(self.view), self.view))
> + menu.addAction(CreateAction("Copy selection as CS&V", "Copy to clipboard as CSV", lambda: CopyCellsToClipboardCSV(self.view), self.view))
> +
> + def AddActions(self, menu):
> + self.AddCopy(menu)
> +
> +class TreeContextMenu(ContextMenu):
> +
> + def __init__(self, view):
> + super(TreeContextMenu, self).__init__(view)
> +
> + def AddActions(self, menu):
> + i = self.view.currentIndex()
> + text = str(i.data()).strip()
> + if len(text):
> + menu.addAction(CreateAction('Copy "' + text + '"', "Copy to clipboard", lambda: QApplication.clipboard().setText(text), self.view))
> + self.AddCopy(menu)
> +
> # Table window
>
> class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
> @@ -2506,6 +2543,8 @@ class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
>
> self.ResizeColumnsToContents()
>
> + self.context_menu = ContextMenu(self.view)
> +
> self.find_bar = FindBar(self, self, True)
>
> self.finder = ChildDataItemFinder(self.data_model)
> @@ -2622,6 +2661,8 @@ class TopCallsWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
> self.view.setSelectionMode(QAbstractItemView.ContiguousSelection)
> self.view.CopyCellsToClipboard = CopyTableCellsToClipboard
>
> + self.context_menu = ContextMenu(self.view)
> +
> self.ResizeColumnsToContents()
>
> self.find_bar = FindBar(self, self, True)
> --
> 2.17.1
--
- Arnaldo
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 6/6] perf scripts python: exported-sql-viewer.py: Add 'About' dialog box
2019-05-03 12:08 ` [PATCH 6/6] perf scripts python: exported-sql-viewer.py: Add 'About' dialog box Adrian Hunter
@ 2019-05-13 20:12 ` Arnaldo Carvalho de Melo
2019-05-18 8:58 ` [tip:perf/core] " tip-bot for Adrian Hunter
1 sibling, 0 replies; 17+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-05-13 20:12 UTC (permalink / raw)
To: Adrian Hunter; +Cc: Jiri Olsa, linux-kernel
Em Fri, May 03, 2019 at 03:08:28PM +0300, Adrian Hunter escreveu:
> With support for Python 2 or 3 and PySide 1 or 2 (Qt 4 or 5), it is useful
> to see what versions are in use. Add an 'About' dialog box that displays
> Python, PySide, Qt and database server (SQLite or PostgreSQL) version
> numbers.
Works as well, here:
Committer testing:
$ python ~acme/libexec/perf-core/scripts/python/exported-sql-viewer.py ~/c/adrian.hunter/simple-retpoline.db
Then go to 'Help', then 'About', select all the lines with the mouse
press 'Control+C', then, on the same terminal press control+shift+V
which shows my current environment:
Python version: 2.7.16
PySide version: 1
Qt version: 4.8.7
SQLite version: 3.26.0
-------------------
Patchkit applied, thanks.
- Arnaldo
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> .../scripts/python/exported-sql-viewer.py | 59 +++++++++++++++++++
> 1 file changed, 59 insertions(+)
>
> diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
> index 421f3828ea43..6fe553258ce5 100755
> --- a/tools/perf/scripts/python/exported-sql-viewer.py
> +++ b/tools/perf/scripts/python/exported-sql-viewer.py
> @@ -2927,6 +2927,60 @@ class HelpOnlyWindow(QMainWindow):
>
> self.setCentralWidget(self.text)
>
> +# PostqreSQL server version
> +
> +def PostqreSQLServerVersion(db):
> + query = QSqlQuery(db)
> + QueryExec(query, "SELECT VERSION()")
> + if query.next():
> + v_str = query.value(0)
> + v_list = v_str.strip().split(" ")
> + if v_list[0] == "PostgreSQL" and v_list[2] == "on":
> + return v_list[1]
> + return v_str
> + return "Unknown"
> +
> +# SQLite version
> +
> +def SQLiteVersion(db):
> + query = QSqlQuery(db)
> + QueryExec(query, "SELECT sqlite_version()")
> + if query.next():
> + return query.value(0)
> + return "Unknown"
> +
> +# About dialog
> +
> +class AboutDialog(QDialog):
> +
> + def __init__(self, glb, parent=None):
> + super(AboutDialog, self).__init__(parent)
> +
> + self.setWindowTitle("About Exported SQL Viewer")
> + self.setMinimumWidth(300)
> +
> + pyside_version = "1" if pyside_version_1 else "2"
> +
> + text = "<pre>"
> + text += "Python version: " + sys.version.split(" ")[0] + "\n"
> + text += "PySide version: " + pyside_version + "\n"
> + text += "Qt version: " + qVersion() + "\n"
> + if glb.dbref.is_sqlite3:
> + text += "SQLite version: " + SQLiteVersion(glb.db) + "\n"
> + else:
> + text += "PostqreSQL version: " + PostqreSQLServerVersion(glb.db) + "\n"
> + text += "</pre>"
> +
> + self.text = QTextBrowser()
> + self.text.setHtml(text)
> + self.text.setReadOnly(True)
> + self.text.setOpenExternalLinks(True)
> +
> + self.vbox = QVBoxLayout()
> + self.vbox.addWidget(self.text)
> +
> + self.setLayout(self.vbox);
> +
> # Font resize
>
> def ResizeFont(widget, diff):
> @@ -3024,6 +3078,7 @@ class MainWindow(QMainWindow):
>
> help_menu = menu.addMenu("&Help")
> help_menu.addAction(CreateAction("&Exported SQL Viewer Help", "Helpful information", self.Help, self, QKeySequence.HelpContents))
> + help_menu.addAction(CreateAction("&About Exported SQL Viewer", "About this application", self.About, self))
>
> def Try(self, fn):
> win = self.mdi_area.activeSubWindow()
> @@ -3109,6 +3164,10 @@ class MainWindow(QMainWindow):
> def Help(self):
> HelpWindow(self.glb, self)
>
> + def About(self):
> + dialog = AboutDialog(self.glb, self)
> + dialog.exec_()
> +
> # XED Disassembler
>
> class xed_state_t(Structure):
> --
> 2.17.1
--
- Arnaldo
^ permalink raw reply [flat|nested] 17+ messages in thread
* [tip:perf/core] perf scripts python: exported-sql-viewer.py: Move view creation
2019-05-03 12:08 ` [PATCH 2/6] perf scripts python: exported-sql-viewer.py: Move view creation Adrian Hunter
@ 2019-05-18 8:54 ` tip-bot for Adrian Hunter
0 siblings, 0 replies; 17+ messages in thread
From: tip-bot for Adrian Hunter @ 2019-05-18 8:54 UTC (permalink / raw)
To: linux-tip-commits
Cc: jolsa, hpa, acme, mingo, adrian.hunter, tglx, linux-kernel
Commit-ID: be6e747136a4dc8aad99259e47fd6f7362a43996
Gitweb: https://git.kernel.org/tip/be6e747136a4dc8aad99259e47fd6f7362a43996
Author: Adrian Hunter <adrian.hunter@intel.com>
AuthorDate: Fri, 3 May 2019 15:08:24 +0300
Committer: Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Wed, 15 May 2019 16:36:47 -0300
perf scripts python: exported-sql-viewer.py: Move view creation
As preparation for adding support for copying to clipboard, create view
in TreeWindowBase instead of derived classes.
Committer testing:
Tested using an old .db used to test some older patches:
$ python ~acme/libexec/perf-core/scripts/python/exported-sql-viewer.py ~/c/adrian.hunter/simple-retpoline.db
Nothing breaks.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: http://lkml.kernel.org/r/20190503120828.25326-3-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/scripts/python/exported-sql-viewer.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
index 74ef92f1d19a..db4655168ab1 100755
--- a/tools/perf/scripts/python/exported-sql-viewer.py
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -877,9 +877,10 @@ class TreeWindowBase(QMdiSubWindow):
super(TreeWindowBase, self).__init__(parent)
self.model = None
- self.view = None
self.find_bar = None
+ self.view = QTreeView()
+
def DisplayFound(self, ids):
if not len(ids):
return False
@@ -921,7 +922,6 @@ class CallGraphWindow(TreeWindowBase):
self.model = LookupCreateModel("Context-Sensitive Call Graph", lambda x=glb: CallGraphModel(x))
- self.view = QTreeView()
self.view.setModel(self.model)
for c, w in ((0, 250), (1, 100), (2, 60), (3, 70), (4, 70), (5, 100)):
@@ -944,7 +944,6 @@ class CallTreeWindow(TreeWindowBase):
self.model = LookupCreateModel("Call Tree", lambda x=glb: CallTreeModel(x))
- self.view = QTreeView()
self.view.setModel(self.model)
for c, w in ((0, 230), (1, 100), (2, 100), (3, 70), (4, 70), (5, 100)):
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [tip:perf/core] perf scripts python: exported-sql-viewer.py: Fix error when shrinking / enlarging font
2019-05-03 12:08 ` [PATCH 1/6] perf scripts python: exported-sql-viewer.py: Fix error when shrinking / enlarging font Adrian Hunter
2019-05-13 19:57 ` Arnaldo Carvalho de Melo
@ 2019-05-18 8:55 ` tip-bot for Adrian Hunter
1 sibling, 0 replies; 17+ messages in thread
From: tip-bot for Adrian Hunter @ 2019-05-18 8:55 UTC (permalink / raw)
To: linux-tip-commits
Cc: mingo, tglx, adrian.hunter, linux-kernel, acme, hpa, jolsa
Commit-ID: 4b2084537e5f3b58337bce894391fb63bf3b0e28
Gitweb: https://git.kernel.org/tip/4b2084537e5f3b58337bce894391fb63bf3b0e28
Author: Adrian Hunter <adrian.hunter@intel.com>
AuthorDate: Fri, 3 May 2019 15:08:23 +0300
Committer: Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Wed, 15 May 2019 16:36:47 -0300
perf scripts python: exported-sql-viewer.py: Fix error when shrinking / enlarging font
Fix the following error if shrink / enlarge font is used with the help
window.
Traceback (most recent call last):
File "tools/perf/scripts/python/exported-sql-viewer.py", line 2791, in ShrinkFont
ShrinkFont(win.view)
AttributeError: 'HelpWindow' object has no attribute 'view'
Committer testing:
Before, matches above output:
$ python ~acme/libexec/perf-core/scripts/python/exported-sql-viewer.py ~/c/adrian.hunter/simple-retpoline.db
Traceback (most recent call last):
File "/home/acme/libexec/perf-core/scripts/python/exported-sql-viewer.py", line 2780, in EnlargeFont
EnlargeFont(win.view)
AttributeError: 'HelpWindow' object has no attribute 'view'
$
After:
No more tracebacks, but the fonts don't get enlarged, which is kinda
frustrating...
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: http://lkml.kernel.org/r/20190503120828.25326-2-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/scripts/python/exported-sql-viewer.py | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
index db4655168ab1..fd073e4af8da 100755
--- a/tools/perf/scripts/python/exported-sql-viewer.py
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -2755,6 +2755,14 @@ class MainWindow(QMainWindow):
help_menu = menu.addMenu("&Help")
help_menu.addAction(CreateAction("&Exported SQL Viewer Help", "Helpful information", self.Help, self, QKeySequence.HelpContents))
+ def Try(self, fn):
+ win = self.mdi_area.activeSubWindow()
+ if win:
+ try:
+ fn(win.view)
+ except:
+ pass
+
def Find(self):
win = self.mdi_area.activeSubWindow()
if win:
@@ -2772,12 +2780,10 @@ class MainWindow(QMainWindow):
pass
def ShrinkFont(self):
- win = self.mdi_area.activeSubWindow()
- ShrinkFont(win.view)
+ self.Try(ShrinkFont)
def EnlargeFont(self):
- win = self.mdi_area.activeSubWindow()
- EnlargeFont(win.view)
+ self.Try(EnlargeFont)
def EventMenu(self, events, reports_menu):
branches_events = 0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [tip:perf/core] perf scripts python: exported-sql-viewer.py: Add tree level
2019-05-03 12:08 ` [PATCH 3/6] perf scripts python: exported-sql-viewer.py: Add tree level Adrian Hunter
@ 2019-05-18 8:55 ` tip-bot for Adrian Hunter
0 siblings, 0 replies; 17+ messages in thread
From: tip-bot for Adrian Hunter @ 2019-05-18 8:55 UTC (permalink / raw)
To: linux-tip-commits
Cc: linux-kernel, mingo, acme, jolsa, tglx, hpa, adrian.hunter
Commit-ID: 3ac641f4acd66c109b74f108f8a61f2905702b10
Gitweb: https://git.kernel.org/tip/3ac641f4acd66c109b74f108f8a61f2905702b10
Author: Adrian Hunter <adrian.hunter@intel.com>
AuthorDate: Fri, 3 May 2019 15:08:25 +0300
Committer: Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Wed, 15 May 2019 16:36:47 -0300
perf scripts python: exported-sql-viewer.py: Add tree level
As preparation for adding support for copying to clipboard, keep track of
what level each item is in tree items.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: http://lkml.kernel.org/r/20190503120828.25326-4-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/scripts/python/exported-sql-viewer.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
index fd073e4af8da..48953257a1f0 100755
--- a/tools/perf/scripts/python/exported-sql-viewer.py
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -456,6 +456,10 @@ class CallGraphLevelItemBase(object):
self.query_done = False;
self.child_count = 0
self.child_items = []
+ if parent_item:
+ self.level = parent_item.level + 1
+ else:
+ self.level = 0
def getChildItem(self, row):
return self.child_items[row]
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [tip:perf/core] perf scripts python: exported-sql-viewer.py: Add copy to clipboard
2019-05-03 12:08 ` [PATCH 4/6] perf scripts python: exported-sql-viewer.py: Add copy to clipboard Adrian Hunter
2019-05-13 20:03 ` Arnaldo Carvalho de Melo
@ 2019-05-18 8:56 ` tip-bot for Adrian Hunter
1 sibling, 0 replies; 17+ messages in thread
From: tip-bot for Adrian Hunter @ 2019-05-18 8:56 UTC (permalink / raw)
To: linux-tip-commits
Cc: jolsa, acme, adrian.hunter, mingo, tglx, hpa, linux-kernel
Commit-ID: 96c43b9a7ab3b70bc35d762f7b76082dfd118a6a
Gitweb: https://git.kernel.org/tip/96c43b9a7ab3b70bc35d762f7b76082dfd118a6a
Author: Adrian Hunter <adrian.hunter@intel.com>
AuthorDate: Fri, 3 May 2019 15:08:26 +0300
Committer: Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Wed, 15 May 2019 16:36:47 -0300
perf scripts python: exported-sql-viewer.py: Add copy to clipboard
Add support for copying to clipboard. Two menu options are added to copy the
selected rows / columns with normal spacing, or as comma-separated-values.
In the case of trees, only entire rows can be copied.
Comitter testing:
$ python ~acme/libexec/perf-core/scripts/python/exported-sql-viewer.py ~/c/adrian.hunter/simple-retpoline.db
Select the lines, press control+C and on the same terminal,
press control+shift+V and voilà:
Call Path Object Count Time (ns) Time (%) Branch Count Branch Count (%)
▼ 14503:14503
▼ _start ld-2.28.so 1 156267 100.0 10602 100.0
unknown unknown 1 2276 1.5 1 0.0
▼ _dl_start ld-2.28.so 1 137047 87.7 10088 95.2
▶ unknown unknown 4 4127 3.0 4 0.0
_dl_setup_hash ld-2.28.so 1 0 0.0 1 0.0
▶ _dl_sysdep_start ld-2.28.so 1 131342 95.8 9981 98.9
▼ _dl_init ld-2.28.so 1 9142 5.9 326 3.1
▼ call_init.part.0 ld-2.28.so 3 9133 99.9 319 97.9
▶ _init libc-2.28.so 1 6877 75.3 110 34.5
▶ check_stdfiles_vtables libc-2.28.so 1 76 0.8 2 0.6
▶ init_cacheinfo libc-2.28.so 1 1991 21.8 197 61.8
▶ _start simple-retpoline 1 7457 4.8 182 1.7
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: http://lkml.kernel.org/r/20190503120828.25326-5-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/scripts/python/exported-sql-viewer.py | 217 +++++++++++++++++++++++
1 file changed, 217 insertions(+)
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
index 48953257a1f0..baa2b220238a 100755
--- a/tools/perf/scripts/python/exported-sql-viewer.py
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -884,6 +884,8 @@ class TreeWindowBase(QMdiSubWindow):
self.find_bar = None
self.view = QTreeView()
+ self.view.setSelectionMode(QAbstractItemView.ContiguousSelection)
+ self.view.CopyCellsToClipboard = CopyTreeCellsToClipboard
def DisplayFound(self, ids):
if not len(ids):
@@ -1652,6 +1654,8 @@ class BranchWindow(QMdiSubWindow):
self.view = QTreeView()
self.view.setUniformRowHeights(True)
+ self.view.setSelectionMode(QAbstractItemView.ContiguousSelection)
+ self.view.CopyCellsToClipboard = CopyTreeCellsToClipboard
self.view.setModel(self.model)
self.ResizeColumnsToContents()
@@ -2264,6 +2268,207 @@ class ResizeColumnsToContentsBase(QObject):
self.data_model.rowsInserted.disconnect(self.UpdateColumnWidths)
self.ResizeColumnsToContents()
+# Convert value to CSV
+
+def ToCSValue(val):
+ if '"' in val:
+ val = val.replace('"', '""')
+ if "," in val or '"' in val:
+ val = '"' + val + '"'
+ return val
+
+# Key to sort table model indexes by row / column, assuming fewer than 1000 columns
+
+glb_max_cols = 1000
+
+def RowColumnKey(a):
+ return a.row() * glb_max_cols + a.column()
+
+# Copy selected table cells to clipboard
+
+def CopyTableCellsToClipboard(view, as_csv=False, with_hdr=False):
+ indexes = sorted(view.selectedIndexes(), key=RowColumnKey)
+ idx_cnt = len(indexes)
+ if not idx_cnt:
+ return
+ if idx_cnt == 1:
+ with_hdr=False
+ min_row = indexes[0].row()
+ max_row = indexes[0].row()
+ min_col = indexes[0].column()
+ max_col = indexes[0].column()
+ for i in indexes:
+ min_row = min(min_row, i.row())
+ max_row = max(max_row, i.row())
+ min_col = min(min_col, i.column())
+ max_col = max(max_col, i.column())
+ if max_col > glb_max_cols:
+ raise RuntimeError("glb_max_cols is too low")
+ max_width = [0] * (1 + max_col - min_col)
+ for i in indexes:
+ c = i.column() - min_col
+ max_width[c] = max(max_width[c], len(str(i.data())))
+ text = ""
+ pad = ""
+ sep = ""
+ if with_hdr:
+ model = indexes[0].model()
+ for col in range(min_col, max_col + 1):
+ val = model.headerData(col, Qt.Horizontal)
+ if as_csv:
+ text += sep + ToCSValue(val)
+ sep = ","
+ else:
+ c = col - min_col
+ max_width[c] = max(max_width[c], len(val))
+ width = max_width[c]
+ align = model.headerData(col, Qt.Horizontal, Qt.TextAlignmentRole)
+ if align & Qt.AlignRight:
+ val = val.rjust(width)
+ text += pad + sep + val
+ pad = " " * (width - len(val))
+ sep = " "
+ text += "\n"
+ pad = ""
+ sep = ""
+ last_row = min_row
+ for i in indexes:
+ if i.row() > last_row:
+ last_row = i.row()
+ text += "\n"
+ pad = ""
+ sep = ""
+ if as_csv:
+ text += sep + ToCSValue(str(i.data()))
+ sep = ","
+ else:
+ width = max_width[i.column() - min_col]
+ if i.data(Qt.TextAlignmentRole) & Qt.AlignRight:
+ val = str(i.data()).rjust(width)
+ else:
+ val = str(i.data())
+ text += pad + sep + val
+ pad = " " * (width - len(val))
+ sep = " "
+ QApplication.clipboard().setText(text)
+
+def CopyTreeCellsToClipboard(view, as_csv=False, with_hdr=False):
+ indexes = view.selectedIndexes()
+ if not len(indexes):
+ return
+
+ selection = view.selectionModel()
+
+ first = None
+ for i in indexes:
+ above = view.indexAbove(i)
+ if not selection.isSelected(above):
+ first = i
+ break
+
+ if first is None:
+ raise RuntimeError("CopyTreeCellsToClipboard internal error")
+
+ model = first.model()
+ row_cnt = 0
+ col_cnt = model.columnCount(first)
+ max_width = [0] * col_cnt
+
+ indent_sz = 2
+ indent_str = " " * indent_sz
+
+ expanded_mark_sz = 2
+ if sys.version_info[0] == 3:
+ expanded_mark = "\u25BC "
+ not_expanded_mark = "\u25B6 "
+ else:
+ expanded_mark = unicode(chr(0xE2) + chr(0x96) + chr(0xBC) + " ", "utf-8")
+ not_expanded_mark = unicode(chr(0xE2) + chr(0x96) + chr(0xB6) + " ", "utf-8")
+ leaf_mark = " "
+
+ if not as_csv:
+ pos = first
+ while True:
+ row_cnt += 1
+ row = pos.row()
+ for c in range(col_cnt):
+ i = pos.sibling(row, c)
+ if c:
+ n = len(str(i.data()))
+ else:
+ n = len(str(i.data()).strip())
+ n += (i.internalPointer().level - 1) * indent_sz
+ n += expanded_mark_sz
+ max_width[c] = max(max_width[c], n)
+ pos = view.indexBelow(pos)
+ if not selection.isSelected(pos):
+ break
+
+ text = ""
+ pad = ""
+ sep = ""
+ if with_hdr:
+ for c in range(col_cnt):
+ val = model.headerData(c, Qt.Horizontal, Qt.DisplayRole).strip()
+ if as_csv:
+ text += sep + ToCSValue(val)
+ sep = ","
+ else:
+ max_width[c] = max(max_width[c], len(val))
+ width = max_width[c]
+ align = model.headerData(c, Qt.Horizontal, Qt.TextAlignmentRole)
+ if align & Qt.AlignRight:
+ val = val.rjust(width)
+ text += pad + sep + val
+ pad = " " * (width - len(val))
+ sep = " "
+ text += "\n"
+ pad = ""
+ sep = ""
+
+ pos = first
+ while True:
+ row = pos.row()
+ for c in range(col_cnt):
+ i = pos.sibling(row, c)
+ val = str(i.data())
+ if not c:
+ if model.hasChildren(i):
+ if view.isExpanded(i):
+ mark = expanded_mark
+ else:
+ mark = not_expanded_mark
+ else:
+ mark = leaf_mark
+ val = indent_str * (i.internalPointer().level - 1) + mark + val.strip()
+ if as_csv:
+ text += sep + ToCSValue(val)
+ sep = ","
+ else:
+ width = max_width[c]
+ if c and i.data(Qt.TextAlignmentRole) & Qt.AlignRight:
+ val = val.rjust(width)
+ text += pad + sep + val
+ pad = " " * (width - len(val))
+ sep = " "
+ pos = view.indexBelow(pos)
+ if not selection.isSelected(pos):
+ break
+ text = text.rstrip() + "\n"
+ pad = ""
+ sep = ""
+
+ QApplication.clipboard().setText(text)
+
+def CopyCellsToClipboard(view, as_csv=False, with_hdr=False):
+ view.CopyCellsToClipboard(view, as_csv, with_hdr)
+
+def CopyCellsToClipboardHdr(view):
+ CopyCellsToClipboard(view, False, True)
+
+def CopyCellsToClipboardCSV(view):
+ CopyCellsToClipboard(view, True, True)
+
# Table window
class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
@@ -2282,6 +2487,8 @@ class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
self.view.verticalHeader().setVisible(False)
self.view.sortByColumn(-1, Qt.AscendingOrder)
self.view.setSortingEnabled(True)
+ self.view.setSelectionMode(QAbstractItemView.ContiguousSelection)
+ self.view.CopyCellsToClipboard = CopyTableCellsToClipboard
self.ResizeColumnsToContents()
@@ -2398,6 +2605,8 @@ class TopCallsWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
self.view.setModel(self.model)
self.view.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.view.verticalHeader().setVisible(False)
+ self.view.setSelectionMode(QAbstractItemView.ContiguousSelection)
+ self.view.CopyCellsToClipboard = CopyTableCellsToClipboard
self.ResizeColumnsToContents()
@@ -2735,6 +2944,8 @@ class MainWindow(QMainWindow):
file_menu.addAction(CreateExitAction(glb.app, self))
edit_menu = menu.addMenu("&Edit")
+ edit_menu.addAction(CreateAction("&Copy", "Copy to clipboard", self.CopyToClipboard, self, QKeySequence.Copy))
+ edit_menu.addAction(CreateAction("Copy as CS&V", "Copy to clipboard as CSV", self.CopyToClipboardCSV, self))
edit_menu.addAction(CreateAction("&Find...", "Find items", self.Find, self, QKeySequence.Find))
edit_menu.addAction(CreateAction("Fetch &more records...", "Fetch more records", self.FetchMoreRecords, self, [QKeySequence(Qt.Key_F8)]))
edit_menu.addAction(CreateAction("&Shrink Font", "Make text smaller", self.ShrinkFont, self, [QKeySequence("Ctrl+-")]))
@@ -2767,6 +2978,12 @@ class MainWindow(QMainWindow):
except:
pass
+ def CopyToClipboard(self):
+ self.Try(CopyCellsToClipboardHdr)
+
+ def CopyToClipboardCSV(self):
+ self.Try(CopyCellsToClipboardCSV)
+
def Find(self):
win = self.mdi_area.activeSubWindow()
if win:
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [tip:perf/core] perf scripts python: exported-sql-viewer.py: Add context menu
2019-05-03 12:08 ` [PATCH 5/6] perf scripts python: exported-sql-viewer.py: Add context menu Adrian Hunter
2019-05-13 20:09 ` Arnaldo Carvalho de Melo
@ 2019-05-18 8:57 ` tip-bot for Adrian Hunter
1 sibling, 0 replies; 17+ messages in thread
From: tip-bot for Adrian Hunter @ 2019-05-18 8:57 UTC (permalink / raw)
To: linux-tip-commits
Cc: hpa, jolsa, linux-kernel, adrian.hunter, acme, tglx, mingo
Commit-ID: 9bc4e4bfe6169343a8f019cd5d7843a558b78363
Gitweb: https://git.kernel.org/tip/9bc4e4bfe6169343a8f019cd5d7843a558b78363
Author: Adrian Hunter <adrian.hunter@intel.com>
AuthorDate: Fri, 3 May 2019 15:08:27 +0300
Committer: Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Wed, 15 May 2019 16:36:47 -0300
perf scripts python: exported-sql-viewer.py: Add context menu
Add a context menu (right-click) that provides options for copying to
clipboard, including, for trees, the ability to copy only the cell under
the mouse pointer.
Committer testing:
$ python ~acme/libexec/perf-core/scripts/python/exported-sql-viewer.py ~/c/adrian.hunter/simple-retpoline.db
Simply right click and pick "Copy selection", that at this point has
just the first line, not expanded, then see what was copied by pressing
shift+control+v on a terminal:
Call Path,Object,Count,Time (ns),Time (%),Branch Count,Branch Count (%)
▶ simple-retpolin,,,,,,
Ditto after expanding, i.e. the selection continues to be just one
line:
Call Path Object Count Time (ns) Time (%) Branch Count Branch Count (%)
▼ simple-retpolin
Now select all the lines with the mouse and control+shift+v again:
Call Path Object Count Time (ns) Time (%) Branch Count Branch Count (%)
▼ 14503:14503
▼ _start ld-2.28.so 1 156267 100.0 10602 100.0
▶ unknown unknown 1 2276 1.5 1 0.0
▶ _dl_start ld-2.28.so 1 137047 87.7 10088 95.2
▶ _dl_init ld-2.28.so 1 9142 5.9 326 3.1
▼ _start simple-retpoline 1 7457 4.8 182 1.7
▶ unknown unknown 1 805 10.8 1 0.5
▶ __libc_start_main libc-2.28.so 1 6347 85.1 179 98.4
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: http://lkml.kernel.org/r/20190503120828.25326-6-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/scripts/python/exported-sql-viewer.py | 41 ++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
index baa2b220238a..affd80ebcae0 100755
--- a/tools/perf/scripts/python/exported-sql-viewer.py
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -887,6 +887,8 @@ class TreeWindowBase(QMdiSubWindow):
self.view.setSelectionMode(QAbstractItemView.ContiguousSelection)
self.view.CopyCellsToClipboard = CopyTreeCellsToClipboard
+ self.context_menu = TreeContextMenu(self.view)
+
def DisplayFound(self, ids):
if not len(ids):
return False
@@ -1660,6 +1662,8 @@ class BranchWindow(QMdiSubWindow):
self.ResizeColumnsToContents()
+ self.context_menu = TreeContextMenu(self.view)
+
self.find_bar = FindBar(self, self, True)
self.finder = ChildDataItemFinder(self.model.root)
@@ -2469,6 +2473,39 @@ def CopyCellsToClipboardHdr(view):
def CopyCellsToClipboardCSV(view):
CopyCellsToClipboard(view, True, True)
+# Context menu
+
+class ContextMenu(object):
+
+ def __init__(self, view):
+ self.view = view
+ self.view.setContextMenuPolicy(Qt.CustomContextMenu)
+ self.view.customContextMenuRequested.connect(self.ShowContextMenu)
+
+ def ShowContextMenu(self, pos):
+ menu = QMenu(self.view)
+ self.AddActions(menu)
+ menu.exec_(self.view.mapToGlobal(pos))
+
+ def AddCopy(self, menu):
+ menu.addAction(CreateAction("&Copy selection", "Copy to clipboard", lambda: CopyCellsToClipboardHdr(self.view), self.view))
+ menu.addAction(CreateAction("Copy selection as CS&V", "Copy to clipboard as CSV", lambda: CopyCellsToClipboardCSV(self.view), self.view))
+
+ def AddActions(self, menu):
+ self.AddCopy(menu)
+
+class TreeContextMenu(ContextMenu):
+
+ def __init__(self, view):
+ super(TreeContextMenu, self).__init__(view)
+
+ def AddActions(self, menu):
+ i = self.view.currentIndex()
+ text = str(i.data()).strip()
+ if len(text):
+ menu.addAction(CreateAction('Copy "' + text + '"', "Copy to clipboard", lambda: QApplication.clipboard().setText(text), self.view))
+ self.AddCopy(menu)
+
# Table window
class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
@@ -2492,6 +2529,8 @@ class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
self.ResizeColumnsToContents()
+ self.context_menu = ContextMenu(self.view)
+
self.find_bar = FindBar(self, self, True)
self.finder = ChildDataItemFinder(self.data_model)
@@ -2608,6 +2647,8 @@ class TopCallsWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
self.view.setSelectionMode(QAbstractItemView.ContiguousSelection)
self.view.CopyCellsToClipboard = CopyTableCellsToClipboard
+ self.context_menu = ContextMenu(self.view)
+
self.ResizeColumnsToContents()
self.find_bar = FindBar(self, self, True)
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [tip:perf/core] perf scripts python: exported-sql-viewer.py: Add 'About' dialog box
2019-05-03 12:08 ` [PATCH 6/6] perf scripts python: exported-sql-viewer.py: Add 'About' dialog box Adrian Hunter
2019-05-13 20:12 ` Arnaldo Carvalho de Melo
@ 2019-05-18 8:58 ` tip-bot for Adrian Hunter
1 sibling, 0 replies; 17+ messages in thread
From: tip-bot for Adrian Hunter @ 2019-05-18 8:58 UTC (permalink / raw)
To: linux-tip-commits
Cc: tglx, mingo, jolsa, hpa, acme, adrian.hunter, linux-kernel
Commit-ID: b62d18aba1109506c1926ab7b564c4ac3bd48786
Gitweb: https://git.kernel.org/tip/b62d18aba1109506c1926ab7b564c4ac3bd48786
Author: Adrian Hunter <adrian.hunter@intel.com>
AuthorDate: Fri, 3 May 2019 15:08:28 +0300
Committer: Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Wed, 15 May 2019 16:36:47 -0300
perf scripts python: exported-sql-viewer.py: Add 'About' dialog box
With support for Python 2 or 3 and PySide 1 or 2 (Qt 4 or 5), it is
useful to see what versions are in use. Add an 'About' dialog box that
displays Python, PySide, Qt and database server (SQLite or PostgreSQL)
version numbers.
Committer testing:
$ python ~acme/libexec/perf-core/scripts/python/exported-sql-viewer.py ~/c/adrian.hunter/simple-retpoline.db
Then go to 'Help', then 'About', select all the lines with the mouse
press 'Control+C', then, on the same terminal press control+shift+V
which shows my current environment:
Python version: 2.7.16
PySide version: 1
Qt version: 4.8.7
SQLite version: 3.26.0
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: http://lkml.kernel.org/r/20190503120828.25326-7-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/scripts/python/exported-sql-viewer.py | 59 ++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
index affd80ebcae0..affed7d149be 100755
--- a/tools/perf/scripts/python/exported-sql-viewer.py
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -2913,6 +2913,60 @@ class HelpOnlyWindow(QMainWindow):
self.setCentralWidget(self.text)
+# PostqreSQL server version
+
+def PostqreSQLServerVersion(db):
+ query = QSqlQuery(db)
+ QueryExec(query, "SELECT VERSION()")
+ if query.next():
+ v_str = query.value(0)
+ v_list = v_str.strip().split(" ")
+ if v_list[0] == "PostgreSQL" and v_list[2] == "on":
+ return v_list[1]
+ return v_str
+ return "Unknown"
+
+# SQLite version
+
+def SQLiteVersion(db):
+ query = QSqlQuery(db)
+ QueryExec(query, "SELECT sqlite_version()")
+ if query.next():
+ return query.value(0)
+ return "Unknown"
+
+# About dialog
+
+class AboutDialog(QDialog):
+
+ def __init__(self, glb, parent=None):
+ super(AboutDialog, self).__init__(parent)
+
+ self.setWindowTitle("About Exported SQL Viewer")
+ self.setMinimumWidth(300)
+
+ pyside_version = "1" if pyside_version_1 else "2"
+
+ text = "<pre>"
+ text += "Python version: " + sys.version.split(" ")[0] + "\n"
+ text += "PySide version: " + pyside_version + "\n"
+ text += "Qt version: " + qVersion() + "\n"
+ if glb.dbref.is_sqlite3:
+ text += "SQLite version: " + SQLiteVersion(glb.db) + "\n"
+ else:
+ text += "PostqreSQL version: " + PostqreSQLServerVersion(glb.db) + "\n"
+ text += "</pre>"
+
+ self.text = QTextBrowser()
+ self.text.setHtml(text)
+ self.text.setReadOnly(True)
+ self.text.setOpenExternalLinks(True)
+
+ self.vbox = QVBoxLayout()
+ self.vbox.addWidget(self.text)
+
+ self.setLayout(self.vbox);
+
# Font resize
def ResizeFont(widget, diff):
@@ -3010,6 +3064,7 @@ class MainWindow(QMainWindow):
help_menu = menu.addMenu("&Help")
help_menu.addAction(CreateAction("&Exported SQL Viewer Help", "Helpful information", self.Help, self, QKeySequence.HelpContents))
+ help_menu.addAction(CreateAction("&About Exported SQL Viewer", "About this application", self.About, self))
def Try(self, fn):
win = self.mdi_area.activeSubWindow()
@@ -3095,6 +3150,10 @@ class MainWindow(QMainWindow):
def Help(self):
HelpWindow(self.glb, self)
+ def About(self):
+ dialog = AboutDialog(self.glb, self)
+ dialog.exec_()
+
# XED Disassembler
class xed_state_t(Structure):
^ permalink raw reply related [flat|nested] 17+ messages in thread
end of thread, other threads:[~2019-05-18 8:58 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-03 12:08 [PATCH 0/6] perf scripts python: exported-sql-viewer.py: Minor improvements Adrian Hunter
2019-05-03 12:08 ` [PATCH 1/6] perf scripts python: exported-sql-viewer.py: Fix error when shrinking / enlarging font Adrian Hunter
2019-05-13 19:57 ` Arnaldo Carvalho de Melo
2019-05-18 8:55 ` [tip:perf/core] " tip-bot for Adrian Hunter
2019-05-03 12:08 ` [PATCH 2/6] perf scripts python: exported-sql-viewer.py: Move view creation Adrian Hunter
2019-05-18 8:54 ` [tip:perf/core] " tip-bot for Adrian Hunter
2019-05-03 12:08 ` [PATCH 3/6] perf scripts python: exported-sql-viewer.py: Add tree level Adrian Hunter
2019-05-18 8:55 ` [tip:perf/core] " tip-bot for Adrian Hunter
2019-05-03 12:08 ` [PATCH 4/6] perf scripts python: exported-sql-viewer.py: Add copy to clipboard Adrian Hunter
2019-05-13 20:03 ` Arnaldo Carvalho de Melo
2019-05-18 8:56 ` [tip:perf/core] " tip-bot for Adrian Hunter
2019-05-03 12:08 ` [PATCH 5/6] perf scripts python: exported-sql-viewer.py: Add context menu Adrian Hunter
2019-05-13 20:09 ` Arnaldo Carvalho de Melo
2019-05-18 8:57 ` [tip:perf/core] " tip-bot for Adrian Hunter
2019-05-03 12:08 ` [PATCH 6/6] perf scripts python: exported-sql-viewer.py: Add 'About' dialog box Adrian Hunter
2019-05-13 20:12 ` Arnaldo Carvalho de Melo
2019-05-18 8:58 ` [tip:perf/core] " tip-bot for Adrian Hunter
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.