def childCount(self): if not self.query_done: self.Select() if not self.child_count: return -1 return self.child_count def hasChildren(self): if not self.query_done: return True return self.child_count > 0 def getData(self, column): return self.data[column] # Context-sensitive call graph data model level 2+ item base class CallGraphLevelTwoPlusItemBase(CallGraphLevelItemBase): def __init__(self, glb, params, row, comm_id, thread_id, call_path_id, time, insn_cnt, cyc_cnt, branch_count, parent_item): super(CallGraphLevelTwoPlusItemBase, self).__init__(glb, params, row, parent_item) self.comm_id = comm_id self.thread_id = thread_id self.call_path_id = call_path_id self.insn_cnt = insn_cnt self.cyc_cnt = cyc_cnt self.branch_count = branch_count self.time = time def Select(self): self.query_done = True query = QSqlQuery(self.glb.db) if self.params.have_ipc: ipc_str = ", SUM(insn_count), SUM(cyc_count)" else: ipc_str = "" QueryExec(query, "SELECT call_path_id, name, short_name, COUNT(calls.id), SUM(return_time - call_time)" + ipc_str + ", SUM(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 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(): if self.params.have_ipc: insn_cnt = int(query.value(5)) cyc_cnt = int(query.value(6)) branch_count = int(query.value(7)) else: insn_cnt = 0 cyc_cnt = 0 branch_count = int(query.value(5)) child_item = CallGraphLevelThreeItem(self.glb, self.params, 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)), insn_cnt, cyc_cnt, branch_count, 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, params, row, comm_id, thread_id, call_path_id, name, dso, count, time, insn_cnt, cyc_cnt, branch_count, parent_item): super(CallGraphLevelThreeItem, self).__init__(glb, params, row, comm_id, thread_id, call_path_id, time, insn_cnt, cyc_cnt, branch_count, parent_item) dso = dsoname(dso) if self.params.have_ipc: insn_pcnt = PercentToOneDP(insn_cnt, parent_item.insn_cnt) cyc_pcnt = PercentToOneDP(cyc_cnt, parent_item.cyc_cnt) br_pcnt = PercentToOneDP(branch_count, parent_item.branch_count) ipc = CalcIPC(cyc_cnt, insn_cnt) self.data = [ name, dso, str(count), str(time), PercentToOneDP(time, parent_item.time), str(insn_cnt), insn_pcnt, str(cyc_cnt), cyc_pcnt, ipc, str(branch_count), br_pcnt ] else: 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, params, row, comm_id, thread_id, pid, tid, parent_item): super(CallGraphLevelTwoItem, self).__init__(glb, params, row, comm_id, thread_id, 1, 0, 0, 0, 0, parent_item) if self.params.have_ipc: self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", "", "", "", "", "", ""] else: 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.insn_cnt += child_item.insn_cnt self.cyc_cnt += child_item.cyc_cnt self.branch_count += child_item.branch_count for child_item in self.child_items: child_item.data[4] = PercentToOneDP(child_item.time, self.time) if self.params.have_ipc: child_item.data[6] = PercentToOneDP(child_item.insn_cnt, self.insn_cnt) child_item.data[8] = PercentToOneDP(child_item.cyc_cnt, self.cyc_cnt) child_item.data[11] = PercentToOneDP(child_item.branch_count, self.branch_count) else: 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, params, row, comm_id, comm, parent_item): super(CallGraphLevelOneItem, self).__init__(glb, params, row, parent_item) if self.params.have_ipc: self.data = [comm, "", "", "", "", "", "", "", "", "", "", ""] else: 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.params, 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, params): super(CallGraphRootItem, self).__init__(glb, params, 0, None) self.dbid = 0 self.query_done = True if_has_calls = "" if IsSelectable(glb.db, "comms", columns = "has_calls"): if_has_calls = " WHERE has_calls = " + glb.dbref.TRUE query = QSqlQuery(glb.db) QueryExec(query, "SELECT id, comm FROM comms" + if_has_calls) while query.next(): if not query.value(0): continue child_item = CallGraphLevelOneItem(glb, params, self.child_count, query.value(0), query.value(1), self) self.child_items.append(child_item) self.child_count += 1 # Call graph model parameters class CallGraphModelParams(): def __init__(self, glb, parent=None): self.have_ipc = IsSelectable(glb.db, "calls", columns = "insn_count, cyc_count") # Context-sensitive call graph data model base class CallGraphModelBase(TreeModel): def __init__(self, glb, parent=None): super(CallGraphModelBase, self).__init__(glb, CallGraphModelParams(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, self.params) def columnCount(self, parent=None): if self.params.have_ipc: return 12 else: return 7 def columnHeader(self, column): if self.params.have_ipc: headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Insn Cnt", "Insn Cnt (%)", "Cyc Cnt", "Cyc Cnt (%)", "IPC", "Branch Count ", "Branch Count (%) "] else: headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "] return headers[column] def columnAlignment(self, column): if self.params.have_ipc: alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ] else: 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 calls.id <> 0" " AND 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, params, row, comm_id, thread_id, calls_id, call_time, time, insn_cnt, cyc_cnt, branch_count, parent_item): super(CallTreeLevelTwoPlusItemBase, self).__init__(glb, params, row, parent_item) self.comm_id = comm_id self.thread_id = thread_id self.calls_id = calls_id self.call_time = call_time self.time = time self.insn_cnt = insn_cnt self.cyc_cnt = cyc_cnt self.branch_count = branch_count 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 = "" if self.params.have_ipc: ipc_str = ", insn_count, cyc_count" else: ipc_str = "" query = QSqlQuery(self.glb.db) QueryExec(query, "SELECT calls.id, name, short_name, call_time, return_time - call_time" + ipc_str + ", 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(): if self.params.have_ipc: insn_cnt = int(query.value(5)) cyc_cnt = int(query.value(6)) branch_count = int(query.value(7)) else: insn_cnt = 0 cyc_cnt = 0 branch_count = int(query.value(5)) child_item = CallTreeLevelThreeItem(self.glb, self.params, 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)), insn_cnt, cyc_cnt, branch_count, 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, params, row, comm_id, thread_id, calls_id, name, dso, call_time, time, insn_cnt, cyc_cnt, branch_count, parent_item): super(CallTreeLevelThreeItem, self).__init__(glb, params, row, comm_id, thread_id, calls_id, call_time, time, insn_cnt, cyc_cnt, branch_count, parent_item) dso = dsoname(dso) if self.params.have_ipc: insn_pcnt = PercentToOneDP(insn_cnt, parent_item.insn_cnt) cyc_pcnt = PercentToOneDP(cyc_cnt, parent_item.cyc_cnt) br_pcnt = PercentToOneDP(branch_count, parent_item.branch_count) ipc = CalcIPC(cyc_cnt, insn_cnt) self.data = [ name, dso, str(call_time), str(time), PercentToOneDP(time, parent_item.time), str(insn_cnt), insn_pcnt, str(cyc_cnt), cyc_pcnt, ipc, str(branch_count), br_pcnt ] else: self.data = [ name, dso, str(call_time), 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, params, row, comm_id, thread_id, pid, tid, parent_item): super(CallTreeLevelTwoItem, self).__init__(glb, params, row, comm_id, thread_id, 0, 0, 0, 0, 0, 0, parent_item) if self.params.have_ipc: self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", "", "", "", "", "", ""] else: 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.insn_cnt += child_item.insn_cnt self.cyc_cnt += child_item.cyc_cnt self.branch_count += child_item.branch_count for child_item in self.child_items: child_item.data[4] = PercentToOneDP(child_item.time, self.time) if self.params.have_ipc: child_item.data[6] = PercentToOneDP(child_item.insn_cnt, self.insn_cnt) child_item.data[8] = PercentToOneDP(child_item.cyc_cnt, self.cyc_cnt) child_item.data[11] = PercentToOneDP(child_item.branch_count, self.branch_count) else: 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, params, row, comm_id, comm, parent_item): super(CallTreeLevelOneItem, self).__init__(glb, params, row, parent_item) if self.params.have_ipc: self.data = [comm, "", "", "", "", "", "", "", "", "", "", ""] else: 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.params, 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, params): super(CallTreeRootItem, self).__init__(glb, params, 0, None) self.dbid = 0 self.query_done = True if_has_calls = "" if IsSelectable(glb.db, "comms", columns = "has_calls"): if_has_calls = " WHERE has_calls = " + glb.dbref.TRUE query = QSqlQuery(glb.db) QueryExec(query, "SELECT id, comm FROM comms" + if_has_calls) while query.next(): if not query.value(0): continue child_item = CallTreeLevelOneItem(glb, params, 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, self.params) def columnCount(self, parent=None): if self.params.have_ipc: return 12 else: return 7 def columnHeader(self, column): if self.params.have_ipc: headers = ["Call Path", "Object", "Call Time", "Time (ns) ", "Time (%) ", "Insn Cnt", "Insn Cnt (%)", "Cyc Cnt", "Cyc Cnt (%)", "IPC", "Branch Count ", "Branch Count (%) "] else: headers = ["Call Path", "Object", "Call Time", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "] return headers[column] def columnAlignment(self, column): if self.params.have_ipc: alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ] else: 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 calls.id <> 0" " AND 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 layout class HBoxLayout(QHBoxLayout): def __init__(self, *children): super(HBoxLayout, self).__init__() self.layout().setContentsMargins(0, 0, 0, 0) for child in children: if child.isWidgetType(): self.layout().addWidget(child) else:Lines 501–1000 of 5108. Previous lines Load more
def childCount(self): if not self.query_done: self.Select() if not self.child_count: return -1 return self.child_count def hasChildren(self): if not self.query_done: return True return self.child_count > 0 def getData(self, column): return self.data[column] # Context-sensitive call graph data model level 2+ item base class CallGraphLevelTwoPlusItemBase(CallGraphLevelItemBase): def __init__(self, glb, params, row, comm_id, thread_id, call_path_id, time, insn_cnt, cyc_cnt, branch_count, parent_item): super(CallGraphLevelTwoPlusItemBase, self).__init__(glb, params, row, parent_item) self.comm_id = comm_id self.thread_id = thread_id self.call_path_id = call_path_id self.insn_cnt = insn_cnt self.cyc_cnt = cyc_cnt self.branch_count = branch_count self.time = time def Select(self): self.query_done = True query = QSqlQuery(self.glb.db) if self.params.have_ipc: ipc_str = ", SUM(insn_count), SUM(cyc_count)" else: ipc_str = "" QueryExec(query, "SELECT call_path_id, name, short_name, COUNT(calls.id), SUM(return_time - call_time)" + ipc_str + ", SUM(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 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(): if self.params.have_ipc: insn_cnt = int(query.value(5)) cyc_cnt = int(query.value(6)) branch_count = int(query.value(7)) else: insn_cnt = 0 cyc_cnt = 0 branch_count = int(query.value(5)) child_item = CallGraphLevelThreeItem(self.glb, self.params, 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)), insn_cnt, cyc_cnt, branch_count, 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, params, row, comm_id, thread_id, call_path_id, name, dso, count, time, insn_cnt, cyc_cnt, branch_count, parent_item): super(CallGraphLevelThreeItem, self).__init__(glb, params, row, comm_id, thread_id, call_path_id, time, insn_cnt, cyc_cnt, branch_count, parent_item) dso = dsoname(dso) if self.params.have_ipc: insn_pcnt = PercentToOneDP(insn_cnt, parent_item.insn_cnt) cyc_pcnt = PercentToOneDP(cyc_cnt, parent_item.cyc_cnt) br_pcnt = PercentToOneDP(branch_count, parent_item.branch_count) ipc = CalcIPC(cyc_cnt, insn_cnt) self.data = [ name, dso, str(count), str(time), PercentToOneDP(time, parent_item.time), str(insn_cnt), insn_pcnt, str(cyc_cnt), cyc_pcnt, ipc, str(branch_count), br_pcnt ] else: 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, params, row, comm_id, thread_id, pid, tid, parent_item): super(CallGraphLevelTwoItem, self).__init__(glb, params, row, comm_id, thread_id, 1, 0, 0, 0, 0, parent_item) if self.params.have_ipc: self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", "", "", "", "", "", ""] else: 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.insn_cnt += child_item.insn_cnt self.cyc_cnt += child_item.cyc_cnt self.branch_count += child_item.branch_count for child_item in self.child_items: child_item.data[4] = PercentToOneDP(child_item.time, self.time) if self.params.have_ipc: child_item.data[6] = PercentToOneDP(child_item.insn_cnt, self.insn_cnt) child_item.data[8] = PercentToOneDP(child_item.cyc_cnt, self.cyc_cnt) child_item.data[11] = PercentToOneDP(child_item.branch_count, self.branch_count) else: 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, params, row, comm_id, comm, parent_item): super(CallGraphLevelOneItem, self).__init__(glb, params, row, parent_item) if self.params.have_ipc: self.data = [comm, "", "", "", "", "", "", "", "", "", "", ""] else: 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.params, 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, params): super(CallGraphRootItem, self).__init__(glb, params, 0, None) self.dbid = 0 self.query_done = True if_has_calls = "" if IsSelectable(glb.db, "comms", columns = "has_calls"): if_has_calls = " WHERE has_calls = " + glb.dbref.TRUE query = QSqlQuery(glb.db) QueryExec(query, "SELECT id, comm FROM comms" + if_has_calls) while query.next(): if not query.value(0): continue child_item = CallGraphLevelOneItem(glb, params, self.child_count, query.value(0), query.value(1), self) self.child_items.append(child_item) self.child_count += 1 # Call graph model parameters class CallGraphModelParams(): def __init__(self, glb, parent=None): self.have_ipc = IsSelectable(glb.db, "calls", columns = "insn_count, cyc_count") # Context-sensitive call graph data model base class CallGraphModelBase(TreeModel): def __init__(self, glb, parent=None): super(CallGraphModelBase, self).__init__(glb, CallGraphModelParams(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, self.params) def columnCount(self, parent=None): if self.params.have_ipc: return 12 else: return 7 def columnHeader(self, column): if self.params.have_ipc: headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Insn Cnt", "Insn Cnt (%)", "Cyc Cnt", "Cyc Cnt (%)", "IPC", "Branch Count ", "Branch Count (%) "] else: headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "] return headers[column] def columnAlignment(self, column): if self.params.have_ipc: alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ] else: 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 calls.id <> 0" " AND 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, params, row, comm_id, thread_id, calls_id, call_time, time, insn_cnt, cyc_cnt, branch_count, parent_item): super(CallTreeLevelTwoPlusItemBase, self).__init__(glb, params, row, parent_item) self.comm_id = comm_id self.thread_id = thread_id self.calls_id = calls_id self.call_time = call_time self.time = time self.insn_cnt = insn_cnt self.cyc_cnt = cyc_cnt self.branch_count = branch_count 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 = "" if self.params.have_ipc: ipc_str = ", insn_count, cyc_count" else: ipc_str = "" query = QSqlQuery(self.glb.db) QueryExec(query, "SELECT calls.id, name, short_name, call_time, return_time - call_time" + ipc_str + ", 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(): if self.params.have_ipc: insn_cnt = int(query.value(5)) cyc_cnt = int(query.value(6)) branch_count = int(query.value(7)) else: insn_cnt = 0 cyc_cnt = 0 branch_count = int(query.value(5)) child_item = CallTreeLevelThreeItem(self.glb, self.params, 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)), insn_cnt, cyc_cnt, branch_count, 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, params, row, comm_id, thread_id, calls_id, name, dso, call_time, time, insn_cnt, cyc_cnt, branch_count, parent_item): super(CallTreeLevelThreeItem, self).__init__(glb, params, row, comm_id, thread_id, calls_id, call_time, time, insn_cnt, cyc_cnt, branch_count, parent_item) dso = dsoname(dso) if self.params.have_ipc: insn_pcnt = PercentToOneDP(insn_cnt, parent_item.insn_cnt) cyc_pcnt = PercentToOneDP(cyc_cnt, parent_item.cyc_cnt) br_pcnt = PercentToOneDP(branch_count, parent_item.branch_count) ipc = CalcIPC(cyc_cnt, insn_cnt) self.data = [ name, dso, str(call_time), str(time), PercentToOneDP(time, parent_item.time), str(insn_cnt), insn_pcnt, str(cyc_cnt), cyc_pcnt, ipc, str(branch_count), br_pcnt ] else: self.data = [ name, dso, str(call_time), 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, params, row, comm_id, thread_id, pid, tid, parent_item): super(CallTreeLevelTwoItem, self).__init__(glb, params, row, comm_id, thread_id, 0, 0, 0, 0, 0, 0, parent_item) if self.params.have_ipc: self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", "", "", "", "", "", ""] else: 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.insn_cnt += child_item.insn_cnt self.cyc_cnt += child_item.cyc_cnt self.branch_count += child_item.branch_count for child_item in self.child_items: child_item.data[4] = PercentToOneDP(child_item.time, self.time) if self.params.have_ipc: child_item.data[6] = PercentToOneDP(child_item.insn_cnt, self.insn_cnt) child_item.data[8] = PercentToOneDP(child_item.cyc_cnt, self.cyc_cnt) child_item.data[11] = PercentToOneDP(child_item.branch_count, self.branch_count) else: 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, params, row, comm_id, comm, parent_item): super(CallTreeLevelOneItem, self).__init__(glb, params, row, parent_item) if self.params.have_ipc: self.data = [comm, "", "", "", "", "", "", "", "", "", "", ""] else: 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.params, 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, params): super(CallTreeRootItem, self).__init__(glb, params, 0, None) self.dbid = 0 self.query_done = True if_has_calls = "" if IsSelectable(glb.db, "comms", columns = "has_calls"): if_has_calls = " WHERE has_calls = " + glb.dbref.TRUE query = QSqlQuery(glb.db) QueryExec(query, "SELECT id, comm FROM comms" + if_has_calls) while query.next(): if not query.value(0): continue child_item = CallTreeLevelOneItem(glb, params, 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, self.params) def columnCount(self, parent=None): if self.params.have_ipc: return 12 else: return 7 def columnHeader(self, column): if self.params.have_ipc: headers = ["Call Path", "Object", "Call Time", "Time (ns) ", "Time (%) ", "Insn Cnt", "Insn Cnt (%)", "Cyc Cnt", "Cyc Cnt (%)", "IPC", "Branch Count ", "Branch Count (%) "] else: headers = ["Call Path", "Object", "Call Time", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "] return headers[column] def columnAlignment(self, column): if self.params.have_ipc: alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ] else: 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 calls.id <> 0" " AND 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 layout class HBoxLayout(QHBoxLayout): def __init__(self, *children): super(HBoxLayout, self).__init__() self.layout().setContentsMargins(0, 0, 0, 0) for child in children: if child.isWidgetType(): self.layout().addWidget(child) else: