All of lore.kernel.org
 help / color / mirror / Atom feed
From: tip-bot for Adrian Hunter <tipbot@zytor.com>
To: linux-tip-commits@vger.kernel.org
Cc: acme@redhat.com, hpa@zytor.com, mingo@kernel.org,
	linux-kernel@vger.kernel.org, ak@linux.intel.com,
	tglx@linutronix.de, adrian.hunter@intel.com, jolsa@redhat.com
Subject: [tip:perf/urgent] perf scripts python: exported-sql-viewer.py: Add support for multiple sub-windows
Date: Fri, 26 Oct 2018 00:42:47 -0700	[thread overview]
Message-ID: <tip-1beb5c7b07040b70975a2ae0e90b87d412fabf06@git.kernel.org> (raw)
In-Reply-To: <20181001062853.28285-14-adrian.hunter@intel.com>

Commit-ID:  1beb5c7b07040b70975a2ae0e90b87d412fabf06
Gitweb:     https://git.kernel.org/tip/1beb5c7b07040b70975a2ae0e90b87d412fabf06
Author:     Adrian Hunter <adrian.hunter@intel.com>
AuthorDate: Mon, 1 Oct 2018 09:28:47 +0300
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 23 Oct 2018 14:27:30 -0300

perf scripts python: exported-sql-viewer.py: Add support for multiple sub-windows

Use Qt MDI (multiple document interface) to support multiple sub-windows.
Put the data model in a cache so that each sub-window can share the same
data. This allows mutiple views of the call-graph at the same time and
paves the way to add more reports.

Committer testing:

Starts with a "File  Reports  Windows" main menu, from the "Reports" I
can get what was available up to now, the "Context-Sensitivi Call Graph"
option.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: http://lkml.kernel.org/r/20181001062853.28285-14-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/scripts/python/exported-sql-viewer.py | 182 +++++++++++++++++++++--
 1 file changed, 173 insertions(+), 9 deletions(-)

diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
index 03e7a1de7f31..c2f44351821e 100755
--- a/tools/perf/scripts/python/exported-sql-viewer.py
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -47,6 +47,8 @@
 #       functions that it calls
 
 import sys
+import weakref
+import threading
 from PySide.QtCore import *
 from PySide.QtGui import *
 from PySide.QtSql import *
@@ -138,6 +140,23 @@ class TreeModel(QAbstractItemModel):
 		item = index.internalPointer()
 		return self.DisplayData(item, index)
 
+# Model cache
+
+model_cache = weakref.WeakValueDictionary()
+model_cache_lock = threading.Lock()
+
+def LookupCreateModel(model_name, create_fn):
+	model_cache_lock.acquire()
+	try:
+		model = model_cache[model_name]
+	except:
+		model = None
+	if model is None:
+		model = create_fn()
+		model_cache[model_name] = model
+	model_cache_lock.release()
+	return model
+
 # Context-sensitive call graph data model item base
 
 class CallGraphLevelItemBase(object):
@@ -289,6 +308,144 @@ class CallGraphModel(TreeModel):
 		alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ]
 		return alignment[column]
 
+# Context-sensitive call graph window
+
+class CallGraphWindow(QMdiSubWindow):
+
+	def __init__(self, glb, parent=None):
+		super(CallGraphWindow, self).__init__(parent)
+
+		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)):
+			self.view.setColumnWidth(c, w)
+
+		self.setWidget(self.view)
+
+		AddSubWindow(glb.mainwindow.mdi_area, self, "Context-Sensitive Call Graph")
+
+# Action Definition
+
+def CreateAction(label, tip, callback, parent=None, shortcut=None):
+	action = QAction(label, parent)
+	if shortcut != None:
+		action.setShortcuts(shortcut)
+	action.setStatusTip(tip)
+	action.triggered.connect(callback)
+	return action
+
+# Typical application actions
+
+def CreateExitAction(app, parent=None):
+	return CreateAction("&Quit", "Exit the application", app.closeAllWindows, parent, QKeySequence.Quit)
+
+# Typical MDI actions
+
+def CreateCloseActiveWindowAction(mdi_area):
+	return CreateAction("Cl&ose", "Close the active window", mdi_area.closeActiveSubWindow, mdi_area)
+
+def CreateCloseAllWindowsAction(mdi_area):
+	return CreateAction("Close &All", "Close all the windows", mdi_area.closeAllSubWindows, mdi_area)
+
+def CreateTileWindowsAction(mdi_area):
+	return CreateAction("&Tile", "Tile the windows", mdi_area.tileSubWindows, mdi_area)
+
+def CreateCascadeWindowsAction(mdi_area):
+	return CreateAction("&Cascade", "Cascade the windows", mdi_area.cascadeSubWindows, mdi_area)
+
+def CreateNextWindowAction(mdi_area):
+	return CreateAction("Ne&xt", "Move the focus to the next window", mdi_area.activateNextSubWindow, mdi_area, QKeySequence.NextChild)
+
+def CreatePreviousWindowAction(mdi_area):
+	return CreateAction("Pre&vious", "Move the focus to the previous window", mdi_area.activatePreviousSubWindow, mdi_area, QKeySequence.PreviousChild)
+
+# Typical MDI window menu
+
+class WindowMenu():
+
+	def __init__(self, mdi_area, menu):
+		self.mdi_area = mdi_area
+		self.window_menu = menu.addMenu("&Windows")
+		self.close_active_window = CreateCloseActiveWindowAction(mdi_area)
+		self.close_all_windows = CreateCloseAllWindowsAction(mdi_area)
+		self.tile_windows = CreateTileWindowsAction(mdi_area)
+		self.cascade_windows = CreateCascadeWindowsAction(mdi_area)
+		self.next_window = CreateNextWindowAction(mdi_area)
+		self.previous_window = CreatePreviousWindowAction(mdi_area)
+		self.window_menu.aboutToShow.connect(self.Update)
+
+	def Update(self):
+		self.window_menu.clear()
+		sub_window_count = len(self.mdi_area.subWindowList())
+		have_sub_windows = sub_window_count != 0
+		self.close_active_window.setEnabled(have_sub_windows)
+		self.close_all_windows.setEnabled(have_sub_windows)
+		self.tile_windows.setEnabled(have_sub_windows)
+		self.cascade_windows.setEnabled(have_sub_windows)
+		self.next_window.setEnabled(have_sub_windows)
+		self.previous_window.setEnabled(have_sub_windows)
+		self.window_menu.addAction(self.close_active_window)
+		self.window_menu.addAction(self.close_all_windows)
+		self.window_menu.addSeparator()
+		self.window_menu.addAction(self.tile_windows)
+		self.window_menu.addAction(self.cascade_windows)
+		self.window_menu.addSeparator()
+		self.window_menu.addAction(self.next_window)
+		self.window_menu.addAction(self.previous_window)
+		if sub_window_count == 0:
+			return
+		self.window_menu.addSeparator()
+		nr = 1
+		for sub_window in self.mdi_area.subWindowList():
+			label = str(nr) + " " + sub_window.name
+			if nr < 10:
+				label = "&" + label
+			action = self.window_menu.addAction(label)
+			action.setCheckable(True)
+			action.setChecked(sub_window == self.mdi_area.activeSubWindow())
+			action.triggered.connect(lambda x=nr: self.setActiveSubWindow(x))
+			self.window_menu.addAction(action)
+			nr += 1
+
+	def setActiveSubWindow(self, nr):
+		self.mdi_area.setActiveSubWindow(self.mdi_area.subWindowList()[nr - 1])
+
+# Unique name for sub-windows
+
+def NumberedWindowName(name, nr):
+	if nr > 1:
+		name += " <" + str(nr) + ">"
+	return name
+
+def UniqueSubWindowName(mdi_area, name):
+	nr = 1
+	while True:
+		unique_name = NumberedWindowName(name, nr)
+		ok = True
+		for sub_window in mdi_area.subWindowList():
+			if sub_window.name == unique_name:
+				ok = False
+				break
+		if ok:
+			return unique_name
+		nr += 1
+
+# Add a sub-window
+
+def AddSubWindow(mdi_area, sub_window, name):
+	unique_name = UniqueSubWindowName(mdi_area, name)
+	sub_window.setMinimumSize(200, 100)
+	sub_window.resize(800, 600)
+	sub_window.setWindowTitle(unique_name)
+	sub_window.setAttribute(Qt.WA_DeleteOnClose)
+	sub_window.setWindowIcon(sub_window.style().standardIcon(QStyle.SP_FileIcon))
+	sub_window.name = unique_name
+	mdi_area.addSubWindow(sub_window)
+	sub_window.show()
+
 # Main window
 
 class MainWindow(QMainWindow):
@@ -298,21 +455,28 @@ class MainWindow(QMainWindow):
 
 		self.glb = glb
 
-		self.setWindowTitle("Call Graph: " + glb.dbname)
-		self.move(100, 100)
-		self.resize(800, 600)
+		self.setWindowTitle("Exported SQL Viewer: " + glb.dbname)
 		self.setWindowIcon(self.style().standardIcon(QStyle.SP_ComputerIcon))
 		self.setMinimumSize(200, 100)
 
-		self.model = CallGraphModel(glb)
+		self.mdi_area = QMdiArea()
+		self.mdi_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
+		self.mdi_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
 
-		self.view = QTreeView()
-		self.view.setModel(self.model)
+		self.setCentralWidget(self.mdi_area)
 
-		for c, w in ((0, 250), (1, 100), (2, 60), (3, 70), (4, 70), (5, 100)):
-			self.view.setColumnWidth(c, w)
+		menu = self.menuBar()
+
+		file_menu = menu.addMenu("&File")
+		file_menu.addAction(CreateExitAction(glb.app, self))
+
+		reports_menu = menu.addMenu("&Reports")
+		reports_menu.addAction(CreateAction("Context-Sensitive Call &Graph", "Create a new window containing a context-sensitive call graph", self.NewCallGraph, self))
+
+		self.window_menu = WindowMenu(self.mdi_area, menu)
 
-		self.setCentralWidget(self.view)
+	def NewCallGraph(self):
+		CallGraphWindow(self.glb, self)
 
 # Global data
 

  reply	other threads:[~2018-10-26  7:42 UTC|newest]

Thread overview: 49+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-10-01  6:28 [PATCH 00/19] perf scripts python: call-graph-from-sql.py / exported-sql-viewer.py disassembly Adrian Hunter
2018-10-01  6:28 ` [PATCH 01/19] perf scripts python: call-graph-from-sql.py: Use SPDX license identifier Adrian Hunter
2018-10-26  7:36   ` [tip:perf/urgent] " tip-bot for Adrian Hunter
2018-10-01  6:28 ` [PATCH 02/19] perf scripts python: call-graph-from-sql.py: Provide better default column sizes Adrian Hunter
2018-10-26  7:36   ` [tip:perf/urgent] " tip-bot for Adrian Hunter
2018-10-01  6:28 ` [PATCH 03/19] perf scripts python: call-graph-from-sql.py: Set a minimum window size Adrian Hunter
2018-10-26  7:37   ` [tip:perf/urgent] " tip-bot for Adrian Hunter
2018-10-01  6:28 ` [PATCH 04/19] perf scripts python: call-graph-from-sql.py: Change icon Adrian Hunter
2018-10-26  7:37   ` [tip:perf/urgent] " tip-bot for Adrian Hunter
2018-10-01  6:28 ` [PATCH 05/19] perf scripts python: call-graph-from-sql.py: Make a "Main" function Adrian Hunter
2018-10-26  7:38   ` [tip:perf/urgent] " tip-bot for Adrian Hunter
2018-10-01  6:28 ` [PATCH 06/19] perf scripts python: call-graph-from-sql.py: Separate the database details into a class Adrian Hunter
2018-10-26  7:38   ` [tip:perf/urgent] " tip-bot for Adrian Hunter
2018-10-01  6:28 ` [PATCH 07/19] perf scripts python: call-graph-from-sql.py: Add a class for global data Adrian Hunter
2018-10-26  7:39   ` [tip:perf/urgent] " tip-bot for Adrian Hunter
2018-10-01  6:28 ` [PATCH 08/19] perf scripts python: call-graph-from-sql.py: Remove use of setObjectName() Adrian Hunter
2018-10-26  7:39   ` [tip:perf/urgent] " tip-bot for Adrian Hunter
2018-10-01  6:28 ` [PATCH 09/19] perf scripts python: call-graph-from-sql.py: Factor out CallGraphModel from TreeModel Adrian Hunter
2018-10-26  7:40   ` [tip:perf/urgent] " tip-bot for Adrian Hunter
2018-10-01  6:28 ` [PATCH 10/19] perf scripts python: call-graph-from-sql.py: Add data helper functions Adrian Hunter
2018-10-26  7:41   ` [tip:perf/urgent] " tip-bot for Adrian Hunter
2018-10-01  6:28 ` [PATCH 11/19] perf scripts python: call-graph-from-sql.py: Refactor TreeItem class Adrian Hunter
2018-10-26  7:41   ` [tip:perf/urgent] " tip-bot for Adrian Hunter
2018-10-01  6:28 ` [PATCH 12/19] perf scripts python: call-graph-from-sql.py: Rename to exported-sql-viewer.py Adrian Hunter
2018-10-26  7:42   ` [tip:perf/urgent] " tip-bot for Adrian Hunter
2018-10-01  6:28 ` [PATCH 13/19] perf scripts python: exported-sql-viewer.py: Add support for multiple sub-windows Adrian Hunter
2018-10-26  7:42   ` tip-bot for Adrian Hunter [this message]
2018-10-01  6:28 ` [PATCH 14/19] perf scripts python: exported-sql-viewer.py: Add ability to find symbols in the call-graph Adrian Hunter
2018-10-26  7:43   ` [tip:perf/urgent] " tip-bot for Adrian Hunter
2018-10-01  6:28 ` [PATCH 15/19] perf scripts python: exported-sql-viewer.py: Add ability to shrink / enlarge font Adrian Hunter
2018-10-26  7:43   ` [tip:perf/urgent] " tip-bot for Adrian Hunter
2018-10-01  6:28 ` [PATCH 16/19] perf scripts python: exported-sql-viewer.py: Add ability to display all the database tables Adrian Hunter
2018-10-26  7:44   ` [tip:perf/urgent] " tip-bot for Adrian Hunter
2018-10-01  6:28 ` [PATCH 17/19] perf scripts python: exported-sql-viewer.py: Add All branches report Adrian Hunter
2018-10-22 18:50   ` Arnaldo Carvalho de Melo
2018-10-22 18:50     ` Arnaldo Carvalho de Melo
2018-10-23  8:20       ` Adrian Hunter
2018-10-23  7:59   ` [PATCH V2 " Adrian Hunter
2018-10-23 18:12     ` Arnaldo Carvalho de Melo
2018-10-23 18:41       ` Hunter, Adrian
2018-10-23 19:29         ` Arnaldo Carvalho de Melo
2018-10-23 19:57           ` Hunter, Adrian
2018-10-23 20:02             ` Arnaldo Carvalho de Melo
2018-10-23 20:31               ` Adrian Hunter
2018-10-24 13:56                 ` Adrian Hunter
2018-10-24 14:16                   ` Arnaldo Carvalho de Melo
2018-10-26  7:45     ` [tip:perf/urgent] " tip-bot for Adrian Hunter
2018-10-01  6:28 ` [PATCH 18/19] perf scripts python: exported-sql-viewer.py: Add Selected " Adrian Hunter
2018-10-01  6:28 ` [PATCH 19/19] perf scripts python: exported-sql-viewer.py: Add help window Adrian Hunter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=tip-1beb5c7b07040b70975a2ae0e90b87d412fabf06@git.kernel.org \
    --to=tipbot@zytor.com \
    --cc=acme@redhat.com \
    --cc=adrian.hunter@intel.com \
    --cc=ak@linux.intel.com \
    --cc=hpa@zytor.com \
    --cc=jolsa@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-tip-commits@vger.kernel.org \
    --cc=mingo@kernel.org \
    --cc=tglx@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.