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 if self.pos >= len(self.rows): self.pos = 0 else: self.pos -= 1 if self.pos < 0: self.pos = len(self.rows) - 1 row = self.rows[self.pos] else: row = -1 return (True, row) def Find(self, value, direction, pattern, context, callback): self.value, self.direction, self.pattern, self.last_value, self.last_pattern = (value, direction,pattern, self.value, self.pattern) # Use a thread so the UI is not blocked thread = Thread(self.FindThread) thread.done.connect(lambda row, t=thread, c=callback: self.FindDone(t, c, row), Qt.QueuedConnection) thread.start() def FindDone(self, thread, callback, row): callback(row) # Number of database records to fetch in one go glb_chunk_sz = 10000 # Background process for SQL data fetcher class SQLFetcherProcess(): def __init__(self, dbref, sql, buffer, head, tail, fetch_count, fetching_done, process_target, wait_event, fetched_event, prep): # Need a unique connection name conn_name = "SQLFetcher" + str(os.getpid()) self.db, dbname = dbref.Open(conn_name) self.sql = sql self.buffer = buffer self.head = head self.tail = tail self.fetch_count = fetch_count self.fetching_done = fetching_done self.process_target = process_target self.wait_event = wait_event self.fetched_event = fetched_event self.prep = prep self.query = QSqlQuery(self.db) self.query_limit = 0 if "$$last_id$$" in sql else 2 self.last_id = -1 self.fetched = 0 self.more = True self.local_head = self.head.value self.local_tail = self.tail.value def Select(self): if self.query_limit: if self.query_limit == 1: return self.query_limit -= 1 stmt = self.sql.replace("$$last_id$$", str(self.last_id)) QueryExec(self.query, stmt) def Next(self): if not self.query.next(): self.Select() if not self.query.next(): return None self.last_id = self.query.value(0) return self.prep(self.query) def WaitForTarget(self): while True: self.wait_event.clear() target = self.process_target.value if target > self.fetched or target < 0: break self.wait_event.wait() return target def HasSpace(self, sz): if self.local_tail <= self.local_head: space = len(self.buffer) - self.local_head if space > sz: return True if space >= glb_nsz: # Use 0 (or space < glb_nsz) to mean there is no more at the top of the buffer nd = pickle.dumps(0, pickle.HIGHEST_PROTOCOL) self.buffer[self.local_head : self.local_head + len(nd)] = nd self.local_head = 0 if self.local_tail - self.local_head > sz: return True return False def WaitForSpace(self, sz): if self.HasSpace(sz): return while True: self.wait_event.clear() self.local_tail = self.tail.value if self.HasSpace(sz): return self.wait_event.wait() def AddToBuffer(self, obj): d = pickle.dumps(obj, pickle.HIGHEST_PROTOCOL) n = len(d) nd = pickle.dumps(n, pickle.HIGHEST_PROTOCOL) sz = n + glb_nsz self.WaitForSpace(sz) pos = self.local_head self.buffer[pos : pos + len(nd)] = nd self.buffer[pos + glb_nsz : pos + sz] = d self.local_head += sz def FetchBatch(self, batch_size): fetched = 0 while batch_size > fetched: obj = self.Next() if obj is None: self.more = False break self.AddToBuffer(obj) fetched += 1 if fetched: self.fetched += fetched with self.fetch_count.get_lock(): self.fetch_count.value += fetched self.head.value = self.local_head self.fetched_event.set() def Run(self): while self.more: target = self.WaitForTarget() if target < 0: break batch_size = min(glb_chunk_sz, target - self.fetched) self.FetchBatch(batch_size) self.fetching_done.value = True self.fetched_event.set() def SQLFetcherFn(*x): process = SQLFetcherProcess(*x) process.Run() # SQL data fetcher class SQLFetcher(QObject): done = Signal(object) def __init__(self, glb, sql, prep, process_data, parent=None): super(SQLFetcher, self).__init__(parent) self.process_data = process_data self.more = True self.target = 0 self.last_target = 0 self.fetched = 0 self.buffer_size = 16 * 1024 * 1024 self.buffer = Array(c_char, self.buffer_size, lock=False) self.head = Value(c_longlong) self.tail = Value(c_longlong) self.local_tail = 0 self.fetch_count = Value(c_longlong) self.fetching_done = Value(c_bool) self.last_count = 0 self.process_target = Value(c_longlong) self.wait_event = Event() self.fetched_event = Event() glb.AddInstanceToShutdownOnExit(self) self.process = Process(target=SQLFetcherFn, args=(glb.dbref, sql, self.buffer, self.head, self.tail, self.fetch_count, self.fetching_done, self.process_target, self.wait_event, self.fetched_event, prep)) self.process.start() self.thread = Thread(self.Thread) self.thread.done.connect(self.ProcessData, Qt.QueuedConnection) self.thread.start() def Shutdown(self): # Tell the thread and process to exit self.process_target.value = -1 self.wait_event.set() self.more = False self.fetching_done.value = True self.fetched_event.set() def Thread(self): if not self.more: return True, 0 while True: self.fetched_event.clear() fetch_count = self.fetch_count.value if fetch_count != self.last_count: break if self.fetching_done.value: self.more = False return True, 0 self.fetched_event.wait() count = fetch_count - self.last_count self.last_count = fetch_count self.fetched += count return False, count def Fetch(self, nr): if not self.more: # -1 inidcates there are no more return -1 result = self.fetched extra = result + nr - self.target if extra > 0: self.target += extra # process_target < 0 indicates shutting down if self.process_target.value >= 0: self.process_target.value = self.target self.wait_event.set() return result def RemoveFromBuffer(self): pos = self.local_tail if len(self.buffer) - pos < glb_nsz: pos = 0 n = pickle.loads(self.buffer[pos : pos + glb_nsz]) if n == 0: pos = 0 n = pickle.loads(self.buffer[0 : glb_nsz]) pos += glb_nsz obj = pickle.loads(self.buffer[pos : pos + n]) self.local_tail = pos + n return obj def ProcessData(self, count): for i in xrange(count): obj = self.RemoveFromBuffer() self.process_data(obj) self.tail.value = self.local_tail self.wait_event.set() self.done.emit(count) # Fetch more records bar class FetchMoreRecordsBar(): def __init__(self, model, parent): self.model = model self.label = QLabel("Number of records (x " + "{:,}".format(glb_chunk_sz) + ") to fetch:") self.label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.fetch_count = QSpinBox() self.fetch_count.setRange(1, 1000000) self.fetch_count.setValue(10) self.fetch_count.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.fetch = QPushButton("Go!") self.fetch.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.fetch.released.connect(self.FetchMoreRecords) self.progress = QProgressBar() self.progress.setRange(0, 100) self.progress.hide() self.done_label = QLabel("All records fetched") self.done_label.hide() self.spacer = QLabel("") self.close_button = QToolButton() self.close_button.setIcon(parent.style().standardIcon(QStyle.SP_DockWidgetCloseButton)) self.close_button.released.connect(self.Deactivate) self.hbox = QHBoxLayout() self.hbox.setContentsMargins(0, 0, 0, 0) self.hbox.addWidget(self.label) self.hbox.addWidget(self.fetch_count) self.hbox.addWidget(self.fetch) self.hbox.addWidget(self.spacer) self.hbox.addWidget(self.progress) self.hbox.addWidget(self.done_label) self.hbox.addWidget(self.close_button) self.bar = QWidget() self.bar.setLayout(self.hbox) self.bar.show() self.in_progress = False self.model.progress.connect(self.Progress) self.done = False if not model.HasMoreRecords(): self.Done() def Widget(self): return self.bar def Activate(self): self.bar.show() self.fetch.setFocus() def Deactivate(self): self.bar.hide() def Enable(self, enable): self.fetch.setEnabled(enable) self.fetch_count.setEnabled(enable) def Busy(self): self.Enable(False) self.fetch.hide() self.spacer.hide() self.progress.show() def Idle(self): self.in_progress = False self.Enable(True) self.progress.hide() self.fetch.show() self.spacer.show() def Target(self): return self.fetch_count.value() * glb_chunk_sz def Done(self): self.done = True self.Idle() self.label.hide() self.fetch_count.hide() self.fetch.hide() self.spacer.hide() self.done_label.show() def Progress(self, count): if self.in_progress: if count: percent = ((count - self.start) * 100) / self.Target() if percent >= 100: self.Idle() else: self.progress.setValue(percent) if not count: # Count value of zero means no more records self.Done() def FetchMoreRecords(self): if self.done: return self.progress.setValue(0) self.Busy() self.in_progress = True self.start = self.model.FetchMoreRecords(self.Target()) # Brance data model level two item class BranchLevelTwoItem(): def __init__(self, row, col, text, parent_item): self.row = row self.parent_item = parent_item self.data = [""] * (col + 1) self.data[col] = text self.level = 2 def getParentItem(self): return self.parent_item def getRow(self): return self.row def childCount(self): return 0 def hasChildren(self): return False def getData(self, column): return self.data[column] # Brance data model level one item class BranchLevelOneItem(): def __init__(self, glb, row, data, parent_item): self.glb = glb self.row = row self.parent_item = parent_item self.child_count = 0 self.child_items = [] self.data = data[1:] self.dbid = data[0] self.level = 1 self.query_done = False self.br_col = len(self.data) - 1 def getChildItem(self, row): return self.child_items[row] def getParentItem(self): return self.parent_item def getRow(self): return self.row def Select(self): self.query_done = True if not self.glb.have_disassembler: return query = QSqlQuery(self.glb.db) QueryExec(query, "SELECT cpu, to_dso_id, to_symbol_id, to_sym_offset, short_name, long_name, build_id, sym_start, to_ip" " FROM samples" " INNER JOIN dsos ON samples.to_dso_id = dsos.id" " INNER JOIN symbols ON samples.to_symbol_id = symbols.id" " WHERE samples.id = " + str(self.dbid)) if not query.next(): return cpu = query.value(0) dso = query.value(1) sym = query.value(2) if dso == 0 or sym == 0: return off = query.value(3) short_name = query.value(4) long_name = query.value(5) build_id = query.value(6) sym_start = query.value(7) ip = query.value(8) QueryExec(query, "SELECT samples.dso_id, symbol_id, sym_offset, sym_start" " FROM samples" " INNER JOIN symbols ON samples.symbol_id = symbols.id" " WHERE samples.id > " + str(self.dbid) + " AND cpu = " + str(cpu) + " ORDER BY samples.id" " LIMIT 1") if not query.next(): return if query.value(0) != dso: # Cannot disassemble from one dso to another return bsym = query.value(1) boff = query.value(2) bsym_start = query.value(3) if bsym == 0: return tot = bsym_start + boff + 1 - sym_start - off if tot <= 0 or tot > 16384: return inst = self.glb.disassembler.Instruction() f = self.glb.FileFromNamesAndBuildId(short_name, long_name, build_id) if not f: return mode = 0 if Is64Bit(f) else 1 self.glb.disassembler.SetMode(inst, mode) buf_sz = tot + 16 buf = create_string_buffer(tot + 16) f.seek(sym_start + off) buf.value = f.read(buf_sz) buf_ptr = addressof(buf) i = 0 while tot > 0: cnt, text = self.glb.disassembler.DisassembleOne(inst, buf_ptr, buf_sz, ip) if cnt: byte_str = tohex(ip).rjust(16) for k in xrange(cnt): byte_str += " %02x" % ord(buf[i]) i += 1 while k < 15: byte_str += " " k += 1 self.child_items.append(BranchLevelTwoItem(0, self.br_col, byte_str + " " + text, self)) self.child_count += 1 else: return buf_ptr += cnt tot -= cnt buf_sz -= cnt ip += cnt 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):Lines 2501–3000 of 5030. Previous lines Load more
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 if self.pos >= len(self.rows): self.pos = 0 else: self.pos -= 1 if self.pos < 0: self.pos = len(self.rows) - 1 row = self.rows[self.pos] else: row = -1 return (True, row) def Find(self, value, direction, pattern, context, callback): self.value, self.direction, self.pattern, self.last_value, self.last_pattern = (value, direction,pattern, self.value, self.pattern) # Use a thread so the UI is not blocked thread = Thread(self.FindThread) thread.done.connect(lambda row, t=thread, c=callback: self.FindDone(t, c, row), Qt.QueuedConnection) thread.start() def FindDone(self, thread, callback, row): callback(row) # Number of database records to fetch in one go glb_chunk_sz = 10000 # Background process for SQL data fetcher class SQLFetcherProcess(): def __init__(self, dbref, sql, buffer, head, tail, fetch_count, fetching_done, process_target, wait_event, fetched_event, prep): # Need a unique connection name conn_name = "SQLFetcher" + str(os.getpid()) self.db, dbname = dbref.Open(conn_name) self.sql = sql self.buffer = buffer self.head = head self.tail = tail self.fetch_count = fetch_count self.fetching_done = fetching_done self.process_target = process_target self.wait_event = wait_event self.fetched_event = fetched_event self.prep = prep self.query = QSqlQuery(self.db) self.query_limit = 0 if "$$last_id$$" in sql else 2 self.last_id = -1 self.fetched = 0 self.more = True self.local_head = self.head.value self.local_tail = self.tail.value def Select(self): if self.query_limit: if self.query_limit == 1: return self.query_limit -= 1 stmt = self.sql.replace("$$last_id$$", str(self.last_id)) QueryExec(self.query, stmt) def Next(self): if not self.query.next(): self.Select() if not self.query.next(): return None self.last_id = self.query.value(0) return self.prep(self.query) def WaitForTarget(self): while True: self.wait_event.clear() target = self.process_target.value if target > self.fetched or target < 0: break self.wait_event.wait() return target def HasSpace(self, sz): if self.local_tail <= self.local_head: space = len(self.buffer) - self.local_head if space > sz: return True if space >= glb_nsz: # Use 0 (or space < glb_nsz) to mean there is no more at the top of the buffer nd = pickle.dumps(0, pickle.HIGHEST_PROTOCOL) self.buffer[self.local_head : self.local_head + len(nd)] = nd self.local_head = 0 if self.local_tail - self.local_head > sz: return True return False def WaitForSpace(self, sz): if self.HasSpace(sz): return while True: self.wait_event.clear() self.local_tail = self.tail.value if self.HasSpace(sz): return self.wait_event.wait() def AddToBuffer(self, obj): d = pickle.dumps(obj, pickle.HIGHEST_PROTOCOL) n = len(d) nd = pickle.dumps(n, pickle.HIGHEST_PROTOCOL) sz = n + glb_nsz self.WaitForSpace(sz) pos = self.local_head self.buffer[pos : pos + len(nd)] = nd self.buffer[pos + glb_nsz : pos + sz] = d self.local_head += sz def FetchBatch(self, batch_size): fetched = 0 while batch_size > fetched: obj = self.Next() if obj is None: self.more = False break self.AddToBuffer(obj) fetched += 1 if fetched: self.fetched += fetched with self.fetch_count.get_lock(): self.fetch_count.value += fetched self.head.value = self.local_head self.fetched_event.set() def Run(self): while self.more: target = self.WaitForTarget() if target < 0: break batch_size = min(glb_chunk_sz, target - self.fetched) self.FetchBatch(batch_size) self.fetching_done.value = True self.fetched_event.set() def SQLFetcherFn(*x): process = SQLFetcherProcess(*x) process.Run() # SQL data fetcher class SQLFetcher(QObject): done = Signal(object) def __init__(self, glb, sql, prep, process_data, parent=None): super(SQLFetcher, self).__init__(parent) self.process_data = process_data self.more = True self.target = 0 self.last_target = 0 self.fetched = 0 self.buffer_size = 16 * 1024 * 1024 self.buffer = Array(c_char, self.buffer_size, lock=False) self.head = Value(c_longlong) self.tail = Value(c_longlong) self.local_tail = 0 self.fetch_count = Value(c_longlong) self.fetching_done = Value(c_bool) self.last_count = 0 self.process_target = Value(c_longlong) self.wait_event = Event() self.fetched_event = Event() glb.AddInstanceToShutdownOnExit(self) self.process = Process(target=SQLFetcherFn, args=(glb.dbref, sql, self.buffer, self.head, self.tail, self.fetch_count, self.fetching_done, self.process_target, self.wait_event, self.fetched_event, prep)) self.process.start() self.thread = Thread(self.Thread) self.thread.done.connect(self.ProcessData, Qt.QueuedConnection) self.thread.start() def Shutdown(self): # Tell the thread and process to exit self.process_target.value = -1 self.wait_event.set() self.more = False self.fetching_done.value = True self.fetched_event.set() def Thread(self): if not self.more: return True, 0 while True: self.fetched_event.clear() fetch_count = self.fetch_count.value if fetch_count != self.last_count: break if self.fetching_done.value: self.more = False return True, 0 self.fetched_event.wait() count = fetch_count - self.last_count self.last_count = fetch_count self.fetched += count return False, count def Fetch(self, nr): if not self.more: # -1 inidcates there are no more return -1 result = self.fetched extra = result + nr - self.target if extra > 0: self.target += extra # process_target < 0 indicates shutting down if self.process_target.value >= 0: self.process_target.value = self.target self.wait_event.set() return result def RemoveFromBuffer(self): pos = self.local_tail if len(self.buffer) - pos < glb_nsz: pos = 0 n = pickle.loads(self.buffer[pos : pos + glb_nsz]) if n == 0: pos = 0 n = pickle.loads(self.buffer[0 : glb_nsz]) pos += glb_nsz obj = pickle.loads(self.buffer[pos : pos + n]) self.local_tail = pos + n return obj def ProcessData(self, count): for i in xrange(count): obj = self.RemoveFromBuffer() self.process_data(obj) self.tail.value = self.local_tail self.wait_event.set() self.done.emit(count) # Fetch more records bar class FetchMoreRecordsBar(): def __init__(self, model, parent): self.model = model self.label = QLabel("Number of records (x " + "{:,}".format(glb_chunk_sz) + ") to fetch:") self.label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.fetch_count = QSpinBox() self.fetch_count.setRange(1, 1000000) self.fetch_count.setValue(10) self.fetch_count.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.fetch = QPushButton("Go!") self.fetch.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.fetch.released.connect(self.FetchMoreRecords) self.progress = QProgressBar() self.progress.setRange(0, 100) self.progress.hide() self.done_label = QLabel("All records fetched") self.done_label.hide() self.spacer = QLabel("") self.close_button = QToolButton() self.close_button.setIcon(parent.style().standardIcon(QStyle.SP_DockWidgetCloseButton)) self.close_button.released.connect(self.Deactivate) self.hbox = QHBoxLayout() self.hbox.setContentsMargins(0, 0, 0, 0) self.hbox.addWidget(self.label) self.hbox.addWidget(self.fetch_count) self.hbox.addWidget(self.fetch) self.hbox.addWidget(self.spacer) self.hbox.addWidget(self.progress) self.hbox.addWidget(self.done_label) self.hbox.addWidget(self.close_button) self.bar = QWidget() self.bar.setLayout(self.hbox) self.bar.show() self.in_progress = False self.model.progress.connect(self.Progress) self.done = False if not model.HasMoreRecords(): self.Done() def Widget(self): return self.bar def Activate(self): self.bar.show() self.fetch.setFocus() def Deactivate(self): self.bar.hide() def Enable(self, enable): self.fetch.setEnabled(enable) self.fetch_count.setEnabled(enable) def Busy(self): self.Enable(False) self.fetch.hide() self.spacer.hide() self.progress.show() def Idle(self): self.in_progress = False self.Enable(True) self.progress.hide() self.fetch.show() self.spacer.show() def Target(self): return self.fetch_count.value() * glb_chunk_sz def Done(self): self.done = True self.Idle() self.label.hide() self.fetch_count.hide() self.fetch.hide() self.spacer.hide() self.done_label.show() def Progress(self, count): if self.in_progress: if count: percent = ((count - self.start) * 100) / self.Target() if percent >= 100: self.Idle() else: self.progress.setValue(percent) if not count: # Count value of zero means no more records self.Done() def FetchMoreRecords(self): if self.done: return self.progress.setValue(0) self.Busy() self.in_progress = True self.start = self.model.FetchMoreRecords(self.Target()) # Brance data model level two item class BranchLevelTwoItem(): def __init__(self, row, col, text, parent_item): self.row = row self.parent_item = parent_item self.data = [""] * (col + 1) self.data[col] = text self.level = 2 def getParentItem(self): return self.parent_item def getRow(self): return self.row def childCount(self): return 0 def hasChildren(self): return False def getData(self, column): return self.data[column] # Brance data model level one item class BranchLevelOneItem(): def __init__(self, glb, row, data, parent_item): self.glb = glb self.row = row self.parent_item = parent_item self.child_count = 0 self.child_items = [] self.data = data[1:] self.dbid = data[0] self.level = 1 self.query_done = False self.br_col = len(self.data) - 1 def getChildItem(self, row): return self.child_items[row] def getParentItem(self): return self.parent_item def getRow(self): return self.row def Select(self): self.query_done = True if not self.glb.have_disassembler: return query = QSqlQuery(self.glb.db) QueryExec(query, "SELECT cpu, to_dso_id, to_symbol_id, to_sym_offset, short_name, long_name, build_id, sym_start, to_ip" " FROM samples" " INNER JOIN dsos ON samples.to_dso_id = dsos.id" " INNER JOIN symbols ON samples.to_symbol_id = symbols.id" " WHERE samples.id = " + str(self.dbid)) if not query.next(): return cpu = query.value(0) dso = query.value(1) sym = query.value(2) if dso == 0 or sym == 0: return off = query.value(3) short_name = query.value(4) long_name = query.value(5) build_id = query.value(6) sym_start = query.value(7) ip = query.value(8) QueryExec(query, "SELECT samples.dso_id, symbol_id, sym_offset, sym_start" " FROM samples" " INNER JOIN symbols ON samples.symbol_id = symbols.id" " WHERE samples.id > " + str(self.dbid) + " AND cpu = " + str(cpu) + " ORDER BY samples.id" " LIMIT 1") if not query.next(): return if query.value(0) != dso: # Cannot disassemble from one dso to another return bsym = query.value(1) boff = query.value(2) bsym_start = query.value(3) if bsym == 0: return tot = bsym_start + boff + 1 - sym_start - off if tot <= 0 or tot > 16384: return inst = self.glb.disassembler.Instruction() f = self.glb.FileFromNamesAndBuildId(short_name, long_name, build_id) if not f: return mode = 0 if Is64Bit(f) else 1 self.glb.disassembler.SetMode(inst, mode) buf_sz = tot + 16 buf = create_string_buffer(tot + 16) f.seek(sym_start + off) buf.value = f.read(buf_sz) buf_ptr = addressof(buf) i = 0 while tot > 0: cnt, text = self.glb.disassembler.DisassembleOne(inst, buf_ptr, buf_sz, ip) if cnt: byte_str = tohex(ip).rjust(16) for k in xrange(cnt): byte_str += " %02x" % ord(buf[i]) i += 1 while k < 15: byte_str += " " k += 1 self.child_items.append(BranchLevelTwoItem(0, self.br_col, byte_str + " " + text, self)) self.child_count += 1 else: return buf_ptr += cnt tot -= cnt buf_sz -= cnt ip += cnt 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):