return self.data[column] # Brance data model root item class BranchRootItem(): def __init__(self): self.child_count = 0 self.child_items = [] self.level = 0 def getChildItem(self, row): return self.child_items[row] def getParentItem(self): return None def getRow(self): return 0 def childCount(self): return self.child_count def hasChildren(self): return self.child_count > 0 def getData(self, column): return "" # Calculate instructions per cycle def CalcIPC(cyc_cnt, insn_cnt): if cyc_cnt and insn_cnt: ipc = Decimal(float(insn_cnt) / cyc_cnt) ipc = str(ipc.quantize(Decimal(".01"), rounding=ROUND_HALF_UP)) else: ipc = "0" return ipc # Branch data preparation def BranchDataPrepBr(query, data): data.append(tohex(query.value(8)).rjust(16) + " " + query.value(9) + offstr(query.value(10)) + " (" + dsoname(query.value(11)) + ")" + " -> " + tohex(query.value(12)) + " " + query.value(13) + offstr(query.value(14)) + " (" + dsoname(query.value(15)) + ")") def BranchDataPrepIPC(query, data): insn_cnt = query.value(16) cyc_cnt = query.value(17) ipc = CalcIPC(cyc_cnt, insn_cnt) data.append(insn_cnt) data.append(cyc_cnt) data.append(ipc) def BranchDataPrep(query): data = [] for i in xrange(0, 8): data.append(query.value(i)) BranchDataPrepBr(query, data) return data def BranchDataPrepWA(query): data = [] data.append(query.value(0)) # Workaround pyside failing to handle large integers (i.e. time) in python3 by converting to a string data.append("{:>19}".format(query.value(1))) for i in xrange(2, 8): data.append(query.value(i)) BranchDataPrepBr(query, data) return data def BranchDataWithIPCPrep(query): data = [] for i in xrange(0, 8): data.append(query.value(i)) BranchDataPrepIPC(query, data) BranchDataPrepBr(query, data) return data def BranchDataWithIPCPrepWA(query): data = [] data.append(query.value(0)) # Workaround pyside failing to handle large integers (i.e. time) in python3 by converting to a string data.append("{:>19}".format(query.value(1))) for i in xrange(2, 8): data.append(query.value(i)) BranchDataPrepIPC(query, data) BranchDataPrepBr(query, data) return data # Branch data model class BranchModel(TreeModel): progress = Signal(object) def __init__(self, glb, event_id, where_clause, parent=None): super(BranchModel, self).__init__(glb, None, parent) self.event_id = event_id self.more = True self.populated = 0 self.have_ipc = IsSelectable(glb.db, "samples", columns = "insn_count, cyc_count") if self.have_ipc: select_ipc = ", insn_count, cyc_count" prep_fn = BranchDataWithIPCPrep prep_wa_fn = BranchDataWithIPCPrepWA else: select_ipc = "" prep_fn = BranchDataPrep prep_wa_fn = BranchDataPrepWA sql = ("SELECT samples.id, time, cpu, comm, pid, tid, branch_types.name," " CASE WHEN in_tx = '0' THEN 'No' ELSE 'Yes' END," " ip, symbols.name, sym_offset, dsos.short_name," " to_ip, to_symbols.name, to_sym_offset, to_dsos.short_name" + select_ipc + " FROM samples" " INNER JOIN comms ON comm_id = comms.id" " INNER JOIN threads ON thread_id = threads.id" " INNER JOIN branch_types ON branch_type = branch_types.id" " INNER JOIN symbols ON symbol_id = symbols.id" " INNER JOIN symbols to_symbols ON to_symbol_id = to_symbols.id" " INNER JOIN dsos ON samples.dso_id = dsos.id" " INNER JOIN dsos AS to_dsos ON samples.to_dso_id = to_dsos.id" " WHERE samples.id > $$last_id$$" + where_clause + " AND evsel_id = " + str(self.event_id) + " ORDER BY samples.id" " LIMIT " + str(glb_chunk_sz)) if pyside_version_1 and sys.version_info[0] == 3: prep = prep_fn else: prep = prep_wa_fn self.fetcher = SQLFetcher(glb, sql, prep, self.AddSample) self.fetcher.done.connect(self.Update) self.fetcher.Fetch(glb_chunk_sz) def GetRoot(self): return BranchRootItem() def columnCount(self, parent=None): if self.have_ipc: return 11 else: return 8 def columnHeader(self, column): if self.have_ipc: return ("Time", "CPU", "Command", "PID", "TID", "Branch Type", "In Tx", "Insn Cnt", "Cyc Cnt", "IPC", "Branch")[column] else: return ("Time", "CPU", "Command", "PID", "TID", "Branch Type", "In Tx", "Branch")[column] def columnFont(self, column): if self.have_ipc: br_col = 10 else: br_col = 7 if column != br_col: return None return QFont("Monospace") def DisplayData(self, item, index): if item.level == 1: self.FetchIfNeeded(item.row) return item.getData(index.column()) def AddSample(self, data): child = BranchLevelOneItem(self.glb, self.populated, data, self.root) self.root.child_items.append(child) self.populated += 1 def Update(self, fetched): if not fetched: self.more = False self.progress.emit(0) child_count = self.root.child_count count = self.populated - child_count if count > 0: parent = QModelIndex() self.beginInsertRows(parent, child_count, child_count + count - 1) self.insertRows(child_count, count, parent) self.root.child_count += count self.endInsertRows() self.progress.emit(self.root.child_count) def FetchMoreRecords(self, count): current = self.root.child_count if self.more: self.fetcher.Fetch(count) else: self.progress.emit(0) return current def HasMoreRecords(self): return self.more # Report Variables class ReportVars(): def __init__(self, name = "", where_clause = "", limit = ""): self.name = name self.where_clause = where_clause self.limit = limit def UniqueId(self): return str(self.where_clause + ";" + self.limit) # Branch window class BranchWindow(QMdiSubWindow): def __init__(self, glb, event_id, report_vars, parent=None): super(BranchWindow, self).__init__(parent) model_name = "Branch Events " + str(event_id) + " " + report_vars.UniqueId() self.model = LookupCreateModel(model_name, lambda: BranchModel(glb, event_id, report_vars.where_clause)) self.view = QTreeView() self.view.setUniformRowHeights(True) self.view.setSelectionMode(QAbstractItemView.ContiguousSelection) self.view.CopyCellsToClipboard = CopyTreeCellsToClipboard self.view.setModel(self.model) self.ResizeColumnsToContents() self.context_menu = TreeContextMenu(self.view) self.find_bar = FindBar(self, self, True) self.finder = ChildDataItemFinder(self.model.root) self.fetch_bar = FetchMoreRecordsBar(self.model, self) self.vbox = VBox(self.view, self.find_bar.Widget(), self.fetch_bar.Widget()) self.setWidget(self.vbox.Widget()) AddSubWindow(glb.mainwindow.mdi_area, self, report_vars.name + " Branch Events") def ResizeColumnToContents(self, column, n): # Using the view's resizeColumnToContents() here is extrememly slow # so implement a crude alternative mm = "MM" if column else "MMMM" font = self.view.font() metrics = QFontMetrics(font) max = 0 for row in xrange(n): val = self.model.root.child_items[row].data[column] len = metrics.width(str(val) + mm) max = len if len > max else max val = self.model.columnHeader(column) len = metrics.width(str(val) + mm) max = len if len > max else max self.view.setColumnWidth(column, max) def ResizeColumnsToContents(self): n = min(self.model.root.child_count, 100) if n < 1: # No data yet, so connect a signal to notify when there is self.model.rowsInserted.connect(self.UpdateColumnWidths) return columns = self.model.columnCount() for i in xrange(columns): self.ResizeColumnToContents(i, n) def UpdateColumnWidths(self, *x): # This only needs to be done once, so disconnect the signal now self.model.rowsInserted.disconnect(self.UpdateColumnWidths) self.ResizeColumnsToContents() def Find(self, value, direction, pattern, context): self.view.setFocus() self.find_bar.Busy() self.finder.Find(value, direction, pattern, context, self.FindDone) def FindDone(self, row): self.find_bar.Idle() if row >= 0: self.view.setCurrentIndex(self.model.index(row, 0, QModelIndex())) else: self.find_bar.NotFound() # Line edit data item class LineEditDataItem(object): def __init__(self, glb, label, placeholder_text, parent, id = "", default = ""): self.glb = glb self.label = label self.placeholder_text = placeholder_text self.parent = parent self.id = id self.value = default self.widget = QLineEdit(default) self.widget.editingFinished.connect(self.Validate) self.widget.textChanged.connect(self.Invalidate) self.red = False self.error = "" self.validated = True if placeholder_text: self.widget.setPlaceholderText(placeholder_text) def TurnTextRed(self): if not self.red: palette = QPalette() palette.setColor(QPalette.Text,Qt.red) self.widget.setPalette(palette) self.red = True def TurnTextNormal(self): if self.red: palette = QPalette() self.widget.setPalette(palette) self.red = False def InvalidValue(self, value): self.value = "" self.TurnTextRed() self.error = self.label + " invalid value '" + value + "'" self.parent.ShowMessage(self.error) def Invalidate(self): self.validated = False def DoValidate(self, input_string): self.value = input_string.strip() def Validate(self): self.validated = True self.error = "" self.TurnTextNormal() self.parent.ClearMessage() input_string = self.widget.text() if not len(input_string.strip()): self.value = "" return self.DoValidate(input_string) def IsValid(self): if not self.validated: self.Validate() if len(self.error): self.parent.ShowMessage(self.error) return False return True def IsNumber(self, value): try: x = int(value) except: x = 0 return str(x) == value # Non-negative integer ranges dialog data item class NonNegativeIntegerRangesDataItem(LineEditDataItem): def __init__(self, glb, label, placeholder_text, column_name, parent): super(NonNegativeIntegerRangesDataItem, self).__init__(glb, label, placeholder_text, parent) self.column_name = column_name def DoValidate(self, input_string): singles = [] ranges = [] for value in [x.strip() for x in input_string.split(",")]: if "-" in value: vrange = value.split("-") if len(vrange) != 2 or not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]): return self.InvalidValue(value) ranges.append(vrange) else: if not self.IsNumber(value): return self.InvalidValue(value) singles.append(value) ranges = [("(" + self.column_name + " >= " + r[0] + " AND " + self.column_name + " <= " + r[1] + ")") for r in ranges] if len(singles): ranges.append(self.column_name + " IN (" + ",".join(singles) + ")") self.value = " OR ".join(ranges) # Positive integer dialog data item class PositiveIntegerDataItem(LineEditDataItem): def __init__(self, glb, label, placeholder_text, parent, id = "", default = ""): super(PositiveIntegerDataItem, self).__init__(glb, label, placeholder_text, parent, id, default) def DoValidate(self, input_string): if not self.IsNumber(input_string.strip()): return self.InvalidValue(input_string) value = int(input_string.strip()) if value <= 0: return self.InvalidValue(input_string) self.value = str(value) # Dialog data item converted and validated using a SQL table class SQLTableDataItem(LineEditDataItem): def __init__(self, glb, label, placeholder_text, table_name, match_column, column_name1, column_name2, parent): super(SQLTableDataItem, self).__init__(glb, label, placeholder_text, parent) self.table_name = table_name self.match_column = match_column self.column_name1 = column_name1 self.column_name2 = column_name2 def ValueToIds(self, value): ids = [] query = QSqlQuery(self.glb.db) stmt = "SELECT id FROM " + self.table_name + " WHERE " + self.match_column + " = '" + value + "'" ret = query.exec_(stmt) if ret: while query.next(): ids.append(str(query.value(0))) return ids def DoValidate(self, input_string): all_ids = [] for value in [x.strip() for x in input_string.split(",")]: ids = self.ValueToIds(value) if len(ids): all_ids.extend(ids) else: return self.InvalidValue(value) self.value = self.column_name1 + " IN (" + ",".join(all_ids) + ")" if self.column_name2: self.value = "( " + self.value + " OR " + self.column_name2 + " IN (" + ",".join(all_ids) + ") )" # Sample time ranges dialog data item converted and validated using 'samples' SQL table class SampleTimeRangesDataItem(LineEditDataItem): def __init__(self, glb, label, placeholder_text, column_name, parent): self.column_name = column_name self.last_id = 0 self.first_time = 0 self.last_time = 2 ** 64 query = QSqlQuery(glb.db) QueryExec(query, "SELECT id, time FROM samples ORDER BY id DESC LIMIT 1") if query.next(): self.last_id = int(query.value(0)) self.first_time = int(glb.HostStartTime()) self.last_time = int(glb.HostFinishTime()) if placeholder_text: placeholder_text += ", between " + str(self.first_time) + " and " + str(self.last_time) super(SampleTimeRangesDataItem, self).__init__(glb, label, placeholder_text, parent) def IdBetween(self, query, lower_id, higher_id, order): QueryExec(query, "SELECT id FROM samples WHERE id > " + str(lower_id) + " AND id < " + str(higher_id) + " ORDER BY id " + order + " LIMIT 1") if query.next(): return True, int(query.value(0)) else: return False, 0 def BinarySearchTime(self, lower_id, higher_id, target_time, get_floor): query = QSqlQuery(self.glb.db) while True: next_id = int((lower_id + higher_id) / 2) QueryExec(query, "SELECT time FROM samples WHERE id = " + str(next_id)) if not query.next(): ok, dbid = self.IdBetween(query, lower_id, next_id, "DESC") if not ok: ok, dbid = self.IdBetween(query, next_id, higher_id, "") if not ok: return str(higher_id) next_id = dbid QueryExec(query, "SELECT time FROM samples WHERE id = " + str(next_id)) next_time = int(query.value(0)) if get_floor: if target_time > next_time: lower_id = next_id else: higher_id = next_id if higher_id <= lower_id + 1: return str(higher_id) else: if target_time >= next_time: lower_id = next_id else: higher_id = next_id if higher_id <= lower_id + 1: return str(lower_id) def ConvertRelativeTime(self, val): mult = 1 suffix = val[-2:] if suffix == "ms": mult = 1000000 elif suffix == "us": mult = 1000 elif suffix == "ns": mult = 1Lines 3001–3500 of 5030. Previous lines Load more
return self.data[column] # Brance data model root item class BranchRootItem(): def __init__(self): self.child_count = 0 self.child_items = [] self.level = 0 def getChildItem(self, row): return self.child_items[row] def getParentItem(self): return None def getRow(self): return 0 def childCount(self): return self.child_count def hasChildren(self): return self.child_count > 0 def getData(self, column): return "" # Calculate instructions per cycle def CalcIPC(cyc_cnt, insn_cnt): if cyc_cnt and insn_cnt: ipc = Decimal(float(insn_cnt) / cyc_cnt) ipc = str(ipc.quantize(Decimal(".01"), rounding=ROUND_HALF_UP)) else: ipc = "0" return ipc # Branch data preparation def BranchDataPrepBr(query, data): data.append(tohex(query.value(8)).rjust(16) + " " + query.value(9) + offstr(query.value(10)) + " (" + dsoname(query.value(11)) + ")" + " -> " + tohex(query.value(12)) + " " + query.value(13) + offstr(query.value(14)) + " (" + dsoname(query.value(15)) + ")") def BranchDataPrepIPC(query, data): insn_cnt = query.value(16) cyc_cnt = query.value(17) ipc = CalcIPC(cyc_cnt, insn_cnt) data.append(insn_cnt) data.append(cyc_cnt) data.append(ipc) def BranchDataPrep(query): data = [] for i in xrange(0, 8): data.append(query.value(i)) BranchDataPrepBr(query, data) return data def BranchDataPrepWA(query): data = [] data.append(query.value(0)) # Workaround pyside failing to handle large integers (i.e. time) in python3 by converting to a string data.append("{:>19}".format(query.value(1))) for i in xrange(2, 8): data.append(query.value(i)) BranchDataPrepBr(query, data) return data def BranchDataWithIPCPrep(query): data = [] for i in xrange(0, 8): data.append(query.value(i)) BranchDataPrepIPC(query, data) BranchDataPrepBr(query, data) return data def BranchDataWithIPCPrepWA(query): data = [] data.append(query.value(0)) # Workaround pyside failing to handle large integers (i.e. time) in python3 by converting to a string data.append("{:>19}".format(query.value(1))) for i in xrange(2, 8): data.append(query.value(i)) BranchDataPrepIPC(query, data) BranchDataPrepBr(query, data) return data # Branch data model class BranchModel(TreeModel): progress = Signal(object) def __init__(self, glb, event_id, where_clause, parent=None): super(BranchModel, self).__init__(glb, None, parent) self.event_id = event_id self.more = True self.populated = 0 self.have_ipc = IsSelectable(glb.db, "samples", columns = "insn_count, cyc_count") if self.have_ipc: select_ipc = ", insn_count, cyc_count" prep_fn = BranchDataWithIPCPrep prep_wa_fn = BranchDataWithIPCPrepWA else: select_ipc = "" prep_fn = BranchDataPrep prep_wa_fn = BranchDataPrepWA sql = ("SELECT samples.id, time, cpu, comm, pid, tid, branch_types.name," " CASE WHEN in_tx = '0' THEN 'No' ELSE 'Yes' END," " ip, symbols.name, sym_offset, dsos.short_name," " to_ip, to_symbols.name, to_sym_offset, to_dsos.short_name" + select_ipc + " FROM samples" " INNER JOIN comms ON comm_id = comms.id" " INNER JOIN threads ON thread_id = threads.id" " INNER JOIN branch_types ON branch_type = branch_types.id" " INNER JOIN symbols ON symbol_id = symbols.id" " INNER JOIN symbols to_symbols ON to_symbol_id = to_symbols.id" " INNER JOIN dsos ON samples.dso_id = dsos.id" " INNER JOIN dsos AS to_dsos ON samples.to_dso_id = to_dsos.id" " WHERE samples.id > $$last_id$$" + where_clause + " AND evsel_id = " + str(self.event_id) + " ORDER BY samples.id" " LIMIT " + str(glb_chunk_sz)) if pyside_version_1 and sys.version_info[0] == 3: prep = prep_fn else: prep = prep_wa_fn self.fetcher = SQLFetcher(glb, sql, prep, self.AddSample) self.fetcher.done.connect(self.Update) self.fetcher.Fetch(glb_chunk_sz) def GetRoot(self): return BranchRootItem() def columnCount(self, parent=None): if self.have_ipc: return 11 else: return 8 def columnHeader(self, column): if self.have_ipc: return ("Time", "CPU", "Command", "PID", "TID", "Branch Type", "In Tx", "Insn Cnt", "Cyc Cnt", "IPC", "Branch")[column] else: return ("Time", "CPU", "Command", "PID", "TID", "Branch Type", "In Tx", "Branch")[column] def columnFont(self, column): if self.have_ipc: br_col = 10 else: br_col = 7 if column != br_col: return None return QFont("Monospace") def DisplayData(self, item, index): if item.level == 1: self.FetchIfNeeded(item.row) return item.getData(index.column()) def AddSample(self, data): child = BranchLevelOneItem(self.glb, self.populated, data, self.root) self.root.child_items.append(child) self.populated += 1 def Update(self, fetched): if not fetched: self.more = False self.progress.emit(0) child_count = self.root.child_count count = self.populated - child_count if count > 0: parent = QModelIndex() self.beginInsertRows(parent, child_count, child_count + count - 1) self.insertRows(child_count, count, parent) self.root.child_count += count self.endInsertRows() self.progress.emit(self.root.child_count) def FetchMoreRecords(self, count): current = self.root.child_count if self.more: self.fetcher.Fetch(count) else: self.progress.emit(0) return current def HasMoreRecords(self): return self.more # Report Variables class ReportVars(): def __init__(self, name = "", where_clause = "", limit = ""): self.name = name self.where_clause = where_clause self.limit = limit def UniqueId(self): return str(self.where_clause + ";" + self.limit) # Branch window class BranchWindow(QMdiSubWindow): def __init__(self, glb, event_id, report_vars, parent=None): super(BranchWindow, self).__init__(parent) model_name = "Branch Events " + str(event_id) + " " + report_vars.UniqueId() self.model = LookupCreateModel(model_name, lambda: BranchModel(glb, event_id, report_vars.where_clause)) self.view = QTreeView() self.view.setUniformRowHeights(True) self.view.setSelectionMode(QAbstractItemView.ContiguousSelection) self.view.CopyCellsToClipboard = CopyTreeCellsToClipboard self.view.setModel(self.model) self.ResizeColumnsToContents() self.context_menu = TreeContextMenu(self.view) self.find_bar = FindBar(self, self, True) self.finder = ChildDataItemFinder(self.model.root) self.fetch_bar = FetchMoreRecordsBar(self.model, self) self.vbox = VBox(self.view, self.find_bar.Widget(), self.fetch_bar.Widget()) self.setWidget(self.vbox.Widget()) AddSubWindow(glb.mainwindow.mdi_area, self, report_vars.name + " Branch Events") def ResizeColumnToContents(self, column, n): # Using the view's resizeColumnToContents() here is extrememly slow # so implement a crude alternative mm = "MM" if column else "MMMM" font = self.view.font() metrics = QFontMetrics(font) max = 0 for row in xrange(n): val = self.model.root.child_items[row].data[column] len = metrics.width(str(val) + mm) max = len if len > max else max val = self.model.columnHeader(column) len = metrics.width(str(val) + mm) max = len if len > max else max self.view.setColumnWidth(column, max) def ResizeColumnsToContents(self): n = min(self.model.root.child_count, 100) if n < 1: # No data yet, so connect a signal to notify when there is self.model.rowsInserted.connect(self.UpdateColumnWidths) return columns = self.model.columnCount() for i in xrange(columns): self.ResizeColumnToContents(i, n) def UpdateColumnWidths(self, *x): # This only needs to be done once, so disconnect the signal now self.model.rowsInserted.disconnect(self.UpdateColumnWidths) self.ResizeColumnsToContents() def Find(self, value, direction, pattern, context): self.view.setFocus() self.find_bar.Busy() self.finder.Find(value, direction, pattern, context, self.FindDone) def FindDone(self, row): self.find_bar.Idle() if row >= 0: self.view.setCurrentIndex(self.model.index(row, 0, QModelIndex())) else: self.find_bar.NotFound() # Line edit data item class LineEditDataItem(object): def __init__(self, glb, label, placeholder_text, parent, id = "", default = ""): self.glb = glb self.label = label self.placeholder_text = placeholder_text self.parent = parent self.id = id self.value = default self.widget = QLineEdit(default) self.widget.editingFinished.connect(self.Validate) self.widget.textChanged.connect(self.Invalidate) self.red = False self.error = "" self.validated = True if placeholder_text: self.widget.setPlaceholderText(placeholder_text) def TurnTextRed(self): if not self.red: palette = QPalette() palette.setColor(QPalette.Text,Qt.red) self.widget.setPalette(palette) self.red = True def TurnTextNormal(self): if self.red: palette = QPalette() self.widget.setPalette(palette) self.red = False def InvalidValue(self, value): self.value = "" self.TurnTextRed() self.error = self.label + " invalid value '" + value + "'" self.parent.ShowMessage(self.error) def Invalidate(self): self.validated = False def DoValidate(self, input_string): self.value = input_string.strip() def Validate(self): self.validated = True self.error = "" self.TurnTextNormal() self.parent.ClearMessage() input_string = self.widget.text() if not len(input_string.strip()): self.value = "" return self.DoValidate(input_string) def IsValid(self): if not self.validated: self.Validate() if len(self.error): self.parent.ShowMessage(self.error) return False return True def IsNumber(self, value): try: x = int(value) except: x = 0 return str(x) == value # Non-negative integer ranges dialog data item class NonNegativeIntegerRangesDataItem(LineEditDataItem): def __init__(self, glb, label, placeholder_text, column_name, parent): super(NonNegativeIntegerRangesDataItem, self).__init__(glb, label, placeholder_text, parent) self.column_name = column_name def DoValidate(self, input_string): singles = [] ranges = [] for value in [x.strip() for x in input_string.split(",")]: if "-" in value: vrange = value.split("-") if len(vrange) != 2 or not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]): return self.InvalidValue(value) ranges.append(vrange) else: if not self.IsNumber(value): return self.InvalidValue(value) singles.append(value) ranges = [("(" + self.column_name + " >= " + r[0] + " AND " + self.column_name + " <= " + r[1] + ")") for r in ranges] if len(singles): ranges.append(self.column_name + " IN (" + ",".join(singles) + ")") self.value = " OR ".join(ranges) # Positive integer dialog data item class PositiveIntegerDataItem(LineEditDataItem): def __init__(self, glb, label, placeholder_text, parent, id = "", default = ""): super(PositiveIntegerDataItem, self).__init__(glb, label, placeholder_text, parent, id, default) def DoValidate(self, input_string): if not self.IsNumber(input_string.strip()): return self.InvalidValue(input_string) value = int(input_string.strip()) if value <= 0: return self.InvalidValue(input_string) self.value = str(value) # Dialog data item converted and validated using a SQL table class SQLTableDataItem(LineEditDataItem): def __init__(self, glb, label, placeholder_text, table_name, match_column, column_name1, column_name2, parent): super(SQLTableDataItem, self).__init__(glb, label, placeholder_text, parent) self.table_name = table_name self.match_column = match_column self.column_name1 = column_name1 self.column_name2 = column_name2 def ValueToIds(self, value): ids = [] query = QSqlQuery(self.glb.db) stmt = "SELECT id FROM " + self.table_name + " WHERE " + self.match_column + " = '" + value + "'" ret = query.exec_(stmt) if ret: while query.next(): ids.append(str(query.value(0))) return ids def DoValidate(self, input_string): all_ids = [] for value in [x.strip() for x in input_string.split(",")]: ids = self.ValueToIds(value) if len(ids): all_ids.extend(ids) else: return self.InvalidValue(value) self.value = self.column_name1 + " IN (" + ",".join(all_ids) + ")" if self.column_name2: self.value = "( " + self.value + " OR " + self.column_name2 + " IN (" + ",".join(all_ids) + ") )" # Sample time ranges dialog data item converted and validated using 'samples' SQL table class SampleTimeRangesDataItem(LineEditDataItem): def __init__(self, glb, label, placeholder_text, column_name, parent): self.column_name = column_name self.last_id = 0 self.first_time = 0 self.last_time = 2 ** 64 query = QSqlQuery(glb.db) QueryExec(query, "SELECT id, time FROM samples ORDER BY id DESC LIMIT 1") if query.next(): self.last_id = int(query.value(0)) self.first_time = int(glb.HostStartTime()) self.last_time = int(glb.HostFinishTime()) if placeholder_text: placeholder_text += ", between " + str(self.first_time) + " and " + str(self.last_time) super(SampleTimeRangesDataItem, self).__init__(glb, label, placeholder_text, parent) def IdBetween(self, query, lower_id, higher_id, order): QueryExec(query, "SELECT id FROM samples WHERE id > " + str(lower_id) + " AND id < " + str(higher_id) + " ORDER BY id " + order + " LIMIT 1") if query.next(): return True, int(query.value(0)) else: return False, 0 def BinarySearchTime(self, lower_id, higher_id, target_time, get_floor): query = QSqlQuery(self.glb.db) while True: next_id = int((lower_id + higher_id) / 2) QueryExec(query, "SELECT time FROM samples WHERE id = " + str(next_id)) if not query.next(): ok, dbid = self.IdBetween(query, lower_id, next_id, "DESC") if not ok: ok, dbid = self.IdBetween(query, next_id, higher_id, "") if not ok: return str(higher_id) next_id = dbid QueryExec(query, "SELECT time FROM samples WHERE id = " + str(next_id)) next_time = int(query.value(0)) if get_floor: if target_time > next_time: lower_id = next_id else: higher_id = next_id if higher_id <= lower_id + 1: return str(higher_id) else: if target_time >= next_time: lower_id = next_id else: higher_id = next_id if higher_id <= lower_id + 1: return str(lower_id) def ConvertRelativeTime(self, val): mult = 1 suffix = val[-2:] if suffix == "ms": mult = 1000000 elif suffix == "us": mult = 1000 elif suffix == "ns": mult = 1