1031c2a00SAdrian Hunter#!/usr/bin/python2 2031c2a00SAdrian Hunter# SPDX-License-Identifier: GPL-2.0 3031c2a00SAdrian Hunter# exported-sql-viewer.py: view data from sql database 4031c2a00SAdrian Hunter# Copyright (c) 2014-2018, Intel Corporation. 5031c2a00SAdrian Hunter 6031c2a00SAdrian Hunter# To use this script you will need to have exported data using either the 7031c2a00SAdrian Hunter# export-to-sqlite.py or the export-to-postgresql.py script. Refer to those 8031c2a00SAdrian Hunter# scripts for details. 9031c2a00SAdrian Hunter# 10031c2a00SAdrian Hunter# Following on from the example in the export scripts, a 11031c2a00SAdrian Hunter# call-graph can be displayed for the pt_example database like this: 12031c2a00SAdrian Hunter# 13031c2a00SAdrian Hunter# python tools/perf/scripts/python/exported-sql-viewer.py pt_example 14031c2a00SAdrian Hunter# 15031c2a00SAdrian Hunter# Note that for PostgreSQL, this script supports connecting to remote databases 16031c2a00SAdrian Hunter# by setting hostname, port, username, password, and dbname e.g. 17031c2a00SAdrian Hunter# 18031c2a00SAdrian Hunter# python tools/perf/scripts/python/exported-sql-viewer.py "hostname=myhost username=myuser password=mypassword dbname=pt_example" 19031c2a00SAdrian Hunter# 20031c2a00SAdrian Hunter# The result is a GUI window with a tree representing a context-sensitive 21031c2a00SAdrian Hunter# call-graph. Expanding a couple of levels of the tree and adjusting column 22031c2a00SAdrian Hunter# widths to suit will display something like: 23031c2a00SAdrian Hunter# 24031c2a00SAdrian Hunter# Call Graph: pt_example 25031c2a00SAdrian Hunter# Call Path Object Count Time(ns) Time(%) Branch Count Branch Count(%) 26031c2a00SAdrian Hunter# v- ls 27031c2a00SAdrian Hunter# v- 2638:2638 28031c2a00SAdrian Hunter# v- _start ld-2.19.so 1 10074071 100.0 211135 100.0 29031c2a00SAdrian Hunter# |- unknown unknown 1 13198 0.1 1 0.0 30031c2a00SAdrian Hunter# >- _dl_start ld-2.19.so 1 1400980 13.9 19637 9.3 31031c2a00SAdrian Hunter# >- _d_linit_internal ld-2.19.so 1 448152 4.4 11094 5.3 32031c2a00SAdrian Hunter# v-__libc_start_main@plt ls 1 8211741 81.5 180397 85.4 33031c2a00SAdrian Hunter# >- _dl_fixup ld-2.19.so 1 7607 0.1 108 0.1 34031c2a00SAdrian Hunter# >- __cxa_atexit libc-2.19.so 1 11737 0.1 10 0.0 35031c2a00SAdrian Hunter# >- __libc_csu_init ls 1 10354 0.1 10 0.0 36031c2a00SAdrian Hunter# |- _setjmp libc-2.19.so 1 0 0.0 4 0.0 37031c2a00SAdrian Hunter# v- main ls 1 8182043 99.6 180254 99.9 38031c2a00SAdrian Hunter# 39031c2a00SAdrian Hunter# Points to note: 40031c2a00SAdrian Hunter# The top level is a command name (comm) 41031c2a00SAdrian Hunter# The next level is a thread (pid:tid) 42031c2a00SAdrian Hunter# Subsequent levels are functions 43031c2a00SAdrian Hunter# 'Count' is the number of calls 44031c2a00SAdrian Hunter# 'Time' is the elapsed time until the function returns 45031c2a00SAdrian Hunter# Percentages are relative to the level above 46031c2a00SAdrian Hunter# 'Branch Count' is the total number of branches for that function and all 47031c2a00SAdrian Hunter# functions that it calls 48031c2a00SAdrian Hunter 4976099f98SAdrian Hunter# There is also a "All branches" report, which displays branches and 5076099f98SAdrian Hunter# possibly disassembly. However, presently, the only supported disassembler is 5176099f98SAdrian Hunter# Intel XED, and additionally the object code must be present in perf build ID 5276099f98SAdrian Hunter# cache. To use Intel XED, libxed.so must be present. To build and install 5376099f98SAdrian Hunter# libxed.so: 5476099f98SAdrian Hunter# git clone https://github.com/intelxed/mbuild.git mbuild 5576099f98SAdrian Hunter# git clone https://github.com/intelxed/xed 5676099f98SAdrian Hunter# cd xed 5776099f98SAdrian Hunter# ./mfile.py --share 5876099f98SAdrian Hunter# sudo ./mfile.py --prefix=/usr/local install 5976099f98SAdrian Hunter# sudo ldconfig 6076099f98SAdrian Hunter# 6176099f98SAdrian Hunter# Example report: 6276099f98SAdrian Hunter# 6376099f98SAdrian Hunter# Time CPU Command PID TID Branch Type In Tx Branch 6476099f98SAdrian Hunter# 8107675239590 2 ls 22011 22011 return from interrupt No ffffffff86a00a67 native_irq_return_iret ([kernel]) -> 7fab593ea260 _start (ld-2.19.so) 6576099f98SAdrian Hunter# 7fab593ea260 48 89 e7 mov %rsp, %rdi 6676099f98SAdrian Hunter# 8107675239899 2 ls 22011 22011 hardware interrupt No 7fab593ea260 _start (ld-2.19.so) -> ffffffff86a012e0 page_fault ([kernel]) 6776099f98SAdrian Hunter# 8107675241900 2 ls 22011 22011 return from interrupt No ffffffff86a00a67 native_irq_return_iret ([kernel]) -> 7fab593ea260 _start (ld-2.19.so) 6876099f98SAdrian Hunter# 7fab593ea260 48 89 e7 mov %rsp, %rdi 6976099f98SAdrian Hunter# 7fab593ea263 e8 c8 06 00 00 callq 0x7fab593ea930 7076099f98SAdrian Hunter# 8107675241900 2 ls 22011 22011 call No 7fab593ea263 _start+0x3 (ld-2.19.so) -> 7fab593ea930 _dl_start (ld-2.19.so) 7176099f98SAdrian Hunter# 7fab593ea930 55 pushq %rbp 7276099f98SAdrian Hunter# 7fab593ea931 48 89 e5 mov %rsp, %rbp 7376099f98SAdrian Hunter# 7fab593ea934 41 57 pushq %r15 7476099f98SAdrian Hunter# 7fab593ea936 41 56 pushq %r14 7576099f98SAdrian Hunter# 7fab593ea938 41 55 pushq %r13 7676099f98SAdrian Hunter# 7fab593ea93a 41 54 pushq %r12 7776099f98SAdrian Hunter# 7fab593ea93c 53 pushq %rbx 7876099f98SAdrian Hunter# 7fab593ea93d 48 89 fb mov %rdi, %rbx 7976099f98SAdrian Hunter# 7fab593ea940 48 83 ec 68 sub $0x68, %rsp 8076099f98SAdrian Hunter# 7fab593ea944 0f 31 rdtsc 8176099f98SAdrian Hunter# 7fab593ea946 48 c1 e2 20 shl $0x20, %rdx 8276099f98SAdrian Hunter# 7fab593ea94a 89 c0 mov %eax, %eax 8376099f98SAdrian Hunter# 7fab593ea94c 48 09 c2 or %rax, %rdx 8476099f98SAdrian Hunter# 7fab593ea94f 48 8b 05 1a 15 22 00 movq 0x22151a(%rip), %rax 8576099f98SAdrian Hunter# 8107675242232 2 ls 22011 22011 hardware interrupt No 7fab593ea94f _dl_start+0x1f (ld-2.19.so) -> ffffffff86a012e0 page_fault ([kernel]) 8676099f98SAdrian Hunter# 8107675242900 2 ls 22011 22011 return from interrupt No ffffffff86a00a67 native_irq_return_iret ([kernel]) -> 7fab593ea94f _dl_start+0x1f (ld-2.19.so) 8776099f98SAdrian Hunter# 7fab593ea94f 48 8b 05 1a 15 22 00 movq 0x22151a(%rip), %rax 8876099f98SAdrian Hunter# 7fab593ea956 48 89 15 3b 13 22 00 movq %rdx, 0x22133b(%rip) 8976099f98SAdrian Hunter# 8107675243232 2 ls 22011 22011 hardware interrupt No 7fab593ea956 _dl_start+0x26 (ld-2.19.so) -> ffffffff86a012e0 page_fault ([kernel]) 9076099f98SAdrian Hunter 91031c2a00SAdrian Hunterimport sys 921beb5c7bSAdrian Hunterimport weakref 931beb5c7bSAdrian Hunterimport threading 94ebd70c7dSAdrian Hunterimport string 958392b74bSAdrian Hunterimport cPickle 968392b74bSAdrian Hunterimport re 978392b74bSAdrian Hunterimport os 98031c2a00SAdrian Hunterfrom PySide.QtCore import * 99031c2a00SAdrian Hunterfrom PySide.QtGui import * 100031c2a00SAdrian Hunterfrom PySide.QtSql import * 101031c2a00SAdrian Hunterfrom decimal import * 1028392b74bSAdrian Hunterfrom ctypes import * 1038392b74bSAdrian Hunterfrom multiprocessing import Process, Array, Value, Event 104031c2a00SAdrian Hunter 105031c2a00SAdrian Hunter# Data formatting helpers 106031c2a00SAdrian Hunter 10776099f98SAdrian Hunterdef tohex(ip): 10876099f98SAdrian Hunter if ip < 0: 10976099f98SAdrian Hunter ip += 1 << 64 11076099f98SAdrian Hunter return "%x" % ip 11176099f98SAdrian Hunter 11276099f98SAdrian Hunterdef offstr(offset): 11376099f98SAdrian Hunter if offset: 11476099f98SAdrian Hunter return "+0x%x" % offset 11576099f98SAdrian Hunter return "" 11676099f98SAdrian Hunter 117031c2a00SAdrian Hunterdef dsoname(name): 118031c2a00SAdrian Hunter if name == "[kernel.kallsyms]": 119031c2a00SAdrian Hunter return "[kernel]" 120031c2a00SAdrian Hunter return name 121031c2a00SAdrian Hunter 122210cf1f9SAdrian Hunterdef findnth(s, sub, n, offs=0): 123210cf1f9SAdrian Hunter pos = s.find(sub) 124210cf1f9SAdrian Hunter if pos < 0: 125210cf1f9SAdrian Hunter return pos 126210cf1f9SAdrian Hunter if n <= 1: 127210cf1f9SAdrian Hunter return offs + pos 128210cf1f9SAdrian Hunter return findnth(s[pos + 1:], sub, n - 1, offs + pos + 1) 129210cf1f9SAdrian Hunter 130031c2a00SAdrian Hunter# Percent to one decimal place 131031c2a00SAdrian Hunter 132031c2a00SAdrian Hunterdef PercentToOneDP(n, d): 133031c2a00SAdrian Hunter if not d: 134031c2a00SAdrian Hunter return "0.0" 135031c2a00SAdrian Hunter x = (n * Decimal(100)) / d 136031c2a00SAdrian Hunter return str(x.quantize(Decimal(".1"), rounding=ROUND_HALF_UP)) 137031c2a00SAdrian Hunter 138031c2a00SAdrian Hunter# Helper for queries that must not fail 139031c2a00SAdrian Hunter 140031c2a00SAdrian Hunterdef QueryExec(query, stmt): 141031c2a00SAdrian Hunter ret = query.exec_(stmt) 142031c2a00SAdrian Hunter if not ret: 143031c2a00SAdrian Hunter raise Exception("Query failed: " + query.lastError().text()) 144031c2a00SAdrian Hunter 145ebd70c7dSAdrian Hunter# Background thread 146ebd70c7dSAdrian Hunter 147ebd70c7dSAdrian Hunterclass Thread(QThread): 148ebd70c7dSAdrian Hunter 149ebd70c7dSAdrian Hunter done = Signal(object) 150ebd70c7dSAdrian Hunter 151ebd70c7dSAdrian Hunter def __init__(self, task, param=None, parent=None): 152ebd70c7dSAdrian Hunter super(Thread, self).__init__(parent) 153ebd70c7dSAdrian Hunter self.task = task 154ebd70c7dSAdrian Hunter self.param = param 155ebd70c7dSAdrian Hunter 156ebd70c7dSAdrian Hunter def run(self): 157ebd70c7dSAdrian Hunter while True: 158ebd70c7dSAdrian Hunter if self.param is None: 159ebd70c7dSAdrian Hunter done, result = self.task() 160ebd70c7dSAdrian Hunter else: 161ebd70c7dSAdrian Hunter done, result = self.task(self.param) 162ebd70c7dSAdrian Hunter self.done.emit(result) 163ebd70c7dSAdrian Hunter if done: 164ebd70c7dSAdrian Hunter break 165ebd70c7dSAdrian Hunter 166031c2a00SAdrian Hunter# Tree data model 167031c2a00SAdrian Hunter 168031c2a00SAdrian Hunterclass TreeModel(QAbstractItemModel): 169031c2a00SAdrian Hunter 170031c2a00SAdrian Hunter def __init__(self, root, parent=None): 171031c2a00SAdrian Hunter super(TreeModel, self).__init__(parent) 172031c2a00SAdrian Hunter self.root = root 173031c2a00SAdrian Hunter self.last_row_read = 0 174031c2a00SAdrian Hunter 175031c2a00SAdrian Hunter def Item(self, parent): 176031c2a00SAdrian Hunter if parent.isValid(): 177031c2a00SAdrian Hunter return parent.internalPointer() 178031c2a00SAdrian Hunter else: 179031c2a00SAdrian Hunter return self.root 180031c2a00SAdrian Hunter 181031c2a00SAdrian Hunter def rowCount(self, parent): 182031c2a00SAdrian Hunter result = self.Item(parent).childCount() 183031c2a00SAdrian Hunter if result < 0: 184031c2a00SAdrian Hunter result = 0 185031c2a00SAdrian Hunter self.dataChanged.emit(parent, parent) 186031c2a00SAdrian Hunter return result 187031c2a00SAdrian Hunter 188031c2a00SAdrian Hunter def hasChildren(self, parent): 189031c2a00SAdrian Hunter return self.Item(parent).hasChildren() 190031c2a00SAdrian Hunter 191031c2a00SAdrian Hunter def headerData(self, section, orientation, role): 192031c2a00SAdrian Hunter if role == Qt.TextAlignmentRole: 193031c2a00SAdrian Hunter return self.columnAlignment(section) 194031c2a00SAdrian Hunter if role != Qt.DisplayRole: 195031c2a00SAdrian Hunter return None 196031c2a00SAdrian Hunter if orientation != Qt.Horizontal: 197031c2a00SAdrian Hunter return None 198031c2a00SAdrian Hunter return self.columnHeader(section) 199031c2a00SAdrian Hunter 200031c2a00SAdrian Hunter def parent(self, child): 201031c2a00SAdrian Hunter child_item = child.internalPointer() 202031c2a00SAdrian Hunter if child_item is self.root: 203031c2a00SAdrian Hunter return QModelIndex() 204031c2a00SAdrian Hunter parent_item = child_item.getParentItem() 205031c2a00SAdrian Hunter return self.createIndex(parent_item.getRow(), 0, parent_item) 206031c2a00SAdrian Hunter 207031c2a00SAdrian Hunter def index(self, row, column, parent): 208031c2a00SAdrian Hunter child_item = self.Item(parent).getChildItem(row) 209031c2a00SAdrian Hunter return self.createIndex(row, column, child_item) 210031c2a00SAdrian Hunter 211031c2a00SAdrian Hunter def DisplayData(self, item, index): 212031c2a00SAdrian Hunter return item.getData(index.column()) 213031c2a00SAdrian Hunter 2148392b74bSAdrian Hunter def FetchIfNeeded(self, row): 2158392b74bSAdrian Hunter if row > self.last_row_read: 2168392b74bSAdrian Hunter self.last_row_read = row 2178392b74bSAdrian Hunter if row + 10 >= self.root.child_count: 2188392b74bSAdrian Hunter self.fetcher.Fetch(glb_chunk_sz) 2198392b74bSAdrian Hunter 2208392b74bSAdrian Hunter def columnAlignment(self, column): 2218392b74bSAdrian Hunter return Qt.AlignLeft 2228392b74bSAdrian Hunter 2238392b74bSAdrian Hunter def columnFont(self, column): 2248392b74bSAdrian Hunter return None 2258392b74bSAdrian Hunter 2268392b74bSAdrian Hunter def data(self, index, role): 2278392b74bSAdrian Hunter if role == Qt.TextAlignmentRole: 2288392b74bSAdrian Hunter return self.columnAlignment(index.column()) 2298392b74bSAdrian Hunter if role == Qt.FontRole: 2308392b74bSAdrian Hunter return self.columnFont(index.column()) 2318392b74bSAdrian Hunter if role != Qt.DisplayRole: 2328392b74bSAdrian Hunter return None 2338392b74bSAdrian Hunter item = index.internalPointer() 2348392b74bSAdrian Hunter return self.DisplayData(item, index) 2358392b74bSAdrian Hunter 2368392b74bSAdrian Hunter# Table data model 2378392b74bSAdrian Hunter 2388392b74bSAdrian Hunterclass TableModel(QAbstractTableModel): 2398392b74bSAdrian Hunter 2408392b74bSAdrian Hunter def __init__(self, parent=None): 2418392b74bSAdrian Hunter super(TableModel, self).__init__(parent) 2428392b74bSAdrian Hunter self.child_count = 0 2438392b74bSAdrian Hunter self.child_items = [] 2448392b74bSAdrian Hunter self.last_row_read = 0 2458392b74bSAdrian Hunter 2468392b74bSAdrian Hunter def Item(self, parent): 2478392b74bSAdrian Hunter if parent.isValid(): 2488392b74bSAdrian Hunter return parent.internalPointer() 2498392b74bSAdrian Hunter else: 2508392b74bSAdrian Hunter return self 2518392b74bSAdrian Hunter 2528392b74bSAdrian Hunter def rowCount(self, parent): 2538392b74bSAdrian Hunter return self.child_count 2548392b74bSAdrian Hunter 2558392b74bSAdrian Hunter def headerData(self, section, orientation, role): 2568392b74bSAdrian Hunter if role == Qt.TextAlignmentRole: 2578392b74bSAdrian Hunter return self.columnAlignment(section) 2588392b74bSAdrian Hunter if role != Qt.DisplayRole: 2598392b74bSAdrian Hunter return None 2608392b74bSAdrian Hunter if orientation != Qt.Horizontal: 2618392b74bSAdrian Hunter return None 2628392b74bSAdrian Hunter return self.columnHeader(section) 2638392b74bSAdrian Hunter 2648392b74bSAdrian Hunter def index(self, row, column, parent): 2658392b74bSAdrian Hunter return self.createIndex(row, column, self.child_items[row]) 2668392b74bSAdrian Hunter 2678392b74bSAdrian Hunter def DisplayData(self, item, index): 2688392b74bSAdrian Hunter return item.getData(index.column()) 2698392b74bSAdrian Hunter 2708392b74bSAdrian Hunter def FetchIfNeeded(self, row): 2718392b74bSAdrian Hunter if row > self.last_row_read: 2728392b74bSAdrian Hunter self.last_row_read = row 2738392b74bSAdrian Hunter if row + 10 >= self.child_count: 2748392b74bSAdrian Hunter self.fetcher.Fetch(glb_chunk_sz) 2758392b74bSAdrian Hunter 276031c2a00SAdrian Hunter def columnAlignment(self, column): 277031c2a00SAdrian Hunter return Qt.AlignLeft 278031c2a00SAdrian Hunter 279031c2a00SAdrian Hunter def columnFont(self, column): 280031c2a00SAdrian Hunter return None 281031c2a00SAdrian Hunter 282031c2a00SAdrian Hunter def data(self, index, role): 283031c2a00SAdrian Hunter if role == Qt.TextAlignmentRole: 284031c2a00SAdrian Hunter return self.columnAlignment(index.column()) 285031c2a00SAdrian Hunter if role == Qt.FontRole: 286031c2a00SAdrian Hunter return self.columnFont(index.column()) 287031c2a00SAdrian Hunter if role != Qt.DisplayRole: 288031c2a00SAdrian Hunter return None 289031c2a00SAdrian Hunter item = index.internalPointer() 290031c2a00SAdrian Hunter return self.DisplayData(item, index) 291031c2a00SAdrian Hunter 2921beb5c7bSAdrian Hunter# Model cache 2931beb5c7bSAdrian Hunter 2941beb5c7bSAdrian Huntermodel_cache = weakref.WeakValueDictionary() 2951beb5c7bSAdrian Huntermodel_cache_lock = threading.Lock() 2961beb5c7bSAdrian Hunter 2971beb5c7bSAdrian Hunterdef LookupCreateModel(model_name, create_fn): 2981beb5c7bSAdrian Hunter model_cache_lock.acquire() 2991beb5c7bSAdrian Hunter try: 3001beb5c7bSAdrian Hunter model = model_cache[model_name] 3011beb5c7bSAdrian Hunter except: 3021beb5c7bSAdrian Hunter model = None 3031beb5c7bSAdrian Hunter if model is None: 3041beb5c7bSAdrian Hunter model = create_fn() 3051beb5c7bSAdrian Hunter model_cache[model_name] = model 3061beb5c7bSAdrian Hunter model_cache_lock.release() 3071beb5c7bSAdrian Hunter return model 3081beb5c7bSAdrian Hunter 309ebd70c7dSAdrian Hunter# Find bar 310ebd70c7dSAdrian Hunter 311ebd70c7dSAdrian Hunterclass FindBar(): 312ebd70c7dSAdrian Hunter 313ebd70c7dSAdrian Hunter def __init__(self, parent, finder, is_reg_expr=False): 314ebd70c7dSAdrian Hunter self.finder = finder 315ebd70c7dSAdrian Hunter self.context = [] 316ebd70c7dSAdrian Hunter self.last_value = None 317ebd70c7dSAdrian Hunter self.last_pattern = None 318ebd70c7dSAdrian Hunter 319ebd70c7dSAdrian Hunter label = QLabel("Find:") 320ebd70c7dSAdrian Hunter label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 321ebd70c7dSAdrian Hunter 322ebd70c7dSAdrian Hunter self.textbox = QComboBox() 323ebd70c7dSAdrian Hunter self.textbox.setEditable(True) 324ebd70c7dSAdrian Hunter self.textbox.currentIndexChanged.connect(self.ValueChanged) 325ebd70c7dSAdrian Hunter 326ebd70c7dSAdrian Hunter self.progress = QProgressBar() 327ebd70c7dSAdrian Hunter self.progress.setRange(0, 0) 328ebd70c7dSAdrian Hunter self.progress.hide() 329ebd70c7dSAdrian Hunter 330ebd70c7dSAdrian Hunter if is_reg_expr: 331ebd70c7dSAdrian Hunter self.pattern = QCheckBox("Regular Expression") 332ebd70c7dSAdrian Hunter else: 333ebd70c7dSAdrian Hunter self.pattern = QCheckBox("Pattern") 334ebd70c7dSAdrian Hunter self.pattern.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 335ebd70c7dSAdrian Hunter 336ebd70c7dSAdrian Hunter self.next_button = QToolButton() 337ebd70c7dSAdrian Hunter self.next_button.setIcon(parent.style().standardIcon(QStyle.SP_ArrowDown)) 338ebd70c7dSAdrian Hunter self.next_button.released.connect(lambda: self.NextPrev(1)) 339ebd70c7dSAdrian Hunter 340ebd70c7dSAdrian Hunter self.prev_button = QToolButton() 341ebd70c7dSAdrian Hunter self.prev_button.setIcon(parent.style().standardIcon(QStyle.SP_ArrowUp)) 342ebd70c7dSAdrian Hunter self.prev_button.released.connect(lambda: self.NextPrev(-1)) 343ebd70c7dSAdrian Hunter 344ebd70c7dSAdrian Hunter self.close_button = QToolButton() 345ebd70c7dSAdrian Hunter self.close_button.setIcon(parent.style().standardIcon(QStyle.SP_DockWidgetCloseButton)) 346ebd70c7dSAdrian Hunter self.close_button.released.connect(self.Deactivate) 347ebd70c7dSAdrian Hunter 348ebd70c7dSAdrian Hunter self.hbox = QHBoxLayout() 349ebd70c7dSAdrian Hunter self.hbox.setContentsMargins(0, 0, 0, 0) 350ebd70c7dSAdrian Hunter 351ebd70c7dSAdrian Hunter self.hbox.addWidget(label) 352ebd70c7dSAdrian Hunter self.hbox.addWidget(self.textbox) 353ebd70c7dSAdrian Hunter self.hbox.addWidget(self.progress) 354ebd70c7dSAdrian Hunter self.hbox.addWidget(self.pattern) 355ebd70c7dSAdrian Hunter self.hbox.addWidget(self.next_button) 356ebd70c7dSAdrian Hunter self.hbox.addWidget(self.prev_button) 357ebd70c7dSAdrian Hunter self.hbox.addWidget(self.close_button) 358ebd70c7dSAdrian Hunter 359ebd70c7dSAdrian Hunter self.bar = QWidget() 360ebd70c7dSAdrian Hunter self.bar.setLayout(self.hbox); 361ebd70c7dSAdrian Hunter self.bar.hide() 362ebd70c7dSAdrian Hunter 363ebd70c7dSAdrian Hunter def Widget(self): 364ebd70c7dSAdrian Hunter return self.bar 365ebd70c7dSAdrian Hunter 366ebd70c7dSAdrian Hunter def Activate(self): 367ebd70c7dSAdrian Hunter self.bar.show() 368ebd70c7dSAdrian Hunter self.textbox.setFocus() 369ebd70c7dSAdrian Hunter 370ebd70c7dSAdrian Hunter def Deactivate(self): 371ebd70c7dSAdrian Hunter self.bar.hide() 372ebd70c7dSAdrian Hunter 373ebd70c7dSAdrian Hunter def Busy(self): 374ebd70c7dSAdrian Hunter self.textbox.setEnabled(False) 375ebd70c7dSAdrian Hunter self.pattern.hide() 376ebd70c7dSAdrian Hunter self.next_button.hide() 377ebd70c7dSAdrian Hunter self.prev_button.hide() 378ebd70c7dSAdrian Hunter self.progress.show() 379ebd70c7dSAdrian Hunter 380ebd70c7dSAdrian Hunter def Idle(self): 381ebd70c7dSAdrian Hunter self.textbox.setEnabled(True) 382ebd70c7dSAdrian Hunter self.progress.hide() 383ebd70c7dSAdrian Hunter self.pattern.show() 384ebd70c7dSAdrian Hunter self.next_button.show() 385ebd70c7dSAdrian Hunter self.prev_button.show() 386ebd70c7dSAdrian Hunter 387ebd70c7dSAdrian Hunter def Find(self, direction): 388ebd70c7dSAdrian Hunter value = self.textbox.currentText() 389ebd70c7dSAdrian Hunter pattern = self.pattern.isChecked() 390ebd70c7dSAdrian Hunter self.last_value = value 391ebd70c7dSAdrian Hunter self.last_pattern = pattern 392ebd70c7dSAdrian Hunter self.finder.Find(value, direction, pattern, self.context) 393ebd70c7dSAdrian Hunter 394ebd70c7dSAdrian Hunter def ValueChanged(self): 395ebd70c7dSAdrian Hunter value = self.textbox.currentText() 396ebd70c7dSAdrian Hunter pattern = self.pattern.isChecked() 397ebd70c7dSAdrian Hunter index = self.textbox.currentIndex() 398ebd70c7dSAdrian Hunter data = self.textbox.itemData(index) 399ebd70c7dSAdrian Hunter # Store the pattern in the combo box to keep it with the text value 400ebd70c7dSAdrian Hunter if data == None: 401ebd70c7dSAdrian Hunter self.textbox.setItemData(index, pattern) 402ebd70c7dSAdrian Hunter else: 403ebd70c7dSAdrian Hunter self.pattern.setChecked(data) 404ebd70c7dSAdrian Hunter self.Find(0) 405ebd70c7dSAdrian Hunter 406ebd70c7dSAdrian Hunter def NextPrev(self, direction): 407ebd70c7dSAdrian Hunter value = self.textbox.currentText() 408ebd70c7dSAdrian Hunter pattern = self.pattern.isChecked() 409ebd70c7dSAdrian Hunter if value != self.last_value: 410ebd70c7dSAdrian Hunter index = self.textbox.findText(value) 411ebd70c7dSAdrian Hunter # Allow for a button press before the value has been added to the combo box 412ebd70c7dSAdrian Hunter if index < 0: 413ebd70c7dSAdrian Hunter index = self.textbox.count() 414ebd70c7dSAdrian Hunter self.textbox.addItem(value, pattern) 415ebd70c7dSAdrian Hunter self.textbox.setCurrentIndex(index) 416ebd70c7dSAdrian Hunter return 417ebd70c7dSAdrian Hunter else: 418ebd70c7dSAdrian Hunter self.textbox.setItemData(index, pattern) 419ebd70c7dSAdrian Hunter elif pattern != self.last_pattern: 420ebd70c7dSAdrian Hunter # Keep the pattern recorded in the combo box up to date 421ebd70c7dSAdrian Hunter index = self.textbox.currentIndex() 422ebd70c7dSAdrian Hunter self.textbox.setItemData(index, pattern) 423ebd70c7dSAdrian Hunter self.Find(direction) 424ebd70c7dSAdrian Hunter 425ebd70c7dSAdrian Hunter def NotFound(self): 426ebd70c7dSAdrian Hunter QMessageBox.information(self.bar, "Find", "'" + self.textbox.currentText() + "' not found") 427ebd70c7dSAdrian Hunter 428031c2a00SAdrian Hunter# Context-sensitive call graph data model item base 429031c2a00SAdrian Hunter 430031c2a00SAdrian Hunterclass CallGraphLevelItemBase(object): 431031c2a00SAdrian Hunter 432031c2a00SAdrian Hunter def __init__(self, glb, row, parent_item): 433031c2a00SAdrian Hunter self.glb = glb 434031c2a00SAdrian Hunter self.row = row 435031c2a00SAdrian Hunter self.parent_item = parent_item 436031c2a00SAdrian Hunter self.query_done = False; 437031c2a00SAdrian Hunter self.child_count = 0 438031c2a00SAdrian Hunter self.child_items = [] 439031c2a00SAdrian Hunter 440031c2a00SAdrian Hunter def getChildItem(self, row): 441031c2a00SAdrian Hunter return self.child_items[row] 442031c2a00SAdrian Hunter 443031c2a00SAdrian Hunter def getParentItem(self): 444031c2a00SAdrian Hunter return self.parent_item 445031c2a00SAdrian Hunter 446031c2a00SAdrian Hunter def getRow(self): 447031c2a00SAdrian Hunter return self.row 448031c2a00SAdrian Hunter 449031c2a00SAdrian Hunter def childCount(self): 450031c2a00SAdrian Hunter if not self.query_done: 451031c2a00SAdrian Hunter self.Select() 452031c2a00SAdrian Hunter if not self.child_count: 453031c2a00SAdrian Hunter return -1 454031c2a00SAdrian Hunter return self.child_count 455031c2a00SAdrian Hunter 456031c2a00SAdrian Hunter def hasChildren(self): 457031c2a00SAdrian Hunter if not self.query_done: 458031c2a00SAdrian Hunter return True 459031c2a00SAdrian Hunter return self.child_count > 0 460031c2a00SAdrian Hunter 461031c2a00SAdrian Hunter def getData(self, column): 462031c2a00SAdrian Hunter return self.data[column] 463031c2a00SAdrian Hunter 464031c2a00SAdrian Hunter# Context-sensitive call graph data model level 2+ item base 465031c2a00SAdrian Hunter 466031c2a00SAdrian Hunterclass CallGraphLevelTwoPlusItemBase(CallGraphLevelItemBase): 467031c2a00SAdrian Hunter 468031c2a00SAdrian Hunter def __init__(self, glb, row, comm_id, thread_id, call_path_id, time, branch_count, parent_item): 469031c2a00SAdrian Hunter super(CallGraphLevelTwoPlusItemBase, self).__init__(glb, row, parent_item) 470031c2a00SAdrian Hunter self.comm_id = comm_id 471031c2a00SAdrian Hunter self.thread_id = thread_id 472031c2a00SAdrian Hunter self.call_path_id = call_path_id 473031c2a00SAdrian Hunter self.branch_count = branch_count 474031c2a00SAdrian Hunter self.time = time 475031c2a00SAdrian Hunter 476031c2a00SAdrian Hunter def Select(self): 477031c2a00SAdrian Hunter self.query_done = True; 478031c2a00SAdrian Hunter query = QSqlQuery(self.glb.db) 479031c2a00SAdrian Hunter QueryExec(query, "SELECT call_path_id, name, short_name, COUNT(calls.id), SUM(return_time - call_time), SUM(branch_count)" 480031c2a00SAdrian Hunter " FROM calls" 481031c2a00SAdrian Hunter " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" 482031c2a00SAdrian Hunter " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" 483031c2a00SAdrian Hunter " INNER JOIN dsos ON symbols.dso_id = dsos.id" 484031c2a00SAdrian Hunter " WHERE parent_call_path_id = " + str(self.call_path_id) + 485031c2a00SAdrian Hunter " AND comm_id = " + str(self.comm_id) + 486031c2a00SAdrian Hunter " AND thread_id = " + str(self.thread_id) + 487031c2a00SAdrian Hunter " GROUP BY call_path_id, name, short_name" 488031c2a00SAdrian Hunter " ORDER BY call_path_id") 489031c2a00SAdrian Hunter while query.next(): 490031c2a00SAdrian Hunter 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) 491031c2a00SAdrian Hunter self.child_items.append(child_item) 492031c2a00SAdrian Hunter self.child_count += 1 493031c2a00SAdrian Hunter 494031c2a00SAdrian Hunter# Context-sensitive call graph data model level three item 495031c2a00SAdrian Hunter 496031c2a00SAdrian Hunterclass CallGraphLevelThreeItem(CallGraphLevelTwoPlusItemBase): 497031c2a00SAdrian Hunter 498031c2a00SAdrian Hunter def __init__(self, glb, row, comm_id, thread_id, call_path_id, name, dso, count, time, branch_count, parent_item): 499031c2a00SAdrian Hunter super(CallGraphLevelThreeItem, self).__init__(glb, row, comm_id, thread_id, call_path_id, time, branch_count, parent_item) 500031c2a00SAdrian Hunter dso = dsoname(dso) 501031c2a00SAdrian Hunter self.data = [ name, dso, str(count), str(time), PercentToOneDP(time, parent_item.time), str(branch_count), PercentToOneDP(branch_count, parent_item.branch_count) ] 502031c2a00SAdrian Hunter self.dbid = call_path_id 503031c2a00SAdrian Hunter 504031c2a00SAdrian Hunter# Context-sensitive call graph data model level two item 505031c2a00SAdrian Hunter 506031c2a00SAdrian Hunterclass CallGraphLevelTwoItem(CallGraphLevelTwoPlusItemBase): 507031c2a00SAdrian Hunter 508031c2a00SAdrian Hunter def __init__(self, glb, row, comm_id, thread_id, pid, tid, parent_item): 509031c2a00SAdrian Hunter super(CallGraphLevelTwoItem, self).__init__(glb, row, comm_id, thread_id, 1, 0, 0, parent_item) 510031c2a00SAdrian Hunter self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", ""] 511031c2a00SAdrian Hunter self.dbid = thread_id 512031c2a00SAdrian Hunter 513031c2a00SAdrian Hunter def Select(self): 514031c2a00SAdrian Hunter super(CallGraphLevelTwoItem, self).Select() 515031c2a00SAdrian Hunter for child_item in self.child_items: 516031c2a00SAdrian Hunter self.time += child_item.time 517031c2a00SAdrian Hunter self.branch_count += child_item.branch_count 518031c2a00SAdrian Hunter for child_item in self.child_items: 519031c2a00SAdrian Hunter child_item.data[4] = PercentToOneDP(child_item.time, self.time) 520031c2a00SAdrian Hunter child_item.data[6] = PercentToOneDP(child_item.branch_count, self.branch_count) 521031c2a00SAdrian Hunter 522031c2a00SAdrian Hunter# Context-sensitive call graph data model level one item 523031c2a00SAdrian Hunter 524031c2a00SAdrian Hunterclass CallGraphLevelOneItem(CallGraphLevelItemBase): 525031c2a00SAdrian Hunter 526031c2a00SAdrian Hunter def __init__(self, glb, row, comm_id, comm, parent_item): 527031c2a00SAdrian Hunter super(CallGraphLevelOneItem, self).__init__(glb, row, parent_item) 528031c2a00SAdrian Hunter self.data = [comm, "", "", "", "", "", ""] 529031c2a00SAdrian Hunter self.dbid = comm_id 530031c2a00SAdrian Hunter 531031c2a00SAdrian Hunter def Select(self): 532031c2a00SAdrian Hunter self.query_done = True; 533031c2a00SAdrian Hunter query = QSqlQuery(self.glb.db) 534031c2a00SAdrian Hunter QueryExec(query, "SELECT thread_id, pid, tid" 535031c2a00SAdrian Hunter " FROM comm_threads" 536031c2a00SAdrian Hunter " INNER JOIN threads ON thread_id = threads.id" 537031c2a00SAdrian Hunter " WHERE comm_id = " + str(self.dbid)) 538031c2a00SAdrian Hunter while query.next(): 539031c2a00SAdrian Hunter child_item = CallGraphLevelTwoItem(self.glb, self.child_count, self.dbid, query.value(0), query.value(1), query.value(2), self) 540031c2a00SAdrian Hunter self.child_items.append(child_item) 541031c2a00SAdrian Hunter self.child_count += 1 542031c2a00SAdrian Hunter 543031c2a00SAdrian Hunter# Context-sensitive call graph data model root item 544031c2a00SAdrian Hunter 545031c2a00SAdrian Hunterclass CallGraphRootItem(CallGraphLevelItemBase): 546031c2a00SAdrian Hunter 547031c2a00SAdrian Hunter def __init__(self, glb): 548031c2a00SAdrian Hunter super(CallGraphRootItem, self).__init__(glb, 0, None) 549031c2a00SAdrian Hunter self.dbid = 0 550031c2a00SAdrian Hunter self.query_done = True; 551031c2a00SAdrian Hunter query = QSqlQuery(glb.db) 552031c2a00SAdrian Hunter QueryExec(query, "SELECT id, comm FROM comms") 553031c2a00SAdrian Hunter while query.next(): 554031c2a00SAdrian Hunter if not query.value(0): 555031c2a00SAdrian Hunter continue 556031c2a00SAdrian Hunter child_item = CallGraphLevelOneItem(glb, self.child_count, query.value(0), query.value(1), self) 557031c2a00SAdrian Hunter self.child_items.append(child_item) 558031c2a00SAdrian Hunter self.child_count += 1 559031c2a00SAdrian Hunter 560031c2a00SAdrian Hunter# Context-sensitive call graph data model 561031c2a00SAdrian Hunter 562031c2a00SAdrian Hunterclass CallGraphModel(TreeModel): 563031c2a00SAdrian Hunter 564031c2a00SAdrian Hunter def __init__(self, glb, parent=None): 565031c2a00SAdrian Hunter super(CallGraphModel, self).__init__(CallGraphRootItem(glb), parent) 566031c2a00SAdrian Hunter self.glb = glb 567031c2a00SAdrian Hunter 568031c2a00SAdrian Hunter def columnCount(self, parent=None): 569031c2a00SAdrian Hunter return 7 570031c2a00SAdrian Hunter 571031c2a00SAdrian Hunter def columnHeader(self, column): 572031c2a00SAdrian Hunter headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "] 573031c2a00SAdrian Hunter return headers[column] 574031c2a00SAdrian Hunter 575031c2a00SAdrian Hunter def columnAlignment(self, column): 576031c2a00SAdrian Hunter alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ] 577031c2a00SAdrian Hunter return alignment[column] 578031c2a00SAdrian Hunter 579ebd70c7dSAdrian Hunter def FindSelect(self, value, pattern, query): 580ebd70c7dSAdrian Hunter if pattern: 581ebd70c7dSAdrian Hunter # postgresql and sqlite pattern patching differences: 582ebd70c7dSAdrian Hunter # postgresql LIKE is case sensitive but sqlite LIKE is not 583ebd70c7dSAdrian Hunter # postgresql LIKE allows % and _ to be escaped with \ but sqlite LIKE does not 584ebd70c7dSAdrian Hunter # postgresql supports ILIKE which is case insensitive 585ebd70c7dSAdrian Hunter # sqlite supports GLOB (text only) which uses * and ? and is case sensitive 586ebd70c7dSAdrian Hunter if not self.glb.dbref.is_sqlite3: 587ebd70c7dSAdrian Hunter # Escape % and _ 588ebd70c7dSAdrian Hunter s = value.replace("%", "\%") 589ebd70c7dSAdrian Hunter s = s.replace("_", "\_") 590ebd70c7dSAdrian Hunter # Translate * and ? into SQL LIKE pattern characters % and _ 591ebd70c7dSAdrian Hunter trans = string.maketrans("*?", "%_") 592ebd70c7dSAdrian Hunter match = " LIKE '" + str(s).translate(trans) + "'" 593ebd70c7dSAdrian Hunter else: 594ebd70c7dSAdrian Hunter match = " GLOB '" + str(value) + "'" 595ebd70c7dSAdrian Hunter else: 596ebd70c7dSAdrian Hunter match = " = '" + str(value) + "'" 597ebd70c7dSAdrian Hunter QueryExec(query, "SELECT call_path_id, comm_id, thread_id" 598ebd70c7dSAdrian Hunter " FROM calls" 599ebd70c7dSAdrian Hunter " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" 600ebd70c7dSAdrian Hunter " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" 601ebd70c7dSAdrian Hunter " WHERE symbols.name" + match + 602ebd70c7dSAdrian Hunter " GROUP BY comm_id, thread_id, call_path_id" 603ebd70c7dSAdrian Hunter " ORDER BY comm_id, thread_id, call_path_id") 604ebd70c7dSAdrian Hunter 605ebd70c7dSAdrian Hunter def FindPath(self, query): 606ebd70c7dSAdrian Hunter # Turn the query result into a list of ids that the tree view can walk 607ebd70c7dSAdrian Hunter # to open the tree at the right place. 608ebd70c7dSAdrian Hunter ids = [] 609ebd70c7dSAdrian Hunter parent_id = query.value(0) 610ebd70c7dSAdrian Hunter while parent_id: 611ebd70c7dSAdrian Hunter ids.insert(0, parent_id) 612ebd70c7dSAdrian Hunter q2 = QSqlQuery(self.glb.db) 613ebd70c7dSAdrian Hunter QueryExec(q2, "SELECT parent_id" 614ebd70c7dSAdrian Hunter " FROM call_paths" 615ebd70c7dSAdrian Hunter " WHERE id = " + str(parent_id)) 616ebd70c7dSAdrian Hunter if not q2.next(): 617ebd70c7dSAdrian Hunter break 618ebd70c7dSAdrian Hunter parent_id = q2.value(0) 619ebd70c7dSAdrian Hunter # The call path root is not used 620ebd70c7dSAdrian Hunter if ids[0] == 1: 621ebd70c7dSAdrian Hunter del ids[0] 622ebd70c7dSAdrian Hunter ids.insert(0, query.value(2)) 623ebd70c7dSAdrian Hunter ids.insert(0, query.value(1)) 624ebd70c7dSAdrian Hunter return ids 625ebd70c7dSAdrian Hunter 626ebd70c7dSAdrian Hunter def Found(self, query, found): 627ebd70c7dSAdrian Hunter if found: 628ebd70c7dSAdrian Hunter return self.FindPath(query) 629ebd70c7dSAdrian Hunter return [] 630ebd70c7dSAdrian Hunter 631ebd70c7dSAdrian Hunter def FindValue(self, value, pattern, query, last_value, last_pattern): 632ebd70c7dSAdrian Hunter if last_value == value and pattern == last_pattern: 633ebd70c7dSAdrian Hunter found = query.first() 634ebd70c7dSAdrian Hunter else: 635ebd70c7dSAdrian Hunter self.FindSelect(value, pattern, query) 636ebd70c7dSAdrian Hunter found = query.next() 637ebd70c7dSAdrian Hunter return self.Found(query, found) 638ebd70c7dSAdrian Hunter 639ebd70c7dSAdrian Hunter def FindNext(self, query): 640ebd70c7dSAdrian Hunter found = query.next() 641ebd70c7dSAdrian Hunter if not found: 642ebd70c7dSAdrian Hunter found = query.first() 643ebd70c7dSAdrian Hunter return self.Found(query, found) 644ebd70c7dSAdrian Hunter 645ebd70c7dSAdrian Hunter def FindPrev(self, query): 646ebd70c7dSAdrian Hunter found = query.previous() 647ebd70c7dSAdrian Hunter if not found: 648ebd70c7dSAdrian Hunter found = query.last() 649ebd70c7dSAdrian Hunter return self.Found(query, found) 650ebd70c7dSAdrian Hunter 651ebd70c7dSAdrian Hunter def FindThread(self, c): 652ebd70c7dSAdrian Hunter if c.direction == 0 or c.value != c.last_value or c.pattern != c.last_pattern: 653ebd70c7dSAdrian Hunter ids = self.FindValue(c.value, c.pattern, c.query, c.last_value, c.last_pattern) 654ebd70c7dSAdrian Hunter elif c.direction > 0: 655ebd70c7dSAdrian Hunter ids = self.FindNext(c.query) 656ebd70c7dSAdrian Hunter else: 657ebd70c7dSAdrian Hunter ids = self.FindPrev(c.query) 658ebd70c7dSAdrian Hunter return (True, ids) 659ebd70c7dSAdrian Hunter 660ebd70c7dSAdrian Hunter def Find(self, value, direction, pattern, context, callback): 661ebd70c7dSAdrian Hunter class Context(): 662ebd70c7dSAdrian Hunter def __init__(self, *x): 663ebd70c7dSAdrian Hunter self.value, self.direction, self.pattern, self.query, self.last_value, self.last_pattern = x 664ebd70c7dSAdrian Hunter def Update(self, *x): 665ebd70c7dSAdrian Hunter self.value, self.direction, self.pattern, self.last_value, self.last_pattern = x + (self.value, self.pattern) 666ebd70c7dSAdrian Hunter if len(context): 667ebd70c7dSAdrian Hunter context[0].Update(value, direction, pattern) 668ebd70c7dSAdrian Hunter else: 669ebd70c7dSAdrian Hunter context.append(Context(value, direction, pattern, QSqlQuery(self.glb.db), None, None)) 670ebd70c7dSAdrian Hunter # Use a thread so the UI is not blocked during the SELECT 671ebd70c7dSAdrian Hunter thread = Thread(self.FindThread, context[0]) 672ebd70c7dSAdrian Hunter thread.done.connect(lambda ids, t=thread, c=callback: self.FindDone(t, c, ids), Qt.QueuedConnection) 673ebd70c7dSAdrian Hunter thread.start() 674ebd70c7dSAdrian Hunter 675ebd70c7dSAdrian Hunter def FindDone(self, thread, callback, ids): 676ebd70c7dSAdrian Hunter callback(ids) 677ebd70c7dSAdrian Hunter 678ebd70c7dSAdrian Hunter# Vertical widget layout 679ebd70c7dSAdrian Hunter 680ebd70c7dSAdrian Hunterclass VBox(): 681ebd70c7dSAdrian Hunter 682ebd70c7dSAdrian Hunter def __init__(self, w1, w2, w3=None): 683ebd70c7dSAdrian Hunter self.vbox = QWidget() 684ebd70c7dSAdrian Hunter self.vbox.setLayout(QVBoxLayout()); 685ebd70c7dSAdrian Hunter 686ebd70c7dSAdrian Hunter self.vbox.layout().setContentsMargins(0, 0, 0, 0) 687ebd70c7dSAdrian Hunter 688ebd70c7dSAdrian Hunter self.vbox.layout().addWidget(w1) 689ebd70c7dSAdrian Hunter self.vbox.layout().addWidget(w2) 690ebd70c7dSAdrian Hunter if w3: 691ebd70c7dSAdrian Hunter self.vbox.layout().addWidget(w3) 692ebd70c7dSAdrian Hunter 693ebd70c7dSAdrian Hunter def Widget(self): 694ebd70c7dSAdrian Hunter return self.vbox 695ebd70c7dSAdrian Hunter 6961beb5c7bSAdrian Hunter# Context-sensitive call graph window 6971beb5c7bSAdrian Hunter 6981beb5c7bSAdrian Hunterclass CallGraphWindow(QMdiSubWindow): 6991beb5c7bSAdrian Hunter 7001beb5c7bSAdrian Hunter def __init__(self, glb, parent=None): 7011beb5c7bSAdrian Hunter super(CallGraphWindow, self).__init__(parent) 7021beb5c7bSAdrian Hunter 7031beb5c7bSAdrian Hunter self.model = LookupCreateModel("Context-Sensitive Call Graph", lambda x=glb: CallGraphModel(x)) 7041beb5c7bSAdrian Hunter 7051beb5c7bSAdrian Hunter self.view = QTreeView() 7061beb5c7bSAdrian Hunter self.view.setModel(self.model) 7071beb5c7bSAdrian Hunter 7081beb5c7bSAdrian Hunter for c, w in ((0, 250), (1, 100), (2, 60), (3, 70), (4, 70), (5, 100)): 7091beb5c7bSAdrian Hunter self.view.setColumnWidth(c, w) 7101beb5c7bSAdrian Hunter 711ebd70c7dSAdrian Hunter self.find_bar = FindBar(self, self) 712ebd70c7dSAdrian Hunter 713ebd70c7dSAdrian Hunter self.vbox = VBox(self.view, self.find_bar.Widget()) 714ebd70c7dSAdrian Hunter 715ebd70c7dSAdrian Hunter self.setWidget(self.vbox.Widget()) 7161beb5c7bSAdrian Hunter 7171beb5c7bSAdrian Hunter AddSubWindow(glb.mainwindow.mdi_area, self, "Context-Sensitive Call Graph") 7181beb5c7bSAdrian Hunter 719ebd70c7dSAdrian Hunter def DisplayFound(self, ids): 720ebd70c7dSAdrian Hunter if not len(ids): 721ebd70c7dSAdrian Hunter return False 722ebd70c7dSAdrian Hunter parent = QModelIndex() 723ebd70c7dSAdrian Hunter for dbid in ids: 724ebd70c7dSAdrian Hunter found = False 725ebd70c7dSAdrian Hunter n = self.model.rowCount(parent) 726ebd70c7dSAdrian Hunter for row in xrange(n): 727ebd70c7dSAdrian Hunter child = self.model.index(row, 0, parent) 728ebd70c7dSAdrian Hunter if child.internalPointer().dbid == dbid: 729ebd70c7dSAdrian Hunter found = True 730ebd70c7dSAdrian Hunter self.view.setCurrentIndex(child) 731ebd70c7dSAdrian Hunter parent = child 732ebd70c7dSAdrian Hunter break 733ebd70c7dSAdrian Hunter if not found: 734ebd70c7dSAdrian Hunter break 735ebd70c7dSAdrian Hunter return found 736ebd70c7dSAdrian Hunter 737ebd70c7dSAdrian Hunter def Find(self, value, direction, pattern, context): 738ebd70c7dSAdrian Hunter self.view.setFocus() 739ebd70c7dSAdrian Hunter self.find_bar.Busy() 740ebd70c7dSAdrian Hunter self.model.Find(value, direction, pattern, context, self.FindDone) 741ebd70c7dSAdrian Hunter 742ebd70c7dSAdrian Hunter def FindDone(self, ids): 743ebd70c7dSAdrian Hunter found = True 744ebd70c7dSAdrian Hunter if not self.DisplayFound(ids): 745ebd70c7dSAdrian Hunter found = False 746ebd70c7dSAdrian Hunter self.find_bar.Idle() 747ebd70c7dSAdrian Hunter if not found: 748ebd70c7dSAdrian Hunter self.find_bar.NotFound() 749ebd70c7dSAdrian Hunter 7508392b74bSAdrian Hunter# Child data item finder 7518392b74bSAdrian Hunter 7528392b74bSAdrian Hunterclass ChildDataItemFinder(): 7538392b74bSAdrian Hunter 7548392b74bSAdrian Hunter def __init__(self, root): 7558392b74bSAdrian Hunter self.root = root 7568392b74bSAdrian Hunter self.value, self.direction, self.pattern, self.last_value, self.last_pattern = (None,) * 5 7578392b74bSAdrian Hunter self.rows = [] 7588392b74bSAdrian Hunter self.pos = 0 7598392b74bSAdrian Hunter 7608392b74bSAdrian Hunter def FindSelect(self): 7618392b74bSAdrian Hunter self.rows = [] 7628392b74bSAdrian Hunter if self.pattern: 7638392b74bSAdrian Hunter pattern = re.compile(self.value) 7648392b74bSAdrian Hunter for child in self.root.child_items: 7658392b74bSAdrian Hunter for column_data in child.data: 7668392b74bSAdrian Hunter if re.search(pattern, str(column_data)) is not None: 7678392b74bSAdrian Hunter self.rows.append(child.row) 7688392b74bSAdrian Hunter break 7698392b74bSAdrian Hunter else: 7708392b74bSAdrian Hunter for child in self.root.child_items: 7718392b74bSAdrian Hunter for column_data in child.data: 7728392b74bSAdrian Hunter if self.value in str(column_data): 7738392b74bSAdrian Hunter self.rows.append(child.row) 7748392b74bSAdrian Hunter break 7758392b74bSAdrian Hunter 7768392b74bSAdrian Hunter def FindValue(self): 7778392b74bSAdrian Hunter self.pos = 0 7788392b74bSAdrian Hunter if self.last_value != self.value or self.pattern != self.last_pattern: 7798392b74bSAdrian Hunter self.FindSelect() 7808392b74bSAdrian Hunter if not len(self.rows): 7818392b74bSAdrian Hunter return -1 7828392b74bSAdrian Hunter return self.rows[self.pos] 7838392b74bSAdrian Hunter 7848392b74bSAdrian Hunter def FindThread(self): 7858392b74bSAdrian Hunter if self.direction == 0 or self.value != self.last_value or self.pattern != self.last_pattern: 7868392b74bSAdrian Hunter row = self.FindValue() 7878392b74bSAdrian Hunter elif len(self.rows): 7888392b74bSAdrian Hunter if self.direction > 0: 7898392b74bSAdrian Hunter self.pos += 1 7908392b74bSAdrian Hunter if self.pos >= len(self.rows): 7918392b74bSAdrian Hunter self.pos = 0 7928392b74bSAdrian Hunter else: 7938392b74bSAdrian Hunter self.pos -= 1 7948392b74bSAdrian Hunter if self.pos < 0: 7958392b74bSAdrian Hunter self.pos = len(self.rows) - 1 7968392b74bSAdrian Hunter row = self.rows[self.pos] 7978392b74bSAdrian Hunter else: 7988392b74bSAdrian Hunter row = -1 7998392b74bSAdrian Hunter return (True, row) 8008392b74bSAdrian Hunter 8018392b74bSAdrian Hunter def Find(self, value, direction, pattern, context, callback): 8028392b74bSAdrian Hunter self.value, self.direction, self.pattern, self.last_value, self.last_pattern = (value, direction,pattern, self.value, self.pattern) 8038392b74bSAdrian Hunter # Use a thread so the UI is not blocked 8048392b74bSAdrian Hunter thread = Thread(self.FindThread) 8058392b74bSAdrian Hunter thread.done.connect(lambda row, t=thread, c=callback: self.FindDone(t, c, row), Qt.QueuedConnection) 8068392b74bSAdrian Hunter thread.start() 8078392b74bSAdrian Hunter 8088392b74bSAdrian Hunter def FindDone(self, thread, callback, row): 8098392b74bSAdrian Hunter callback(row) 8108392b74bSAdrian Hunter 8118392b74bSAdrian Hunter# Number of database records to fetch in one go 8128392b74bSAdrian Hunter 8138392b74bSAdrian Hunterglb_chunk_sz = 10000 8148392b74bSAdrian Hunter 8158392b74bSAdrian Hunter# size of pickled integer big enough for record size 8168392b74bSAdrian Hunter 8178392b74bSAdrian Hunterglb_nsz = 8 8188392b74bSAdrian Hunter 8198392b74bSAdrian Hunter# Background process for SQL data fetcher 8208392b74bSAdrian Hunter 8218392b74bSAdrian Hunterclass SQLFetcherProcess(): 8228392b74bSAdrian Hunter 8238392b74bSAdrian Hunter def __init__(self, dbref, sql, buffer, head, tail, fetch_count, fetching_done, process_target, wait_event, fetched_event, prep): 8248392b74bSAdrian Hunter # Need a unique connection name 8258392b74bSAdrian Hunter conn_name = "SQLFetcher" + str(os.getpid()) 8268392b74bSAdrian Hunter self.db, dbname = dbref.Open(conn_name) 8278392b74bSAdrian Hunter self.sql = sql 8288392b74bSAdrian Hunter self.buffer = buffer 8298392b74bSAdrian Hunter self.head = head 8308392b74bSAdrian Hunter self.tail = tail 8318392b74bSAdrian Hunter self.fetch_count = fetch_count 8328392b74bSAdrian Hunter self.fetching_done = fetching_done 8338392b74bSAdrian Hunter self.process_target = process_target 8348392b74bSAdrian Hunter self.wait_event = wait_event 8358392b74bSAdrian Hunter self.fetched_event = fetched_event 8368392b74bSAdrian Hunter self.prep = prep 8378392b74bSAdrian Hunter self.query = QSqlQuery(self.db) 8388392b74bSAdrian Hunter self.query_limit = 0 if "$$last_id$$" in sql else 2 8398392b74bSAdrian Hunter self.last_id = -1 8408392b74bSAdrian Hunter self.fetched = 0 8418392b74bSAdrian Hunter self.more = True 8428392b74bSAdrian Hunter self.local_head = self.head.value 8438392b74bSAdrian Hunter self.local_tail = self.tail.value 8448392b74bSAdrian Hunter 8458392b74bSAdrian Hunter def Select(self): 8468392b74bSAdrian Hunter if self.query_limit: 8478392b74bSAdrian Hunter if self.query_limit == 1: 8488392b74bSAdrian Hunter return 8498392b74bSAdrian Hunter self.query_limit -= 1 8508392b74bSAdrian Hunter stmt = self.sql.replace("$$last_id$$", str(self.last_id)) 8518392b74bSAdrian Hunter QueryExec(self.query, stmt) 8528392b74bSAdrian Hunter 8538392b74bSAdrian Hunter def Next(self): 8548392b74bSAdrian Hunter if not self.query.next(): 8558392b74bSAdrian Hunter self.Select() 8568392b74bSAdrian Hunter if not self.query.next(): 8578392b74bSAdrian Hunter return None 8588392b74bSAdrian Hunter self.last_id = self.query.value(0) 8598392b74bSAdrian Hunter return self.prep(self.query) 8608392b74bSAdrian Hunter 8618392b74bSAdrian Hunter def WaitForTarget(self): 8628392b74bSAdrian Hunter while True: 8638392b74bSAdrian Hunter self.wait_event.clear() 8648392b74bSAdrian Hunter target = self.process_target.value 8658392b74bSAdrian Hunter if target > self.fetched or target < 0: 8668392b74bSAdrian Hunter break 8678392b74bSAdrian Hunter self.wait_event.wait() 8688392b74bSAdrian Hunter return target 8698392b74bSAdrian Hunter 8708392b74bSAdrian Hunter def HasSpace(self, sz): 8718392b74bSAdrian Hunter if self.local_tail <= self.local_head: 8728392b74bSAdrian Hunter space = len(self.buffer) - self.local_head 8738392b74bSAdrian Hunter if space > sz: 8748392b74bSAdrian Hunter return True 8758392b74bSAdrian Hunter if space >= glb_nsz: 8768392b74bSAdrian Hunter # Use 0 (or space < glb_nsz) to mean there is no more at the top of the buffer 8778392b74bSAdrian Hunter nd = cPickle.dumps(0, cPickle.HIGHEST_PROTOCOL) 8788392b74bSAdrian Hunter self.buffer[self.local_head : self.local_head + len(nd)] = nd 8798392b74bSAdrian Hunter self.local_head = 0 8808392b74bSAdrian Hunter if self.local_tail - self.local_head > sz: 8818392b74bSAdrian Hunter return True 8828392b74bSAdrian Hunter return False 8838392b74bSAdrian Hunter 8848392b74bSAdrian Hunter def WaitForSpace(self, sz): 8858392b74bSAdrian Hunter if self.HasSpace(sz): 8868392b74bSAdrian Hunter return 8878392b74bSAdrian Hunter while True: 8888392b74bSAdrian Hunter self.wait_event.clear() 8898392b74bSAdrian Hunter self.local_tail = self.tail.value 8908392b74bSAdrian Hunter if self.HasSpace(sz): 8918392b74bSAdrian Hunter return 8928392b74bSAdrian Hunter self.wait_event.wait() 8938392b74bSAdrian Hunter 8948392b74bSAdrian Hunter def AddToBuffer(self, obj): 8958392b74bSAdrian Hunter d = cPickle.dumps(obj, cPickle.HIGHEST_PROTOCOL) 8968392b74bSAdrian Hunter n = len(d) 8978392b74bSAdrian Hunter nd = cPickle.dumps(n, cPickle.HIGHEST_PROTOCOL) 8988392b74bSAdrian Hunter sz = n + glb_nsz 8998392b74bSAdrian Hunter self.WaitForSpace(sz) 9008392b74bSAdrian Hunter pos = self.local_head 9018392b74bSAdrian Hunter self.buffer[pos : pos + len(nd)] = nd 9028392b74bSAdrian Hunter self.buffer[pos + glb_nsz : pos + sz] = d 9038392b74bSAdrian Hunter self.local_head += sz 9048392b74bSAdrian Hunter 9058392b74bSAdrian Hunter def FetchBatch(self, batch_size): 9068392b74bSAdrian Hunter fetched = 0 9078392b74bSAdrian Hunter while batch_size > fetched: 9088392b74bSAdrian Hunter obj = self.Next() 9098392b74bSAdrian Hunter if obj is None: 9108392b74bSAdrian Hunter self.more = False 9118392b74bSAdrian Hunter break 9128392b74bSAdrian Hunter self.AddToBuffer(obj) 9138392b74bSAdrian Hunter fetched += 1 9148392b74bSAdrian Hunter if fetched: 9158392b74bSAdrian Hunter self.fetched += fetched 9168392b74bSAdrian Hunter with self.fetch_count.get_lock(): 9178392b74bSAdrian Hunter self.fetch_count.value += fetched 9188392b74bSAdrian Hunter self.head.value = self.local_head 9198392b74bSAdrian Hunter self.fetched_event.set() 9208392b74bSAdrian Hunter 9218392b74bSAdrian Hunter def Run(self): 9228392b74bSAdrian Hunter while self.more: 9238392b74bSAdrian Hunter target = self.WaitForTarget() 9248392b74bSAdrian Hunter if target < 0: 9258392b74bSAdrian Hunter break 9268392b74bSAdrian Hunter batch_size = min(glb_chunk_sz, target - self.fetched) 9278392b74bSAdrian Hunter self.FetchBatch(batch_size) 9288392b74bSAdrian Hunter self.fetching_done.value = True 9298392b74bSAdrian Hunter self.fetched_event.set() 9308392b74bSAdrian Hunter 9318392b74bSAdrian Hunterdef SQLFetcherFn(*x): 9328392b74bSAdrian Hunter process = SQLFetcherProcess(*x) 9338392b74bSAdrian Hunter process.Run() 9348392b74bSAdrian Hunter 9358392b74bSAdrian Hunter# SQL data fetcher 9368392b74bSAdrian Hunter 9378392b74bSAdrian Hunterclass SQLFetcher(QObject): 9388392b74bSAdrian Hunter 9398392b74bSAdrian Hunter done = Signal(object) 9408392b74bSAdrian Hunter 9418392b74bSAdrian Hunter def __init__(self, glb, sql, prep, process_data, parent=None): 9428392b74bSAdrian Hunter super(SQLFetcher, self).__init__(parent) 9438392b74bSAdrian Hunter self.process_data = process_data 9448392b74bSAdrian Hunter self.more = True 9458392b74bSAdrian Hunter self.target = 0 9468392b74bSAdrian Hunter self.last_target = 0 9478392b74bSAdrian Hunter self.fetched = 0 9488392b74bSAdrian Hunter self.buffer_size = 16 * 1024 * 1024 9498392b74bSAdrian Hunter self.buffer = Array(c_char, self.buffer_size, lock=False) 9508392b74bSAdrian Hunter self.head = Value(c_longlong) 9518392b74bSAdrian Hunter self.tail = Value(c_longlong) 9528392b74bSAdrian Hunter self.local_tail = 0 9538392b74bSAdrian Hunter self.fetch_count = Value(c_longlong) 9548392b74bSAdrian Hunter self.fetching_done = Value(c_bool) 9558392b74bSAdrian Hunter self.last_count = 0 9568392b74bSAdrian Hunter self.process_target = Value(c_longlong) 9578392b74bSAdrian Hunter self.wait_event = Event() 9588392b74bSAdrian Hunter self.fetched_event = Event() 9598392b74bSAdrian Hunter glb.AddInstanceToShutdownOnExit(self) 9608392b74bSAdrian Hunter 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)) 9618392b74bSAdrian Hunter self.process.start() 9628392b74bSAdrian Hunter self.thread = Thread(self.Thread) 9638392b74bSAdrian Hunter self.thread.done.connect(self.ProcessData, Qt.QueuedConnection) 9648392b74bSAdrian Hunter self.thread.start() 9658392b74bSAdrian Hunter 9668392b74bSAdrian Hunter def Shutdown(self): 9678392b74bSAdrian Hunter # Tell the thread and process to exit 9688392b74bSAdrian Hunter self.process_target.value = -1 9698392b74bSAdrian Hunter self.wait_event.set() 9708392b74bSAdrian Hunter self.more = False 9718392b74bSAdrian Hunter self.fetching_done.value = True 9728392b74bSAdrian Hunter self.fetched_event.set() 9738392b74bSAdrian Hunter 9748392b74bSAdrian Hunter def Thread(self): 9758392b74bSAdrian Hunter if not self.more: 9768392b74bSAdrian Hunter return True, 0 9778392b74bSAdrian Hunter while True: 9788392b74bSAdrian Hunter self.fetched_event.clear() 9798392b74bSAdrian Hunter fetch_count = self.fetch_count.value 9808392b74bSAdrian Hunter if fetch_count != self.last_count: 9818392b74bSAdrian Hunter break 9828392b74bSAdrian Hunter if self.fetching_done.value: 9838392b74bSAdrian Hunter self.more = False 9848392b74bSAdrian Hunter return True, 0 9858392b74bSAdrian Hunter self.fetched_event.wait() 9868392b74bSAdrian Hunter count = fetch_count - self.last_count 9878392b74bSAdrian Hunter self.last_count = fetch_count 9888392b74bSAdrian Hunter self.fetched += count 9898392b74bSAdrian Hunter return False, count 9908392b74bSAdrian Hunter 9918392b74bSAdrian Hunter def Fetch(self, nr): 9928392b74bSAdrian Hunter if not self.more: 9938392b74bSAdrian Hunter # -1 inidcates there are no more 9948392b74bSAdrian Hunter return -1 9958392b74bSAdrian Hunter result = self.fetched 9968392b74bSAdrian Hunter extra = result + nr - self.target 9978392b74bSAdrian Hunter if extra > 0: 9988392b74bSAdrian Hunter self.target += extra 9998392b74bSAdrian Hunter # process_target < 0 indicates shutting down 10008392b74bSAdrian Hunter if self.process_target.value >= 0: 10018392b74bSAdrian Hunter self.process_target.value = self.target 10028392b74bSAdrian Hunter self.wait_event.set() 10038392b74bSAdrian Hunter return result 10048392b74bSAdrian Hunter 10058392b74bSAdrian Hunter def RemoveFromBuffer(self): 10068392b74bSAdrian Hunter pos = self.local_tail 10078392b74bSAdrian Hunter if len(self.buffer) - pos < glb_nsz: 10088392b74bSAdrian Hunter pos = 0 10098392b74bSAdrian Hunter n = cPickle.loads(self.buffer[pos : pos + glb_nsz]) 10108392b74bSAdrian Hunter if n == 0: 10118392b74bSAdrian Hunter pos = 0 10128392b74bSAdrian Hunter n = cPickle.loads(self.buffer[0 : glb_nsz]) 10138392b74bSAdrian Hunter pos += glb_nsz 10148392b74bSAdrian Hunter obj = cPickle.loads(self.buffer[pos : pos + n]) 10158392b74bSAdrian Hunter self.local_tail = pos + n 10168392b74bSAdrian Hunter return obj 10178392b74bSAdrian Hunter 10188392b74bSAdrian Hunter def ProcessData(self, count): 10198392b74bSAdrian Hunter for i in xrange(count): 10208392b74bSAdrian Hunter obj = self.RemoveFromBuffer() 10218392b74bSAdrian Hunter self.process_data(obj) 10228392b74bSAdrian Hunter self.tail.value = self.local_tail 10238392b74bSAdrian Hunter self.wait_event.set() 10248392b74bSAdrian Hunter self.done.emit(count) 10258392b74bSAdrian Hunter 10268392b74bSAdrian Hunter# Fetch more records bar 10278392b74bSAdrian Hunter 10288392b74bSAdrian Hunterclass FetchMoreRecordsBar(): 10298392b74bSAdrian Hunter 10308392b74bSAdrian Hunter def __init__(self, model, parent): 10318392b74bSAdrian Hunter self.model = model 10328392b74bSAdrian Hunter 10338392b74bSAdrian Hunter self.label = QLabel("Number of records (x " + "{:,}".format(glb_chunk_sz) + ") to fetch:") 10348392b74bSAdrian Hunter self.label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 10358392b74bSAdrian Hunter 10368392b74bSAdrian Hunter self.fetch_count = QSpinBox() 10378392b74bSAdrian Hunter self.fetch_count.setRange(1, 1000000) 10388392b74bSAdrian Hunter self.fetch_count.setValue(10) 10398392b74bSAdrian Hunter self.fetch_count.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 10408392b74bSAdrian Hunter 10418392b74bSAdrian Hunter self.fetch = QPushButton("Go!") 10428392b74bSAdrian Hunter self.fetch.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 10438392b74bSAdrian Hunter self.fetch.released.connect(self.FetchMoreRecords) 10448392b74bSAdrian Hunter 10458392b74bSAdrian Hunter self.progress = QProgressBar() 10468392b74bSAdrian Hunter self.progress.setRange(0, 100) 10478392b74bSAdrian Hunter self.progress.hide() 10488392b74bSAdrian Hunter 10498392b74bSAdrian Hunter self.done_label = QLabel("All records fetched") 10508392b74bSAdrian Hunter self.done_label.hide() 10518392b74bSAdrian Hunter 10528392b74bSAdrian Hunter self.spacer = QLabel("") 10538392b74bSAdrian Hunter 10548392b74bSAdrian Hunter self.close_button = QToolButton() 10558392b74bSAdrian Hunter self.close_button.setIcon(parent.style().standardIcon(QStyle.SP_DockWidgetCloseButton)) 10568392b74bSAdrian Hunter self.close_button.released.connect(self.Deactivate) 10578392b74bSAdrian Hunter 10588392b74bSAdrian Hunter self.hbox = QHBoxLayout() 10598392b74bSAdrian Hunter self.hbox.setContentsMargins(0, 0, 0, 0) 10608392b74bSAdrian Hunter 10618392b74bSAdrian Hunter self.hbox.addWidget(self.label) 10628392b74bSAdrian Hunter self.hbox.addWidget(self.fetch_count) 10638392b74bSAdrian Hunter self.hbox.addWidget(self.fetch) 10648392b74bSAdrian Hunter self.hbox.addWidget(self.spacer) 10658392b74bSAdrian Hunter self.hbox.addWidget(self.progress) 10668392b74bSAdrian Hunter self.hbox.addWidget(self.done_label) 10678392b74bSAdrian Hunter self.hbox.addWidget(self.close_button) 10688392b74bSAdrian Hunter 10698392b74bSAdrian Hunter self.bar = QWidget() 10708392b74bSAdrian Hunter self.bar.setLayout(self.hbox); 10718392b74bSAdrian Hunter self.bar.show() 10728392b74bSAdrian Hunter 10738392b74bSAdrian Hunter self.in_progress = False 10748392b74bSAdrian Hunter self.model.progress.connect(self.Progress) 10758392b74bSAdrian Hunter 10768392b74bSAdrian Hunter self.done = False 10778392b74bSAdrian Hunter 10788392b74bSAdrian Hunter if not model.HasMoreRecords(): 10798392b74bSAdrian Hunter self.Done() 10808392b74bSAdrian Hunter 10818392b74bSAdrian Hunter def Widget(self): 10828392b74bSAdrian Hunter return self.bar 10838392b74bSAdrian Hunter 10848392b74bSAdrian Hunter def Activate(self): 10858392b74bSAdrian Hunter self.bar.show() 10868392b74bSAdrian Hunter self.fetch.setFocus() 10878392b74bSAdrian Hunter 10888392b74bSAdrian Hunter def Deactivate(self): 10898392b74bSAdrian Hunter self.bar.hide() 10908392b74bSAdrian Hunter 10918392b74bSAdrian Hunter def Enable(self, enable): 10928392b74bSAdrian Hunter self.fetch.setEnabled(enable) 10938392b74bSAdrian Hunter self.fetch_count.setEnabled(enable) 10948392b74bSAdrian Hunter 10958392b74bSAdrian Hunter def Busy(self): 10968392b74bSAdrian Hunter self.Enable(False) 10978392b74bSAdrian Hunter self.fetch.hide() 10988392b74bSAdrian Hunter self.spacer.hide() 10998392b74bSAdrian Hunter self.progress.show() 11008392b74bSAdrian Hunter 11018392b74bSAdrian Hunter def Idle(self): 11028392b74bSAdrian Hunter self.in_progress = False 11038392b74bSAdrian Hunter self.Enable(True) 11048392b74bSAdrian Hunter self.progress.hide() 11058392b74bSAdrian Hunter self.fetch.show() 11068392b74bSAdrian Hunter self.spacer.show() 11078392b74bSAdrian Hunter 11088392b74bSAdrian Hunter def Target(self): 11098392b74bSAdrian Hunter return self.fetch_count.value() * glb_chunk_sz 11108392b74bSAdrian Hunter 11118392b74bSAdrian Hunter def Done(self): 11128392b74bSAdrian Hunter self.done = True 11138392b74bSAdrian Hunter self.Idle() 11148392b74bSAdrian Hunter self.label.hide() 11158392b74bSAdrian Hunter self.fetch_count.hide() 11168392b74bSAdrian Hunter self.fetch.hide() 11178392b74bSAdrian Hunter self.spacer.hide() 11188392b74bSAdrian Hunter self.done_label.show() 11198392b74bSAdrian Hunter 11208392b74bSAdrian Hunter def Progress(self, count): 11218392b74bSAdrian Hunter if self.in_progress: 11228392b74bSAdrian Hunter if count: 11238392b74bSAdrian Hunter percent = ((count - self.start) * 100) / self.Target() 11248392b74bSAdrian Hunter if percent >= 100: 11258392b74bSAdrian Hunter self.Idle() 11268392b74bSAdrian Hunter else: 11278392b74bSAdrian Hunter self.progress.setValue(percent) 11288392b74bSAdrian Hunter if not count: 11298392b74bSAdrian Hunter # Count value of zero means no more records 11308392b74bSAdrian Hunter self.Done() 11318392b74bSAdrian Hunter 11328392b74bSAdrian Hunter def FetchMoreRecords(self): 11338392b74bSAdrian Hunter if self.done: 11348392b74bSAdrian Hunter return 11358392b74bSAdrian Hunter self.progress.setValue(0) 11368392b74bSAdrian Hunter self.Busy() 11378392b74bSAdrian Hunter self.in_progress = True 11388392b74bSAdrian Hunter self.start = self.model.FetchMoreRecords(self.Target()) 11398392b74bSAdrian Hunter 114076099f98SAdrian Hunter# Brance data model level two item 114176099f98SAdrian Hunter 114276099f98SAdrian Hunterclass BranchLevelTwoItem(): 114376099f98SAdrian Hunter 114476099f98SAdrian Hunter def __init__(self, row, text, parent_item): 114576099f98SAdrian Hunter self.row = row 114676099f98SAdrian Hunter self.parent_item = parent_item 114776099f98SAdrian Hunter self.data = [""] * 8 114876099f98SAdrian Hunter self.data[7] = text 114976099f98SAdrian Hunter self.level = 2 115076099f98SAdrian Hunter 115176099f98SAdrian Hunter def getParentItem(self): 115276099f98SAdrian Hunter return self.parent_item 115376099f98SAdrian Hunter 115476099f98SAdrian Hunter def getRow(self): 115576099f98SAdrian Hunter return self.row 115676099f98SAdrian Hunter 115776099f98SAdrian Hunter def childCount(self): 115876099f98SAdrian Hunter return 0 115976099f98SAdrian Hunter 116076099f98SAdrian Hunter def hasChildren(self): 116176099f98SAdrian Hunter return False 116276099f98SAdrian Hunter 116376099f98SAdrian Hunter def getData(self, column): 116476099f98SAdrian Hunter return self.data[column] 116576099f98SAdrian Hunter 116676099f98SAdrian Hunter# Brance data model level one item 116776099f98SAdrian Hunter 116876099f98SAdrian Hunterclass BranchLevelOneItem(): 116976099f98SAdrian Hunter 117076099f98SAdrian Hunter def __init__(self, glb, row, data, parent_item): 117176099f98SAdrian Hunter self.glb = glb 117276099f98SAdrian Hunter self.row = row 117376099f98SAdrian Hunter self.parent_item = parent_item 117476099f98SAdrian Hunter self.child_count = 0 117576099f98SAdrian Hunter self.child_items = [] 117676099f98SAdrian Hunter self.data = data[1:] 117776099f98SAdrian Hunter self.dbid = data[0] 117876099f98SAdrian Hunter self.level = 1 117976099f98SAdrian Hunter self.query_done = False 118076099f98SAdrian Hunter 118176099f98SAdrian Hunter def getChildItem(self, row): 118276099f98SAdrian Hunter return self.child_items[row] 118376099f98SAdrian Hunter 118476099f98SAdrian Hunter def getParentItem(self): 118576099f98SAdrian Hunter return self.parent_item 118676099f98SAdrian Hunter 118776099f98SAdrian Hunter def getRow(self): 118876099f98SAdrian Hunter return self.row 118976099f98SAdrian Hunter 119076099f98SAdrian Hunter def Select(self): 119176099f98SAdrian Hunter self.query_done = True 119276099f98SAdrian Hunter 119376099f98SAdrian Hunter if not self.glb.have_disassembler: 119476099f98SAdrian Hunter return 119576099f98SAdrian Hunter 119676099f98SAdrian Hunter query = QSqlQuery(self.glb.db) 119776099f98SAdrian Hunter 119876099f98SAdrian Hunter QueryExec(query, "SELECT cpu, to_dso_id, to_symbol_id, to_sym_offset, short_name, long_name, build_id, sym_start, to_ip" 119976099f98SAdrian Hunter " FROM samples" 120076099f98SAdrian Hunter " INNER JOIN dsos ON samples.to_dso_id = dsos.id" 120176099f98SAdrian Hunter " INNER JOIN symbols ON samples.to_symbol_id = symbols.id" 120276099f98SAdrian Hunter " WHERE samples.id = " + str(self.dbid)) 120376099f98SAdrian Hunter if not query.next(): 120476099f98SAdrian Hunter return 120576099f98SAdrian Hunter cpu = query.value(0) 120676099f98SAdrian Hunter dso = query.value(1) 120776099f98SAdrian Hunter sym = query.value(2) 120876099f98SAdrian Hunter if dso == 0 or sym == 0: 120976099f98SAdrian Hunter return 121076099f98SAdrian Hunter off = query.value(3) 121176099f98SAdrian Hunter short_name = query.value(4) 121276099f98SAdrian Hunter long_name = query.value(5) 121376099f98SAdrian Hunter build_id = query.value(6) 121476099f98SAdrian Hunter sym_start = query.value(7) 121576099f98SAdrian Hunter ip = query.value(8) 121676099f98SAdrian Hunter 121776099f98SAdrian Hunter QueryExec(query, "SELECT samples.dso_id, symbol_id, sym_offset, sym_start" 121876099f98SAdrian Hunter " FROM samples" 121976099f98SAdrian Hunter " INNER JOIN symbols ON samples.symbol_id = symbols.id" 122076099f98SAdrian Hunter " WHERE samples.id > " + str(self.dbid) + " AND cpu = " + str(cpu) + 122176099f98SAdrian Hunter " ORDER BY samples.id" 122276099f98SAdrian Hunter " LIMIT 1") 122376099f98SAdrian Hunter if not query.next(): 122476099f98SAdrian Hunter return 122576099f98SAdrian Hunter if query.value(0) != dso: 122676099f98SAdrian Hunter # Cannot disassemble from one dso to another 122776099f98SAdrian Hunter return 122876099f98SAdrian Hunter bsym = query.value(1) 122976099f98SAdrian Hunter boff = query.value(2) 123076099f98SAdrian Hunter bsym_start = query.value(3) 123176099f98SAdrian Hunter if bsym == 0: 123276099f98SAdrian Hunter return 123376099f98SAdrian Hunter tot = bsym_start + boff + 1 - sym_start - off 123476099f98SAdrian Hunter if tot <= 0 or tot > 16384: 123576099f98SAdrian Hunter return 123676099f98SAdrian Hunter 123776099f98SAdrian Hunter inst = self.glb.disassembler.Instruction() 123876099f98SAdrian Hunter f = self.glb.FileFromNamesAndBuildId(short_name, long_name, build_id) 123976099f98SAdrian Hunter if not f: 124076099f98SAdrian Hunter return 124176099f98SAdrian Hunter mode = 0 if Is64Bit(f) else 1 124276099f98SAdrian Hunter self.glb.disassembler.SetMode(inst, mode) 124376099f98SAdrian Hunter 124476099f98SAdrian Hunter buf_sz = tot + 16 124576099f98SAdrian Hunter buf = create_string_buffer(tot + 16) 124676099f98SAdrian Hunter f.seek(sym_start + off) 124776099f98SAdrian Hunter buf.value = f.read(buf_sz) 124876099f98SAdrian Hunter buf_ptr = addressof(buf) 124976099f98SAdrian Hunter i = 0 125076099f98SAdrian Hunter while tot > 0: 125176099f98SAdrian Hunter cnt, text = self.glb.disassembler.DisassembleOne(inst, buf_ptr, buf_sz, ip) 125276099f98SAdrian Hunter if cnt: 125376099f98SAdrian Hunter byte_str = tohex(ip).rjust(16) 125476099f98SAdrian Hunter for k in xrange(cnt): 125576099f98SAdrian Hunter byte_str += " %02x" % ord(buf[i]) 125676099f98SAdrian Hunter i += 1 125776099f98SAdrian Hunter while k < 15: 125876099f98SAdrian Hunter byte_str += " " 125976099f98SAdrian Hunter k += 1 126076099f98SAdrian Hunter self.child_items.append(BranchLevelTwoItem(0, byte_str + " " + text, self)) 126176099f98SAdrian Hunter self.child_count += 1 126276099f98SAdrian Hunter else: 126376099f98SAdrian Hunter return 126476099f98SAdrian Hunter buf_ptr += cnt 126576099f98SAdrian Hunter tot -= cnt 126676099f98SAdrian Hunter buf_sz -= cnt 126776099f98SAdrian Hunter ip += cnt 126876099f98SAdrian Hunter 126976099f98SAdrian Hunter def childCount(self): 127076099f98SAdrian Hunter if not self.query_done: 127176099f98SAdrian Hunter self.Select() 127276099f98SAdrian Hunter if not self.child_count: 127376099f98SAdrian Hunter return -1 127476099f98SAdrian Hunter return self.child_count 127576099f98SAdrian Hunter 127676099f98SAdrian Hunter def hasChildren(self): 127776099f98SAdrian Hunter if not self.query_done: 127876099f98SAdrian Hunter return True 127976099f98SAdrian Hunter return self.child_count > 0 128076099f98SAdrian Hunter 128176099f98SAdrian Hunter def getData(self, column): 128276099f98SAdrian Hunter return self.data[column] 128376099f98SAdrian Hunter 128476099f98SAdrian Hunter# Brance data model root item 128576099f98SAdrian Hunter 128676099f98SAdrian Hunterclass BranchRootItem(): 128776099f98SAdrian Hunter 128876099f98SAdrian Hunter def __init__(self): 128976099f98SAdrian Hunter self.child_count = 0 129076099f98SAdrian Hunter self.child_items = [] 129176099f98SAdrian Hunter self.level = 0 129276099f98SAdrian Hunter 129376099f98SAdrian Hunter def getChildItem(self, row): 129476099f98SAdrian Hunter return self.child_items[row] 129576099f98SAdrian Hunter 129676099f98SAdrian Hunter def getParentItem(self): 129776099f98SAdrian Hunter return None 129876099f98SAdrian Hunter 129976099f98SAdrian Hunter def getRow(self): 130076099f98SAdrian Hunter return 0 130176099f98SAdrian Hunter 130276099f98SAdrian Hunter def childCount(self): 130376099f98SAdrian Hunter return self.child_count 130476099f98SAdrian Hunter 130576099f98SAdrian Hunter def hasChildren(self): 130676099f98SAdrian Hunter return self.child_count > 0 130776099f98SAdrian Hunter 130876099f98SAdrian Hunter def getData(self, column): 130976099f98SAdrian Hunter return "" 131076099f98SAdrian Hunter 131176099f98SAdrian Hunter# Branch data preparation 131276099f98SAdrian Hunter 131376099f98SAdrian Hunterdef BranchDataPrep(query): 131476099f98SAdrian Hunter data = [] 131576099f98SAdrian Hunter for i in xrange(0, 8): 131676099f98SAdrian Hunter data.append(query.value(i)) 131776099f98SAdrian Hunter data.append(tohex(query.value(8)).rjust(16) + " " + query.value(9) + offstr(query.value(10)) + 131876099f98SAdrian Hunter " (" + dsoname(query.value(11)) + ")" + " -> " + 131976099f98SAdrian Hunter tohex(query.value(12)) + " " + query.value(13) + offstr(query.value(14)) + 132076099f98SAdrian Hunter " (" + dsoname(query.value(15)) + ")") 132176099f98SAdrian Hunter return data 132276099f98SAdrian Hunter 132376099f98SAdrian Hunter# Branch data model 132476099f98SAdrian Hunter 132576099f98SAdrian Hunterclass BranchModel(TreeModel): 132676099f98SAdrian Hunter 132776099f98SAdrian Hunter progress = Signal(object) 132876099f98SAdrian Hunter 132976099f98SAdrian Hunter def __init__(self, glb, event_id, where_clause, parent=None): 133076099f98SAdrian Hunter super(BranchModel, self).__init__(BranchRootItem(), parent) 133176099f98SAdrian Hunter self.glb = glb 133276099f98SAdrian Hunter self.event_id = event_id 133376099f98SAdrian Hunter self.more = True 133476099f98SAdrian Hunter self.populated = 0 133576099f98SAdrian Hunter sql = ("SELECT samples.id, time, cpu, comm, pid, tid, branch_types.name," 133676099f98SAdrian Hunter " CASE WHEN in_tx = '0' THEN 'No' ELSE 'Yes' END," 133776099f98SAdrian Hunter " ip, symbols.name, sym_offset, dsos.short_name," 133876099f98SAdrian Hunter " to_ip, to_symbols.name, to_sym_offset, to_dsos.short_name" 133976099f98SAdrian Hunter " FROM samples" 134076099f98SAdrian Hunter " INNER JOIN comms ON comm_id = comms.id" 134176099f98SAdrian Hunter " INNER JOIN threads ON thread_id = threads.id" 134276099f98SAdrian Hunter " INNER JOIN branch_types ON branch_type = branch_types.id" 134376099f98SAdrian Hunter " INNER JOIN symbols ON symbol_id = symbols.id" 134476099f98SAdrian Hunter " INNER JOIN symbols to_symbols ON to_symbol_id = to_symbols.id" 134576099f98SAdrian Hunter " INNER JOIN dsos ON samples.dso_id = dsos.id" 134676099f98SAdrian Hunter " INNER JOIN dsos AS to_dsos ON samples.to_dso_id = to_dsos.id" 134776099f98SAdrian Hunter " WHERE samples.id > $$last_id$$" + where_clause + 134876099f98SAdrian Hunter " AND evsel_id = " + str(self.event_id) + 134976099f98SAdrian Hunter " ORDER BY samples.id" 135076099f98SAdrian Hunter " LIMIT " + str(glb_chunk_sz)) 135176099f98SAdrian Hunter self.fetcher = SQLFetcher(glb, sql, BranchDataPrep, self.AddSample) 135276099f98SAdrian Hunter self.fetcher.done.connect(self.Update) 135376099f98SAdrian Hunter self.fetcher.Fetch(glb_chunk_sz) 135476099f98SAdrian Hunter 135576099f98SAdrian Hunter def columnCount(self, parent=None): 135676099f98SAdrian Hunter return 8 135776099f98SAdrian Hunter 135876099f98SAdrian Hunter def columnHeader(self, column): 135976099f98SAdrian Hunter return ("Time", "CPU", "Command", "PID", "TID", "Branch Type", "In Tx", "Branch")[column] 136076099f98SAdrian Hunter 136176099f98SAdrian Hunter def columnFont(self, column): 136276099f98SAdrian Hunter if column != 7: 136376099f98SAdrian Hunter return None 136476099f98SAdrian Hunter return QFont("Monospace") 136576099f98SAdrian Hunter 136676099f98SAdrian Hunter def DisplayData(self, item, index): 136776099f98SAdrian Hunter if item.level == 1: 136876099f98SAdrian Hunter self.FetchIfNeeded(item.row) 136976099f98SAdrian Hunter return item.getData(index.column()) 137076099f98SAdrian Hunter 137176099f98SAdrian Hunter def AddSample(self, data): 137276099f98SAdrian Hunter child = BranchLevelOneItem(self.glb, self.populated, data, self.root) 137376099f98SAdrian Hunter self.root.child_items.append(child) 137476099f98SAdrian Hunter self.populated += 1 137576099f98SAdrian Hunter 137676099f98SAdrian Hunter def Update(self, fetched): 137776099f98SAdrian Hunter if not fetched: 137876099f98SAdrian Hunter self.more = False 137976099f98SAdrian Hunter self.progress.emit(0) 138076099f98SAdrian Hunter child_count = self.root.child_count 138176099f98SAdrian Hunter count = self.populated - child_count 138276099f98SAdrian Hunter if count > 0: 138376099f98SAdrian Hunter parent = QModelIndex() 138476099f98SAdrian Hunter self.beginInsertRows(parent, child_count, child_count + count - 1) 138576099f98SAdrian Hunter self.insertRows(child_count, count, parent) 138676099f98SAdrian Hunter self.root.child_count += count 138776099f98SAdrian Hunter self.endInsertRows() 138876099f98SAdrian Hunter self.progress.emit(self.root.child_count) 138976099f98SAdrian Hunter 139076099f98SAdrian Hunter def FetchMoreRecords(self, count): 139176099f98SAdrian Hunter current = self.root.child_count 139276099f98SAdrian Hunter if self.more: 139376099f98SAdrian Hunter self.fetcher.Fetch(count) 139476099f98SAdrian Hunter else: 139576099f98SAdrian Hunter self.progress.emit(0) 139676099f98SAdrian Hunter return current 139776099f98SAdrian Hunter 139876099f98SAdrian Hunter def HasMoreRecords(self): 139976099f98SAdrian Hunter return self.more 140076099f98SAdrian Hunter 140176099f98SAdrian Hunter# Branch window 140276099f98SAdrian Hunter 140376099f98SAdrian Hunterclass BranchWindow(QMdiSubWindow): 140476099f98SAdrian Hunter 140576099f98SAdrian Hunter def __init__(self, glb, event_id, name, where_clause, parent=None): 140676099f98SAdrian Hunter super(BranchWindow, self).__init__(parent) 140776099f98SAdrian Hunter 140876099f98SAdrian Hunter model_name = "Branch Events " + str(event_id) 140976099f98SAdrian Hunter if len(where_clause): 141076099f98SAdrian Hunter model_name = where_clause + " " + model_name 141176099f98SAdrian Hunter 141276099f98SAdrian Hunter self.model = LookupCreateModel(model_name, lambda: BranchModel(glb, event_id, where_clause)) 141376099f98SAdrian Hunter 141476099f98SAdrian Hunter self.view = QTreeView() 141576099f98SAdrian Hunter self.view.setUniformRowHeights(True) 141676099f98SAdrian Hunter self.view.setModel(self.model) 141776099f98SAdrian Hunter 141876099f98SAdrian Hunter self.ResizeColumnsToContents() 141976099f98SAdrian Hunter 142076099f98SAdrian Hunter self.find_bar = FindBar(self, self, True) 142176099f98SAdrian Hunter 142276099f98SAdrian Hunter self.finder = ChildDataItemFinder(self.model.root) 142376099f98SAdrian Hunter 142476099f98SAdrian Hunter self.fetch_bar = FetchMoreRecordsBar(self.model, self) 142576099f98SAdrian Hunter 142676099f98SAdrian Hunter self.vbox = VBox(self.view, self.find_bar.Widget(), self.fetch_bar.Widget()) 142776099f98SAdrian Hunter 142876099f98SAdrian Hunter self.setWidget(self.vbox.Widget()) 142976099f98SAdrian Hunter 143076099f98SAdrian Hunter AddSubWindow(glb.mainwindow.mdi_area, self, name + " Branch Events") 143176099f98SAdrian Hunter 143276099f98SAdrian Hunter def ResizeColumnToContents(self, column, n): 143376099f98SAdrian Hunter # Using the view's resizeColumnToContents() here is extrememly slow 143476099f98SAdrian Hunter # so implement a crude alternative 143576099f98SAdrian Hunter mm = "MM" if column else "MMMM" 143676099f98SAdrian Hunter font = self.view.font() 143776099f98SAdrian Hunter metrics = QFontMetrics(font) 143876099f98SAdrian Hunter max = 0 143976099f98SAdrian Hunter for row in xrange(n): 144076099f98SAdrian Hunter val = self.model.root.child_items[row].data[column] 144176099f98SAdrian Hunter len = metrics.width(str(val) + mm) 144276099f98SAdrian Hunter max = len if len > max else max 144376099f98SAdrian Hunter val = self.model.columnHeader(column) 144476099f98SAdrian Hunter len = metrics.width(str(val) + mm) 144576099f98SAdrian Hunter max = len if len > max else max 144676099f98SAdrian Hunter self.view.setColumnWidth(column, max) 144776099f98SAdrian Hunter 144876099f98SAdrian Hunter def ResizeColumnsToContents(self): 144976099f98SAdrian Hunter n = min(self.model.root.child_count, 100) 145076099f98SAdrian Hunter if n < 1: 145176099f98SAdrian Hunter # No data yet, so connect a signal to notify when there is 145276099f98SAdrian Hunter self.model.rowsInserted.connect(self.UpdateColumnWidths) 145376099f98SAdrian Hunter return 145476099f98SAdrian Hunter columns = self.model.columnCount() 145576099f98SAdrian Hunter for i in xrange(columns): 145676099f98SAdrian Hunter self.ResizeColumnToContents(i, n) 145776099f98SAdrian Hunter 145876099f98SAdrian Hunter def UpdateColumnWidths(self, *x): 145976099f98SAdrian Hunter # This only needs to be done once, so disconnect the signal now 146076099f98SAdrian Hunter self.model.rowsInserted.disconnect(self.UpdateColumnWidths) 146176099f98SAdrian Hunter self.ResizeColumnsToContents() 146276099f98SAdrian Hunter 146376099f98SAdrian Hunter def Find(self, value, direction, pattern, context): 146476099f98SAdrian Hunter self.view.setFocus() 146576099f98SAdrian Hunter self.find_bar.Busy() 146676099f98SAdrian Hunter self.finder.Find(value, direction, pattern, context, self.FindDone) 146776099f98SAdrian Hunter 146876099f98SAdrian Hunter def FindDone(self, row): 146976099f98SAdrian Hunter self.find_bar.Idle() 147076099f98SAdrian Hunter if row >= 0: 147176099f98SAdrian Hunter self.view.setCurrentIndex(self.model.index(row, 0, QModelIndex())) 147276099f98SAdrian Hunter else: 147376099f98SAdrian Hunter self.find_bar.NotFound() 147476099f98SAdrian Hunter 1475210cf1f9SAdrian Hunter# Dialog data item converted and validated using a SQL table 1476210cf1f9SAdrian Hunter 1477210cf1f9SAdrian Hunterclass SQLTableDialogDataItem(): 1478210cf1f9SAdrian Hunter 1479210cf1f9SAdrian Hunter def __init__(self, glb, label, placeholder_text, table_name, match_column, column_name1, column_name2, parent): 1480210cf1f9SAdrian Hunter self.glb = glb 1481210cf1f9SAdrian Hunter self.label = label 1482210cf1f9SAdrian Hunter self.placeholder_text = placeholder_text 1483210cf1f9SAdrian Hunter self.table_name = table_name 1484210cf1f9SAdrian Hunter self.match_column = match_column 1485210cf1f9SAdrian Hunter self.column_name1 = column_name1 1486210cf1f9SAdrian Hunter self.column_name2 = column_name2 1487210cf1f9SAdrian Hunter self.parent = parent 1488210cf1f9SAdrian Hunter 1489210cf1f9SAdrian Hunter self.value = "" 1490210cf1f9SAdrian Hunter 1491210cf1f9SAdrian Hunter self.widget = QLineEdit() 1492210cf1f9SAdrian Hunter self.widget.editingFinished.connect(self.Validate) 1493210cf1f9SAdrian Hunter self.widget.textChanged.connect(self.Invalidate) 1494210cf1f9SAdrian Hunter self.red = False 1495210cf1f9SAdrian Hunter self.error = "" 1496210cf1f9SAdrian Hunter self.validated = True 1497210cf1f9SAdrian Hunter 1498210cf1f9SAdrian Hunter self.last_id = 0 1499210cf1f9SAdrian Hunter self.first_time = 0 1500210cf1f9SAdrian Hunter self.last_time = 2 ** 64 1501210cf1f9SAdrian Hunter if self.table_name == "<timeranges>": 1502210cf1f9SAdrian Hunter query = QSqlQuery(self.glb.db) 1503210cf1f9SAdrian Hunter QueryExec(query, "SELECT id, time FROM samples ORDER BY id DESC LIMIT 1") 1504210cf1f9SAdrian Hunter if query.next(): 1505210cf1f9SAdrian Hunter self.last_id = int(query.value(0)) 1506210cf1f9SAdrian Hunter self.last_time = int(query.value(1)) 1507210cf1f9SAdrian Hunter QueryExec(query, "SELECT time FROM samples WHERE time != 0 ORDER BY id LIMIT 1") 1508210cf1f9SAdrian Hunter if query.next(): 1509210cf1f9SAdrian Hunter self.first_time = int(query.value(0)) 1510210cf1f9SAdrian Hunter if placeholder_text: 1511210cf1f9SAdrian Hunter placeholder_text += ", between " + str(self.first_time) + " and " + str(self.last_time) 1512210cf1f9SAdrian Hunter 1513210cf1f9SAdrian Hunter if placeholder_text: 1514210cf1f9SAdrian Hunter self.widget.setPlaceholderText(placeholder_text) 1515210cf1f9SAdrian Hunter 1516210cf1f9SAdrian Hunter def ValueToIds(self, value): 1517210cf1f9SAdrian Hunter ids = [] 1518210cf1f9SAdrian Hunter query = QSqlQuery(self.glb.db) 1519210cf1f9SAdrian Hunter stmt = "SELECT id FROM " + self.table_name + " WHERE " + self.match_column + " = '" + value + "'" 1520210cf1f9SAdrian Hunter ret = query.exec_(stmt) 1521210cf1f9SAdrian Hunter if ret: 1522210cf1f9SAdrian Hunter while query.next(): 1523210cf1f9SAdrian Hunter ids.append(str(query.value(0))) 1524210cf1f9SAdrian Hunter return ids 1525210cf1f9SAdrian Hunter 1526210cf1f9SAdrian Hunter def IdBetween(self, query, lower_id, higher_id, order): 1527210cf1f9SAdrian Hunter QueryExec(query, "SELECT id FROM samples WHERE id > " + str(lower_id) + " AND id < " + str(higher_id) + " ORDER BY id " + order + " LIMIT 1") 1528210cf1f9SAdrian Hunter if query.next(): 1529210cf1f9SAdrian Hunter return True, int(query.value(0)) 1530210cf1f9SAdrian Hunter else: 1531210cf1f9SAdrian Hunter return False, 0 1532210cf1f9SAdrian Hunter 1533210cf1f9SAdrian Hunter def BinarySearchTime(self, lower_id, higher_id, target_time, get_floor): 1534210cf1f9SAdrian Hunter query = QSqlQuery(self.glb.db) 1535210cf1f9SAdrian Hunter while True: 1536210cf1f9SAdrian Hunter next_id = int((lower_id + higher_id) / 2) 1537210cf1f9SAdrian Hunter QueryExec(query, "SELECT time FROM samples WHERE id = " + str(next_id)) 1538210cf1f9SAdrian Hunter if not query.next(): 1539210cf1f9SAdrian Hunter ok, dbid = self.IdBetween(query, lower_id, next_id, "DESC") 1540210cf1f9SAdrian Hunter if not ok: 1541210cf1f9SAdrian Hunter ok, dbid = self.IdBetween(query, next_id, higher_id, "") 1542210cf1f9SAdrian Hunter if not ok: 1543210cf1f9SAdrian Hunter return str(higher_id) 1544210cf1f9SAdrian Hunter next_id = dbid 1545210cf1f9SAdrian Hunter QueryExec(query, "SELECT time FROM samples WHERE id = " + str(next_id)) 1546210cf1f9SAdrian Hunter next_time = int(query.value(0)) 1547210cf1f9SAdrian Hunter if get_floor: 1548210cf1f9SAdrian Hunter if target_time > next_time: 1549210cf1f9SAdrian Hunter lower_id = next_id 1550210cf1f9SAdrian Hunter else: 1551210cf1f9SAdrian Hunter higher_id = next_id 1552210cf1f9SAdrian Hunter if higher_id <= lower_id + 1: 1553210cf1f9SAdrian Hunter return str(higher_id) 1554210cf1f9SAdrian Hunter else: 1555210cf1f9SAdrian Hunter if target_time >= next_time: 1556210cf1f9SAdrian Hunter lower_id = next_id 1557210cf1f9SAdrian Hunter else: 1558210cf1f9SAdrian Hunter higher_id = next_id 1559210cf1f9SAdrian Hunter if higher_id <= lower_id + 1: 1560210cf1f9SAdrian Hunter return str(lower_id) 1561210cf1f9SAdrian Hunter 1562210cf1f9SAdrian Hunter def ConvertRelativeTime(self, val): 1563210cf1f9SAdrian Hunter print "val ", val 1564210cf1f9SAdrian Hunter mult = 1 1565210cf1f9SAdrian Hunter suffix = val[-2:] 1566210cf1f9SAdrian Hunter if suffix == "ms": 1567210cf1f9SAdrian Hunter mult = 1000000 1568210cf1f9SAdrian Hunter elif suffix == "us": 1569210cf1f9SAdrian Hunter mult = 1000 1570210cf1f9SAdrian Hunter elif suffix == "ns": 1571210cf1f9SAdrian Hunter mult = 1 1572210cf1f9SAdrian Hunter else: 1573210cf1f9SAdrian Hunter return val 1574210cf1f9SAdrian Hunter val = val[:-2].strip() 1575210cf1f9SAdrian Hunter if not self.IsNumber(val): 1576210cf1f9SAdrian Hunter return val 1577210cf1f9SAdrian Hunter val = int(val) * mult 1578210cf1f9SAdrian Hunter if val >= 0: 1579210cf1f9SAdrian Hunter val += self.first_time 1580210cf1f9SAdrian Hunter else: 1581210cf1f9SAdrian Hunter val += self.last_time 1582210cf1f9SAdrian Hunter return str(val) 1583210cf1f9SAdrian Hunter 1584210cf1f9SAdrian Hunter def ConvertTimeRange(self, vrange): 1585210cf1f9SAdrian Hunter print "vrange ", vrange 1586210cf1f9SAdrian Hunter if vrange[0] == "": 1587210cf1f9SAdrian Hunter vrange[0] = str(self.first_time) 1588210cf1f9SAdrian Hunter if vrange[1] == "": 1589210cf1f9SAdrian Hunter vrange[1] = str(self.last_time) 1590210cf1f9SAdrian Hunter vrange[0] = self.ConvertRelativeTime(vrange[0]) 1591210cf1f9SAdrian Hunter vrange[1] = self.ConvertRelativeTime(vrange[1]) 1592210cf1f9SAdrian Hunter print "vrange2 ", vrange 1593210cf1f9SAdrian Hunter if not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]): 1594210cf1f9SAdrian Hunter return False 1595210cf1f9SAdrian Hunter print "ok1" 1596210cf1f9SAdrian Hunter beg_range = max(int(vrange[0]), self.first_time) 1597210cf1f9SAdrian Hunter end_range = min(int(vrange[1]), self.last_time) 1598210cf1f9SAdrian Hunter if beg_range > self.last_time or end_range < self.first_time: 1599210cf1f9SAdrian Hunter return False 1600210cf1f9SAdrian Hunter print "ok2" 1601210cf1f9SAdrian Hunter vrange[0] = self.BinarySearchTime(0, self.last_id, beg_range, True) 1602210cf1f9SAdrian Hunter vrange[1] = self.BinarySearchTime(1, self.last_id + 1, end_range, False) 1603210cf1f9SAdrian Hunter print "vrange3 ", vrange 1604210cf1f9SAdrian Hunter return True 1605210cf1f9SAdrian Hunter 1606210cf1f9SAdrian Hunter def AddTimeRange(self, value, ranges): 1607210cf1f9SAdrian Hunter print "value ", value 1608210cf1f9SAdrian Hunter n = value.count("-") 1609210cf1f9SAdrian Hunter if n == 1: 1610210cf1f9SAdrian Hunter pass 1611210cf1f9SAdrian Hunter elif n == 2: 1612210cf1f9SAdrian Hunter if value.split("-")[1].strip() == "": 1613210cf1f9SAdrian Hunter n = 1 1614210cf1f9SAdrian Hunter elif n == 3: 1615210cf1f9SAdrian Hunter n = 2 1616210cf1f9SAdrian Hunter else: 1617210cf1f9SAdrian Hunter return False 1618210cf1f9SAdrian Hunter pos = findnth(value, "-", n) 1619210cf1f9SAdrian Hunter vrange = [value[:pos].strip() ,value[pos+1:].strip()] 1620210cf1f9SAdrian Hunter if self.ConvertTimeRange(vrange): 1621210cf1f9SAdrian Hunter ranges.append(vrange) 1622210cf1f9SAdrian Hunter return True 1623210cf1f9SAdrian Hunter return False 1624210cf1f9SAdrian Hunter 1625210cf1f9SAdrian Hunter def InvalidValue(self, value): 1626210cf1f9SAdrian Hunter self.value = "" 1627210cf1f9SAdrian Hunter palette = QPalette() 1628210cf1f9SAdrian Hunter palette.setColor(QPalette.Text,Qt.red) 1629210cf1f9SAdrian Hunter self.widget.setPalette(palette) 1630210cf1f9SAdrian Hunter self.red = True 1631210cf1f9SAdrian Hunter self.error = self.label + " invalid value '" + value + "'" 1632210cf1f9SAdrian Hunter self.parent.ShowMessage(self.error) 1633210cf1f9SAdrian Hunter 1634210cf1f9SAdrian Hunter def IsNumber(self, value): 1635210cf1f9SAdrian Hunter try: 1636210cf1f9SAdrian Hunter x = int(value) 1637210cf1f9SAdrian Hunter except: 1638210cf1f9SAdrian Hunter x = 0 1639210cf1f9SAdrian Hunter return str(x) == value 1640210cf1f9SAdrian Hunter 1641210cf1f9SAdrian Hunter def Invalidate(self): 1642210cf1f9SAdrian Hunter self.validated = False 1643210cf1f9SAdrian Hunter 1644210cf1f9SAdrian Hunter def Validate(self): 1645210cf1f9SAdrian Hunter input_string = self.widget.text() 1646210cf1f9SAdrian Hunter self.validated = True 1647210cf1f9SAdrian Hunter if self.red: 1648210cf1f9SAdrian Hunter palette = QPalette() 1649210cf1f9SAdrian Hunter self.widget.setPalette(palette) 1650210cf1f9SAdrian Hunter self.red = False 1651210cf1f9SAdrian Hunter if not len(input_string.strip()): 1652210cf1f9SAdrian Hunter self.error = "" 1653210cf1f9SAdrian Hunter self.value = "" 1654210cf1f9SAdrian Hunter return 1655210cf1f9SAdrian Hunter if self.table_name == "<timeranges>": 1656210cf1f9SAdrian Hunter ranges = [] 1657210cf1f9SAdrian Hunter for value in [x.strip() for x in input_string.split(",")]: 1658210cf1f9SAdrian Hunter if not self.AddTimeRange(value, ranges): 1659210cf1f9SAdrian Hunter return self.InvalidValue(value) 1660210cf1f9SAdrian Hunter ranges = [("(" + self.column_name1 + " >= " + r[0] + " AND " + self.column_name1 + " <= " + r[1] + ")") for r in ranges] 1661210cf1f9SAdrian Hunter self.value = " OR ".join(ranges) 1662210cf1f9SAdrian Hunter elif self.table_name == "<ranges>": 1663210cf1f9SAdrian Hunter singles = [] 1664210cf1f9SAdrian Hunter ranges = [] 1665210cf1f9SAdrian Hunter for value in [x.strip() for x in input_string.split(",")]: 1666210cf1f9SAdrian Hunter if "-" in value: 1667210cf1f9SAdrian Hunter vrange = value.split("-") 1668210cf1f9SAdrian Hunter if len(vrange) != 2 or not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]): 1669210cf1f9SAdrian Hunter return self.InvalidValue(value) 1670210cf1f9SAdrian Hunter ranges.append(vrange) 1671210cf1f9SAdrian Hunter else: 1672210cf1f9SAdrian Hunter if not self.IsNumber(value): 1673210cf1f9SAdrian Hunter return self.InvalidValue(value) 1674210cf1f9SAdrian Hunter singles.append(value) 1675210cf1f9SAdrian Hunter ranges = [("(" + self.column_name1 + " >= " + r[0] + " AND " + self.column_name1 + " <= " + r[1] + ")") for r in ranges] 1676210cf1f9SAdrian Hunter if len(singles): 1677210cf1f9SAdrian Hunter ranges.append(self.column_name1 + " IN (" + ",".join(singles) + ")") 1678210cf1f9SAdrian Hunter self.value = " OR ".join(ranges) 1679210cf1f9SAdrian Hunter elif self.table_name: 1680210cf1f9SAdrian Hunter all_ids = [] 1681210cf1f9SAdrian Hunter for value in [x.strip() for x in input_string.split(",")]: 1682210cf1f9SAdrian Hunter ids = self.ValueToIds(value) 1683210cf1f9SAdrian Hunter if len(ids): 1684210cf1f9SAdrian Hunter all_ids.extend(ids) 1685210cf1f9SAdrian Hunter else: 1686210cf1f9SAdrian Hunter return self.InvalidValue(value) 1687210cf1f9SAdrian Hunter self.value = self.column_name1 + " IN (" + ",".join(all_ids) + ")" 1688210cf1f9SAdrian Hunter if self.column_name2: 1689210cf1f9SAdrian Hunter self.value = "( " + self.value + " OR " + self.column_name2 + " IN (" + ",".join(all_ids) + ") )" 1690210cf1f9SAdrian Hunter else: 1691210cf1f9SAdrian Hunter self.value = input_string.strip() 1692210cf1f9SAdrian Hunter self.error = "" 1693210cf1f9SAdrian Hunter self.parent.ClearMessage() 1694210cf1f9SAdrian Hunter 1695210cf1f9SAdrian Hunter def IsValid(self): 1696210cf1f9SAdrian Hunter if not self.validated: 1697210cf1f9SAdrian Hunter self.Validate() 1698210cf1f9SAdrian Hunter if len(self.error): 1699210cf1f9SAdrian Hunter self.parent.ShowMessage(self.error) 1700210cf1f9SAdrian Hunter return False 1701210cf1f9SAdrian Hunter return True 1702210cf1f9SAdrian Hunter 1703210cf1f9SAdrian Hunter# Selected branch report creation dialog 1704210cf1f9SAdrian Hunter 1705210cf1f9SAdrian Hunterclass SelectedBranchDialog(QDialog): 1706210cf1f9SAdrian Hunter 1707210cf1f9SAdrian Hunter def __init__(self, glb, parent=None): 1708210cf1f9SAdrian Hunter super(SelectedBranchDialog, self).__init__(parent) 1709210cf1f9SAdrian Hunter 1710210cf1f9SAdrian Hunter self.glb = glb 1711210cf1f9SAdrian Hunter 1712210cf1f9SAdrian Hunter self.name = "" 1713210cf1f9SAdrian Hunter self.where_clause = "" 1714210cf1f9SAdrian Hunter 1715210cf1f9SAdrian Hunter self.setWindowTitle("Selected Branches") 1716210cf1f9SAdrian Hunter self.setMinimumWidth(600) 1717210cf1f9SAdrian Hunter 1718210cf1f9SAdrian Hunter items = ( 1719210cf1f9SAdrian Hunter ("Report name:", "Enter a name to appear in the window title bar", "", "", "", ""), 1720210cf1f9SAdrian Hunter ("Time ranges:", "Enter time ranges", "<timeranges>", "", "samples.id", ""), 1721210cf1f9SAdrian Hunter ("CPUs:", "Enter CPUs or ranges e.g. 0,5-6", "<ranges>", "", "cpu", ""), 1722210cf1f9SAdrian Hunter ("Commands:", "Only branches with these commands will be included", "comms", "comm", "comm_id", ""), 1723210cf1f9SAdrian Hunter ("PIDs:", "Only branches with these process IDs will be included", "threads", "pid", "thread_id", ""), 1724210cf1f9SAdrian Hunter ("TIDs:", "Only branches with these thread IDs will be included", "threads", "tid", "thread_id", ""), 1725210cf1f9SAdrian Hunter ("DSOs:", "Only branches with these DSOs will be included", "dsos", "short_name", "samples.dso_id", "to_dso_id"), 1726210cf1f9SAdrian Hunter ("Symbols:", "Only branches with these symbols will be included", "symbols", "name", "symbol_id", "to_symbol_id"), 1727210cf1f9SAdrian Hunter ("Raw SQL clause: ", "Enter a raw SQL WHERE clause", "", "", "", ""), 1728210cf1f9SAdrian Hunter ) 1729210cf1f9SAdrian Hunter self.data_items = [SQLTableDialogDataItem(glb, *x, parent=self) for x in items] 1730210cf1f9SAdrian Hunter 1731210cf1f9SAdrian Hunter self.grid = QGridLayout() 1732210cf1f9SAdrian Hunter 1733210cf1f9SAdrian Hunter for row in xrange(len(self.data_items)): 1734210cf1f9SAdrian Hunter self.grid.addWidget(QLabel(self.data_items[row].label), row, 0) 1735210cf1f9SAdrian Hunter self.grid.addWidget(self.data_items[row].widget, row, 1) 1736210cf1f9SAdrian Hunter 1737210cf1f9SAdrian Hunter self.status = QLabel() 1738210cf1f9SAdrian Hunter 1739210cf1f9SAdrian Hunter self.ok_button = QPushButton("Ok", self) 1740210cf1f9SAdrian Hunter self.ok_button.setDefault(True) 1741210cf1f9SAdrian Hunter self.ok_button.released.connect(self.Ok) 1742210cf1f9SAdrian Hunter self.ok_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 1743210cf1f9SAdrian Hunter 1744210cf1f9SAdrian Hunter self.cancel_button = QPushButton("Cancel", self) 1745210cf1f9SAdrian Hunter self.cancel_button.released.connect(self.reject) 1746210cf1f9SAdrian Hunter self.cancel_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 1747210cf1f9SAdrian Hunter 1748210cf1f9SAdrian Hunter self.hbox = QHBoxLayout() 1749210cf1f9SAdrian Hunter #self.hbox.addStretch() 1750210cf1f9SAdrian Hunter self.hbox.addWidget(self.status) 1751210cf1f9SAdrian Hunter self.hbox.addWidget(self.ok_button) 1752210cf1f9SAdrian Hunter self.hbox.addWidget(self.cancel_button) 1753210cf1f9SAdrian Hunter 1754210cf1f9SAdrian Hunter self.vbox = QVBoxLayout() 1755210cf1f9SAdrian Hunter self.vbox.addLayout(self.grid) 1756210cf1f9SAdrian Hunter self.vbox.addLayout(self.hbox) 1757210cf1f9SAdrian Hunter 1758210cf1f9SAdrian Hunter self.setLayout(self.vbox); 1759210cf1f9SAdrian Hunter 1760210cf1f9SAdrian Hunter def Ok(self): 1761210cf1f9SAdrian Hunter self.name = self.data_items[0].value 1762210cf1f9SAdrian Hunter if not self.name: 1763210cf1f9SAdrian Hunter self.ShowMessage("Report name is required") 1764210cf1f9SAdrian Hunter return 1765210cf1f9SAdrian Hunter for d in self.data_items: 1766210cf1f9SAdrian Hunter if not d.IsValid(): 1767210cf1f9SAdrian Hunter return 1768210cf1f9SAdrian Hunter for d in self.data_items[1:]: 1769210cf1f9SAdrian Hunter if len(d.value): 1770210cf1f9SAdrian Hunter if len(self.where_clause): 1771210cf1f9SAdrian Hunter self.where_clause += " AND " 1772210cf1f9SAdrian Hunter self.where_clause += d.value 1773210cf1f9SAdrian Hunter if len(self.where_clause): 1774210cf1f9SAdrian Hunter self.where_clause = " AND ( " + self.where_clause + " ) " 1775210cf1f9SAdrian Hunter else: 1776210cf1f9SAdrian Hunter self.ShowMessage("No selection") 1777210cf1f9SAdrian Hunter return 1778210cf1f9SAdrian Hunter self.accept() 1779210cf1f9SAdrian Hunter 1780210cf1f9SAdrian Hunter def ShowMessage(self, msg): 1781210cf1f9SAdrian Hunter self.status.setText("<font color=#FF0000>" + msg) 1782210cf1f9SAdrian Hunter 1783210cf1f9SAdrian Hunter def ClearMessage(self): 1784210cf1f9SAdrian Hunter self.status.setText("") 1785210cf1f9SAdrian Hunter 178676099f98SAdrian Hunter# Event list 178776099f98SAdrian Hunter 178876099f98SAdrian Hunterdef GetEventList(db): 178976099f98SAdrian Hunter events = [] 179076099f98SAdrian Hunter query = QSqlQuery(db) 179176099f98SAdrian Hunter QueryExec(query, "SELECT name FROM selected_events WHERE id > 0 ORDER BY id") 179276099f98SAdrian Hunter while query.next(): 179376099f98SAdrian Hunter events.append(query.value(0)) 179476099f98SAdrian Hunter return events 179576099f98SAdrian Hunter 17968392b74bSAdrian Hunter# SQL data preparation 17978392b74bSAdrian Hunter 17988392b74bSAdrian Hunterdef SQLTableDataPrep(query, count): 17998392b74bSAdrian Hunter data = [] 18008392b74bSAdrian Hunter for i in xrange(count): 18018392b74bSAdrian Hunter data.append(query.value(i)) 18028392b74bSAdrian Hunter return data 18038392b74bSAdrian Hunter 18048392b74bSAdrian Hunter# SQL table data model item 18058392b74bSAdrian Hunter 18068392b74bSAdrian Hunterclass SQLTableItem(): 18078392b74bSAdrian Hunter 18088392b74bSAdrian Hunter def __init__(self, row, data): 18098392b74bSAdrian Hunter self.row = row 18108392b74bSAdrian Hunter self.data = data 18118392b74bSAdrian Hunter 18128392b74bSAdrian Hunter def getData(self, column): 18138392b74bSAdrian Hunter return self.data[column] 18148392b74bSAdrian Hunter 18158392b74bSAdrian Hunter# SQL table data model 18168392b74bSAdrian Hunter 18178392b74bSAdrian Hunterclass SQLTableModel(TableModel): 18188392b74bSAdrian Hunter 18198392b74bSAdrian Hunter progress = Signal(object) 18208392b74bSAdrian Hunter 18218392b74bSAdrian Hunter def __init__(self, glb, sql, column_count, parent=None): 18228392b74bSAdrian Hunter super(SQLTableModel, self).__init__(parent) 18238392b74bSAdrian Hunter self.glb = glb 18248392b74bSAdrian Hunter self.more = True 18258392b74bSAdrian Hunter self.populated = 0 18268392b74bSAdrian Hunter self.fetcher = SQLFetcher(glb, sql, lambda x, y=column_count: SQLTableDataPrep(x, y), self.AddSample) 18278392b74bSAdrian Hunter self.fetcher.done.connect(self.Update) 18288392b74bSAdrian Hunter self.fetcher.Fetch(glb_chunk_sz) 18298392b74bSAdrian Hunter 18308392b74bSAdrian Hunter def DisplayData(self, item, index): 18318392b74bSAdrian Hunter self.FetchIfNeeded(item.row) 18328392b74bSAdrian Hunter return item.getData(index.column()) 18338392b74bSAdrian Hunter 18348392b74bSAdrian Hunter def AddSample(self, data): 18358392b74bSAdrian Hunter child = SQLTableItem(self.populated, data) 18368392b74bSAdrian Hunter self.child_items.append(child) 18378392b74bSAdrian Hunter self.populated += 1 18388392b74bSAdrian Hunter 18398392b74bSAdrian Hunter def Update(self, fetched): 18408392b74bSAdrian Hunter if not fetched: 18418392b74bSAdrian Hunter self.more = False 18428392b74bSAdrian Hunter self.progress.emit(0) 18438392b74bSAdrian Hunter child_count = self.child_count 18448392b74bSAdrian Hunter count = self.populated - child_count 18458392b74bSAdrian Hunter if count > 0: 18468392b74bSAdrian Hunter parent = QModelIndex() 18478392b74bSAdrian Hunter self.beginInsertRows(parent, child_count, child_count + count - 1) 18488392b74bSAdrian Hunter self.insertRows(child_count, count, parent) 18498392b74bSAdrian Hunter self.child_count += count 18508392b74bSAdrian Hunter self.endInsertRows() 18518392b74bSAdrian Hunter self.progress.emit(self.child_count) 18528392b74bSAdrian Hunter 18538392b74bSAdrian Hunter def FetchMoreRecords(self, count): 18548392b74bSAdrian Hunter current = self.child_count 18558392b74bSAdrian Hunter if self.more: 18568392b74bSAdrian Hunter self.fetcher.Fetch(count) 18578392b74bSAdrian Hunter else: 18588392b74bSAdrian Hunter self.progress.emit(0) 18598392b74bSAdrian Hunter return current 18608392b74bSAdrian Hunter 18618392b74bSAdrian Hunter def HasMoreRecords(self): 18628392b74bSAdrian Hunter return self.more 18638392b74bSAdrian Hunter 18648392b74bSAdrian Hunter# SQL automatic table data model 18658392b74bSAdrian Hunter 18668392b74bSAdrian Hunterclass SQLAutoTableModel(SQLTableModel): 18678392b74bSAdrian Hunter 18688392b74bSAdrian Hunter def __init__(self, glb, table_name, parent=None): 18698392b74bSAdrian Hunter sql = "SELECT * FROM " + table_name + " WHERE id > $$last_id$$ ORDER BY id LIMIT " + str(glb_chunk_sz) 18708392b74bSAdrian Hunter if table_name == "comm_threads_view": 18718392b74bSAdrian Hunter # For now, comm_threads_view has no id column 18728392b74bSAdrian Hunter sql = "SELECT * FROM " + table_name + " WHERE comm_id > $$last_id$$ ORDER BY comm_id LIMIT " + str(glb_chunk_sz) 18738392b74bSAdrian Hunter self.column_headers = [] 18748392b74bSAdrian Hunter query = QSqlQuery(glb.db) 18758392b74bSAdrian Hunter if glb.dbref.is_sqlite3: 18768392b74bSAdrian Hunter QueryExec(query, "PRAGMA table_info(" + table_name + ")") 18778392b74bSAdrian Hunter while query.next(): 18788392b74bSAdrian Hunter self.column_headers.append(query.value(1)) 18798392b74bSAdrian Hunter if table_name == "sqlite_master": 18808392b74bSAdrian Hunter sql = "SELECT * FROM " + table_name 18818392b74bSAdrian Hunter else: 18828392b74bSAdrian Hunter if table_name[:19] == "information_schema.": 18838392b74bSAdrian Hunter sql = "SELECT * FROM " + table_name 18848392b74bSAdrian Hunter select_table_name = table_name[19:] 18858392b74bSAdrian Hunter schema = "information_schema" 18868392b74bSAdrian Hunter else: 18878392b74bSAdrian Hunter select_table_name = table_name 18888392b74bSAdrian Hunter schema = "public" 18898392b74bSAdrian Hunter QueryExec(query, "SELECT column_name FROM information_schema.columns WHERE table_schema = '" + schema + "' and table_name = '" + select_table_name + "'") 18908392b74bSAdrian Hunter while query.next(): 18918392b74bSAdrian Hunter self.column_headers.append(query.value(0)) 18928392b74bSAdrian Hunter super(SQLAutoTableModel, self).__init__(glb, sql, len(self.column_headers), parent) 18938392b74bSAdrian Hunter 18948392b74bSAdrian Hunter def columnCount(self, parent=None): 18958392b74bSAdrian Hunter return len(self.column_headers) 18968392b74bSAdrian Hunter 18978392b74bSAdrian Hunter def columnHeader(self, column): 18988392b74bSAdrian Hunter return self.column_headers[column] 18998392b74bSAdrian Hunter 19008392b74bSAdrian Hunter# Base class for custom ResizeColumnsToContents 19018392b74bSAdrian Hunter 19028392b74bSAdrian Hunterclass ResizeColumnsToContentsBase(QObject): 19038392b74bSAdrian Hunter 19048392b74bSAdrian Hunter def __init__(self, parent=None): 19058392b74bSAdrian Hunter super(ResizeColumnsToContentsBase, self).__init__(parent) 19068392b74bSAdrian Hunter 19078392b74bSAdrian Hunter def ResizeColumnToContents(self, column, n): 19088392b74bSAdrian Hunter # Using the view's resizeColumnToContents() here is extrememly slow 19098392b74bSAdrian Hunter # so implement a crude alternative 19108392b74bSAdrian Hunter font = self.view.font() 19118392b74bSAdrian Hunter metrics = QFontMetrics(font) 19128392b74bSAdrian Hunter max = 0 19138392b74bSAdrian Hunter for row in xrange(n): 19148392b74bSAdrian Hunter val = self.data_model.child_items[row].data[column] 19158392b74bSAdrian Hunter len = metrics.width(str(val) + "MM") 19168392b74bSAdrian Hunter max = len if len > max else max 19178392b74bSAdrian Hunter val = self.data_model.columnHeader(column) 19188392b74bSAdrian Hunter len = metrics.width(str(val) + "MM") 19198392b74bSAdrian Hunter max = len if len > max else max 19208392b74bSAdrian Hunter self.view.setColumnWidth(column, max) 19218392b74bSAdrian Hunter 19228392b74bSAdrian Hunter def ResizeColumnsToContents(self): 19238392b74bSAdrian Hunter n = min(self.data_model.child_count, 100) 19248392b74bSAdrian Hunter if n < 1: 19258392b74bSAdrian Hunter # No data yet, so connect a signal to notify when there is 19268392b74bSAdrian Hunter self.data_model.rowsInserted.connect(self.UpdateColumnWidths) 19278392b74bSAdrian Hunter return 19288392b74bSAdrian Hunter columns = self.data_model.columnCount() 19298392b74bSAdrian Hunter for i in xrange(columns): 19308392b74bSAdrian Hunter self.ResizeColumnToContents(i, n) 19318392b74bSAdrian Hunter 19328392b74bSAdrian Hunter def UpdateColumnWidths(self, *x): 19338392b74bSAdrian Hunter # This only needs to be done once, so disconnect the signal now 19348392b74bSAdrian Hunter self.data_model.rowsInserted.disconnect(self.UpdateColumnWidths) 19358392b74bSAdrian Hunter self.ResizeColumnsToContents() 19368392b74bSAdrian Hunter 19378392b74bSAdrian Hunter# Table window 19388392b74bSAdrian Hunter 19398392b74bSAdrian Hunterclass TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase): 19408392b74bSAdrian Hunter 19418392b74bSAdrian Hunter def __init__(self, glb, table_name, parent=None): 19428392b74bSAdrian Hunter super(TableWindow, self).__init__(parent) 19438392b74bSAdrian Hunter 19448392b74bSAdrian Hunter self.data_model = LookupCreateModel(table_name + " Table", lambda: SQLAutoTableModel(glb, table_name)) 19458392b74bSAdrian Hunter 19468392b74bSAdrian Hunter self.model = QSortFilterProxyModel() 19478392b74bSAdrian Hunter self.model.setSourceModel(self.data_model) 19488392b74bSAdrian Hunter 19498392b74bSAdrian Hunter self.view = QTableView() 19508392b74bSAdrian Hunter self.view.setModel(self.model) 19518392b74bSAdrian Hunter self.view.setEditTriggers(QAbstractItemView.NoEditTriggers) 19528392b74bSAdrian Hunter self.view.verticalHeader().setVisible(False) 19538392b74bSAdrian Hunter self.view.sortByColumn(-1, Qt.AscendingOrder) 19548392b74bSAdrian Hunter self.view.setSortingEnabled(True) 19558392b74bSAdrian Hunter 19568392b74bSAdrian Hunter self.ResizeColumnsToContents() 19578392b74bSAdrian Hunter 19588392b74bSAdrian Hunter self.find_bar = FindBar(self, self, True) 19598392b74bSAdrian Hunter 19608392b74bSAdrian Hunter self.finder = ChildDataItemFinder(self.data_model) 19618392b74bSAdrian Hunter 19628392b74bSAdrian Hunter self.fetch_bar = FetchMoreRecordsBar(self.data_model, self) 19638392b74bSAdrian Hunter 19648392b74bSAdrian Hunter self.vbox = VBox(self.view, self.find_bar.Widget(), self.fetch_bar.Widget()) 19658392b74bSAdrian Hunter 19668392b74bSAdrian Hunter self.setWidget(self.vbox.Widget()) 19678392b74bSAdrian Hunter 19688392b74bSAdrian Hunter AddSubWindow(glb.mainwindow.mdi_area, self, table_name + " Table") 19698392b74bSAdrian Hunter 19708392b74bSAdrian Hunter def Find(self, value, direction, pattern, context): 19718392b74bSAdrian Hunter self.view.setFocus() 19728392b74bSAdrian Hunter self.find_bar.Busy() 19738392b74bSAdrian Hunter self.finder.Find(value, direction, pattern, context, self.FindDone) 19748392b74bSAdrian Hunter 19758392b74bSAdrian Hunter def FindDone(self, row): 19768392b74bSAdrian Hunter self.find_bar.Idle() 19778392b74bSAdrian Hunter if row >= 0: 19788392b74bSAdrian Hunter self.view.setCurrentIndex(self.model.index(row, 0, QModelIndex())) 19798392b74bSAdrian Hunter else: 19808392b74bSAdrian Hunter self.find_bar.NotFound() 19818392b74bSAdrian Hunter 19828392b74bSAdrian Hunter# Table list 19838392b74bSAdrian Hunter 19848392b74bSAdrian Hunterdef GetTableList(glb): 19858392b74bSAdrian Hunter tables = [] 19868392b74bSAdrian Hunter query = QSqlQuery(glb.db) 19878392b74bSAdrian Hunter if glb.dbref.is_sqlite3: 19888392b74bSAdrian Hunter QueryExec(query, "SELECT name FROM sqlite_master WHERE type IN ( 'table' , 'view' ) ORDER BY name") 19898392b74bSAdrian Hunter else: 19908392b74bSAdrian Hunter QueryExec(query, "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_type IN ( 'BASE TABLE' , 'VIEW' ) ORDER BY table_name") 19918392b74bSAdrian Hunter while query.next(): 19928392b74bSAdrian Hunter tables.append(query.value(0)) 19938392b74bSAdrian Hunter if glb.dbref.is_sqlite3: 19948392b74bSAdrian Hunter tables.append("sqlite_master") 19958392b74bSAdrian Hunter else: 19968392b74bSAdrian Hunter tables.append("information_schema.tables") 19978392b74bSAdrian Hunter tables.append("information_schema.views") 19988392b74bSAdrian Hunter tables.append("information_schema.columns") 19998392b74bSAdrian Hunter return tables 20008392b74bSAdrian Hunter 20011beb5c7bSAdrian Hunter# Action Definition 20021beb5c7bSAdrian Hunter 20031beb5c7bSAdrian Hunterdef CreateAction(label, tip, callback, parent=None, shortcut=None): 20041beb5c7bSAdrian Hunter action = QAction(label, parent) 20051beb5c7bSAdrian Hunter if shortcut != None: 20061beb5c7bSAdrian Hunter action.setShortcuts(shortcut) 20071beb5c7bSAdrian Hunter action.setStatusTip(tip) 20081beb5c7bSAdrian Hunter action.triggered.connect(callback) 20091beb5c7bSAdrian Hunter return action 20101beb5c7bSAdrian Hunter 20111beb5c7bSAdrian Hunter# Typical application actions 20121beb5c7bSAdrian Hunter 20131beb5c7bSAdrian Hunterdef CreateExitAction(app, parent=None): 20141beb5c7bSAdrian Hunter return CreateAction("&Quit", "Exit the application", app.closeAllWindows, parent, QKeySequence.Quit) 20151beb5c7bSAdrian Hunter 20161beb5c7bSAdrian Hunter# Typical MDI actions 20171beb5c7bSAdrian Hunter 20181beb5c7bSAdrian Hunterdef CreateCloseActiveWindowAction(mdi_area): 20191beb5c7bSAdrian Hunter return CreateAction("Cl&ose", "Close the active window", mdi_area.closeActiveSubWindow, mdi_area) 20201beb5c7bSAdrian Hunter 20211beb5c7bSAdrian Hunterdef CreateCloseAllWindowsAction(mdi_area): 20221beb5c7bSAdrian Hunter return CreateAction("Close &All", "Close all the windows", mdi_area.closeAllSubWindows, mdi_area) 20231beb5c7bSAdrian Hunter 20241beb5c7bSAdrian Hunterdef CreateTileWindowsAction(mdi_area): 20251beb5c7bSAdrian Hunter return CreateAction("&Tile", "Tile the windows", mdi_area.tileSubWindows, mdi_area) 20261beb5c7bSAdrian Hunter 20271beb5c7bSAdrian Hunterdef CreateCascadeWindowsAction(mdi_area): 20281beb5c7bSAdrian Hunter return CreateAction("&Cascade", "Cascade the windows", mdi_area.cascadeSubWindows, mdi_area) 20291beb5c7bSAdrian Hunter 20301beb5c7bSAdrian Hunterdef CreateNextWindowAction(mdi_area): 20311beb5c7bSAdrian Hunter return CreateAction("Ne&xt", "Move the focus to the next window", mdi_area.activateNextSubWindow, mdi_area, QKeySequence.NextChild) 20321beb5c7bSAdrian Hunter 20331beb5c7bSAdrian Hunterdef CreatePreviousWindowAction(mdi_area): 20341beb5c7bSAdrian Hunter return CreateAction("Pre&vious", "Move the focus to the previous window", mdi_area.activatePreviousSubWindow, mdi_area, QKeySequence.PreviousChild) 20351beb5c7bSAdrian Hunter 20361beb5c7bSAdrian Hunter# Typical MDI window menu 20371beb5c7bSAdrian Hunter 20381beb5c7bSAdrian Hunterclass WindowMenu(): 20391beb5c7bSAdrian Hunter 20401beb5c7bSAdrian Hunter def __init__(self, mdi_area, menu): 20411beb5c7bSAdrian Hunter self.mdi_area = mdi_area 20421beb5c7bSAdrian Hunter self.window_menu = menu.addMenu("&Windows") 20431beb5c7bSAdrian Hunter self.close_active_window = CreateCloseActiveWindowAction(mdi_area) 20441beb5c7bSAdrian Hunter self.close_all_windows = CreateCloseAllWindowsAction(mdi_area) 20451beb5c7bSAdrian Hunter self.tile_windows = CreateTileWindowsAction(mdi_area) 20461beb5c7bSAdrian Hunter self.cascade_windows = CreateCascadeWindowsAction(mdi_area) 20471beb5c7bSAdrian Hunter self.next_window = CreateNextWindowAction(mdi_area) 20481beb5c7bSAdrian Hunter self.previous_window = CreatePreviousWindowAction(mdi_area) 20491beb5c7bSAdrian Hunter self.window_menu.aboutToShow.connect(self.Update) 20501beb5c7bSAdrian Hunter 20511beb5c7bSAdrian Hunter def Update(self): 20521beb5c7bSAdrian Hunter self.window_menu.clear() 20531beb5c7bSAdrian Hunter sub_window_count = len(self.mdi_area.subWindowList()) 20541beb5c7bSAdrian Hunter have_sub_windows = sub_window_count != 0 20551beb5c7bSAdrian Hunter self.close_active_window.setEnabled(have_sub_windows) 20561beb5c7bSAdrian Hunter self.close_all_windows.setEnabled(have_sub_windows) 20571beb5c7bSAdrian Hunter self.tile_windows.setEnabled(have_sub_windows) 20581beb5c7bSAdrian Hunter self.cascade_windows.setEnabled(have_sub_windows) 20591beb5c7bSAdrian Hunter self.next_window.setEnabled(have_sub_windows) 20601beb5c7bSAdrian Hunter self.previous_window.setEnabled(have_sub_windows) 20611beb5c7bSAdrian Hunter self.window_menu.addAction(self.close_active_window) 20621beb5c7bSAdrian Hunter self.window_menu.addAction(self.close_all_windows) 20631beb5c7bSAdrian Hunter self.window_menu.addSeparator() 20641beb5c7bSAdrian Hunter self.window_menu.addAction(self.tile_windows) 20651beb5c7bSAdrian Hunter self.window_menu.addAction(self.cascade_windows) 20661beb5c7bSAdrian Hunter self.window_menu.addSeparator() 20671beb5c7bSAdrian Hunter self.window_menu.addAction(self.next_window) 20681beb5c7bSAdrian Hunter self.window_menu.addAction(self.previous_window) 20691beb5c7bSAdrian Hunter if sub_window_count == 0: 20701beb5c7bSAdrian Hunter return 20711beb5c7bSAdrian Hunter self.window_menu.addSeparator() 20721beb5c7bSAdrian Hunter nr = 1 20731beb5c7bSAdrian Hunter for sub_window in self.mdi_area.subWindowList(): 20741beb5c7bSAdrian Hunter label = str(nr) + " " + sub_window.name 20751beb5c7bSAdrian Hunter if nr < 10: 20761beb5c7bSAdrian Hunter label = "&" + label 20771beb5c7bSAdrian Hunter action = self.window_menu.addAction(label) 20781beb5c7bSAdrian Hunter action.setCheckable(True) 20791beb5c7bSAdrian Hunter action.setChecked(sub_window == self.mdi_area.activeSubWindow()) 20801beb5c7bSAdrian Hunter action.triggered.connect(lambda x=nr: self.setActiveSubWindow(x)) 20811beb5c7bSAdrian Hunter self.window_menu.addAction(action) 20821beb5c7bSAdrian Hunter nr += 1 20831beb5c7bSAdrian Hunter 20841beb5c7bSAdrian Hunter def setActiveSubWindow(self, nr): 20851beb5c7bSAdrian Hunter self.mdi_area.setActiveSubWindow(self.mdi_area.subWindowList()[nr - 1]) 20861beb5c7bSAdrian Hunter 2087*65b24292SAdrian Hunter# Help text 2088*65b24292SAdrian Hunter 2089*65b24292SAdrian Hunterglb_help_text = """ 2090*65b24292SAdrian Hunter<h1>Contents</h1> 2091*65b24292SAdrian Hunter<style> 2092*65b24292SAdrian Hunterp.c1 { 2093*65b24292SAdrian Hunter text-indent: 40px; 2094*65b24292SAdrian Hunter} 2095*65b24292SAdrian Hunterp.c2 { 2096*65b24292SAdrian Hunter text-indent: 80px; 2097*65b24292SAdrian Hunter} 2098*65b24292SAdrian Hunter} 2099*65b24292SAdrian Hunter</style> 2100*65b24292SAdrian Hunter<p class=c1><a href=#reports>1. Reports</a></p> 2101*65b24292SAdrian Hunter<p class=c2><a href=#callgraph>1.1 Context-Sensitive Call Graph</a></p> 2102*65b24292SAdrian Hunter<p class=c2><a href=#allbranches>1.2 All branches</a></p> 2103*65b24292SAdrian Hunter<p class=c2><a href=#selectedbranches>1.3 Selected branches</a></p> 2104*65b24292SAdrian Hunter<p class=c1><a href=#tables>2. Tables</a></p> 2105*65b24292SAdrian Hunter<h1 id=reports>1. Reports</h1> 2106*65b24292SAdrian Hunter<h2 id=callgraph>1.1 Context-Sensitive Call Graph</h2> 2107*65b24292SAdrian HunterThe result is a GUI window with a tree representing a context-sensitive 2108*65b24292SAdrian Huntercall-graph. Expanding a couple of levels of the tree and adjusting column 2109*65b24292SAdrian Hunterwidths to suit will display something like: 2110*65b24292SAdrian Hunter<pre> 2111*65b24292SAdrian Hunter Call Graph: pt_example 2112*65b24292SAdrian HunterCall Path Object Count Time(ns) Time(%) Branch Count Branch Count(%) 2113*65b24292SAdrian Hunterv- ls 2114*65b24292SAdrian Hunter v- 2638:2638 2115*65b24292SAdrian Hunter v- _start ld-2.19.so 1 10074071 100.0 211135 100.0 2116*65b24292SAdrian Hunter |- unknown unknown 1 13198 0.1 1 0.0 2117*65b24292SAdrian Hunter >- _dl_start ld-2.19.so 1 1400980 13.9 19637 9.3 2118*65b24292SAdrian Hunter >- _d_linit_internal ld-2.19.so 1 448152 4.4 11094 5.3 2119*65b24292SAdrian Hunter v-__libc_start_main@plt ls 1 8211741 81.5 180397 85.4 2120*65b24292SAdrian Hunter >- _dl_fixup ld-2.19.so 1 7607 0.1 108 0.1 2121*65b24292SAdrian Hunter >- __cxa_atexit libc-2.19.so 1 11737 0.1 10 0.0 2122*65b24292SAdrian Hunter >- __libc_csu_init ls 1 10354 0.1 10 0.0 2123*65b24292SAdrian Hunter |- _setjmp libc-2.19.so 1 0 0.0 4 0.0 2124*65b24292SAdrian Hunter v- main ls 1 8182043 99.6 180254 99.9 2125*65b24292SAdrian Hunter</pre> 2126*65b24292SAdrian Hunter<h3>Points to note:</h3> 2127*65b24292SAdrian Hunter<ul> 2128*65b24292SAdrian Hunter<li>The top level is a command name (comm)</li> 2129*65b24292SAdrian Hunter<li>The next level is a thread (pid:tid)</li> 2130*65b24292SAdrian Hunter<li>Subsequent levels are functions</li> 2131*65b24292SAdrian Hunter<li>'Count' is the number of calls</li> 2132*65b24292SAdrian Hunter<li>'Time' is the elapsed time until the function returns</li> 2133*65b24292SAdrian Hunter<li>Percentages are relative to the level above</li> 2134*65b24292SAdrian Hunter<li>'Branch Count' is the total number of branches for that function and all functions that it calls 2135*65b24292SAdrian Hunter</ul> 2136*65b24292SAdrian Hunter<h3>Find</h3> 2137*65b24292SAdrian HunterCtrl-F displays a Find bar which finds function names by either an exact match or a pattern match. 2138*65b24292SAdrian HunterThe pattern matching symbols are ? for any character and * for zero or more characters. 2139*65b24292SAdrian Hunter<h2 id=allbranches>1.2 All branches</h2> 2140*65b24292SAdrian HunterThe All branches report displays all branches in chronological order. 2141*65b24292SAdrian HunterNot all data is fetched immediately. More records can be fetched using the Fetch bar provided. 2142*65b24292SAdrian Hunter<h3>Disassembly</h3> 2143*65b24292SAdrian HunterOpen a branch to display disassembly. This only works if: 2144*65b24292SAdrian Hunter<ol> 2145*65b24292SAdrian Hunter<li>The disassembler is available. Currently, only Intel XED is supported - see <a href=#xed>Intel XED Setup</a></li> 2146*65b24292SAdrian Hunter<li>The object code is available. Currently, only the perf build ID cache is searched for object code. 2147*65b24292SAdrian HunterThe default directory ~/.debug can be overridden by setting environment variable PERF_BUILDID_DIR. 2148*65b24292SAdrian HunterOne exception is kcore where the DSO long name is used (refer dsos_view on the Tables menu), 2149*65b24292SAdrian Hunteror alternatively, set environment variable PERF_KCORE to the kcore file name.</li> 2150*65b24292SAdrian Hunter</ol> 2151*65b24292SAdrian Hunter<h4 id=xed>Intel XED Setup</h4> 2152*65b24292SAdrian HunterTo use Intel XED, libxed.so must be present. To build and install libxed.so: 2153*65b24292SAdrian Hunter<pre> 2154*65b24292SAdrian Huntergit clone https://github.com/intelxed/mbuild.git mbuild 2155*65b24292SAdrian Huntergit clone https://github.com/intelxed/xed 2156*65b24292SAdrian Huntercd xed 2157*65b24292SAdrian Hunter./mfile.py --share 2158*65b24292SAdrian Huntersudo ./mfile.py --prefix=/usr/local install 2159*65b24292SAdrian Huntersudo ldconfig 2160*65b24292SAdrian Hunter</pre> 2161*65b24292SAdrian Hunter<h3>Find</h3> 2162*65b24292SAdrian HunterCtrl-F displays a Find bar which finds substrings by either an exact match or a regular expression match. 2163*65b24292SAdrian HunterRefer to Python documentation for the regular expression syntax. 2164*65b24292SAdrian HunterAll columns are searched, but only currently fetched rows are searched. 2165*65b24292SAdrian Hunter<h2 id=selectedbranches>1.3 Selected branches</h2> 2166*65b24292SAdrian HunterThis is the same as the <a href=#allbranches>All branches</a> report but with the data reduced 2167*65b24292SAdrian Hunterby various selection criteria. A dialog box displays available criteria which are AND'ed together. 2168*65b24292SAdrian Hunter<h3>1.3.1 Time ranges</h3> 2169*65b24292SAdrian HunterThe time ranges hint text shows the total time range. Relative time ranges can also be entered in 2170*65b24292SAdrian Hunterms, us or ns. Also, negative values are relative to the end of trace. Examples: 2171*65b24292SAdrian Hunter<pre> 2172*65b24292SAdrian Hunter 81073085947329-81073085958238 From 81073085947329 to 81073085958238 2173*65b24292SAdrian Hunter 100us-200us From 100us to 200us 2174*65b24292SAdrian Hunter 10ms- From 10ms to the end 2175*65b24292SAdrian Hunter -100ns The first 100ns 2176*65b24292SAdrian Hunter -10ms- The last 10ms 2177*65b24292SAdrian Hunter</pre> 2178*65b24292SAdrian HunterN.B. Due to the granularity of timestamps, there could be no branches in any given time range. 2179*65b24292SAdrian Hunter<h1 id=tables>2. Tables</h1> 2180*65b24292SAdrian HunterThe Tables menu shows all tables and views in the database. Most tables have an associated view 2181*65b24292SAdrian Hunterwhich displays the information in a more friendly way. Not all data for large tables is fetched 2182*65b24292SAdrian Hunterimmediately. More records can be fetched using the Fetch bar provided. Columns can be sorted, 2183*65b24292SAdrian Hunterbut that can be slow for large tables. 2184*65b24292SAdrian Hunter<p>There are also tables of database meta-information. 2185*65b24292SAdrian HunterFor SQLite3 databases, the sqlite_master table is included. 2186*65b24292SAdrian HunterFor PostgreSQL databases, information_schema.tables/views/columns are included. 2187*65b24292SAdrian Hunter<h3>Find</h3> 2188*65b24292SAdrian HunterCtrl-F displays a Find bar which finds substrings by either an exact match or a regular expression match. 2189*65b24292SAdrian HunterRefer to Python documentation for the regular expression syntax. 2190*65b24292SAdrian HunterAll columns are searched, but only currently fetched rows are searched. 2191*65b24292SAdrian Hunter""" 2192*65b24292SAdrian Hunter 2193*65b24292SAdrian Hunter# Help window 2194*65b24292SAdrian Hunter 2195*65b24292SAdrian Hunterclass HelpWindow(QMdiSubWindow): 2196*65b24292SAdrian Hunter 2197*65b24292SAdrian Hunter def __init__(self, glb, parent=None): 2198*65b24292SAdrian Hunter super(HelpWindow, self).__init__(parent) 2199*65b24292SAdrian Hunter 2200*65b24292SAdrian Hunter self.text = QTextBrowser() 2201*65b24292SAdrian Hunter self.text.setHtml(glb_help_text) 2202*65b24292SAdrian Hunter self.text.setReadOnly(True) 2203*65b24292SAdrian Hunter self.text.setOpenExternalLinks(True) 2204*65b24292SAdrian Hunter 2205*65b24292SAdrian Hunter self.setWidget(self.text) 2206*65b24292SAdrian Hunter 2207*65b24292SAdrian Hunter AddSubWindow(glb.mainwindow.mdi_area, self, "Exported SQL Viewer Help") 2208*65b24292SAdrian Hunter 2209*65b24292SAdrian Hunter# Main window that only displays the help text 2210*65b24292SAdrian Hunter 2211*65b24292SAdrian Hunterclass HelpOnlyWindow(QMainWindow): 2212*65b24292SAdrian Hunter 2213*65b24292SAdrian Hunter def __init__(self, parent=None): 2214*65b24292SAdrian Hunter super(HelpOnlyWindow, self).__init__(parent) 2215*65b24292SAdrian Hunter 2216*65b24292SAdrian Hunter self.setMinimumSize(200, 100) 2217*65b24292SAdrian Hunter self.resize(800, 600) 2218*65b24292SAdrian Hunter self.setWindowTitle("Exported SQL Viewer Help") 2219*65b24292SAdrian Hunter self.setWindowIcon(self.style().standardIcon(QStyle.SP_MessageBoxInformation)) 2220*65b24292SAdrian Hunter 2221*65b24292SAdrian Hunter self.text = QTextBrowser() 2222*65b24292SAdrian Hunter self.text.setHtml(glb_help_text) 2223*65b24292SAdrian Hunter self.text.setReadOnly(True) 2224*65b24292SAdrian Hunter self.text.setOpenExternalLinks(True) 2225*65b24292SAdrian Hunter 2226*65b24292SAdrian Hunter self.setCentralWidget(self.text) 2227*65b24292SAdrian Hunter 222882f68e28SAdrian Hunter# Font resize 222982f68e28SAdrian Hunter 223082f68e28SAdrian Hunterdef ResizeFont(widget, diff): 223182f68e28SAdrian Hunter font = widget.font() 223282f68e28SAdrian Hunter sz = font.pointSize() 223382f68e28SAdrian Hunter font.setPointSize(sz + diff) 223482f68e28SAdrian Hunter widget.setFont(font) 223582f68e28SAdrian Hunter 223682f68e28SAdrian Hunterdef ShrinkFont(widget): 223782f68e28SAdrian Hunter ResizeFont(widget, -1) 223882f68e28SAdrian Hunter 223982f68e28SAdrian Hunterdef EnlargeFont(widget): 224082f68e28SAdrian Hunter ResizeFont(widget, 1) 224182f68e28SAdrian Hunter 22421beb5c7bSAdrian Hunter# Unique name for sub-windows 22431beb5c7bSAdrian Hunter 22441beb5c7bSAdrian Hunterdef NumberedWindowName(name, nr): 22451beb5c7bSAdrian Hunter if nr > 1: 22461beb5c7bSAdrian Hunter name += " <" + str(nr) + ">" 22471beb5c7bSAdrian Hunter return name 22481beb5c7bSAdrian Hunter 22491beb5c7bSAdrian Hunterdef UniqueSubWindowName(mdi_area, name): 22501beb5c7bSAdrian Hunter nr = 1 22511beb5c7bSAdrian Hunter while True: 22521beb5c7bSAdrian Hunter unique_name = NumberedWindowName(name, nr) 22531beb5c7bSAdrian Hunter ok = True 22541beb5c7bSAdrian Hunter for sub_window in mdi_area.subWindowList(): 22551beb5c7bSAdrian Hunter if sub_window.name == unique_name: 22561beb5c7bSAdrian Hunter ok = False 22571beb5c7bSAdrian Hunter break 22581beb5c7bSAdrian Hunter if ok: 22591beb5c7bSAdrian Hunter return unique_name 22601beb5c7bSAdrian Hunter nr += 1 22611beb5c7bSAdrian Hunter 22621beb5c7bSAdrian Hunter# Add a sub-window 22631beb5c7bSAdrian Hunter 22641beb5c7bSAdrian Hunterdef AddSubWindow(mdi_area, sub_window, name): 22651beb5c7bSAdrian Hunter unique_name = UniqueSubWindowName(mdi_area, name) 22661beb5c7bSAdrian Hunter sub_window.setMinimumSize(200, 100) 22671beb5c7bSAdrian Hunter sub_window.resize(800, 600) 22681beb5c7bSAdrian Hunter sub_window.setWindowTitle(unique_name) 22691beb5c7bSAdrian Hunter sub_window.setAttribute(Qt.WA_DeleteOnClose) 22701beb5c7bSAdrian Hunter sub_window.setWindowIcon(sub_window.style().standardIcon(QStyle.SP_FileIcon)) 22711beb5c7bSAdrian Hunter sub_window.name = unique_name 22721beb5c7bSAdrian Hunter mdi_area.addSubWindow(sub_window) 22731beb5c7bSAdrian Hunter sub_window.show() 22741beb5c7bSAdrian Hunter 2275031c2a00SAdrian Hunter# Main window 2276031c2a00SAdrian Hunter 2277031c2a00SAdrian Hunterclass MainWindow(QMainWindow): 2278031c2a00SAdrian Hunter 2279031c2a00SAdrian Hunter def __init__(self, glb, parent=None): 2280031c2a00SAdrian Hunter super(MainWindow, self).__init__(parent) 2281031c2a00SAdrian Hunter 2282031c2a00SAdrian Hunter self.glb = glb 2283031c2a00SAdrian Hunter 22841beb5c7bSAdrian Hunter self.setWindowTitle("Exported SQL Viewer: " + glb.dbname) 2285031c2a00SAdrian Hunter self.setWindowIcon(self.style().standardIcon(QStyle.SP_ComputerIcon)) 2286031c2a00SAdrian Hunter self.setMinimumSize(200, 100) 2287031c2a00SAdrian Hunter 22881beb5c7bSAdrian Hunter self.mdi_area = QMdiArea() 22891beb5c7bSAdrian Hunter self.mdi_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) 22901beb5c7bSAdrian Hunter self.mdi_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) 2291031c2a00SAdrian Hunter 22921beb5c7bSAdrian Hunter self.setCentralWidget(self.mdi_area) 2293031c2a00SAdrian Hunter 22941beb5c7bSAdrian Hunter menu = self.menuBar() 2295031c2a00SAdrian Hunter 22961beb5c7bSAdrian Hunter file_menu = menu.addMenu("&File") 22971beb5c7bSAdrian Hunter file_menu.addAction(CreateExitAction(glb.app, self)) 22981beb5c7bSAdrian Hunter 2299ebd70c7dSAdrian Hunter edit_menu = menu.addMenu("&Edit") 2300ebd70c7dSAdrian Hunter edit_menu.addAction(CreateAction("&Find...", "Find items", self.Find, self, QKeySequence.Find)) 23018392b74bSAdrian Hunter edit_menu.addAction(CreateAction("Fetch &more records...", "Fetch more records", self.FetchMoreRecords, self, [QKeySequence(Qt.Key_F8)])) 230282f68e28SAdrian Hunter edit_menu.addAction(CreateAction("&Shrink Font", "Make text smaller", self.ShrinkFont, self, [QKeySequence("Ctrl+-")])) 230382f68e28SAdrian Hunter edit_menu.addAction(CreateAction("&Enlarge Font", "Make text bigger", self.EnlargeFont, self, [QKeySequence("Ctrl++")])) 2304ebd70c7dSAdrian Hunter 23051beb5c7bSAdrian Hunter reports_menu = menu.addMenu("&Reports") 23061beb5c7bSAdrian Hunter reports_menu.addAction(CreateAction("Context-Sensitive Call &Graph", "Create a new window containing a context-sensitive call graph", self.NewCallGraph, self)) 23071beb5c7bSAdrian Hunter 230876099f98SAdrian Hunter self.EventMenu(GetEventList(glb.db), reports_menu) 230976099f98SAdrian Hunter 23108392b74bSAdrian Hunter self.TableMenu(GetTableList(glb), menu) 23118392b74bSAdrian Hunter 23121beb5c7bSAdrian Hunter self.window_menu = WindowMenu(self.mdi_area, menu) 23131beb5c7bSAdrian Hunter 2314*65b24292SAdrian Hunter help_menu = menu.addMenu("&Help") 2315*65b24292SAdrian Hunter help_menu.addAction(CreateAction("&Exported SQL Viewer Help", "Helpful information", self.Help, self, QKeySequence.HelpContents)) 2316*65b24292SAdrian Hunter 2317ebd70c7dSAdrian Hunter def Find(self): 2318ebd70c7dSAdrian Hunter win = self.mdi_area.activeSubWindow() 2319ebd70c7dSAdrian Hunter if win: 2320ebd70c7dSAdrian Hunter try: 2321ebd70c7dSAdrian Hunter win.find_bar.Activate() 2322ebd70c7dSAdrian Hunter except: 2323ebd70c7dSAdrian Hunter pass 2324ebd70c7dSAdrian Hunter 23258392b74bSAdrian Hunter def FetchMoreRecords(self): 23268392b74bSAdrian Hunter win = self.mdi_area.activeSubWindow() 23278392b74bSAdrian Hunter if win: 23288392b74bSAdrian Hunter try: 23298392b74bSAdrian Hunter win.fetch_bar.Activate() 23308392b74bSAdrian Hunter except: 23318392b74bSAdrian Hunter pass 23328392b74bSAdrian Hunter 233382f68e28SAdrian Hunter def ShrinkFont(self): 233482f68e28SAdrian Hunter win = self.mdi_area.activeSubWindow() 233582f68e28SAdrian Hunter ShrinkFont(win.view) 233682f68e28SAdrian Hunter 233782f68e28SAdrian Hunter def EnlargeFont(self): 233882f68e28SAdrian Hunter win = self.mdi_area.activeSubWindow() 233982f68e28SAdrian Hunter EnlargeFont(win.view) 234082f68e28SAdrian Hunter 234176099f98SAdrian Hunter def EventMenu(self, events, reports_menu): 234276099f98SAdrian Hunter branches_events = 0 234376099f98SAdrian Hunter for event in events: 234476099f98SAdrian Hunter event = event.split(":")[0] 234576099f98SAdrian Hunter if event == "branches": 234676099f98SAdrian Hunter branches_events += 1 234776099f98SAdrian Hunter dbid = 0 234876099f98SAdrian Hunter for event in events: 234976099f98SAdrian Hunter dbid += 1 235076099f98SAdrian Hunter event = event.split(":")[0] 235176099f98SAdrian Hunter if event == "branches": 235276099f98SAdrian Hunter label = "All branches" if branches_events == 1 else "All branches " + "(id=" + dbid + ")" 235376099f98SAdrian Hunter reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewBranchView(x), self)) 2354210cf1f9SAdrian Hunter label = "Selected branches" if branches_events == 1 else "Selected branches " + "(id=" + dbid + ")" 2355210cf1f9SAdrian Hunter reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewSelectedBranchView(x), self)) 235676099f98SAdrian Hunter 23578392b74bSAdrian Hunter def TableMenu(self, tables, menu): 23588392b74bSAdrian Hunter table_menu = menu.addMenu("&Tables") 23598392b74bSAdrian Hunter for table in tables: 23608392b74bSAdrian Hunter table_menu.addAction(CreateAction(table, "Create a new window containing a table view", lambda t=table: self.NewTableView(t), self)) 23618392b74bSAdrian Hunter 23621beb5c7bSAdrian Hunter def NewCallGraph(self): 23631beb5c7bSAdrian Hunter CallGraphWindow(self.glb, self) 2364031c2a00SAdrian Hunter 236576099f98SAdrian Hunter def NewBranchView(self, event_id): 236676099f98SAdrian Hunter BranchWindow(self.glb, event_id, "", "", self) 236776099f98SAdrian Hunter 2368210cf1f9SAdrian Hunter def NewSelectedBranchView(self, event_id): 2369210cf1f9SAdrian Hunter dialog = SelectedBranchDialog(self.glb, self) 2370210cf1f9SAdrian Hunter ret = dialog.exec_() 2371210cf1f9SAdrian Hunter if ret: 2372210cf1f9SAdrian Hunter BranchWindow(self.glb, event_id, dialog.name, dialog.where_clause, self) 2373210cf1f9SAdrian Hunter 23748392b74bSAdrian Hunter def NewTableView(self, table_name): 23758392b74bSAdrian Hunter TableWindow(self.glb, table_name, self) 23768392b74bSAdrian Hunter 2377*65b24292SAdrian Hunter def Help(self): 2378*65b24292SAdrian Hunter HelpWindow(self.glb, self) 2379*65b24292SAdrian Hunter 238076099f98SAdrian Hunter# XED Disassembler 238176099f98SAdrian Hunter 238276099f98SAdrian Hunterclass xed_state_t(Structure): 238376099f98SAdrian Hunter 238476099f98SAdrian Hunter _fields_ = [ 238576099f98SAdrian Hunter ("mode", c_int), 238676099f98SAdrian Hunter ("width", c_int) 238776099f98SAdrian Hunter ] 238876099f98SAdrian Hunter 238976099f98SAdrian Hunterclass XEDInstruction(): 239076099f98SAdrian Hunter 239176099f98SAdrian Hunter def __init__(self, libxed): 239276099f98SAdrian Hunter # Current xed_decoded_inst_t structure is 192 bytes. Use 512 to allow for future expansion 239376099f98SAdrian Hunter xedd_t = c_byte * 512 239476099f98SAdrian Hunter self.xedd = xedd_t() 239576099f98SAdrian Hunter self.xedp = addressof(self.xedd) 239676099f98SAdrian Hunter libxed.xed_decoded_inst_zero(self.xedp) 239776099f98SAdrian Hunter self.state = xed_state_t() 239876099f98SAdrian Hunter self.statep = addressof(self.state) 239976099f98SAdrian Hunter # Buffer for disassembled instruction text 240076099f98SAdrian Hunter self.buffer = create_string_buffer(256) 240176099f98SAdrian Hunter self.bufferp = addressof(self.buffer) 240276099f98SAdrian Hunter 240376099f98SAdrian Hunterclass LibXED(): 240476099f98SAdrian Hunter 240576099f98SAdrian Hunter def __init__(self): 24065ed4419dSAdrian Hunter try: 240776099f98SAdrian Hunter self.libxed = CDLL("libxed.so") 24085ed4419dSAdrian Hunter except: 24095ed4419dSAdrian Hunter self.libxed = None 24105ed4419dSAdrian Hunter if not self.libxed: 24115ed4419dSAdrian Hunter self.libxed = CDLL("/usr/local/lib/libxed.so") 241276099f98SAdrian Hunter 241376099f98SAdrian Hunter self.xed_tables_init = self.libxed.xed_tables_init 241476099f98SAdrian Hunter self.xed_tables_init.restype = None 241576099f98SAdrian Hunter self.xed_tables_init.argtypes = [] 241676099f98SAdrian Hunter 241776099f98SAdrian Hunter self.xed_decoded_inst_zero = self.libxed.xed_decoded_inst_zero 241876099f98SAdrian Hunter self.xed_decoded_inst_zero.restype = None 241976099f98SAdrian Hunter self.xed_decoded_inst_zero.argtypes = [ c_void_p ] 242076099f98SAdrian Hunter 242176099f98SAdrian Hunter self.xed_operand_values_set_mode = self.libxed.xed_operand_values_set_mode 242276099f98SAdrian Hunter self.xed_operand_values_set_mode.restype = None 242376099f98SAdrian Hunter self.xed_operand_values_set_mode.argtypes = [ c_void_p, c_void_p ] 242476099f98SAdrian Hunter 242576099f98SAdrian Hunter self.xed_decoded_inst_zero_keep_mode = self.libxed.xed_decoded_inst_zero_keep_mode 242676099f98SAdrian Hunter self.xed_decoded_inst_zero_keep_mode.restype = None 242776099f98SAdrian Hunter self.xed_decoded_inst_zero_keep_mode.argtypes = [ c_void_p ] 242876099f98SAdrian Hunter 242976099f98SAdrian Hunter self.xed_decode = self.libxed.xed_decode 243076099f98SAdrian Hunter self.xed_decode.restype = c_int 243176099f98SAdrian Hunter self.xed_decode.argtypes = [ c_void_p, c_void_p, c_uint ] 243276099f98SAdrian Hunter 243376099f98SAdrian Hunter self.xed_format_context = self.libxed.xed_format_context 243476099f98SAdrian Hunter self.xed_format_context.restype = c_uint 243576099f98SAdrian Hunter self.xed_format_context.argtypes = [ c_int, c_void_p, c_void_p, c_int, c_ulonglong, c_void_p, c_void_p ] 243676099f98SAdrian Hunter 243776099f98SAdrian Hunter self.xed_tables_init() 243876099f98SAdrian Hunter 243976099f98SAdrian Hunter def Instruction(self): 244076099f98SAdrian Hunter return XEDInstruction(self) 244176099f98SAdrian Hunter 244276099f98SAdrian Hunter def SetMode(self, inst, mode): 244376099f98SAdrian Hunter if mode: 244476099f98SAdrian Hunter inst.state.mode = 4 # 32-bit 244576099f98SAdrian Hunter inst.state.width = 4 # 4 bytes 244676099f98SAdrian Hunter else: 244776099f98SAdrian Hunter inst.state.mode = 1 # 64-bit 244876099f98SAdrian Hunter inst.state.width = 8 # 8 bytes 244976099f98SAdrian Hunter self.xed_operand_values_set_mode(inst.xedp, inst.statep) 245076099f98SAdrian Hunter 245176099f98SAdrian Hunter def DisassembleOne(self, inst, bytes_ptr, bytes_cnt, ip): 245276099f98SAdrian Hunter self.xed_decoded_inst_zero_keep_mode(inst.xedp) 245376099f98SAdrian Hunter err = self.xed_decode(inst.xedp, bytes_ptr, bytes_cnt) 245476099f98SAdrian Hunter if err: 245576099f98SAdrian Hunter return 0, "" 245676099f98SAdrian Hunter # Use AT&T mode (2), alternative is Intel (3) 245776099f98SAdrian Hunter ok = self.xed_format_context(2, inst.xedp, inst.bufferp, sizeof(inst.buffer), ip, 0, 0) 245876099f98SAdrian Hunter if not ok: 245976099f98SAdrian Hunter return 0, "" 246076099f98SAdrian Hunter # Return instruction length and the disassembled instruction text 246176099f98SAdrian Hunter # For now, assume the length is in byte 166 246276099f98SAdrian Hunter return inst.xedd[166], inst.buffer.value 246376099f98SAdrian Hunter 246476099f98SAdrian Hunterdef TryOpen(file_name): 246576099f98SAdrian Hunter try: 246676099f98SAdrian Hunter return open(file_name, "rb") 246776099f98SAdrian Hunter except: 246876099f98SAdrian Hunter return None 246976099f98SAdrian Hunter 247076099f98SAdrian Hunterdef Is64Bit(f): 247176099f98SAdrian Hunter result = sizeof(c_void_p) 247276099f98SAdrian Hunter # ELF support only 247376099f98SAdrian Hunter pos = f.tell() 247476099f98SAdrian Hunter f.seek(0) 247576099f98SAdrian Hunter header = f.read(7) 247676099f98SAdrian Hunter f.seek(pos) 247776099f98SAdrian Hunter magic = header[0:4] 247876099f98SAdrian Hunter eclass = ord(header[4]) 247976099f98SAdrian Hunter encoding = ord(header[5]) 248076099f98SAdrian Hunter version = ord(header[6]) 248176099f98SAdrian Hunter if magic == chr(127) + "ELF" and eclass > 0 and eclass < 3 and encoding > 0 and encoding < 3 and version == 1: 248276099f98SAdrian Hunter result = True if eclass == 2 else False 248376099f98SAdrian Hunter return result 248476099f98SAdrian Hunter 2485031c2a00SAdrian Hunter# Global data 2486031c2a00SAdrian Hunter 2487031c2a00SAdrian Hunterclass Glb(): 2488031c2a00SAdrian Hunter 2489031c2a00SAdrian Hunter def __init__(self, dbref, db, dbname): 2490031c2a00SAdrian Hunter self.dbref = dbref 2491031c2a00SAdrian Hunter self.db = db 2492031c2a00SAdrian Hunter self.dbname = dbname 249376099f98SAdrian Hunter self.home_dir = os.path.expanduser("~") 249476099f98SAdrian Hunter self.buildid_dir = os.getenv("PERF_BUILDID_DIR") 249576099f98SAdrian Hunter if self.buildid_dir: 249676099f98SAdrian Hunter self.buildid_dir += "/.build-id/" 249776099f98SAdrian Hunter else: 249876099f98SAdrian Hunter self.buildid_dir = self.home_dir + "/.debug/.build-id/" 2499031c2a00SAdrian Hunter self.app = None 2500031c2a00SAdrian Hunter self.mainwindow = None 25018392b74bSAdrian Hunter self.instances_to_shutdown_on_exit = weakref.WeakSet() 250276099f98SAdrian Hunter try: 250376099f98SAdrian Hunter self.disassembler = LibXED() 250476099f98SAdrian Hunter self.have_disassembler = True 250576099f98SAdrian Hunter except: 250676099f98SAdrian Hunter self.have_disassembler = False 250776099f98SAdrian Hunter 250876099f98SAdrian Hunter def FileFromBuildId(self, build_id): 250976099f98SAdrian Hunter file_name = self.buildid_dir + build_id[0:2] + "/" + build_id[2:] + "/elf" 251076099f98SAdrian Hunter return TryOpen(file_name) 251176099f98SAdrian Hunter 251276099f98SAdrian Hunter def FileFromNamesAndBuildId(self, short_name, long_name, build_id): 251376099f98SAdrian Hunter # Assume current machine i.e. no support for virtualization 251476099f98SAdrian Hunter if short_name[0:7] == "[kernel" and os.path.basename(long_name) == "kcore": 251576099f98SAdrian Hunter file_name = os.getenv("PERF_KCORE") 251676099f98SAdrian Hunter f = TryOpen(file_name) if file_name else None 251776099f98SAdrian Hunter if f: 251876099f98SAdrian Hunter return f 251976099f98SAdrian Hunter # For now, no special handling if long_name is /proc/kcore 252076099f98SAdrian Hunter f = TryOpen(long_name) 252176099f98SAdrian Hunter if f: 252276099f98SAdrian Hunter return f 252376099f98SAdrian Hunter f = self.FileFromBuildId(build_id) 252476099f98SAdrian Hunter if f: 252576099f98SAdrian Hunter return f 252676099f98SAdrian Hunter return None 25278392b74bSAdrian Hunter 25288392b74bSAdrian Hunter def AddInstanceToShutdownOnExit(self, instance): 25298392b74bSAdrian Hunter self.instances_to_shutdown_on_exit.add(instance) 25308392b74bSAdrian Hunter 25318392b74bSAdrian Hunter # Shutdown any background processes or threads 25328392b74bSAdrian Hunter def ShutdownInstances(self): 25338392b74bSAdrian Hunter for x in self.instances_to_shutdown_on_exit: 25348392b74bSAdrian Hunter try: 25358392b74bSAdrian Hunter x.Shutdown() 25368392b74bSAdrian Hunter except: 25378392b74bSAdrian Hunter pass 2538031c2a00SAdrian Hunter 2539031c2a00SAdrian Hunter# Database reference 2540031c2a00SAdrian Hunter 2541031c2a00SAdrian Hunterclass DBRef(): 2542031c2a00SAdrian Hunter 2543031c2a00SAdrian Hunter def __init__(self, is_sqlite3, dbname): 2544031c2a00SAdrian Hunter self.is_sqlite3 = is_sqlite3 2545031c2a00SAdrian Hunter self.dbname = dbname 2546031c2a00SAdrian Hunter 2547031c2a00SAdrian Hunter def Open(self, connection_name): 2548031c2a00SAdrian Hunter dbname = self.dbname 2549031c2a00SAdrian Hunter if self.is_sqlite3: 2550031c2a00SAdrian Hunter db = QSqlDatabase.addDatabase("QSQLITE", connection_name) 2551031c2a00SAdrian Hunter else: 2552031c2a00SAdrian Hunter db = QSqlDatabase.addDatabase("QPSQL", connection_name) 2553031c2a00SAdrian Hunter opts = dbname.split() 2554031c2a00SAdrian Hunter for opt in opts: 2555031c2a00SAdrian Hunter if "=" in opt: 2556031c2a00SAdrian Hunter opt = opt.split("=") 2557031c2a00SAdrian Hunter if opt[0] == "hostname": 2558031c2a00SAdrian Hunter db.setHostName(opt[1]) 2559031c2a00SAdrian Hunter elif opt[0] == "port": 2560031c2a00SAdrian Hunter db.setPort(int(opt[1])) 2561031c2a00SAdrian Hunter elif opt[0] == "username": 2562031c2a00SAdrian Hunter db.setUserName(opt[1]) 2563031c2a00SAdrian Hunter elif opt[0] == "password": 2564031c2a00SAdrian Hunter db.setPassword(opt[1]) 2565031c2a00SAdrian Hunter elif opt[0] == "dbname": 2566031c2a00SAdrian Hunter dbname = opt[1] 2567031c2a00SAdrian Hunter else: 2568031c2a00SAdrian Hunter dbname = opt 2569031c2a00SAdrian Hunter 2570031c2a00SAdrian Hunter db.setDatabaseName(dbname) 2571031c2a00SAdrian Hunter if not db.open(): 2572031c2a00SAdrian Hunter raise Exception("Failed to open database " + dbname + " error: " + db.lastError().text()) 2573031c2a00SAdrian Hunter return db, dbname 2574031c2a00SAdrian Hunter 2575031c2a00SAdrian Hunter# Main 2576031c2a00SAdrian Hunter 2577031c2a00SAdrian Hunterdef Main(): 2578031c2a00SAdrian Hunter if (len(sys.argv) < 2): 2579*65b24292SAdrian Hunter print >> sys.stderr, "Usage is: exported-sql-viewer.py {<database name> | --help-only}" 2580031c2a00SAdrian Hunter raise Exception("Too few arguments") 2581031c2a00SAdrian Hunter 2582031c2a00SAdrian Hunter dbname = sys.argv[1] 2583*65b24292SAdrian Hunter if dbname == "--help-only": 2584*65b24292SAdrian Hunter app = QApplication(sys.argv) 2585*65b24292SAdrian Hunter mainwindow = HelpOnlyWindow() 2586*65b24292SAdrian Hunter mainwindow.show() 2587*65b24292SAdrian Hunter err = app.exec_() 2588*65b24292SAdrian Hunter sys.exit(err) 2589031c2a00SAdrian Hunter 2590031c2a00SAdrian Hunter is_sqlite3 = False 2591031c2a00SAdrian Hunter try: 2592031c2a00SAdrian Hunter f = open(dbname) 2593031c2a00SAdrian Hunter if f.read(15) == "SQLite format 3": 2594031c2a00SAdrian Hunter is_sqlite3 = True 2595031c2a00SAdrian Hunter f.close() 2596031c2a00SAdrian Hunter except: 2597031c2a00SAdrian Hunter pass 2598031c2a00SAdrian Hunter 2599031c2a00SAdrian Hunter dbref = DBRef(is_sqlite3, dbname) 2600031c2a00SAdrian Hunter db, dbname = dbref.Open("main") 2601031c2a00SAdrian Hunter glb = Glb(dbref, db, dbname) 2602031c2a00SAdrian Hunter app = QApplication(sys.argv) 2603031c2a00SAdrian Hunter glb.app = app 2604031c2a00SAdrian Hunter mainwindow = MainWindow(glb) 2605031c2a00SAdrian Hunter glb.mainwindow = mainwindow 2606031c2a00SAdrian Hunter mainwindow.show() 2607031c2a00SAdrian Hunter err = app.exec_() 26088392b74bSAdrian Hunter glb.ShutdownInstances() 2609031c2a00SAdrian Hunter db.close() 2610031c2a00SAdrian Hunter sys.exit(err) 2611031c2a00SAdrian Hunter 2612031c2a00SAdrian Hunterif __name__ == "__main__": 2613031c2a00SAdrian Hunter Main() 2614