1b3a67546SAdrian Hunter#!/usr/bin/env 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 1401*0bf0947aSAdrian Hunter# Report Variables 1402*0bf0947aSAdrian Hunter 1403*0bf0947aSAdrian Hunterclass ReportVars(): 1404*0bf0947aSAdrian Hunter 1405*0bf0947aSAdrian Hunter def __init__(self, where_clause = ""): 1406*0bf0947aSAdrian Hunter self.where_clause = where_clause 1407*0bf0947aSAdrian Hunter 1408*0bf0947aSAdrian Hunter def UniqueId(self): 1409*0bf0947aSAdrian Hunter return str(self.where_clause) 1410*0bf0947aSAdrian Hunter 141176099f98SAdrian Hunter# Branch window 141276099f98SAdrian Hunter 141376099f98SAdrian Hunterclass BranchWindow(QMdiSubWindow): 141476099f98SAdrian Hunter 1415*0bf0947aSAdrian Hunter def __init__(self, glb, event_id, name, report_vars, parent=None): 141676099f98SAdrian Hunter super(BranchWindow, self).__init__(parent) 141776099f98SAdrian Hunter 1418*0bf0947aSAdrian Hunter model_name = "Branch Events " + str(event_id) + " " + report_vars.UniqueId() 141976099f98SAdrian Hunter 1420*0bf0947aSAdrian Hunter self.model = LookupCreateModel(model_name, lambda: BranchModel(glb, event_id, report_vars.where_clause)) 142176099f98SAdrian Hunter 142276099f98SAdrian Hunter self.view = QTreeView() 142376099f98SAdrian Hunter self.view.setUniformRowHeights(True) 142476099f98SAdrian Hunter self.view.setModel(self.model) 142576099f98SAdrian Hunter 142676099f98SAdrian Hunter self.ResizeColumnsToContents() 142776099f98SAdrian Hunter 142876099f98SAdrian Hunter self.find_bar = FindBar(self, self, True) 142976099f98SAdrian Hunter 143076099f98SAdrian Hunter self.finder = ChildDataItemFinder(self.model.root) 143176099f98SAdrian Hunter 143276099f98SAdrian Hunter self.fetch_bar = FetchMoreRecordsBar(self.model, self) 143376099f98SAdrian Hunter 143476099f98SAdrian Hunter self.vbox = VBox(self.view, self.find_bar.Widget(), self.fetch_bar.Widget()) 143576099f98SAdrian Hunter 143676099f98SAdrian Hunter self.setWidget(self.vbox.Widget()) 143776099f98SAdrian Hunter 143876099f98SAdrian Hunter AddSubWindow(glb.mainwindow.mdi_area, self, name + " Branch Events") 143976099f98SAdrian Hunter 144076099f98SAdrian Hunter def ResizeColumnToContents(self, column, n): 144176099f98SAdrian Hunter # Using the view's resizeColumnToContents() here is extrememly slow 144276099f98SAdrian Hunter # so implement a crude alternative 144376099f98SAdrian Hunter mm = "MM" if column else "MMMM" 144476099f98SAdrian Hunter font = self.view.font() 144576099f98SAdrian Hunter metrics = QFontMetrics(font) 144676099f98SAdrian Hunter max = 0 144776099f98SAdrian Hunter for row in xrange(n): 144876099f98SAdrian Hunter val = self.model.root.child_items[row].data[column] 144976099f98SAdrian Hunter len = metrics.width(str(val) + mm) 145076099f98SAdrian Hunter max = len if len > max else max 145176099f98SAdrian Hunter val = self.model.columnHeader(column) 145276099f98SAdrian Hunter len = metrics.width(str(val) + mm) 145376099f98SAdrian Hunter max = len if len > max else max 145476099f98SAdrian Hunter self.view.setColumnWidth(column, max) 145576099f98SAdrian Hunter 145676099f98SAdrian Hunter def ResizeColumnsToContents(self): 145776099f98SAdrian Hunter n = min(self.model.root.child_count, 100) 145876099f98SAdrian Hunter if n < 1: 145976099f98SAdrian Hunter # No data yet, so connect a signal to notify when there is 146076099f98SAdrian Hunter self.model.rowsInserted.connect(self.UpdateColumnWidths) 146176099f98SAdrian Hunter return 146276099f98SAdrian Hunter columns = self.model.columnCount() 146376099f98SAdrian Hunter for i in xrange(columns): 146476099f98SAdrian Hunter self.ResizeColumnToContents(i, n) 146576099f98SAdrian Hunter 146676099f98SAdrian Hunter def UpdateColumnWidths(self, *x): 146776099f98SAdrian Hunter # This only needs to be done once, so disconnect the signal now 146876099f98SAdrian Hunter self.model.rowsInserted.disconnect(self.UpdateColumnWidths) 146976099f98SAdrian Hunter self.ResizeColumnsToContents() 147076099f98SAdrian Hunter 147176099f98SAdrian Hunter def Find(self, value, direction, pattern, context): 147276099f98SAdrian Hunter self.view.setFocus() 147376099f98SAdrian Hunter self.find_bar.Busy() 147476099f98SAdrian Hunter self.finder.Find(value, direction, pattern, context, self.FindDone) 147576099f98SAdrian Hunter 147676099f98SAdrian Hunter def FindDone(self, row): 147776099f98SAdrian Hunter self.find_bar.Idle() 147876099f98SAdrian Hunter if row >= 0: 147976099f98SAdrian Hunter self.view.setCurrentIndex(self.model.index(row, 0, QModelIndex())) 148076099f98SAdrian Hunter else: 148176099f98SAdrian Hunter self.find_bar.NotFound() 148276099f98SAdrian Hunter 1483210cf1f9SAdrian Hunter# Dialog data item converted and validated using a SQL table 1484210cf1f9SAdrian Hunter 1485210cf1f9SAdrian Hunterclass SQLTableDialogDataItem(): 1486210cf1f9SAdrian Hunter 1487210cf1f9SAdrian Hunter def __init__(self, glb, label, placeholder_text, table_name, match_column, column_name1, column_name2, parent): 1488210cf1f9SAdrian Hunter self.glb = glb 1489210cf1f9SAdrian Hunter self.label = label 1490210cf1f9SAdrian Hunter self.placeholder_text = placeholder_text 1491210cf1f9SAdrian Hunter self.table_name = table_name 1492210cf1f9SAdrian Hunter self.match_column = match_column 1493210cf1f9SAdrian Hunter self.column_name1 = column_name1 1494210cf1f9SAdrian Hunter self.column_name2 = column_name2 1495210cf1f9SAdrian Hunter self.parent = parent 1496210cf1f9SAdrian Hunter 1497210cf1f9SAdrian Hunter self.value = "" 1498210cf1f9SAdrian Hunter 1499210cf1f9SAdrian Hunter self.widget = QLineEdit() 1500210cf1f9SAdrian Hunter self.widget.editingFinished.connect(self.Validate) 1501210cf1f9SAdrian Hunter self.widget.textChanged.connect(self.Invalidate) 1502210cf1f9SAdrian Hunter self.red = False 1503210cf1f9SAdrian Hunter self.error = "" 1504210cf1f9SAdrian Hunter self.validated = True 1505210cf1f9SAdrian Hunter 1506210cf1f9SAdrian Hunter self.last_id = 0 1507210cf1f9SAdrian Hunter self.first_time = 0 1508210cf1f9SAdrian Hunter self.last_time = 2 ** 64 1509210cf1f9SAdrian Hunter if self.table_name == "<timeranges>": 1510210cf1f9SAdrian Hunter query = QSqlQuery(self.glb.db) 1511210cf1f9SAdrian Hunter QueryExec(query, "SELECT id, time FROM samples ORDER BY id DESC LIMIT 1") 1512210cf1f9SAdrian Hunter if query.next(): 1513210cf1f9SAdrian Hunter self.last_id = int(query.value(0)) 1514210cf1f9SAdrian Hunter self.last_time = int(query.value(1)) 1515210cf1f9SAdrian Hunter QueryExec(query, "SELECT time FROM samples WHERE time != 0 ORDER BY id LIMIT 1") 1516210cf1f9SAdrian Hunter if query.next(): 1517210cf1f9SAdrian Hunter self.first_time = int(query.value(0)) 1518210cf1f9SAdrian Hunter if placeholder_text: 1519210cf1f9SAdrian Hunter placeholder_text += ", between " + str(self.first_time) + " and " + str(self.last_time) 1520210cf1f9SAdrian Hunter 1521210cf1f9SAdrian Hunter if placeholder_text: 1522210cf1f9SAdrian Hunter self.widget.setPlaceholderText(placeholder_text) 1523210cf1f9SAdrian Hunter 1524210cf1f9SAdrian Hunter def ValueToIds(self, value): 1525210cf1f9SAdrian Hunter ids = [] 1526210cf1f9SAdrian Hunter query = QSqlQuery(self.glb.db) 1527210cf1f9SAdrian Hunter stmt = "SELECT id FROM " + self.table_name + " WHERE " + self.match_column + " = '" + value + "'" 1528210cf1f9SAdrian Hunter ret = query.exec_(stmt) 1529210cf1f9SAdrian Hunter if ret: 1530210cf1f9SAdrian Hunter while query.next(): 1531210cf1f9SAdrian Hunter ids.append(str(query.value(0))) 1532210cf1f9SAdrian Hunter return ids 1533210cf1f9SAdrian Hunter 1534210cf1f9SAdrian Hunter def IdBetween(self, query, lower_id, higher_id, order): 1535210cf1f9SAdrian Hunter QueryExec(query, "SELECT id FROM samples WHERE id > " + str(lower_id) + " AND id < " + str(higher_id) + " ORDER BY id " + order + " LIMIT 1") 1536210cf1f9SAdrian Hunter if query.next(): 1537210cf1f9SAdrian Hunter return True, int(query.value(0)) 1538210cf1f9SAdrian Hunter else: 1539210cf1f9SAdrian Hunter return False, 0 1540210cf1f9SAdrian Hunter 1541210cf1f9SAdrian Hunter def BinarySearchTime(self, lower_id, higher_id, target_time, get_floor): 1542210cf1f9SAdrian Hunter query = QSqlQuery(self.glb.db) 1543210cf1f9SAdrian Hunter while True: 1544210cf1f9SAdrian Hunter next_id = int((lower_id + higher_id) / 2) 1545210cf1f9SAdrian Hunter QueryExec(query, "SELECT time FROM samples WHERE id = " + str(next_id)) 1546210cf1f9SAdrian Hunter if not query.next(): 1547210cf1f9SAdrian Hunter ok, dbid = self.IdBetween(query, lower_id, next_id, "DESC") 1548210cf1f9SAdrian Hunter if not ok: 1549210cf1f9SAdrian Hunter ok, dbid = self.IdBetween(query, next_id, higher_id, "") 1550210cf1f9SAdrian Hunter if not ok: 1551210cf1f9SAdrian Hunter return str(higher_id) 1552210cf1f9SAdrian Hunter next_id = dbid 1553210cf1f9SAdrian Hunter QueryExec(query, "SELECT time FROM samples WHERE id = " + str(next_id)) 1554210cf1f9SAdrian Hunter next_time = int(query.value(0)) 1555210cf1f9SAdrian Hunter if get_floor: 1556210cf1f9SAdrian Hunter if target_time > next_time: 1557210cf1f9SAdrian Hunter lower_id = next_id 1558210cf1f9SAdrian Hunter else: 1559210cf1f9SAdrian Hunter higher_id = next_id 1560210cf1f9SAdrian Hunter if higher_id <= lower_id + 1: 1561210cf1f9SAdrian Hunter return str(higher_id) 1562210cf1f9SAdrian Hunter else: 1563210cf1f9SAdrian Hunter if target_time >= next_time: 1564210cf1f9SAdrian Hunter lower_id = next_id 1565210cf1f9SAdrian Hunter else: 1566210cf1f9SAdrian Hunter higher_id = next_id 1567210cf1f9SAdrian Hunter if higher_id <= lower_id + 1: 1568210cf1f9SAdrian Hunter return str(lower_id) 1569210cf1f9SAdrian Hunter 1570210cf1f9SAdrian Hunter def ConvertRelativeTime(self, val): 1571210cf1f9SAdrian Hunter mult = 1 1572210cf1f9SAdrian Hunter suffix = val[-2:] 1573210cf1f9SAdrian Hunter if suffix == "ms": 1574210cf1f9SAdrian Hunter mult = 1000000 1575210cf1f9SAdrian Hunter elif suffix == "us": 1576210cf1f9SAdrian Hunter mult = 1000 1577210cf1f9SAdrian Hunter elif suffix == "ns": 1578210cf1f9SAdrian Hunter mult = 1 1579210cf1f9SAdrian Hunter else: 1580210cf1f9SAdrian Hunter return val 1581210cf1f9SAdrian Hunter val = val[:-2].strip() 1582210cf1f9SAdrian Hunter if not self.IsNumber(val): 1583210cf1f9SAdrian Hunter return val 1584210cf1f9SAdrian Hunter val = int(val) * mult 1585210cf1f9SAdrian Hunter if val >= 0: 1586210cf1f9SAdrian Hunter val += self.first_time 1587210cf1f9SAdrian Hunter else: 1588210cf1f9SAdrian Hunter val += self.last_time 1589210cf1f9SAdrian Hunter return str(val) 1590210cf1f9SAdrian Hunter 1591210cf1f9SAdrian Hunter def ConvertTimeRange(self, vrange): 1592210cf1f9SAdrian Hunter if vrange[0] == "": 1593210cf1f9SAdrian Hunter vrange[0] = str(self.first_time) 1594210cf1f9SAdrian Hunter if vrange[1] == "": 1595210cf1f9SAdrian Hunter vrange[1] = str(self.last_time) 1596210cf1f9SAdrian Hunter vrange[0] = self.ConvertRelativeTime(vrange[0]) 1597210cf1f9SAdrian Hunter vrange[1] = self.ConvertRelativeTime(vrange[1]) 1598210cf1f9SAdrian Hunter if not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]): 1599210cf1f9SAdrian Hunter return False 1600210cf1f9SAdrian Hunter beg_range = max(int(vrange[0]), self.first_time) 1601210cf1f9SAdrian Hunter end_range = min(int(vrange[1]), self.last_time) 1602210cf1f9SAdrian Hunter if beg_range > self.last_time or end_range < self.first_time: 1603210cf1f9SAdrian Hunter return False 1604210cf1f9SAdrian Hunter vrange[0] = self.BinarySearchTime(0, self.last_id, beg_range, True) 1605210cf1f9SAdrian Hunter vrange[1] = self.BinarySearchTime(1, self.last_id + 1, end_range, False) 1606210cf1f9SAdrian Hunter return True 1607210cf1f9SAdrian Hunter 1608210cf1f9SAdrian Hunter def AddTimeRange(self, value, ranges): 1609210cf1f9SAdrian Hunter n = value.count("-") 1610210cf1f9SAdrian Hunter if n == 1: 1611210cf1f9SAdrian Hunter pass 1612210cf1f9SAdrian Hunter elif n == 2: 1613210cf1f9SAdrian Hunter if value.split("-")[1].strip() == "": 1614210cf1f9SAdrian Hunter n = 1 1615210cf1f9SAdrian Hunter elif n == 3: 1616210cf1f9SAdrian Hunter n = 2 1617210cf1f9SAdrian Hunter else: 1618210cf1f9SAdrian Hunter return False 1619210cf1f9SAdrian Hunter pos = findnth(value, "-", n) 1620210cf1f9SAdrian Hunter vrange = [value[:pos].strip() ,value[pos+1:].strip()] 1621210cf1f9SAdrian Hunter if self.ConvertTimeRange(vrange): 1622210cf1f9SAdrian Hunter ranges.append(vrange) 1623210cf1f9SAdrian Hunter return True 1624210cf1f9SAdrian Hunter return False 1625210cf1f9SAdrian Hunter 1626210cf1f9SAdrian Hunter def InvalidValue(self, value): 1627210cf1f9SAdrian Hunter self.value = "" 1628210cf1f9SAdrian Hunter palette = QPalette() 1629210cf1f9SAdrian Hunter palette.setColor(QPalette.Text,Qt.red) 1630210cf1f9SAdrian Hunter self.widget.setPalette(palette) 1631210cf1f9SAdrian Hunter self.red = True 1632210cf1f9SAdrian Hunter self.error = self.label + " invalid value '" + value + "'" 1633210cf1f9SAdrian Hunter self.parent.ShowMessage(self.error) 1634210cf1f9SAdrian Hunter 1635210cf1f9SAdrian Hunter def IsNumber(self, value): 1636210cf1f9SAdrian Hunter try: 1637210cf1f9SAdrian Hunter x = int(value) 1638210cf1f9SAdrian Hunter except: 1639210cf1f9SAdrian Hunter x = 0 1640210cf1f9SAdrian Hunter return str(x) == value 1641210cf1f9SAdrian Hunter 1642210cf1f9SAdrian Hunter def Invalidate(self): 1643210cf1f9SAdrian Hunter self.validated = False 1644210cf1f9SAdrian Hunter 1645210cf1f9SAdrian Hunter def Validate(self): 1646210cf1f9SAdrian Hunter input_string = self.widget.text() 1647210cf1f9SAdrian Hunter self.validated = True 1648210cf1f9SAdrian Hunter if self.red: 1649210cf1f9SAdrian Hunter palette = QPalette() 1650210cf1f9SAdrian Hunter self.widget.setPalette(palette) 1651210cf1f9SAdrian Hunter self.red = False 1652210cf1f9SAdrian Hunter if not len(input_string.strip()): 1653210cf1f9SAdrian Hunter self.error = "" 1654210cf1f9SAdrian Hunter self.value = "" 1655210cf1f9SAdrian Hunter return 1656210cf1f9SAdrian Hunter if self.table_name == "<timeranges>": 1657210cf1f9SAdrian Hunter ranges = [] 1658210cf1f9SAdrian Hunter for value in [x.strip() for x in input_string.split(",")]: 1659210cf1f9SAdrian Hunter if not self.AddTimeRange(value, ranges): 1660210cf1f9SAdrian Hunter return self.InvalidValue(value) 1661210cf1f9SAdrian Hunter ranges = [("(" + self.column_name1 + " >= " + r[0] + " AND " + self.column_name1 + " <= " + r[1] + ")") for r in ranges] 1662210cf1f9SAdrian Hunter self.value = " OR ".join(ranges) 1663210cf1f9SAdrian Hunter elif self.table_name == "<ranges>": 1664210cf1f9SAdrian Hunter singles = [] 1665210cf1f9SAdrian Hunter ranges = [] 1666210cf1f9SAdrian Hunter for value in [x.strip() for x in input_string.split(",")]: 1667210cf1f9SAdrian Hunter if "-" in value: 1668210cf1f9SAdrian Hunter vrange = value.split("-") 1669210cf1f9SAdrian Hunter if len(vrange) != 2 or not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]): 1670210cf1f9SAdrian Hunter return self.InvalidValue(value) 1671210cf1f9SAdrian Hunter ranges.append(vrange) 1672210cf1f9SAdrian Hunter else: 1673210cf1f9SAdrian Hunter if not self.IsNumber(value): 1674210cf1f9SAdrian Hunter return self.InvalidValue(value) 1675210cf1f9SAdrian Hunter singles.append(value) 1676210cf1f9SAdrian Hunter ranges = [("(" + self.column_name1 + " >= " + r[0] + " AND " + self.column_name1 + " <= " + r[1] + ")") for r in ranges] 1677210cf1f9SAdrian Hunter if len(singles): 1678210cf1f9SAdrian Hunter ranges.append(self.column_name1 + " IN (" + ",".join(singles) + ")") 1679210cf1f9SAdrian Hunter self.value = " OR ".join(ranges) 1680210cf1f9SAdrian Hunter elif self.table_name: 1681210cf1f9SAdrian Hunter all_ids = [] 1682210cf1f9SAdrian Hunter for value in [x.strip() for x in input_string.split(",")]: 1683210cf1f9SAdrian Hunter ids = self.ValueToIds(value) 1684210cf1f9SAdrian Hunter if len(ids): 1685210cf1f9SAdrian Hunter all_ids.extend(ids) 1686210cf1f9SAdrian Hunter else: 1687210cf1f9SAdrian Hunter return self.InvalidValue(value) 1688210cf1f9SAdrian Hunter self.value = self.column_name1 + " IN (" + ",".join(all_ids) + ")" 1689210cf1f9SAdrian Hunter if self.column_name2: 1690210cf1f9SAdrian Hunter self.value = "( " + self.value + " OR " + self.column_name2 + " IN (" + ",".join(all_ids) + ") )" 1691210cf1f9SAdrian Hunter else: 1692210cf1f9SAdrian Hunter self.value = input_string.strip() 1693210cf1f9SAdrian Hunter self.error = "" 1694210cf1f9SAdrian Hunter self.parent.ClearMessage() 1695210cf1f9SAdrian Hunter 1696210cf1f9SAdrian Hunter def IsValid(self): 1697210cf1f9SAdrian Hunter if not self.validated: 1698210cf1f9SAdrian Hunter self.Validate() 1699210cf1f9SAdrian Hunter if len(self.error): 1700210cf1f9SAdrian Hunter self.parent.ShowMessage(self.error) 1701210cf1f9SAdrian Hunter return False 1702210cf1f9SAdrian Hunter return True 1703210cf1f9SAdrian Hunter 17040924cd68SAdrian Hunter# Report Dialog Base 1705210cf1f9SAdrian Hunter 17060924cd68SAdrian Hunterclass ReportDialogBase(QDialog): 1707210cf1f9SAdrian Hunter 17080924cd68SAdrian Hunter def __init__(self, glb, title, items, partial, parent=None): 17090924cd68SAdrian Hunter super(ReportDialogBase, self).__init__(parent) 1710210cf1f9SAdrian Hunter 1711210cf1f9SAdrian Hunter self.glb = glb 1712210cf1f9SAdrian Hunter 1713210cf1f9SAdrian Hunter self.name = "" 1714*0bf0947aSAdrian Hunter self.report_vars = ReportVars() 1715210cf1f9SAdrian Hunter 17160924cd68SAdrian Hunter self.setWindowTitle(title) 1717210cf1f9SAdrian Hunter self.setMinimumWidth(600) 1718210cf1f9SAdrian Hunter 1719210cf1f9SAdrian Hunter self.data_items = [SQLTableDialogDataItem(glb, *x, parent=self) for x in items] 1720210cf1f9SAdrian Hunter 17210924cd68SAdrian Hunter self.partial = partial 17220924cd68SAdrian Hunter 1723210cf1f9SAdrian Hunter self.grid = QGridLayout() 1724210cf1f9SAdrian Hunter 1725210cf1f9SAdrian Hunter for row in xrange(len(self.data_items)): 1726210cf1f9SAdrian Hunter self.grid.addWidget(QLabel(self.data_items[row].label), row, 0) 1727210cf1f9SAdrian Hunter self.grid.addWidget(self.data_items[row].widget, row, 1) 1728210cf1f9SAdrian Hunter 1729210cf1f9SAdrian Hunter self.status = QLabel() 1730210cf1f9SAdrian Hunter 1731210cf1f9SAdrian Hunter self.ok_button = QPushButton("Ok", self) 1732210cf1f9SAdrian Hunter self.ok_button.setDefault(True) 1733210cf1f9SAdrian Hunter self.ok_button.released.connect(self.Ok) 1734210cf1f9SAdrian Hunter self.ok_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 1735210cf1f9SAdrian Hunter 1736210cf1f9SAdrian Hunter self.cancel_button = QPushButton("Cancel", self) 1737210cf1f9SAdrian Hunter self.cancel_button.released.connect(self.reject) 1738210cf1f9SAdrian Hunter self.cancel_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 1739210cf1f9SAdrian Hunter 1740210cf1f9SAdrian Hunter self.hbox = QHBoxLayout() 1741210cf1f9SAdrian Hunter #self.hbox.addStretch() 1742210cf1f9SAdrian Hunter self.hbox.addWidget(self.status) 1743210cf1f9SAdrian Hunter self.hbox.addWidget(self.ok_button) 1744210cf1f9SAdrian Hunter self.hbox.addWidget(self.cancel_button) 1745210cf1f9SAdrian Hunter 1746210cf1f9SAdrian Hunter self.vbox = QVBoxLayout() 1747210cf1f9SAdrian Hunter self.vbox.addLayout(self.grid) 1748210cf1f9SAdrian Hunter self.vbox.addLayout(self.hbox) 1749210cf1f9SAdrian Hunter 1750210cf1f9SAdrian Hunter self.setLayout(self.vbox); 1751210cf1f9SAdrian Hunter 1752210cf1f9SAdrian Hunter def Ok(self): 1753*0bf0947aSAdrian Hunter vars = self.report_vars 1754210cf1f9SAdrian Hunter self.name = self.data_items[0].value 1755210cf1f9SAdrian Hunter if not self.name: 1756210cf1f9SAdrian Hunter self.ShowMessage("Report name is required") 1757210cf1f9SAdrian Hunter return 1758210cf1f9SAdrian Hunter for d in self.data_items: 1759210cf1f9SAdrian Hunter if not d.IsValid(): 1760210cf1f9SAdrian Hunter return 1761210cf1f9SAdrian Hunter for d in self.data_items[1:]: 1762210cf1f9SAdrian Hunter if len(d.value): 1763*0bf0947aSAdrian Hunter if len(vars.where_clause): 1764*0bf0947aSAdrian Hunter vars.where_clause += " AND " 1765*0bf0947aSAdrian Hunter vars.where_clause += d.value 1766*0bf0947aSAdrian Hunter if len(vars.where_clause): 17670924cd68SAdrian Hunter if self.partial: 1768*0bf0947aSAdrian Hunter vars.where_clause = " AND ( " + vars.where_clause + " ) " 1769210cf1f9SAdrian Hunter else: 1770*0bf0947aSAdrian Hunter vars.where_clause = " WHERE " + vars.where_clause + " " 17710924cd68SAdrian Hunter else: 1772210cf1f9SAdrian Hunter self.ShowMessage("No selection") 1773210cf1f9SAdrian Hunter return 1774210cf1f9SAdrian Hunter self.accept() 1775210cf1f9SAdrian Hunter 1776210cf1f9SAdrian Hunter def ShowMessage(self, msg): 1777210cf1f9SAdrian Hunter self.status.setText("<font color=#FF0000>" + msg) 1778210cf1f9SAdrian Hunter 1779210cf1f9SAdrian Hunter def ClearMessage(self): 1780210cf1f9SAdrian Hunter self.status.setText("") 1781210cf1f9SAdrian Hunter 17820924cd68SAdrian Hunter# Selected branch report creation dialog 17830924cd68SAdrian Hunter 17840924cd68SAdrian Hunterclass SelectedBranchDialog(ReportDialogBase): 17850924cd68SAdrian Hunter 17860924cd68SAdrian Hunter def __init__(self, glb, parent=None): 17870924cd68SAdrian Hunter title = "Selected Branches" 17880924cd68SAdrian Hunter items = ( 17890924cd68SAdrian Hunter ("Report name:", "Enter a name to appear in the window title bar", "", "", "", ""), 17900924cd68SAdrian Hunter ("Time ranges:", "Enter time ranges", "<timeranges>", "", "samples.id", ""), 17910924cd68SAdrian Hunter ("CPUs:", "Enter CPUs or ranges e.g. 0,5-6", "<ranges>", "", "cpu", ""), 17920924cd68SAdrian Hunter ("Commands:", "Only branches with these commands will be included", "comms", "comm", "comm_id", ""), 17930924cd68SAdrian Hunter ("PIDs:", "Only branches with these process IDs will be included", "threads", "pid", "thread_id", ""), 17940924cd68SAdrian Hunter ("TIDs:", "Only branches with these thread IDs will be included", "threads", "tid", "thread_id", ""), 17950924cd68SAdrian Hunter ("DSOs:", "Only branches with these DSOs will be included", "dsos", "short_name", "samples.dso_id", "to_dso_id"), 17960924cd68SAdrian Hunter ("Symbols:", "Only branches with these symbols will be included", "symbols", "name", "symbol_id", "to_symbol_id"), 17970924cd68SAdrian Hunter ("Raw SQL clause: ", "Enter a raw SQL WHERE clause", "", "", "", ""), 17980924cd68SAdrian Hunter ) 17990924cd68SAdrian Hunter super(SelectedBranchDialog, self).__init__(glb, title, items, True, parent) 18000924cd68SAdrian Hunter 180176099f98SAdrian Hunter# Event list 180276099f98SAdrian Hunter 180376099f98SAdrian Hunterdef GetEventList(db): 180476099f98SAdrian Hunter events = [] 180576099f98SAdrian Hunter query = QSqlQuery(db) 180676099f98SAdrian Hunter QueryExec(query, "SELECT name FROM selected_events WHERE id > 0 ORDER BY id") 180776099f98SAdrian Hunter while query.next(): 180876099f98SAdrian Hunter events.append(query.value(0)) 180976099f98SAdrian Hunter return events 181076099f98SAdrian Hunter 1811655cb952SAdrian Hunter# Is a table selectable 1812655cb952SAdrian Hunter 1813655cb952SAdrian Hunterdef IsSelectable(db, table): 1814655cb952SAdrian Hunter query = QSqlQuery(db) 1815655cb952SAdrian Hunter try: 1816655cb952SAdrian Hunter QueryExec(query, "SELECT * FROM " + table + " LIMIT 1") 1817655cb952SAdrian Hunter except: 1818655cb952SAdrian Hunter return False 1819655cb952SAdrian Hunter return True 1820655cb952SAdrian Hunter 18218392b74bSAdrian Hunter# SQL data preparation 18228392b74bSAdrian Hunter 18238392b74bSAdrian Hunterdef SQLTableDataPrep(query, count): 18248392b74bSAdrian Hunter data = [] 18258392b74bSAdrian Hunter for i in xrange(count): 18268392b74bSAdrian Hunter data.append(query.value(i)) 18278392b74bSAdrian Hunter return data 18288392b74bSAdrian Hunter 18298392b74bSAdrian Hunter# SQL table data model item 18308392b74bSAdrian Hunter 18318392b74bSAdrian Hunterclass SQLTableItem(): 18328392b74bSAdrian Hunter 18338392b74bSAdrian Hunter def __init__(self, row, data): 18348392b74bSAdrian Hunter self.row = row 18358392b74bSAdrian Hunter self.data = data 18368392b74bSAdrian Hunter 18378392b74bSAdrian Hunter def getData(self, column): 18388392b74bSAdrian Hunter return self.data[column] 18398392b74bSAdrian Hunter 18408392b74bSAdrian Hunter# SQL table data model 18418392b74bSAdrian Hunter 18428392b74bSAdrian Hunterclass SQLTableModel(TableModel): 18438392b74bSAdrian Hunter 18448392b74bSAdrian Hunter progress = Signal(object) 18458392b74bSAdrian Hunter 18468c90fef9SAdrian Hunter def __init__(self, glb, sql, column_headers, parent=None): 18478392b74bSAdrian Hunter super(SQLTableModel, self).__init__(parent) 18488392b74bSAdrian Hunter self.glb = glb 18498392b74bSAdrian Hunter self.more = True 18508392b74bSAdrian Hunter self.populated = 0 18518c90fef9SAdrian Hunter self.column_headers = column_headers 18528c90fef9SAdrian Hunter self.fetcher = SQLFetcher(glb, sql, lambda x, y=len(column_headers): SQLTableDataPrep(x, y), self.AddSample) 18538392b74bSAdrian Hunter self.fetcher.done.connect(self.Update) 18548392b74bSAdrian Hunter self.fetcher.Fetch(glb_chunk_sz) 18558392b74bSAdrian Hunter 18568392b74bSAdrian Hunter def DisplayData(self, item, index): 18578392b74bSAdrian Hunter self.FetchIfNeeded(item.row) 18588392b74bSAdrian Hunter return item.getData(index.column()) 18598392b74bSAdrian Hunter 18608392b74bSAdrian Hunter def AddSample(self, data): 18618392b74bSAdrian Hunter child = SQLTableItem(self.populated, data) 18628392b74bSAdrian Hunter self.child_items.append(child) 18638392b74bSAdrian Hunter self.populated += 1 18648392b74bSAdrian Hunter 18658392b74bSAdrian Hunter def Update(self, fetched): 18668392b74bSAdrian Hunter if not fetched: 18678392b74bSAdrian Hunter self.more = False 18688392b74bSAdrian Hunter self.progress.emit(0) 18698392b74bSAdrian Hunter child_count = self.child_count 18708392b74bSAdrian Hunter count = self.populated - child_count 18718392b74bSAdrian Hunter if count > 0: 18728392b74bSAdrian Hunter parent = QModelIndex() 18738392b74bSAdrian Hunter self.beginInsertRows(parent, child_count, child_count + count - 1) 18748392b74bSAdrian Hunter self.insertRows(child_count, count, parent) 18758392b74bSAdrian Hunter self.child_count += count 18768392b74bSAdrian Hunter self.endInsertRows() 18778392b74bSAdrian Hunter self.progress.emit(self.child_count) 18788392b74bSAdrian Hunter 18798392b74bSAdrian Hunter def FetchMoreRecords(self, count): 18808392b74bSAdrian Hunter current = self.child_count 18818392b74bSAdrian Hunter if self.more: 18828392b74bSAdrian Hunter self.fetcher.Fetch(count) 18838392b74bSAdrian Hunter else: 18848392b74bSAdrian Hunter self.progress.emit(0) 18858392b74bSAdrian Hunter return current 18868392b74bSAdrian Hunter 18878392b74bSAdrian Hunter def HasMoreRecords(self): 18888392b74bSAdrian Hunter return self.more 18898392b74bSAdrian Hunter 18908c90fef9SAdrian Hunter def columnCount(self, parent=None): 18918c90fef9SAdrian Hunter return len(self.column_headers) 18928c90fef9SAdrian Hunter 18938c90fef9SAdrian Hunter def columnHeader(self, column): 18948c90fef9SAdrian Hunter return self.column_headers[column] 18958c90fef9SAdrian Hunter 18968392b74bSAdrian Hunter# SQL automatic table data model 18978392b74bSAdrian Hunter 18988392b74bSAdrian Hunterclass SQLAutoTableModel(SQLTableModel): 18998392b74bSAdrian Hunter 19008392b74bSAdrian Hunter def __init__(self, glb, table_name, parent=None): 19018392b74bSAdrian Hunter sql = "SELECT * FROM " + table_name + " WHERE id > $$last_id$$ ORDER BY id LIMIT " + str(glb_chunk_sz) 19028392b74bSAdrian Hunter if table_name == "comm_threads_view": 19038392b74bSAdrian Hunter # For now, comm_threads_view has no id column 19048392b74bSAdrian Hunter sql = "SELECT * FROM " + table_name + " WHERE comm_id > $$last_id$$ ORDER BY comm_id LIMIT " + str(glb_chunk_sz) 19058c90fef9SAdrian Hunter column_headers = [] 19068392b74bSAdrian Hunter query = QSqlQuery(glb.db) 19078392b74bSAdrian Hunter if glb.dbref.is_sqlite3: 19088392b74bSAdrian Hunter QueryExec(query, "PRAGMA table_info(" + table_name + ")") 19098392b74bSAdrian Hunter while query.next(): 19108c90fef9SAdrian Hunter column_headers.append(query.value(1)) 19118392b74bSAdrian Hunter if table_name == "sqlite_master": 19128392b74bSAdrian Hunter sql = "SELECT * FROM " + table_name 19138392b74bSAdrian Hunter else: 19148392b74bSAdrian Hunter if table_name[:19] == "information_schema.": 19158392b74bSAdrian Hunter sql = "SELECT * FROM " + table_name 19168392b74bSAdrian Hunter select_table_name = table_name[19:] 19178392b74bSAdrian Hunter schema = "information_schema" 19188392b74bSAdrian Hunter else: 19198392b74bSAdrian Hunter select_table_name = table_name 19208392b74bSAdrian Hunter schema = "public" 19218392b74bSAdrian Hunter QueryExec(query, "SELECT column_name FROM information_schema.columns WHERE table_schema = '" + schema + "' and table_name = '" + select_table_name + "'") 19228392b74bSAdrian Hunter while query.next(): 19238c90fef9SAdrian Hunter column_headers.append(query.value(0)) 19248c90fef9SAdrian Hunter super(SQLAutoTableModel, self).__init__(glb, sql, column_headers, parent) 19258392b74bSAdrian Hunter 19268392b74bSAdrian Hunter# Base class for custom ResizeColumnsToContents 19278392b74bSAdrian Hunter 19288392b74bSAdrian Hunterclass ResizeColumnsToContentsBase(QObject): 19298392b74bSAdrian Hunter 19308392b74bSAdrian Hunter def __init__(self, parent=None): 19318392b74bSAdrian Hunter super(ResizeColumnsToContentsBase, self).__init__(parent) 19328392b74bSAdrian Hunter 19338392b74bSAdrian Hunter def ResizeColumnToContents(self, column, n): 19348392b74bSAdrian Hunter # Using the view's resizeColumnToContents() here is extrememly slow 19358392b74bSAdrian Hunter # so implement a crude alternative 19368392b74bSAdrian Hunter font = self.view.font() 19378392b74bSAdrian Hunter metrics = QFontMetrics(font) 19388392b74bSAdrian Hunter max = 0 19398392b74bSAdrian Hunter for row in xrange(n): 19408392b74bSAdrian Hunter val = self.data_model.child_items[row].data[column] 19418392b74bSAdrian Hunter len = metrics.width(str(val) + "MM") 19428392b74bSAdrian Hunter max = len if len > max else max 19438392b74bSAdrian Hunter val = self.data_model.columnHeader(column) 19448392b74bSAdrian Hunter len = metrics.width(str(val) + "MM") 19458392b74bSAdrian Hunter max = len if len > max else max 19468392b74bSAdrian Hunter self.view.setColumnWidth(column, max) 19478392b74bSAdrian Hunter 19488392b74bSAdrian Hunter def ResizeColumnsToContents(self): 19498392b74bSAdrian Hunter n = min(self.data_model.child_count, 100) 19508392b74bSAdrian Hunter if n < 1: 19518392b74bSAdrian Hunter # No data yet, so connect a signal to notify when there is 19528392b74bSAdrian Hunter self.data_model.rowsInserted.connect(self.UpdateColumnWidths) 19538392b74bSAdrian Hunter return 19548392b74bSAdrian Hunter columns = self.data_model.columnCount() 19558392b74bSAdrian Hunter for i in xrange(columns): 19568392b74bSAdrian Hunter self.ResizeColumnToContents(i, n) 19578392b74bSAdrian Hunter 19588392b74bSAdrian Hunter def UpdateColumnWidths(self, *x): 19598392b74bSAdrian Hunter # This only needs to be done once, so disconnect the signal now 19608392b74bSAdrian Hunter self.data_model.rowsInserted.disconnect(self.UpdateColumnWidths) 19618392b74bSAdrian Hunter self.ResizeColumnsToContents() 19628392b74bSAdrian Hunter 19638392b74bSAdrian Hunter# Table window 19648392b74bSAdrian Hunter 19658392b74bSAdrian Hunterclass TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase): 19668392b74bSAdrian Hunter 19678392b74bSAdrian Hunter def __init__(self, glb, table_name, parent=None): 19688392b74bSAdrian Hunter super(TableWindow, self).__init__(parent) 19698392b74bSAdrian Hunter 19708392b74bSAdrian Hunter self.data_model = LookupCreateModel(table_name + " Table", lambda: SQLAutoTableModel(glb, table_name)) 19718392b74bSAdrian Hunter 19728392b74bSAdrian Hunter self.model = QSortFilterProxyModel() 19738392b74bSAdrian Hunter self.model.setSourceModel(self.data_model) 19748392b74bSAdrian Hunter 19758392b74bSAdrian Hunter self.view = QTableView() 19768392b74bSAdrian Hunter self.view.setModel(self.model) 19778392b74bSAdrian Hunter self.view.setEditTriggers(QAbstractItemView.NoEditTriggers) 19788392b74bSAdrian Hunter self.view.verticalHeader().setVisible(False) 19798392b74bSAdrian Hunter self.view.sortByColumn(-1, Qt.AscendingOrder) 19808392b74bSAdrian Hunter self.view.setSortingEnabled(True) 19818392b74bSAdrian Hunter 19828392b74bSAdrian Hunter self.ResizeColumnsToContents() 19838392b74bSAdrian Hunter 19848392b74bSAdrian Hunter self.find_bar = FindBar(self, self, True) 19858392b74bSAdrian Hunter 19868392b74bSAdrian Hunter self.finder = ChildDataItemFinder(self.data_model) 19878392b74bSAdrian Hunter 19888392b74bSAdrian Hunter self.fetch_bar = FetchMoreRecordsBar(self.data_model, self) 19898392b74bSAdrian Hunter 19908392b74bSAdrian Hunter self.vbox = VBox(self.view, self.find_bar.Widget(), self.fetch_bar.Widget()) 19918392b74bSAdrian Hunter 19928392b74bSAdrian Hunter self.setWidget(self.vbox.Widget()) 19938392b74bSAdrian Hunter 19948392b74bSAdrian Hunter AddSubWindow(glb.mainwindow.mdi_area, self, table_name + " Table") 19958392b74bSAdrian Hunter 19968392b74bSAdrian Hunter def Find(self, value, direction, pattern, context): 19978392b74bSAdrian Hunter self.view.setFocus() 19988392b74bSAdrian Hunter self.find_bar.Busy() 19998392b74bSAdrian Hunter self.finder.Find(value, direction, pattern, context, self.FindDone) 20008392b74bSAdrian Hunter 20018392b74bSAdrian Hunter def FindDone(self, row): 20028392b74bSAdrian Hunter self.find_bar.Idle() 20038392b74bSAdrian Hunter if row >= 0: 200435fa1ceeSAdrian Hunter self.view.setCurrentIndex(self.model.mapFromSource(self.data_model.index(row, 0, QModelIndex()))) 20058392b74bSAdrian Hunter else: 20068392b74bSAdrian Hunter self.find_bar.NotFound() 20078392b74bSAdrian Hunter 20088392b74bSAdrian Hunter# Table list 20098392b74bSAdrian Hunter 20108392b74bSAdrian Hunterdef GetTableList(glb): 20118392b74bSAdrian Hunter tables = [] 20128392b74bSAdrian Hunter query = QSqlQuery(glb.db) 20138392b74bSAdrian Hunter if glb.dbref.is_sqlite3: 20148392b74bSAdrian Hunter QueryExec(query, "SELECT name FROM sqlite_master WHERE type IN ( 'table' , 'view' ) ORDER BY name") 20158392b74bSAdrian Hunter else: 20168392b74bSAdrian 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") 20178392b74bSAdrian Hunter while query.next(): 20188392b74bSAdrian Hunter tables.append(query.value(0)) 20198392b74bSAdrian Hunter if glb.dbref.is_sqlite3: 20208392b74bSAdrian Hunter tables.append("sqlite_master") 20218392b74bSAdrian Hunter else: 20228392b74bSAdrian Hunter tables.append("information_schema.tables") 20238392b74bSAdrian Hunter tables.append("information_schema.views") 20248392b74bSAdrian Hunter tables.append("information_schema.columns") 20258392b74bSAdrian Hunter return tables 20268392b74bSAdrian Hunter 20271beb5c7bSAdrian Hunter# Action Definition 20281beb5c7bSAdrian Hunter 20291beb5c7bSAdrian Hunterdef CreateAction(label, tip, callback, parent=None, shortcut=None): 20301beb5c7bSAdrian Hunter action = QAction(label, parent) 20311beb5c7bSAdrian Hunter if shortcut != None: 20321beb5c7bSAdrian Hunter action.setShortcuts(shortcut) 20331beb5c7bSAdrian Hunter action.setStatusTip(tip) 20341beb5c7bSAdrian Hunter action.triggered.connect(callback) 20351beb5c7bSAdrian Hunter return action 20361beb5c7bSAdrian Hunter 20371beb5c7bSAdrian Hunter# Typical application actions 20381beb5c7bSAdrian Hunter 20391beb5c7bSAdrian Hunterdef CreateExitAction(app, parent=None): 20401beb5c7bSAdrian Hunter return CreateAction("&Quit", "Exit the application", app.closeAllWindows, parent, QKeySequence.Quit) 20411beb5c7bSAdrian Hunter 20421beb5c7bSAdrian Hunter# Typical MDI actions 20431beb5c7bSAdrian Hunter 20441beb5c7bSAdrian Hunterdef CreateCloseActiveWindowAction(mdi_area): 20451beb5c7bSAdrian Hunter return CreateAction("Cl&ose", "Close the active window", mdi_area.closeActiveSubWindow, mdi_area) 20461beb5c7bSAdrian Hunter 20471beb5c7bSAdrian Hunterdef CreateCloseAllWindowsAction(mdi_area): 20481beb5c7bSAdrian Hunter return CreateAction("Close &All", "Close all the windows", mdi_area.closeAllSubWindows, mdi_area) 20491beb5c7bSAdrian Hunter 20501beb5c7bSAdrian Hunterdef CreateTileWindowsAction(mdi_area): 20511beb5c7bSAdrian Hunter return CreateAction("&Tile", "Tile the windows", mdi_area.tileSubWindows, mdi_area) 20521beb5c7bSAdrian Hunter 20531beb5c7bSAdrian Hunterdef CreateCascadeWindowsAction(mdi_area): 20541beb5c7bSAdrian Hunter return CreateAction("&Cascade", "Cascade the windows", mdi_area.cascadeSubWindows, mdi_area) 20551beb5c7bSAdrian Hunter 20561beb5c7bSAdrian Hunterdef CreateNextWindowAction(mdi_area): 20571beb5c7bSAdrian Hunter return CreateAction("Ne&xt", "Move the focus to the next window", mdi_area.activateNextSubWindow, mdi_area, QKeySequence.NextChild) 20581beb5c7bSAdrian Hunter 20591beb5c7bSAdrian Hunterdef CreatePreviousWindowAction(mdi_area): 20601beb5c7bSAdrian Hunter return CreateAction("Pre&vious", "Move the focus to the previous window", mdi_area.activatePreviousSubWindow, mdi_area, QKeySequence.PreviousChild) 20611beb5c7bSAdrian Hunter 20621beb5c7bSAdrian Hunter# Typical MDI window menu 20631beb5c7bSAdrian Hunter 20641beb5c7bSAdrian Hunterclass WindowMenu(): 20651beb5c7bSAdrian Hunter 20661beb5c7bSAdrian Hunter def __init__(self, mdi_area, menu): 20671beb5c7bSAdrian Hunter self.mdi_area = mdi_area 20681beb5c7bSAdrian Hunter self.window_menu = menu.addMenu("&Windows") 20691beb5c7bSAdrian Hunter self.close_active_window = CreateCloseActiveWindowAction(mdi_area) 20701beb5c7bSAdrian Hunter self.close_all_windows = CreateCloseAllWindowsAction(mdi_area) 20711beb5c7bSAdrian Hunter self.tile_windows = CreateTileWindowsAction(mdi_area) 20721beb5c7bSAdrian Hunter self.cascade_windows = CreateCascadeWindowsAction(mdi_area) 20731beb5c7bSAdrian Hunter self.next_window = CreateNextWindowAction(mdi_area) 20741beb5c7bSAdrian Hunter self.previous_window = CreatePreviousWindowAction(mdi_area) 20751beb5c7bSAdrian Hunter self.window_menu.aboutToShow.connect(self.Update) 20761beb5c7bSAdrian Hunter 20771beb5c7bSAdrian Hunter def Update(self): 20781beb5c7bSAdrian Hunter self.window_menu.clear() 20791beb5c7bSAdrian Hunter sub_window_count = len(self.mdi_area.subWindowList()) 20801beb5c7bSAdrian Hunter have_sub_windows = sub_window_count != 0 20811beb5c7bSAdrian Hunter self.close_active_window.setEnabled(have_sub_windows) 20821beb5c7bSAdrian Hunter self.close_all_windows.setEnabled(have_sub_windows) 20831beb5c7bSAdrian Hunter self.tile_windows.setEnabled(have_sub_windows) 20841beb5c7bSAdrian Hunter self.cascade_windows.setEnabled(have_sub_windows) 20851beb5c7bSAdrian Hunter self.next_window.setEnabled(have_sub_windows) 20861beb5c7bSAdrian Hunter self.previous_window.setEnabled(have_sub_windows) 20871beb5c7bSAdrian Hunter self.window_menu.addAction(self.close_active_window) 20881beb5c7bSAdrian Hunter self.window_menu.addAction(self.close_all_windows) 20891beb5c7bSAdrian Hunter self.window_menu.addSeparator() 20901beb5c7bSAdrian Hunter self.window_menu.addAction(self.tile_windows) 20911beb5c7bSAdrian Hunter self.window_menu.addAction(self.cascade_windows) 20921beb5c7bSAdrian Hunter self.window_menu.addSeparator() 20931beb5c7bSAdrian Hunter self.window_menu.addAction(self.next_window) 20941beb5c7bSAdrian Hunter self.window_menu.addAction(self.previous_window) 20951beb5c7bSAdrian Hunter if sub_window_count == 0: 20961beb5c7bSAdrian Hunter return 20971beb5c7bSAdrian Hunter self.window_menu.addSeparator() 20981beb5c7bSAdrian Hunter nr = 1 20991beb5c7bSAdrian Hunter for sub_window in self.mdi_area.subWindowList(): 21001beb5c7bSAdrian Hunter label = str(nr) + " " + sub_window.name 21011beb5c7bSAdrian Hunter if nr < 10: 21021beb5c7bSAdrian Hunter label = "&" + label 21031beb5c7bSAdrian Hunter action = self.window_menu.addAction(label) 21041beb5c7bSAdrian Hunter action.setCheckable(True) 21051beb5c7bSAdrian Hunter action.setChecked(sub_window == self.mdi_area.activeSubWindow()) 21061beb5c7bSAdrian Hunter action.triggered.connect(lambda x=nr: self.setActiveSubWindow(x)) 21071beb5c7bSAdrian Hunter self.window_menu.addAction(action) 21081beb5c7bSAdrian Hunter nr += 1 21091beb5c7bSAdrian Hunter 21101beb5c7bSAdrian Hunter def setActiveSubWindow(self, nr): 21111beb5c7bSAdrian Hunter self.mdi_area.setActiveSubWindow(self.mdi_area.subWindowList()[nr - 1]) 21121beb5c7bSAdrian Hunter 211365b24292SAdrian Hunter# Help text 211465b24292SAdrian Hunter 211565b24292SAdrian Hunterglb_help_text = """ 211665b24292SAdrian Hunter<h1>Contents</h1> 211765b24292SAdrian Hunter<style> 211865b24292SAdrian Hunterp.c1 { 211965b24292SAdrian Hunter text-indent: 40px; 212065b24292SAdrian Hunter} 212165b24292SAdrian Hunterp.c2 { 212265b24292SAdrian Hunter text-indent: 80px; 212365b24292SAdrian Hunter} 212465b24292SAdrian Hunter} 212565b24292SAdrian Hunter</style> 212665b24292SAdrian Hunter<p class=c1><a href=#reports>1. Reports</a></p> 212765b24292SAdrian Hunter<p class=c2><a href=#callgraph>1.1 Context-Sensitive Call Graph</a></p> 212865b24292SAdrian Hunter<p class=c2><a href=#allbranches>1.2 All branches</a></p> 212965b24292SAdrian Hunter<p class=c2><a href=#selectedbranches>1.3 Selected branches</a></p> 213065b24292SAdrian Hunter<p class=c1><a href=#tables>2. Tables</a></p> 213165b24292SAdrian Hunter<h1 id=reports>1. Reports</h1> 213265b24292SAdrian Hunter<h2 id=callgraph>1.1 Context-Sensitive Call Graph</h2> 213365b24292SAdrian HunterThe result is a GUI window with a tree representing a context-sensitive 213465b24292SAdrian Huntercall-graph. Expanding a couple of levels of the tree and adjusting column 213565b24292SAdrian Hunterwidths to suit will display something like: 213665b24292SAdrian Hunter<pre> 213765b24292SAdrian Hunter Call Graph: pt_example 213865b24292SAdrian HunterCall Path Object Count Time(ns) Time(%) Branch Count Branch Count(%) 213965b24292SAdrian Hunterv- ls 214065b24292SAdrian Hunter v- 2638:2638 214165b24292SAdrian Hunter v- _start ld-2.19.so 1 10074071 100.0 211135 100.0 214265b24292SAdrian Hunter |- unknown unknown 1 13198 0.1 1 0.0 214365b24292SAdrian Hunter >- _dl_start ld-2.19.so 1 1400980 13.9 19637 9.3 214465b24292SAdrian Hunter >- _d_linit_internal ld-2.19.so 1 448152 4.4 11094 5.3 214565b24292SAdrian Hunter v-__libc_start_main@plt ls 1 8211741 81.5 180397 85.4 214665b24292SAdrian Hunter >- _dl_fixup ld-2.19.so 1 7607 0.1 108 0.1 214765b24292SAdrian Hunter >- __cxa_atexit libc-2.19.so 1 11737 0.1 10 0.0 214865b24292SAdrian Hunter >- __libc_csu_init ls 1 10354 0.1 10 0.0 214965b24292SAdrian Hunter |- _setjmp libc-2.19.so 1 0 0.0 4 0.0 215065b24292SAdrian Hunter v- main ls 1 8182043 99.6 180254 99.9 215165b24292SAdrian Hunter</pre> 215265b24292SAdrian Hunter<h3>Points to note:</h3> 215365b24292SAdrian Hunter<ul> 215465b24292SAdrian Hunter<li>The top level is a command name (comm)</li> 215565b24292SAdrian Hunter<li>The next level is a thread (pid:tid)</li> 215665b24292SAdrian Hunter<li>Subsequent levels are functions</li> 215765b24292SAdrian Hunter<li>'Count' is the number of calls</li> 215865b24292SAdrian Hunter<li>'Time' is the elapsed time until the function returns</li> 215965b24292SAdrian Hunter<li>Percentages are relative to the level above</li> 216065b24292SAdrian Hunter<li>'Branch Count' is the total number of branches for that function and all functions that it calls 216165b24292SAdrian Hunter</ul> 216265b24292SAdrian Hunter<h3>Find</h3> 216365b24292SAdrian HunterCtrl-F displays a Find bar which finds function names by either an exact match or a pattern match. 216465b24292SAdrian HunterThe pattern matching symbols are ? for any character and * for zero or more characters. 216565b24292SAdrian Hunter<h2 id=allbranches>1.2 All branches</h2> 216665b24292SAdrian HunterThe All branches report displays all branches in chronological order. 216765b24292SAdrian HunterNot all data is fetched immediately. More records can be fetched using the Fetch bar provided. 216865b24292SAdrian Hunter<h3>Disassembly</h3> 216965b24292SAdrian HunterOpen a branch to display disassembly. This only works if: 217065b24292SAdrian Hunter<ol> 217165b24292SAdrian Hunter<li>The disassembler is available. Currently, only Intel XED is supported - see <a href=#xed>Intel XED Setup</a></li> 217265b24292SAdrian Hunter<li>The object code is available. Currently, only the perf build ID cache is searched for object code. 217365b24292SAdrian HunterThe default directory ~/.debug can be overridden by setting environment variable PERF_BUILDID_DIR. 217465b24292SAdrian HunterOne exception is kcore where the DSO long name is used (refer dsos_view on the Tables menu), 217565b24292SAdrian Hunteror alternatively, set environment variable PERF_KCORE to the kcore file name.</li> 217665b24292SAdrian Hunter</ol> 217765b24292SAdrian Hunter<h4 id=xed>Intel XED Setup</h4> 217865b24292SAdrian HunterTo use Intel XED, libxed.so must be present. To build and install libxed.so: 217965b24292SAdrian Hunter<pre> 218065b24292SAdrian Huntergit clone https://github.com/intelxed/mbuild.git mbuild 218165b24292SAdrian Huntergit clone https://github.com/intelxed/xed 218265b24292SAdrian Huntercd xed 218365b24292SAdrian Hunter./mfile.py --share 218465b24292SAdrian Huntersudo ./mfile.py --prefix=/usr/local install 218565b24292SAdrian Huntersudo ldconfig 218665b24292SAdrian Hunter</pre> 218765b24292SAdrian Hunter<h3>Find</h3> 218865b24292SAdrian HunterCtrl-F displays a Find bar which finds substrings by either an exact match or a regular expression match. 218965b24292SAdrian HunterRefer to Python documentation for the regular expression syntax. 219065b24292SAdrian HunterAll columns are searched, but only currently fetched rows are searched. 219165b24292SAdrian Hunter<h2 id=selectedbranches>1.3 Selected branches</h2> 219265b24292SAdrian HunterThis is the same as the <a href=#allbranches>All branches</a> report but with the data reduced 219365b24292SAdrian Hunterby various selection criteria. A dialog box displays available criteria which are AND'ed together. 219465b24292SAdrian Hunter<h3>1.3.1 Time ranges</h3> 219565b24292SAdrian HunterThe time ranges hint text shows the total time range. Relative time ranges can also be entered in 219665b24292SAdrian Hunterms, us or ns. Also, negative values are relative to the end of trace. Examples: 219765b24292SAdrian Hunter<pre> 219865b24292SAdrian Hunter 81073085947329-81073085958238 From 81073085947329 to 81073085958238 219965b24292SAdrian Hunter 100us-200us From 100us to 200us 220065b24292SAdrian Hunter 10ms- From 10ms to the end 220165b24292SAdrian Hunter -100ns The first 100ns 220265b24292SAdrian Hunter -10ms- The last 10ms 220365b24292SAdrian Hunter</pre> 220465b24292SAdrian HunterN.B. Due to the granularity of timestamps, there could be no branches in any given time range. 220565b24292SAdrian Hunter<h1 id=tables>2. Tables</h1> 220665b24292SAdrian HunterThe Tables menu shows all tables and views in the database. Most tables have an associated view 220765b24292SAdrian Hunterwhich displays the information in a more friendly way. Not all data for large tables is fetched 220865b24292SAdrian Hunterimmediately. More records can be fetched using the Fetch bar provided. Columns can be sorted, 220965b24292SAdrian Hunterbut that can be slow for large tables. 221065b24292SAdrian Hunter<p>There are also tables of database meta-information. 221165b24292SAdrian HunterFor SQLite3 databases, the sqlite_master table is included. 221265b24292SAdrian HunterFor PostgreSQL databases, information_schema.tables/views/columns are included. 221365b24292SAdrian Hunter<h3>Find</h3> 221465b24292SAdrian HunterCtrl-F displays a Find bar which finds substrings by either an exact match or a regular expression match. 221565b24292SAdrian HunterRefer to Python documentation for the regular expression syntax. 221665b24292SAdrian HunterAll columns are searched, but only currently fetched rows are searched. 221735fa1ceeSAdrian Hunter<p>N.B. Results are found in id order, so if the table is re-ordered, find-next and find-previous 221835fa1ceeSAdrian Hunterwill go to the next/previous result in id order, instead of display order. 221965b24292SAdrian Hunter""" 222065b24292SAdrian Hunter 222165b24292SAdrian Hunter# Help window 222265b24292SAdrian Hunter 222365b24292SAdrian Hunterclass HelpWindow(QMdiSubWindow): 222465b24292SAdrian Hunter 222565b24292SAdrian Hunter def __init__(self, glb, parent=None): 222665b24292SAdrian Hunter super(HelpWindow, self).__init__(parent) 222765b24292SAdrian Hunter 222865b24292SAdrian Hunter self.text = QTextBrowser() 222965b24292SAdrian Hunter self.text.setHtml(glb_help_text) 223065b24292SAdrian Hunter self.text.setReadOnly(True) 223165b24292SAdrian Hunter self.text.setOpenExternalLinks(True) 223265b24292SAdrian Hunter 223365b24292SAdrian Hunter self.setWidget(self.text) 223465b24292SAdrian Hunter 223565b24292SAdrian Hunter AddSubWindow(glb.mainwindow.mdi_area, self, "Exported SQL Viewer Help") 223665b24292SAdrian Hunter 223765b24292SAdrian Hunter# Main window that only displays the help text 223865b24292SAdrian Hunter 223965b24292SAdrian Hunterclass HelpOnlyWindow(QMainWindow): 224065b24292SAdrian Hunter 224165b24292SAdrian Hunter def __init__(self, parent=None): 224265b24292SAdrian Hunter super(HelpOnlyWindow, self).__init__(parent) 224365b24292SAdrian Hunter 224465b24292SAdrian Hunter self.setMinimumSize(200, 100) 224565b24292SAdrian Hunter self.resize(800, 600) 224665b24292SAdrian Hunter self.setWindowTitle("Exported SQL Viewer Help") 224765b24292SAdrian Hunter self.setWindowIcon(self.style().standardIcon(QStyle.SP_MessageBoxInformation)) 224865b24292SAdrian Hunter 224965b24292SAdrian Hunter self.text = QTextBrowser() 225065b24292SAdrian Hunter self.text.setHtml(glb_help_text) 225165b24292SAdrian Hunter self.text.setReadOnly(True) 225265b24292SAdrian Hunter self.text.setOpenExternalLinks(True) 225365b24292SAdrian Hunter 225465b24292SAdrian Hunter self.setCentralWidget(self.text) 225565b24292SAdrian Hunter 225682f68e28SAdrian Hunter# Font resize 225782f68e28SAdrian Hunter 225882f68e28SAdrian Hunterdef ResizeFont(widget, diff): 225982f68e28SAdrian Hunter font = widget.font() 226082f68e28SAdrian Hunter sz = font.pointSize() 226182f68e28SAdrian Hunter font.setPointSize(sz + diff) 226282f68e28SAdrian Hunter widget.setFont(font) 226382f68e28SAdrian Hunter 226482f68e28SAdrian Hunterdef ShrinkFont(widget): 226582f68e28SAdrian Hunter ResizeFont(widget, -1) 226682f68e28SAdrian Hunter 226782f68e28SAdrian Hunterdef EnlargeFont(widget): 226882f68e28SAdrian Hunter ResizeFont(widget, 1) 226982f68e28SAdrian Hunter 22701beb5c7bSAdrian Hunter# Unique name for sub-windows 22711beb5c7bSAdrian Hunter 22721beb5c7bSAdrian Hunterdef NumberedWindowName(name, nr): 22731beb5c7bSAdrian Hunter if nr > 1: 22741beb5c7bSAdrian Hunter name += " <" + str(nr) + ">" 22751beb5c7bSAdrian Hunter return name 22761beb5c7bSAdrian Hunter 22771beb5c7bSAdrian Hunterdef UniqueSubWindowName(mdi_area, name): 22781beb5c7bSAdrian Hunter nr = 1 22791beb5c7bSAdrian Hunter while True: 22801beb5c7bSAdrian Hunter unique_name = NumberedWindowName(name, nr) 22811beb5c7bSAdrian Hunter ok = True 22821beb5c7bSAdrian Hunter for sub_window in mdi_area.subWindowList(): 22831beb5c7bSAdrian Hunter if sub_window.name == unique_name: 22841beb5c7bSAdrian Hunter ok = False 22851beb5c7bSAdrian Hunter break 22861beb5c7bSAdrian Hunter if ok: 22871beb5c7bSAdrian Hunter return unique_name 22881beb5c7bSAdrian Hunter nr += 1 22891beb5c7bSAdrian Hunter 22901beb5c7bSAdrian Hunter# Add a sub-window 22911beb5c7bSAdrian Hunter 22921beb5c7bSAdrian Hunterdef AddSubWindow(mdi_area, sub_window, name): 22931beb5c7bSAdrian Hunter unique_name = UniqueSubWindowName(mdi_area, name) 22941beb5c7bSAdrian Hunter sub_window.setMinimumSize(200, 100) 22951beb5c7bSAdrian Hunter sub_window.resize(800, 600) 22961beb5c7bSAdrian Hunter sub_window.setWindowTitle(unique_name) 22971beb5c7bSAdrian Hunter sub_window.setAttribute(Qt.WA_DeleteOnClose) 22981beb5c7bSAdrian Hunter sub_window.setWindowIcon(sub_window.style().standardIcon(QStyle.SP_FileIcon)) 22991beb5c7bSAdrian Hunter sub_window.name = unique_name 23001beb5c7bSAdrian Hunter mdi_area.addSubWindow(sub_window) 23011beb5c7bSAdrian Hunter sub_window.show() 23021beb5c7bSAdrian Hunter 2303031c2a00SAdrian Hunter# Main window 2304031c2a00SAdrian Hunter 2305031c2a00SAdrian Hunterclass MainWindow(QMainWindow): 2306031c2a00SAdrian Hunter 2307031c2a00SAdrian Hunter def __init__(self, glb, parent=None): 2308031c2a00SAdrian Hunter super(MainWindow, self).__init__(parent) 2309031c2a00SAdrian Hunter 2310031c2a00SAdrian Hunter self.glb = glb 2311031c2a00SAdrian Hunter 23121beb5c7bSAdrian Hunter self.setWindowTitle("Exported SQL Viewer: " + glb.dbname) 2313031c2a00SAdrian Hunter self.setWindowIcon(self.style().standardIcon(QStyle.SP_ComputerIcon)) 2314031c2a00SAdrian Hunter self.setMinimumSize(200, 100) 2315031c2a00SAdrian Hunter 23161beb5c7bSAdrian Hunter self.mdi_area = QMdiArea() 23171beb5c7bSAdrian Hunter self.mdi_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) 23181beb5c7bSAdrian Hunter self.mdi_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) 2319031c2a00SAdrian Hunter 23201beb5c7bSAdrian Hunter self.setCentralWidget(self.mdi_area) 2321031c2a00SAdrian Hunter 23221beb5c7bSAdrian Hunter menu = self.menuBar() 2323031c2a00SAdrian Hunter 23241beb5c7bSAdrian Hunter file_menu = menu.addMenu("&File") 23251beb5c7bSAdrian Hunter file_menu.addAction(CreateExitAction(glb.app, self)) 23261beb5c7bSAdrian Hunter 2327ebd70c7dSAdrian Hunter edit_menu = menu.addMenu("&Edit") 2328ebd70c7dSAdrian Hunter edit_menu.addAction(CreateAction("&Find...", "Find items", self.Find, self, QKeySequence.Find)) 23298392b74bSAdrian Hunter edit_menu.addAction(CreateAction("Fetch &more records...", "Fetch more records", self.FetchMoreRecords, self, [QKeySequence(Qt.Key_F8)])) 233082f68e28SAdrian Hunter edit_menu.addAction(CreateAction("&Shrink Font", "Make text smaller", self.ShrinkFont, self, [QKeySequence("Ctrl+-")])) 233182f68e28SAdrian Hunter edit_menu.addAction(CreateAction("&Enlarge Font", "Make text bigger", self.EnlargeFont, self, [QKeySequence("Ctrl++")])) 2332ebd70c7dSAdrian Hunter 23331beb5c7bSAdrian Hunter reports_menu = menu.addMenu("&Reports") 2334655cb952SAdrian Hunter if IsSelectable(glb.db, "calls"): 23351beb5c7bSAdrian Hunter reports_menu.addAction(CreateAction("Context-Sensitive Call &Graph", "Create a new window containing a context-sensitive call graph", self.NewCallGraph, self)) 23361beb5c7bSAdrian Hunter 233776099f98SAdrian Hunter self.EventMenu(GetEventList(glb.db), reports_menu) 233876099f98SAdrian Hunter 23398392b74bSAdrian Hunter self.TableMenu(GetTableList(glb), menu) 23408392b74bSAdrian Hunter 23411beb5c7bSAdrian Hunter self.window_menu = WindowMenu(self.mdi_area, menu) 23421beb5c7bSAdrian Hunter 234365b24292SAdrian Hunter help_menu = menu.addMenu("&Help") 234465b24292SAdrian Hunter help_menu.addAction(CreateAction("&Exported SQL Viewer Help", "Helpful information", self.Help, self, QKeySequence.HelpContents)) 234565b24292SAdrian Hunter 2346ebd70c7dSAdrian Hunter def Find(self): 2347ebd70c7dSAdrian Hunter win = self.mdi_area.activeSubWindow() 2348ebd70c7dSAdrian Hunter if win: 2349ebd70c7dSAdrian Hunter try: 2350ebd70c7dSAdrian Hunter win.find_bar.Activate() 2351ebd70c7dSAdrian Hunter except: 2352ebd70c7dSAdrian Hunter pass 2353ebd70c7dSAdrian Hunter 23548392b74bSAdrian Hunter def FetchMoreRecords(self): 23558392b74bSAdrian Hunter win = self.mdi_area.activeSubWindow() 23568392b74bSAdrian Hunter if win: 23578392b74bSAdrian Hunter try: 23588392b74bSAdrian Hunter win.fetch_bar.Activate() 23598392b74bSAdrian Hunter except: 23608392b74bSAdrian Hunter pass 23618392b74bSAdrian Hunter 236282f68e28SAdrian Hunter def ShrinkFont(self): 236382f68e28SAdrian Hunter win = self.mdi_area.activeSubWindow() 236482f68e28SAdrian Hunter ShrinkFont(win.view) 236582f68e28SAdrian Hunter 236682f68e28SAdrian Hunter def EnlargeFont(self): 236782f68e28SAdrian Hunter win = self.mdi_area.activeSubWindow() 236882f68e28SAdrian Hunter EnlargeFont(win.view) 236982f68e28SAdrian Hunter 237076099f98SAdrian Hunter def EventMenu(self, events, reports_menu): 237176099f98SAdrian Hunter branches_events = 0 237276099f98SAdrian Hunter for event in events: 237376099f98SAdrian Hunter event = event.split(":")[0] 237476099f98SAdrian Hunter if event == "branches": 237576099f98SAdrian Hunter branches_events += 1 237676099f98SAdrian Hunter dbid = 0 237776099f98SAdrian Hunter for event in events: 237876099f98SAdrian Hunter dbid += 1 237976099f98SAdrian Hunter event = event.split(":")[0] 238076099f98SAdrian Hunter if event == "branches": 238176099f98SAdrian Hunter label = "All branches" if branches_events == 1 else "All branches " + "(id=" + dbid + ")" 238276099f98SAdrian Hunter reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewBranchView(x), self)) 2383210cf1f9SAdrian Hunter label = "Selected branches" if branches_events == 1 else "Selected branches " + "(id=" + dbid + ")" 2384210cf1f9SAdrian Hunter reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewSelectedBranchView(x), self)) 238576099f98SAdrian Hunter 23868392b74bSAdrian Hunter def TableMenu(self, tables, menu): 23878392b74bSAdrian Hunter table_menu = menu.addMenu("&Tables") 23888392b74bSAdrian Hunter for table in tables: 23898392b74bSAdrian Hunter table_menu.addAction(CreateAction(table, "Create a new window containing a table view", lambda t=table: self.NewTableView(t), self)) 23908392b74bSAdrian Hunter 23911beb5c7bSAdrian Hunter def NewCallGraph(self): 23921beb5c7bSAdrian Hunter CallGraphWindow(self.glb, self) 2393031c2a00SAdrian Hunter 239476099f98SAdrian Hunter def NewBranchView(self, event_id): 2395*0bf0947aSAdrian Hunter BranchWindow(self.glb, event_id, "", ReportVars(), self) 239676099f98SAdrian Hunter 2397210cf1f9SAdrian Hunter def NewSelectedBranchView(self, event_id): 2398210cf1f9SAdrian Hunter dialog = SelectedBranchDialog(self.glb, self) 2399210cf1f9SAdrian Hunter ret = dialog.exec_() 2400210cf1f9SAdrian Hunter if ret: 2401*0bf0947aSAdrian Hunter BranchWindow(self.glb, event_id, dialog.name, dialog.report_vars, self) 2402210cf1f9SAdrian Hunter 24038392b74bSAdrian Hunter def NewTableView(self, table_name): 24048392b74bSAdrian Hunter TableWindow(self.glb, table_name, self) 24058392b74bSAdrian Hunter 240665b24292SAdrian Hunter def Help(self): 240765b24292SAdrian Hunter HelpWindow(self.glb, self) 240865b24292SAdrian Hunter 240976099f98SAdrian Hunter# XED Disassembler 241076099f98SAdrian Hunter 241176099f98SAdrian Hunterclass xed_state_t(Structure): 241276099f98SAdrian Hunter 241376099f98SAdrian Hunter _fields_ = [ 241476099f98SAdrian Hunter ("mode", c_int), 241576099f98SAdrian Hunter ("width", c_int) 241676099f98SAdrian Hunter ] 241776099f98SAdrian Hunter 241876099f98SAdrian Hunterclass XEDInstruction(): 241976099f98SAdrian Hunter 242076099f98SAdrian Hunter def __init__(self, libxed): 242176099f98SAdrian Hunter # Current xed_decoded_inst_t structure is 192 bytes. Use 512 to allow for future expansion 242276099f98SAdrian Hunter xedd_t = c_byte * 512 242376099f98SAdrian Hunter self.xedd = xedd_t() 242476099f98SAdrian Hunter self.xedp = addressof(self.xedd) 242576099f98SAdrian Hunter libxed.xed_decoded_inst_zero(self.xedp) 242676099f98SAdrian Hunter self.state = xed_state_t() 242776099f98SAdrian Hunter self.statep = addressof(self.state) 242876099f98SAdrian Hunter # Buffer for disassembled instruction text 242976099f98SAdrian Hunter self.buffer = create_string_buffer(256) 243076099f98SAdrian Hunter self.bufferp = addressof(self.buffer) 243176099f98SAdrian Hunter 243276099f98SAdrian Hunterclass LibXED(): 243376099f98SAdrian Hunter 243476099f98SAdrian Hunter def __init__(self): 24355ed4419dSAdrian Hunter try: 243676099f98SAdrian Hunter self.libxed = CDLL("libxed.so") 24375ed4419dSAdrian Hunter except: 24385ed4419dSAdrian Hunter self.libxed = None 24395ed4419dSAdrian Hunter if not self.libxed: 24405ed4419dSAdrian Hunter self.libxed = CDLL("/usr/local/lib/libxed.so") 244176099f98SAdrian Hunter 244276099f98SAdrian Hunter self.xed_tables_init = self.libxed.xed_tables_init 244376099f98SAdrian Hunter self.xed_tables_init.restype = None 244476099f98SAdrian Hunter self.xed_tables_init.argtypes = [] 244576099f98SAdrian Hunter 244676099f98SAdrian Hunter self.xed_decoded_inst_zero = self.libxed.xed_decoded_inst_zero 244776099f98SAdrian Hunter self.xed_decoded_inst_zero.restype = None 244876099f98SAdrian Hunter self.xed_decoded_inst_zero.argtypes = [ c_void_p ] 244976099f98SAdrian Hunter 245076099f98SAdrian Hunter self.xed_operand_values_set_mode = self.libxed.xed_operand_values_set_mode 245176099f98SAdrian Hunter self.xed_operand_values_set_mode.restype = None 245276099f98SAdrian Hunter self.xed_operand_values_set_mode.argtypes = [ c_void_p, c_void_p ] 245376099f98SAdrian Hunter 245476099f98SAdrian Hunter self.xed_decoded_inst_zero_keep_mode = self.libxed.xed_decoded_inst_zero_keep_mode 245576099f98SAdrian Hunter self.xed_decoded_inst_zero_keep_mode.restype = None 245676099f98SAdrian Hunter self.xed_decoded_inst_zero_keep_mode.argtypes = [ c_void_p ] 245776099f98SAdrian Hunter 245876099f98SAdrian Hunter self.xed_decode = self.libxed.xed_decode 245976099f98SAdrian Hunter self.xed_decode.restype = c_int 246076099f98SAdrian Hunter self.xed_decode.argtypes = [ c_void_p, c_void_p, c_uint ] 246176099f98SAdrian Hunter 246276099f98SAdrian Hunter self.xed_format_context = self.libxed.xed_format_context 246376099f98SAdrian Hunter self.xed_format_context.restype = c_uint 246476099f98SAdrian Hunter self.xed_format_context.argtypes = [ c_int, c_void_p, c_void_p, c_int, c_ulonglong, c_void_p, c_void_p ] 246576099f98SAdrian Hunter 246676099f98SAdrian Hunter self.xed_tables_init() 246776099f98SAdrian Hunter 246876099f98SAdrian Hunter def Instruction(self): 246976099f98SAdrian Hunter return XEDInstruction(self) 247076099f98SAdrian Hunter 247176099f98SAdrian Hunter def SetMode(self, inst, mode): 247276099f98SAdrian Hunter if mode: 247376099f98SAdrian Hunter inst.state.mode = 4 # 32-bit 247476099f98SAdrian Hunter inst.state.width = 4 # 4 bytes 247576099f98SAdrian Hunter else: 247676099f98SAdrian Hunter inst.state.mode = 1 # 64-bit 247776099f98SAdrian Hunter inst.state.width = 8 # 8 bytes 247876099f98SAdrian Hunter self.xed_operand_values_set_mode(inst.xedp, inst.statep) 247976099f98SAdrian Hunter 248076099f98SAdrian Hunter def DisassembleOne(self, inst, bytes_ptr, bytes_cnt, ip): 248176099f98SAdrian Hunter self.xed_decoded_inst_zero_keep_mode(inst.xedp) 248276099f98SAdrian Hunter err = self.xed_decode(inst.xedp, bytes_ptr, bytes_cnt) 248376099f98SAdrian Hunter if err: 248476099f98SAdrian Hunter return 0, "" 248576099f98SAdrian Hunter # Use AT&T mode (2), alternative is Intel (3) 248676099f98SAdrian Hunter ok = self.xed_format_context(2, inst.xedp, inst.bufferp, sizeof(inst.buffer), ip, 0, 0) 248776099f98SAdrian Hunter if not ok: 248876099f98SAdrian Hunter return 0, "" 248976099f98SAdrian Hunter # Return instruction length and the disassembled instruction text 249076099f98SAdrian Hunter # For now, assume the length is in byte 166 249176099f98SAdrian Hunter return inst.xedd[166], inst.buffer.value 249276099f98SAdrian Hunter 249376099f98SAdrian Hunterdef TryOpen(file_name): 249476099f98SAdrian Hunter try: 249576099f98SAdrian Hunter return open(file_name, "rb") 249676099f98SAdrian Hunter except: 249776099f98SAdrian Hunter return None 249876099f98SAdrian Hunter 249976099f98SAdrian Hunterdef Is64Bit(f): 250076099f98SAdrian Hunter result = sizeof(c_void_p) 250176099f98SAdrian Hunter # ELF support only 250276099f98SAdrian Hunter pos = f.tell() 250376099f98SAdrian Hunter f.seek(0) 250476099f98SAdrian Hunter header = f.read(7) 250576099f98SAdrian Hunter f.seek(pos) 250676099f98SAdrian Hunter magic = header[0:4] 250776099f98SAdrian Hunter eclass = ord(header[4]) 250876099f98SAdrian Hunter encoding = ord(header[5]) 250976099f98SAdrian Hunter version = ord(header[6]) 251076099f98SAdrian Hunter if magic == chr(127) + "ELF" and eclass > 0 and eclass < 3 and encoding > 0 and encoding < 3 and version == 1: 251176099f98SAdrian Hunter result = True if eclass == 2 else False 251276099f98SAdrian Hunter return result 251376099f98SAdrian Hunter 2514031c2a00SAdrian Hunter# Global data 2515031c2a00SAdrian Hunter 2516031c2a00SAdrian Hunterclass Glb(): 2517031c2a00SAdrian Hunter 2518031c2a00SAdrian Hunter def __init__(self, dbref, db, dbname): 2519031c2a00SAdrian Hunter self.dbref = dbref 2520031c2a00SAdrian Hunter self.db = db 2521031c2a00SAdrian Hunter self.dbname = dbname 252276099f98SAdrian Hunter self.home_dir = os.path.expanduser("~") 252376099f98SAdrian Hunter self.buildid_dir = os.getenv("PERF_BUILDID_DIR") 252476099f98SAdrian Hunter if self.buildid_dir: 252576099f98SAdrian Hunter self.buildid_dir += "/.build-id/" 252676099f98SAdrian Hunter else: 252776099f98SAdrian Hunter self.buildid_dir = self.home_dir + "/.debug/.build-id/" 2528031c2a00SAdrian Hunter self.app = None 2529031c2a00SAdrian Hunter self.mainwindow = None 25308392b74bSAdrian Hunter self.instances_to_shutdown_on_exit = weakref.WeakSet() 253176099f98SAdrian Hunter try: 253276099f98SAdrian Hunter self.disassembler = LibXED() 253376099f98SAdrian Hunter self.have_disassembler = True 253476099f98SAdrian Hunter except: 253576099f98SAdrian Hunter self.have_disassembler = False 253676099f98SAdrian Hunter 253776099f98SAdrian Hunter def FileFromBuildId(self, build_id): 253876099f98SAdrian Hunter file_name = self.buildid_dir + build_id[0:2] + "/" + build_id[2:] + "/elf" 253976099f98SAdrian Hunter return TryOpen(file_name) 254076099f98SAdrian Hunter 254176099f98SAdrian Hunter def FileFromNamesAndBuildId(self, short_name, long_name, build_id): 254276099f98SAdrian Hunter # Assume current machine i.e. no support for virtualization 254376099f98SAdrian Hunter if short_name[0:7] == "[kernel" and os.path.basename(long_name) == "kcore": 254476099f98SAdrian Hunter file_name = os.getenv("PERF_KCORE") 254576099f98SAdrian Hunter f = TryOpen(file_name) if file_name else None 254676099f98SAdrian Hunter if f: 254776099f98SAdrian Hunter return f 254876099f98SAdrian Hunter # For now, no special handling if long_name is /proc/kcore 254976099f98SAdrian Hunter f = TryOpen(long_name) 255076099f98SAdrian Hunter if f: 255176099f98SAdrian Hunter return f 255276099f98SAdrian Hunter f = self.FileFromBuildId(build_id) 255376099f98SAdrian Hunter if f: 255476099f98SAdrian Hunter return f 255576099f98SAdrian Hunter return None 25568392b74bSAdrian Hunter 25578392b74bSAdrian Hunter def AddInstanceToShutdownOnExit(self, instance): 25588392b74bSAdrian Hunter self.instances_to_shutdown_on_exit.add(instance) 25598392b74bSAdrian Hunter 25608392b74bSAdrian Hunter # Shutdown any background processes or threads 25618392b74bSAdrian Hunter def ShutdownInstances(self): 25628392b74bSAdrian Hunter for x in self.instances_to_shutdown_on_exit: 25638392b74bSAdrian Hunter try: 25648392b74bSAdrian Hunter x.Shutdown() 25658392b74bSAdrian Hunter except: 25668392b74bSAdrian Hunter pass 2567031c2a00SAdrian Hunter 2568031c2a00SAdrian Hunter# Database reference 2569031c2a00SAdrian Hunter 2570031c2a00SAdrian Hunterclass DBRef(): 2571031c2a00SAdrian Hunter 2572031c2a00SAdrian Hunter def __init__(self, is_sqlite3, dbname): 2573031c2a00SAdrian Hunter self.is_sqlite3 = is_sqlite3 2574031c2a00SAdrian Hunter self.dbname = dbname 2575031c2a00SAdrian Hunter 2576031c2a00SAdrian Hunter def Open(self, connection_name): 2577031c2a00SAdrian Hunter dbname = self.dbname 2578031c2a00SAdrian Hunter if self.is_sqlite3: 2579031c2a00SAdrian Hunter db = QSqlDatabase.addDatabase("QSQLITE", connection_name) 2580031c2a00SAdrian Hunter else: 2581031c2a00SAdrian Hunter db = QSqlDatabase.addDatabase("QPSQL", connection_name) 2582031c2a00SAdrian Hunter opts = dbname.split() 2583031c2a00SAdrian Hunter for opt in opts: 2584031c2a00SAdrian Hunter if "=" in opt: 2585031c2a00SAdrian Hunter opt = opt.split("=") 2586031c2a00SAdrian Hunter if opt[0] == "hostname": 2587031c2a00SAdrian Hunter db.setHostName(opt[1]) 2588031c2a00SAdrian Hunter elif opt[0] == "port": 2589031c2a00SAdrian Hunter db.setPort(int(opt[1])) 2590031c2a00SAdrian Hunter elif opt[0] == "username": 2591031c2a00SAdrian Hunter db.setUserName(opt[1]) 2592031c2a00SAdrian Hunter elif opt[0] == "password": 2593031c2a00SAdrian Hunter db.setPassword(opt[1]) 2594031c2a00SAdrian Hunter elif opt[0] == "dbname": 2595031c2a00SAdrian Hunter dbname = opt[1] 2596031c2a00SAdrian Hunter else: 2597031c2a00SAdrian Hunter dbname = opt 2598031c2a00SAdrian Hunter 2599031c2a00SAdrian Hunter db.setDatabaseName(dbname) 2600031c2a00SAdrian Hunter if not db.open(): 2601031c2a00SAdrian Hunter raise Exception("Failed to open database " + dbname + " error: " + db.lastError().text()) 2602031c2a00SAdrian Hunter return db, dbname 2603031c2a00SAdrian Hunter 2604031c2a00SAdrian Hunter# Main 2605031c2a00SAdrian Hunter 2606031c2a00SAdrian Hunterdef Main(): 2607031c2a00SAdrian Hunter if (len(sys.argv) < 2): 260865b24292SAdrian Hunter print >> sys.stderr, "Usage is: exported-sql-viewer.py {<database name> | --help-only}" 2609031c2a00SAdrian Hunter raise Exception("Too few arguments") 2610031c2a00SAdrian Hunter 2611031c2a00SAdrian Hunter dbname = sys.argv[1] 261265b24292SAdrian Hunter if dbname == "--help-only": 261365b24292SAdrian Hunter app = QApplication(sys.argv) 261465b24292SAdrian Hunter mainwindow = HelpOnlyWindow() 261565b24292SAdrian Hunter mainwindow.show() 261665b24292SAdrian Hunter err = app.exec_() 261765b24292SAdrian Hunter sys.exit(err) 2618031c2a00SAdrian Hunter 2619031c2a00SAdrian Hunter is_sqlite3 = False 2620031c2a00SAdrian Hunter try: 2621031c2a00SAdrian Hunter f = open(dbname) 2622031c2a00SAdrian Hunter if f.read(15) == "SQLite format 3": 2623031c2a00SAdrian Hunter is_sqlite3 = True 2624031c2a00SAdrian Hunter f.close() 2625031c2a00SAdrian Hunter except: 2626031c2a00SAdrian Hunter pass 2627031c2a00SAdrian Hunter 2628031c2a00SAdrian Hunter dbref = DBRef(is_sqlite3, dbname) 2629031c2a00SAdrian Hunter db, dbname = dbref.Open("main") 2630031c2a00SAdrian Hunter glb = Glb(dbref, db, dbname) 2631031c2a00SAdrian Hunter app = QApplication(sys.argv) 2632031c2a00SAdrian Hunter glb.app = app 2633031c2a00SAdrian Hunter mainwindow = MainWindow(glb) 2634031c2a00SAdrian Hunter glb.mainwindow = mainwindow 2635031c2a00SAdrian Hunter mainwindow.show() 2636031c2a00SAdrian Hunter err = app.exec_() 26378392b74bSAdrian Hunter glb.ShutdownInstances() 2638031c2a00SAdrian Hunter db.close() 2639031c2a00SAdrian Hunter sys.exit(err) 2640031c2a00SAdrian Hunter 2641031c2a00SAdrian Hunterif __name__ == "__main__": 2642031c2a00SAdrian Hunter Main() 2643