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 Load more
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())