" INNER JOIN call_paths ON calls.call_path_id = call_paths.id" " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" " INNER JOIN dsos ON symbols.dso_id = dsos.id" " WHERE parent_call_path_id = " + str(self.call_path_id) + " AND comm_id = " + str(self.comm_id) + " AND thread_id = " + str(self.thread_id) + " GROUP BY call_path_id, name, short_name" " ORDER BY call_path_id") while query.next(): child_item = CallGraphLevelThreeItem(self.glb, self.child_count, self.comm_id, self.thread_id, query.value(0), query.value(1), query.value(2), query.value(3), int(query.value(4)), int(query.value(5)), self) self.child_items.append(child_item) self.child_count += 1 # Context-sensitive call graph data model level three item class CallGraphLevelThreeItem(CallGraphLevelTwoPlusItemBase): def __init__(self, glb, row, comm_id, thread_id, call_path_id, name, dso, count, time, branch_count, parent_item): super(CallGraphLevelThreeItem, self).__init__(glb, row, comm_id, thread_id, call_path_id, time, branch_count, parent_item) dso = dsoname(dso) self.data = [ name, dso, str(count), str(time), PercentToOneDP(time, parent_item.time), str(branch_count), PercentToOneDP(branch_count, parent_item.branch_count) ] self.dbid = call_path_id # Context-sensitive call graph data model level two item class CallGraphLevelTwoItem(CallGraphLevelTwoPlusItemBase): def __init__(self, glb, row, comm_id, thread_id, pid, tid, parent_item): super(CallGraphLevelTwoItem, self).__init__(glb, row, comm_id, thread_id, 1, 0, 0, parent_item) self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", ""] self.dbid = thread_id def Select(self): super(CallGraphLevelTwoItem, self).Select() for child_item in self.child_items: self.time += child_item.time self.branch_count += child_item.branch_count for child_item in self.child_items: child_item.data[4] = PercentToOneDP(child_item.time, self.time) child_item.data[6] = PercentToOneDP(child_item.branch_count, self.branch_count) # Context-sensitive call graph data model level one item class CallGraphLevelOneItem(CallGraphLevelItemBase): def __init__(self, glb, row, comm_id, comm, parent_item): super(CallGraphLevelOneItem, self).__init__(glb, row, parent_item) self.data = [comm, "", "", "", "", "", ""] self.dbid = comm_id def Select(self): self.query_done = True; query = QSqlQuery(self.glb.db) QueryExec(query, "SELECT thread_id, pid, tid" " FROM comm_threads" " INNER JOIN threads ON thread_id = threads.id" " WHERE comm_id = " + str(self.dbid)) while query.next(): child_item = CallGraphLevelTwoItem(self.glb, self.child_count, self.dbid, query.value(0), query.value(1), query.value(2), self) self.child_items.append(child_item) self.child_count += 1 # Context-sensitive call graph data model root item class CallGraphRootItem(CallGraphLevelItemBase): def __init__(self, glb): super(CallGraphRootItem, self).__init__(glb, 0, None) self.dbid = 0 self.query_done = True; query = QSqlQuery(glb.db) QueryExec(query, "SELECT id, comm FROM comms") while query.next(): if not query.value(0): continue child_item = CallGraphLevelOneItem(glb, self.child_count, query.value(0), query.value(1), self) self.child_items.append(child_item) self.child_count += 1 # Context-sensitive call graph data model base class CallGraphModelBase(TreeModel): def __init__(self, glb, parent=None): super(CallGraphModelBase, self).__init__(glb, parent) def FindSelect(self, value, pattern, query): if pattern: # postgresql and sqlite pattern patching differences: # postgresql LIKE is case sensitive but sqlite LIKE is not # postgresql LIKE allows % and _ to be escaped with \ but sqlite LIKE does not # postgresql supports ILIKE which is case insensitive # sqlite supports GLOB (text only) which uses * and ? and is case sensitive if not self.glb.dbref.is_sqlite3: # Escape % and _ s = value.replace("%", "\%") s = s.replace("_", "\_") # Translate * and ? into SQL LIKE pattern characters % and _ trans = string.maketrans("*?", "%_") match = " LIKE '" + str(s).translate(trans) + "'" else: match = " GLOB '" + str(value) + "'" else: match = " = '" + str(value) + "'" self.DoFindSelect(query, match) def Found(self, query, found): if found: return self.FindPath(query) return [] def FindValue(self, value, pattern, query, last_value, last_pattern): if last_value == value and pattern == last_pattern: found = query.first() else: self.FindSelect(value, pattern, query) found = query.next() return self.Found(query, found) def FindNext(self, query): found = query.next() if not found: found = query.first() return self.Found(query, found) def FindPrev(self, query): found = query.previous() if not found: found = query.last() return self.Found(query, found) def FindThread(self, c): if c.direction == 0 or c.value != c.last_value or c.pattern != c.last_pattern: ids = self.FindValue(c.value, c.pattern, c.query, c.last_value, c.last_pattern) elif c.direction > 0: ids = self.FindNext(c.query) else: ids = self.FindPrev(c.query) return (True, ids) def Find(self, value, direction, pattern, context, callback): class Context(): def __init__(self, *x): self.value, self.direction, self.pattern, self.query, self.last_value, self.last_pattern = x def Update(self, *x): self.value, self.direction, self.pattern, self.last_value, self.last_pattern = x + (self.value, self.pattern) if len(context): context[0].Update(value, direction, pattern) else: context.append(Context(value, direction, pattern, QSqlQuery(self.glb.db), None, None)) # Use a thread so the UI is not blocked during the SELECT thread = Thread(self.FindThread, context[0]) thread.done.connect(lambda ids, t=thread, c=callback: self.FindDone(t, c, ids), Qt.QueuedConnection) thread.start() def FindDone(self, thread, callback, ids): callback(ids) # Context-sensitive call graph data model class CallGraphModel(CallGraphModelBase): def __init__(self, glb, parent=None): super(CallGraphModel, self).__init__(glb, parent) def GetRoot(self): return CallGraphRootItem(self.glb) def columnCount(self, parent=None): return 7 def columnHeader(self, column): headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "] return headers[column] def columnAlignment(self, column): alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ] return alignment[column] def DoFindSelect(self, query, match): QueryExec(query, "SELECT call_path_id, comm_id, thread_id" " FROM calls" " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" " WHERE symbols.name" + match + " GROUP BY comm_id, thread_id, call_path_id" " ORDER BY comm_id, thread_id, call_path_id") def FindPath(self, query): # Turn the query result into a list of ids that the tree view can walk # to open the tree at the right place. ids = [] parent_id = query.value(0) while parent_id: ids.insert(0, parent_id) q2 = QSqlQuery(self.glb.db) QueryExec(q2, "SELECT parent_id" " FROM call_paths" " WHERE id = " + str(parent_id)) if not q2.next(): break parent_id = q2.value(0) # The call path root is not used if ids[0] == 1: del ids[0] ids.insert(0, query.value(2)) ids.insert(0, query.value(1)) return ids # Call tree data model level 2+ item base class CallTreeLevelTwoPlusItemBase(CallGraphLevelItemBase): def __init__(self, glb, row, comm_id, thread_id, calls_id, time, branch_count, parent_item): super(CallTreeLevelTwoPlusItemBase, self).__init__(glb, row, parent_item) self.comm_id = comm_id self.thread_id = thread_id self.calls_id = calls_id self.branch_count = branch_count self.time = time def Select(self): self.query_done = True; if self.calls_id == 0: comm_thread = " AND comm_id = " + str(self.comm_id) + " AND thread_id = " + str(self.thread_id) else: comm_thread = "" query = QSqlQuery(self.glb.db) QueryExec(query, "SELECT calls.id, name, short_name, call_time, return_time - call_time, branch_count" " FROM calls" " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" " INNER JOIN dsos ON symbols.dso_id = dsos.id" " WHERE calls.parent_id = " + str(self.calls_id) + comm_thread + " ORDER BY call_time, calls.id") while query.next(): child_item = CallTreeLevelThreeItem(self.glb, self.child_count, self.comm_id, self.thread_id, query.value(0), query.value(1), query.value(2), query.value(3), int(query.value(4)), int(query.value(5)), self) self.child_items.append(child_item) self.child_count += 1 # Call tree data model level three item class CallTreeLevelThreeItem(CallTreeLevelTwoPlusItemBase): def __init__(self, glb, row, comm_id, thread_id, calls_id, name, dso, count, time, branch_count, parent_item): super(CallTreeLevelThreeItem, self).__init__(glb, row, comm_id, thread_id, calls_id, time, branch_count, parent_item) dso = dsoname(dso) self.data = [ name, dso, str(count), str(time), PercentToOneDP(time, parent_item.time), str(branch_count), PercentToOneDP(branch_count, parent_item.branch_count) ] self.dbid = calls_id # Call tree data model level two item class CallTreeLevelTwoItem(CallTreeLevelTwoPlusItemBase): def __init__(self, glb, row, comm_id, thread_id, pid, tid, parent_item): super(CallTreeLevelTwoItem, self).__init__(glb, row, comm_id, thread_id, 0, 0, 0, parent_item) self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", ""] self.dbid = thread_id def Select(self): super(CallTreeLevelTwoItem, self).Select() for child_item in self.child_items: self.time += child_item.time self.branch_count += child_item.branch_count for child_item in self.child_items: child_item.data[4] = PercentToOneDP(child_item.time, self.time) child_item.data[6] = PercentToOneDP(child_item.branch_count, self.branch_count) # Call tree data model level one item class CallTreeLevelOneItem(CallGraphLevelItemBase): def __init__(self, glb, row, comm_id, comm, parent_item): super(CallTreeLevelOneItem, self).__init__(glb, row, parent_item) self.data = [comm, "", "", "", "", "", ""] self.dbid = comm_id def Select(self): self.query_done = True; query = QSqlQuery(self.glb.db) QueryExec(query, "SELECT thread_id, pid, tid" " FROM comm_threads" " INNER JOIN threads ON thread_id = threads.id" " WHERE comm_id = " + str(self.dbid)) while query.next(): child_item = CallTreeLevelTwoItem(self.glb, self.child_count, self.dbid, query.value(0), query.value(1), query.value(2), self) self.child_items.append(child_item) self.child_count += 1 # Call tree data model root item class CallTreeRootItem(CallGraphLevelItemBase): def __init__(self, glb): super(CallTreeRootItem, self).__init__(glb, 0, None) self.dbid = 0 self.query_done = True; query = QSqlQuery(glb.db) QueryExec(query, "SELECT id, comm FROM comms") while query.next(): if not query.value(0): continue child_item = CallTreeLevelOneItem(glb, self.child_count, query.value(0), query.value(1), self) self.child_items.append(child_item) self.child_count += 1 # Call Tree data model class CallTreeModel(CallGraphModelBase): def __init__(self, glb, parent=None): super(CallTreeModel, self).__init__(glb, parent) def GetRoot(self): return CallTreeRootItem(self.glb) def columnCount(self, parent=None): return 7 def columnHeader(self, column): headers = ["Call Path", "Object", "Call Time", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "] return headers[column] def columnAlignment(self, column): alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ] return alignment[column] def DoFindSelect(self, query, match): QueryExec(query, "SELECT calls.id, comm_id, thread_id" " FROM calls" " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" " WHERE symbols.name" + match + " ORDER BY comm_id, thread_id, call_time, calls.id") def FindPath(self, query): # Turn the query result into a list of ids that the tree view can walk # to open the tree at the right place. ids = [] parent_id = query.value(0) while parent_id: ids.insert(0, parent_id) q2 = QSqlQuery(self.glb.db) QueryExec(q2, "SELECT parent_id" " FROM calls" " WHERE id = " + str(parent_id)) if not q2.next(): break parent_id = q2.value(0) ids.insert(0, query.value(2)) ids.insert(0, query.value(1)) return ids # Vertical widget layout class VBox(): def __init__(self, w1, w2, w3=None): self.vbox = QWidget() self.vbox.setLayout(QVBoxLayout()); self.vbox.layout().setContentsMargins(0, 0, 0, 0) self.vbox.layout().addWidget(w1) self.vbox.layout().addWidget(w2) if w3: self.vbox.layout().addWidget(w3) def Widget(self): return self.vbox # Tree window base class TreeWindowBase(QMdiSubWindow): def __init__(self, parent=None): super(TreeWindowBase, self).__init__(parent) self.model = None self.view = None self.find_bar = None def DisplayFound(self, ids): if not len(ids): return False parent = QModelIndex() for dbid in ids: found = False n = self.model.rowCount(parent) for row in xrange(n): child = self.model.index(row, 0, parent) if child.internalPointer().dbid == dbid: found = True self.view.setCurrentIndex(child) parent = child break if not found: break return found def Find(self, value, direction, pattern, context): self.view.setFocus() self.find_bar.Busy() self.model.Find(value, direction, pattern, context, self.FindDone) def FindDone(self, ids): found = True if not self.DisplayFound(ids): found = False self.find_bar.Idle() if not found: self.find_bar.NotFound() # Context-sensitive call graph window class CallGraphWindow(TreeWindowBase): 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.find_bar = FindBar(self, self) self.vbox = VBox(self.view, self.find_bar.Widget()) self.setWidget(self.vbox.Widget()) AddSubWindow(glb.mainwindow.mdi_area, self, "Context-Sensitive Call Graph") # Call tree window class CallTreeWindow(TreeWindowBase): def __init__(self, glb, parent=None): super(CallTreeWindow, self).__init__(parent) 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)): self.view.setColumnWidth(c, w) self.find_bar = FindBar(self, self) self.vbox = VBox(self.view, self.find_bar.Widget()) self.setWidget(self.vbox.Widget()) AddSubWindow(glb.mainwindow.mdi_area, self, "Call Tree") # Child data item finder class ChildDataItemFinder(): def __init__(self, root): self.root = root self.value, self.direction, self.pattern, self.last_value, self.last_pattern = (None,) * 5 self.rows = [] self.pos = 0 def FindSelect(self): self.rows = [] if self.pattern: pattern = re.compile(self.value) for child in self.root.child_items: for column_data in child.data: if re.search(pattern, str(column_data)) is not None: self.rows.append(child.row) break else: for child in self.root.child_items: for column_data in child.data: if self.value in str(column_data): self.rows.append(child.row) break def FindValue(self): self.pos = 0 if self.last_value != self.value or self.pattern != self.last_pattern: self.FindSelect() if not len(self.rows): return -1 return self.rows[self.pos] def FindThread(self): if self.direction == 0 or self.value != self.last_value or self.pattern != self.last_pattern: row = self.FindValue() elif len(self.rows): if self.direction > 0: self.pos += 1Lines 501–1000 of 3073. Previous lines Load more
" INNER JOIN call_paths ON calls.call_path_id = call_paths.id" " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" " INNER JOIN dsos ON symbols.dso_id = dsos.id" " WHERE parent_call_path_id = " + str(self.call_path_id) + " AND comm_id = " + str(self.comm_id) + " AND thread_id = " + str(self.thread_id) + " GROUP BY call_path_id, name, short_name" " ORDER BY call_path_id") while query.next(): child_item = CallGraphLevelThreeItem(self.glb, self.child_count, self.comm_id, self.thread_id, query.value(0), query.value(1), query.value(2), query.value(3), int(query.value(4)), int(query.value(5)), self) self.child_items.append(child_item) self.child_count += 1 # Context-sensitive call graph data model level three item class CallGraphLevelThreeItem(CallGraphLevelTwoPlusItemBase): def __init__(self, glb, row, comm_id, thread_id, call_path_id, name, dso, count, time, branch_count, parent_item): super(CallGraphLevelThreeItem, self).__init__(glb, row, comm_id, thread_id, call_path_id, time, branch_count, parent_item) dso = dsoname(dso) self.data = [ name, dso, str(count), str(time), PercentToOneDP(time, parent_item.time), str(branch_count), PercentToOneDP(branch_count, parent_item.branch_count) ] self.dbid = call_path_id # Context-sensitive call graph data model level two item class CallGraphLevelTwoItem(CallGraphLevelTwoPlusItemBase): def __init__(self, glb, row, comm_id, thread_id, pid, tid, parent_item): super(CallGraphLevelTwoItem, self).__init__(glb, row, comm_id, thread_id, 1, 0, 0, parent_item) self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", ""] self.dbid = thread_id def Select(self): super(CallGraphLevelTwoItem, self).Select() for child_item in self.child_items: self.time += child_item.time self.branch_count += child_item.branch_count for child_item in self.child_items: child_item.data[4] = PercentToOneDP(child_item.time, self.time) child_item.data[6] = PercentToOneDP(child_item.branch_count, self.branch_count) # Context-sensitive call graph data model level one item class CallGraphLevelOneItem(CallGraphLevelItemBase): def __init__(self, glb, row, comm_id, comm, parent_item): super(CallGraphLevelOneItem, self).__init__(glb, row, parent_item) self.data = [comm, "", "", "", "", "", ""] self.dbid = comm_id def Select(self): self.query_done = True; query = QSqlQuery(self.glb.db) QueryExec(query, "SELECT thread_id, pid, tid" " FROM comm_threads" " INNER JOIN threads ON thread_id = threads.id" " WHERE comm_id = " + str(self.dbid)) while query.next(): child_item = CallGraphLevelTwoItem(self.glb, self.child_count, self.dbid, query.value(0), query.value(1), query.value(2), self) self.child_items.append(child_item) self.child_count += 1 # Context-sensitive call graph data model root item class CallGraphRootItem(CallGraphLevelItemBase): def __init__(self, glb): super(CallGraphRootItem, self).__init__(glb, 0, None) self.dbid = 0 self.query_done = True; query = QSqlQuery(glb.db) QueryExec(query, "SELECT id, comm FROM comms") while query.next(): if not query.value(0): continue child_item = CallGraphLevelOneItem(glb, self.child_count, query.value(0), query.value(1), self) self.child_items.append(child_item) self.child_count += 1 # Context-sensitive call graph data model base class CallGraphModelBase(TreeModel): def __init__(self, glb, parent=None): super(CallGraphModelBase, self).__init__(glb, parent) def FindSelect(self, value, pattern, query): if pattern: # postgresql and sqlite pattern patching differences: # postgresql LIKE is case sensitive but sqlite LIKE is not # postgresql LIKE allows % and _ to be escaped with \ but sqlite LIKE does not # postgresql supports ILIKE which is case insensitive # sqlite supports GLOB (text only) which uses * and ? and is case sensitive if not self.glb.dbref.is_sqlite3: # Escape % and _ s = value.replace("%", "\%") s = s.replace("_", "\_") # Translate * and ? into SQL LIKE pattern characters % and _ trans = string.maketrans("*?", "%_") match = " LIKE '" + str(s).translate(trans) + "'" else: match = " GLOB '" + str(value) + "'" else: match = " = '" + str(value) + "'" self.DoFindSelect(query, match) def Found(self, query, found): if found: return self.FindPath(query) return [] def FindValue(self, value, pattern, query, last_value, last_pattern): if last_value == value and pattern == last_pattern: found = query.first() else: self.FindSelect(value, pattern, query) found = query.next() return self.Found(query, found) def FindNext(self, query): found = query.next() if not found: found = query.first() return self.Found(query, found) def FindPrev(self, query): found = query.previous() if not found: found = query.last() return self.Found(query, found) def FindThread(self, c): if c.direction == 0 or c.value != c.last_value or c.pattern != c.last_pattern: ids = self.FindValue(c.value, c.pattern, c.query, c.last_value, c.last_pattern) elif c.direction > 0: ids = self.FindNext(c.query) else: ids = self.FindPrev(c.query) return (True, ids) def Find(self, value, direction, pattern, context, callback): class Context(): def __init__(self, *x): self.value, self.direction, self.pattern, self.query, self.last_value, self.last_pattern = x def Update(self, *x): self.value, self.direction, self.pattern, self.last_value, self.last_pattern = x + (self.value, self.pattern) if len(context): context[0].Update(value, direction, pattern) else: context.append(Context(value, direction, pattern, QSqlQuery(self.glb.db), None, None)) # Use a thread so the UI is not blocked during the SELECT thread = Thread(self.FindThread, context[0]) thread.done.connect(lambda ids, t=thread, c=callback: self.FindDone(t, c, ids), Qt.QueuedConnection) thread.start() def FindDone(self, thread, callback, ids): callback(ids) # Context-sensitive call graph data model class CallGraphModel(CallGraphModelBase): def __init__(self, glb, parent=None): super(CallGraphModel, self).__init__(glb, parent) def GetRoot(self): return CallGraphRootItem(self.glb) def columnCount(self, parent=None): return 7 def columnHeader(self, column): headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "] return headers[column] def columnAlignment(self, column): alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ] return alignment[column] def DoFindSelect(self, query, match): QueryExec(query, "SELECT call_path_id, comm_id, thread_id" " FROM calls" " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" " WHERE symbols.name" + match + " GROUP BY comm_id, thread_id, call_path_id" " ORDER BY comm_id, thread_id, call_path_id") def FindPath(self, query): # Turn the query result into a list of ids that the tree view can walk # to open the tree at the right place. ids = [] parent_id = query.value(0) while parent_id: ids.insert(0, parent_id) q2 = QSqlQuery(self.glb.db) QueryExec(q2, "SELECT parent_id" " FROM call_paths" " WHERE id = " + str(parent_id)) if not q2.next(): break parent_id = q2.value(0) # The call path root is not used if ids[0] == 1: del ids[0] ids.insert(0, query.value(2)) ids.insert(0, query.value(1)) return ids # Call tree data model level 2+ item base class CallTreeLevelTwoPlusItemBase(CallGraphLevelItemBase): def __init__(self, glb, row, comm_id, thread_id, calls_id, time, branch_count, parent_item): super(CallTreeLevelTwoPlusItemBase, self).__init__(glb, row, parent_item) self.comm_id = comm_id self.thread_id = thread_id self.calls_id = calls_id self.branch_count = branch_count self.time = time def Select(self): self.query_done = True; if self.calls_id == 0: comm_thread = " AND comm_id = " + str(self.comm_id) + " AND thread_id = " + str(self.thread_id) else: comm_thread = "" query = QSqlQuery(self.glb.db) QueryExec(query, "SELECT calls.id, name, short_name, call_time, return_time - call_time, branch_count" " FROM calls" " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" " INNER JOIN dsos ON symbols.dso_id = dsos.id" " WHERE calls.parent_id = " + str(self.calls_id) + comm_thread + " ORDER BY call_time, calls.id") while query.next(): child_item = CallTreeLevelThreeItem(self.glb, self.child_count, self.comm_id, self.thread_id, query.value(0), query.value(1), query.value(2), query.value(3), int(query.value(4)), int(query.value(5)), self) self.child_items.append(child_item) self.child_count += 1 # Call tree data model level three item class CallTreeLevelThreeItem(CallTreeLevelTwoPlusItemBase): def __init__(self, glb, row, comm_id, thread_id, calls_id, name, dso, count, time, branch_count, parent_item): super(CallTreeLevelThreeItem, self).__init__(glb, row, comm_id, thread_id, calls_id, time, branch_count, parent_item) dso = dsoname(dso) self.data = [ name, dso, str(count), str(time), PercentToOneDP(time, parent_item.time), str(branch_count), PercentToOneDP(branch_count, parent_item.branch_count) ] self.dbid = calls_id # Call tree data model level two item class CallTreeLevelTwoItem(CallTreeLevelTwoPlusItemBase): def __init__(self, glb, row, comm_id, thread_id, pid, tid, parent_item): super(CallTreeLevelTwoItem, self).__init__(glb, row, comm_id, thread_id, 0, 0, 0, parent_item) self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", ""] self.dbid = thread_id def Select(self): super(CallTreeLevelTwoItem, self).Select() for child_item in self.child_items: self.time += child_item.time self.branch_count += child_item.branch_count for child_item in self.child_items: child_item.data[4] = PercentToOneDP(child_item.time, self.time) child_item.data[6] = PercentToOneDP(child_item.branch_count, self.branch_count) # Call tree data model level one item class CallTreeLevelOneItem(CallGraphLevelItemBase): def __init__(self, glb, row, comm_id, comm, parent_item): super(CallTreeLevelOneItem, self).__init__(glb, row, parent_item) self.data = [comm, "", "", "", "", "", ""] self.dbid = comm_id def Select(self): self.query_done = True; query = QSqlQuery(self.glb.db) QueryExec(query, "SELECT thread_id, pid, tid" " FROM comm_threads" " INNER JOIN threads ON thread_id = threads.id" " WHERE comm_id = " + str(self.dbid)) while query.next(): child_item = CallTreeLevelTwoItem(self.glb, self.child_count, self.dbid, query.value(0), query.value(1), query.value(2), self) self.child_items.append(child_item) self.child_count += 1 # Call tree data model root item class CallTreeRootItem(CallGraphLevelItemBase): def __init__(self, glb): super(CallTreeRootItem, self).__init__(glb, 0, None) self.dbid = 0 self.query_done = True; query = QSqlQuery(glb.db) QueryExec(query, "SELECT id, comm FROM comms") while query.next(): if not query.value(0): continue child_item = CallTreeLevelOneItem(glb, self.child_count, query.value(0), query.value(1), self) self.child_items.append(child_item) self.child_count += 1 # Call Tree data model class CallTreeModel(CallGraphModelBase): def __init__(self, glb, parent=None): super(CallTreeModel, self).__init__(glb, parent) def GetRoot(self): return CallTreeRootItem(self.glb) def columnCount(self, parent=None): return 7 def columnHeader(self, column): headers = ["Call Path", "Object", "Call Time", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "] return headers[column] def columnAlignment(self, column): alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ] return alignment[column] def DoFindSelect(self, query, match): QueryExec(query, "SELECT calls.id, comm_id, thread_id" " FROM calls" " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" " WHERE symbols.name" + match + " ORDER BY comm_id, thread_id, call_time, calls.id") def FindPath(self, query): # Turn the query result into a list of ids that the tree view can walk # to open the tree at the right place. ids = [] parent_id = query.value(0) while parent_id: ids.insert(0, parent_id) q2 = QSqlQuery(self.glb.db) QueryExec(q2, "SELECT parent_id" " FROM calls" " WHERE id = " + str(parent_id)) if not q2.next(): break parent_id = q2.value(0) ids.insert(0, query.value(2)) ids.insert(0, query.value(1)) return ids # Vertical widget layout class VBox(): def __init__(self, w1, w2, w3=None): self.vbox = QWidget() self.vbox.setLayout(QVBoxLayout()); self.vbox.layout().setContentsMargins(0, 0, 0, 0) self.vbox.layout().addWidget(w1) self.vbox.layout().addWidget(w2) if w3: self.vbox.layout().addWidget(w3) def Widget(self): return self.vbox # Tree window base class TreeWindowBase(QMdiSubWindow): def __init__(self, parent=None): super(TreeWindowBase, self).__init__(parent) self.model = None self.view = None self.find_bar = None def DisplayFound(self, ids): if not len(ids): return False parent = QModelIndex() for dbid in ids: found = False n = self.model.rowCount(parent) for row in xrange(n): child = self.model.index(row, 0, parent) if child.internalPointer().dbid == dbid: found = True self.view.setCurrentIndex(child) parent = child break if not found: break return found def Find(self, value, direction, pattern, context): self.view.setFocus() self.find_bar.Busy() self.model.Find(value, direction, pattern, context, self.FindDone) def FindDone(self, ids): found = True if not self.DisplayFound(ids): found = False self.find_bar.Idle() if not found: self.find_bar.NotFound() # Context-sensitive call graph window class CallGraphWindow(TreeWindowBase): 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.find_bar = FindBar(self, self) self.vbox = VBox(self.view, self.find_bar.Widget()) self.setWidget(self.vbox.Widget()) AddSubWindow(glb.mainwindow.mdi_area, self, "Context-Sensitive Call Graph") # Call tree window class CallTreeWindow(TreeWindowBase): def __init__(self, glb, parent=None): super(CallTreeWindow, self).__init__(parent) 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)): self.view.setColumnWidth(c, w) self.find_bar = FindBar(self, self) self.vbox = VBox(self.view, self.find_bar.Widget()) self.setWidget(self.vbox.Widget()) AddSubWindow(glb.mainwindow.mdi_area, self, "Call Tree") # Child data item finder class ChildDataItemFinder(): def __init__(self, root): self.root = root self.value, self.direction, self.pattern, self.last_value, self.last_pattern = (None,) * 5 self.rows = [] self.pos = 0 def FindSelect(self): self.rows = [] if self.pattern: pattern = re.compile(self.value) for child in self.root.child_items: for column_data in child.data: if re.search(pattern, str(column_data)) is not None: self.rows.append(child.row) break else: for child in self.root.child_items: for column_data in child.data: if self.value in str(column_data): self.rows.append(child.row) break def FindValue(self): self.pos = 0 if self.last_value != self.value or self.pattern != self.last_pattern: self.FindSelect() if not len(self.rows): return -1 return self.rows[self.pos] def FindThread(self): if self.direction == 0 or self.value != self.last_value or self.pattern != self.last_pattern: row = self.FindValue() elif len(self.rows): if self.direction > 0: self.pos += 1