5108 lines · 155.9 KB · Python
RawDownload
	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):	font = widget.font()	sz = font.pointSize()	font.setPointSize(sz + diff)	widget.setFont(font) def ShrinkFont(widget):	ResizeFont(widget, -1) def EnlargeFont(widget):	ResizeFont(widget, 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): 	def __init__(self, glb, parent=None):		super(MainWindow, self).__init__(parent) 		self.glb = glb 		self.setWindowTitle("Exported SQL Viewer: " + glb.dbname)		self.setWindowIcon(self.style().standardIcon(QStyle.SP_ComputerIcon))		self.setMinimumSize(200, 100) 		self.mdi_area = QMdiArea()		self.mdi_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)		self.mdi_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) 		self.setCentralWidget(self.mdi_area) 		menu = self.menuBar() 		file_menu = menu.addMenu("&File")		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+-")]))		edit_menu.addAction(CreateAction("&Enlarge Font", "Make text bigger", self.EnlargeFont, self, [QKeySequence("Ctrl++")])) 		reports_menu = menu.addMenu("&Reports")		if IsSelectable(glb.db, "calls"):			reports_menu.addAction(CreateAction("Context-Sensitive Call &Graph", "Create a new window containing a context-sensitive call graph", self.NewCallGraph, self)) 		if IsSelectable(glb.db, "calls", "WHERE parent_id >= 0"):			reports_menu.addAction(CreateAction("Call &Tree", "Create a new window containing a call tree", self.NewCallTree, self)) 		self.EventMenu(GetEventList(glb.db), reports_menu) 		if IsSelectable(glb.db, "calls"):			reports_menu.addAction(CreateAction("&Top calls by elapsed time", "Create a new window displaying top calls by elapsed time", self.NewTopCalls, self)) 		if IsSelectable(glb.db, "context_switches"):			charts_menu = menu.addMenu("&Charts")			charts_menu.addAction(CreateAction("&Time chart by CPU", "Create a new window displaying time charts by CPU", self.TimeChartByCPU, self)) 		self.TableMenu(GetTableList(glb), menu) 		self.window_menu = WindowMenu(self.mdi_area, menu) 		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()		if win:			try:				fn(win.view)			except:				pass 	def CopyToClipboard(self):		self.Try(CopyCellsToClipboardHdr) 	def CopyToClipboardCSV(self):		self.Try(CopyCellsToClipboardCSV) 	def Find(self):		win = self.mdi_area.activeSubWindow()		if win:			try:				win.find_bar.Activate()			except:				pass 	def FetchMoreRecords(self):		win = self.mdi_area.activeSubWindow()		if win:			try:				win.fetch_bar.Activate()			except:				pass 	def ShrinkFont(self):		self.Try(ShrinkFont) 	def EnlargeFont(self):		self.Try(EnlargeFont) 	def EventMenu(self, events, reports_menu):		branches_events = 0		for event in events:			event = event.split(":")[0]			if event == "branches":				branches_events += 1		dbid = 0		for event in events:			dbid += 1			event = event.split(":")[0]			if event == "branches":				label = "All branches" if branches_events == 1 else "All branches " + "(id=" + dbid + ")"				reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda a=None,x=dbid: self.NewBranchView(x), self))				label = "Selected branches" if branches_events == 1 else "Selected branches " + "(id=" + dbid + ")"				reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda a=None,x=dbid: self.NewSelectedBranchView(x), self)) 	def TimeChartByCPU(self):		TimeChartByCPUWindow(self.glb, self) 	def TableMenu(self, tables, menu):		table_menu = menu.addMenu("&Tables")		for table in tables:			table_menu.addAction(CreateAction(table, "Create a new window containing a table view", lambda a=None,t=table: self.NewTableView(t), self)) 	def NewCallGraph(self):		CallGraphWindow(self.glb, self) 	def NewCallTree(self):		CallTreeWindow(self.glb, self) 	def NewTopCalls(self):		dialog = TopCallsDialog(self.glb, self)		ret = dialog.exec_()		if ret:			TopCallsWindow(self.glb, dialog.report_vars, self) 	def NewBranchView(self, event_id):		BranchWindow(self.glb, event_id, ReportVars(), self) 	def NewSelectedBranchView(self, event_id):		dialog = SelectedBranchDialog(self.glb, self)		ret = dialog.exec_()		if ret:			BranchWindow(self.glb, event_id, dialog.report_vars, self) 	def NewTableView(self, table_name):		TableWindow(self.glb, table_name, self) 	def Help(self):		HelpWindow(self.glb, self) 	def About(self):		dialog = AboutDialog(self.glb, self)		dialog.exec_() # XED Disassembler class xed_state_t(Structure): 	_fields_ = [		("mode", c_int),		("width", c_int)	] class XEDInstruction(): 	def __init__(self, libxed):		# Current xed_decoded_inst_t structure is 192 bytes. Use 512 to allow for future expansion		xedd_t = c_byte * 512		self.xedd = xedd_t()		self.xedp = addressof(self.xedd)		libxed.xed_decoded_inst_zero(self.xedp)		self.state = xed_state_t()		self.statep = addressof(self.state)		# Buffer for disassembled instruction text		self.buffer = create_string_buffer(256)		self.bufferp = addressof(self.buffer) class LibXED(): 	def __init__(self):		try:			self.libxed = CDLL("libxed.so")		except:			self.libxed = None		if not self.libxed:			self.libxed = CDLL("/usr/local/lib/libxed.so") 		self.xed_tables_init = self.libxed.xed_tables_init		self.xed_tables_init.restype = None		self.xed_tables_init.argtypes = [] 		self.xed_decoded_inst_zero = self.libxed.xed_decoded_inst_zero		self.xed_decoded_inst_zero.restype = None		self.xed_decoded_inst_zero.argtypes = [ c_void_p ] 		self.xed_operand_values_set_mode = self.libxed.xed_operand_values_set_mode		self.xed_operand_values_set_mode.restype = None		self.xed_operand_values_set_mode.argtypes = [ c_void_p, c_void_p ] 		self.xed_decoded_inst_zero_keep_mode = self.libxed.xed_decoded_inst_zero_keep_mode		self.xed_decoded_inst_zero_keep_mode.restype = None		self.xed_decoded_inst_zero_keep_mode.argtypes = [ c_void_p ] 		self.xed_decode = self.libxed.xed_decode		self.xed_decode.restype = c_int		self.xed_decode.argtypes = [ c_void_p, c_void_p, c_uint ] 		self.xed_format_context = self.libxed.xed_format_context		self.xed_format_context.restype = c_uint		self.xed_format_context.argtypes = [ c_int, c_void_p, c_void_p, c_int, c_ulonglong, c_void_p, c_void_p ] 		self.xed_tables_init() 	def Instruction(self):		return XEDInstruction(self) 	def SetMode(self, inst, mode):		if mode:			inst.state.mode = 4 # 32-bit			inst.state.width = 4 # 4 bytes		else:			inst.state.mode = 1 # 64-bit			inst.state.width = 8 # 8 bytes		self.xed_operand_values_set_mode(inst.xedp, inst.statep) 	def DisassembleOne(self, inst, bytes_ptr, bytes_cnt, ip):		self.xed_decoded_inst_zero_keep_mode(inst.xedp)		err = self.xed_decode(inst.xedp, bytes_ptr, bytes_cnt)		if err:			return 0, ""		# Use AT&T mode (2), alternative is Intel (3)		ok = self.xed_format_context(2, inst.xedp, inst.bufferp, sizeof(inst.buffer), ip, 0, 0)		if not ok:			return 0, ""		if sys.version_info[0] == 2:			result = inst.buffer.value		else:			result = inst.buffer.value.decode()		# Return instruction length and the disassembled instruction text		# For now, assume the length is in byte 166		return inst.xedd[166], result def TryOpen(file_name):	try:		return open(file_name, "rb")	except:		return None def Is64Bit(f):	result = sizeof(c_void_p)	# ELF support only	pos = f.tell()	f.seek(0)	header = f.read(7)	f.seek(pos)	magic = header[0:4]	if sys.version_info[0] == 2:		eclass = ord(header[4])		encoding = ord(header[5])		version = ord(header[6])	else:		eclass = header[4]		encoding = header[5]		version = header[6]	if magic == chr(127) + "ELF" and eclass > 0 and eclass < 3 and encoding > 0 and encoding < 3 and version == 1:		result = True if eclass == 2 else False	return result # Global data class Glb(): 	def __init__(self, dbref, db, dbname):		self.dbref = dbref		self.db = db		self.dbname = dbname		self.home_dir = os.path.expanduser("~")		self.buildid_dir = os.getenv("PERF_BUILDID_DIR")		if self.buildid_dir:			self.buildid_dir += "/.build-id/"		else:			self.buildid_dir = self.home_dir + "/.debug/.build-id/"		self.app = None		self.mainwindow = None		self.instances_to_shutdown_on_exit = weakref.WeakSet()		try:			self.disassembler = LibXED()			self.have_disassembler = True		except:			self.have_disassembler = False		self.host_machine_id = 0		self.host_start_time = 0		self.host_finish_time = 0 	def FileFromBuildId(self, build_id):		file_name = self.buildid_dir + build_id[0:2] + "/" + build_id[2:] + "/elf"		return TryOpen(file_name) 	def FileFromNamesAndBuildId(self, short_name, long_name, build_id):		# Assume current machine i.e. no support for virtualization		if short_name[0:7] == "[kernel" and os.path.basename(long_name) == "kcore":			file_name = os.getenv("PERF_KCORE")			f = TryOpen(file_name) if file_name else None			if f:				return f			# For now, no special handling if long_name is /proc/kcore			f = TryOpen(long_name)			if f:				return f		f = self.FileFromBuildId(build_id)		if f:			return f		return None 	def AddInstanceToShutdownOnExit(self, instance):		self.instances_to_shutdown_on_exit.add(instance) 	# Shutdown any background processes or threads	def ShutdownInstances(self):		for x in self.instances_to_shutdown_on_exit:			try:				x.Shutdown()			except:				pass 	def GetHostMachineId(self):		query = QSqlQuery(self.db)		QueryExec(query, "SELECT id FROM machines WHERE pid = -1")		if query.next():			self.host_machine_id = query.value(0)		else:			self.host_machine_id = 0		return self.host_machine_id 	def HostMachineId(self):		if self.host_machine_id:			return self.host_machine_id		return self.GetHostMachineId() 	def SelectValue(self, sql):		query = QSqlQuery(self.db)		try:			QueryExec(query, sql)		except:			return None		if query.next():			return Decimal(query.value(0))		return None 	def SwitchesMinTime(self, machine_id):		return self.SelectValue("SELECT time"					" FROM context_switches"					" WHERE time != 0 AND machine_id = " + str(machine_id) +					" ORDER BY id LIMIT 1") 	def SwitchesMaxTime(self, machine_id):		return self.SelectValue("SELECT time"					" FROM context_switches"					" WHERE time != 0 AND machine_id = " + str(machine_id) +					" ORDER BY id DESC LIMIT 1") 	def SamplesMinTime(self, machine_id):		return self.SelectValue("SELECT time"					" FROM samples"					" WHERE time != 0 AND machine_id = " + str(machine_id) +					" ORDER BY id LIMIT 1") 	def SamplesMaxTime(self, machine_id):		return self.SelectValue("SELECT time"					" FROM samples"					" WHERE time != 0 AND machine_id = " + str(machine_id) +					" ORDER BY id DESC LIMIT 1") 	def CallsMinTime(self, machine_id):		return self.SelectValue("SELECT calls.call_time"					" FROM calls"					" INNER JOIN threads ON threads.thread_id = calls.thread_id"					" WHERE calls.call_time != 0 AND threads.machine_id = " + str(machine_id) +					" ORDER BY calls.id LIMIT 1") 	def CallsMaxTime(self, machine_id):		return self.SelectValue("SELECT calls.return_time"					" FROM calls"					" INNER JOIN threads ON threads.thread_id = calls.thread_id"					" WHERE calls.return_time != 0 AND threads.machine_id = " + str(machine_id) +					" ORDER BY calls.return_time DESC LIMIT 1") 	def GetStartTime(self, machine_id):		t0 = self.SwitchesMinTime(machine_id)		t1 = self.SamplesMinTime(machine_id)		t2 = self.CallsMinTime(machine_id)		if t0 is None or (not(t1 is None) and t1 < t0):			t0 = t1		if t0 is None or (not(t2 is None) and t2 < t0):			t0 = t2		return t0 	def GetFinishTime(self, machine_id):		t0 = self.SwitchesMaxTime(machine_id)		t1 = self.SamplesMaxTime(machine_id)		t2 = self.CallsMaxTime(machine_id)		if t0 is None or (not(t1 is None) and t1 > t0):			t0 = t1		if t0 is None or (not(t2 is None) and t2 > t0):			t0 = t2		return t0 	def HostStartTime(self):		if self.host_start_time:			return self.host_start_time		self.host_start_time = self.GetStartTime(self.HostMachineId())

Lines 4501–5000 of 5108. Previous lines