5030 lines · 153.7 KB · Python
RawDownload
		else:			return val		val = val[:-2].strip()		if not self.IsNumber(val):			return val		val = int(val) * mult		if val >= 0:			val += self.first_time		else:			val += self.last_time		return str(val) 	def ConvertTimeRange(self, vrange):		if vrange[0] == "":			vrange[0] = str(self.first_time)		if vrange[1] == "":			vrange[1] = str(self.last_time)		vrange[0] = self.ConvertRelativeTime(vrange[0])		vrange[1] = self.ConvertRelativeTime(vrange[1])		if not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]):			return False		beg_range = max(int(vrange[0]), self.first_time)		end_range = min(int(vrange[1]), self.last_time)		if beg_range > self.last_time or end_range < self.first_time:			return False		vrange[0] = self.BinarySearchTime(0, self.last_id, beg_range, True)		vrange[1] = self.BinarySearchTime(1, self.last_id + 1, end_range, False)		return True 	def AddTimeRange(self, value, ranges):		n = value.count("-")		if n == 1:			pass		elif n == 2:			if value.split("-")[1].strip() == "":				n = 1		elif n == 3:			n = 2		else:			return False		pos = findnth(value, "-", n)		vrange = [value[:pos].strip() ,value[pos+1:].strip()]		if self.ConvertTimeRange(vrange):			ranges.append(vrange)			return True		return False 	def DoValidate(self, input_string):		ranges = []		for value in [x.strip() for x in input_string.split(",")]:			if not self.AddTimeRange(value, ranges):				return self.InvalidValue(value)		ranges = [("(" + self.column_name + " >= " + r[0] + " AND " + self.column_name + " <= " + r[1] + ")") for r in ranges]		self.value = " OR ".join(ranges) # Report Dialog Base class ReportDialogBase(QDialog): 	def __init__(self, glb, title, items, partial, parent=None):		super(ReportDialogBase, self).__init__(parent) 		self.glb = glb 		self.report_vars = ReportVars() 		self.setWindowTitle(title)		self.setMinimumWidth(600) 		self.data_items = [x(glb, self) for x in items] 		self.partial = partial 		self.grid = QGridLayout() 		for row in xrange(len(self.data_items)):			self.grid.addWidget(QLabel(self.data_items[row].label), row, 0)			self.grid.addWidget(self.data_items[row].widget, row, 1) 		self.status = QLabel() 		self.ok_button = QPushButton("Ok", self)		self.ok_button.setDefault(True)		self.ok_button.released.connect(self.Ok)		self.ok_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 		self.cancel_button = QPushButton("Cancel", self)		self.cancel_button.released.connect(self.reject)		self.cancel_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 		self.hbox = QHBoxLayout()		#self.hbox.addStretch()		self.hbox.addWidget(self.status)		self.hbox.addWidget(self.ok_button)		self.hbox.addWidget(self.cancel_button) 		self.vbox = QVBoxLayout()		self.vbox.addLayout(self.grid)		self.vbox.addLayout(self.hbox) 		self.setLayout(self.vbox) 	def Ok(self):		vars = self.report_vars		for d in self.data_items:			if d.id == "REPORTNAME":				vars.name = d.value		if not vars.name:			self.ShowMessage("Report name is required")			return		for d in self.data_items:			if not d.IsValid():				return		for d in self.data_items[1:]:			if d.id == "LIMIT":				vars.limit = d.value			elif len(d.value):				if len(vars.where_clause):					vars.where_clause += " AND "				vars.where_clause += d.value		if len(vars.where_clause):			if self.partial:				vars.where_clause = " AND ( " + vars.where_clause + " ) "			else:				vars.where_clause = " WHERE " + vars.where_clause + " "		self.accept() 	def ShowMessage(self, msg):		self.status.setText("<font color=#FF0000>" + msg) 	def ClearMessage(self):		self.status.setText("") # Selected branch report creation dialog class SelectedBranchDialog(ReportDialogBase): 	def __init__(self, glb, parent=None):		title = "Selected Branches"		items = (lambda g, p: LineEditDataItem(g, "Report name:", "Enter a name to appear in the window title bar", p, "REPORTNAME"),			 lambda g, p: SampleTimeRangesDataItem(g, "Time ranges:", "Enter time ranges", "samples.id", p),			 lambda g, p: NonNegativeIntegerRangesDataItem(g, "CPUs:", "Enter CPUs or ranges e.g. 0,5-6", "cpu", p),			 lambda g, p: SQLTableDataItem(g, "Commands:", "Only branches with these commands will be included", "comms", "comm", "comm_id", "", p),			 lambda g, p: SQLTableDataItem(g, "PIDs:", "Only branches with these process IDs will be included", "threads", "pid", "thread_id", "", p),			 lambda g, p: SQLTableDataItem(g, "TIDs:", "Only branches with these thread IDs will be included", "threads", "tid", "thread_id", "", p),			 lambda g, p: SQLTableDataItem(g, "DSOs:", "Only branches with these DSOs will be included", "dsos", "short_name", "samples.dso_id", "to_dso_id", p),			 lambda g, p: SQLTableDataItem(g, "Symbols:", "Only branches with these symbols will be included", "symbols", "name", "symbol_id", "to_symbol_id", p),			 lambda g, p: LineEditDataItem(g, "Raw SQL clause: ", "Enter a raw SQL WHERE clause", p))		super(SelectedBranchDialog, self).__init__(glb, title, items, True, parent) # Event list def GetEventList(db):	events = []	query = QSqlQuery(db)	QueryExec(query, "SELECT name FROM selected_events WHERE id > 0 ORDER BY id")	while query.next():		events.append(query.value(0))	return events # Is a table selectable def IsSelectable(db, table, sql = "", columns = "*"):	query = QSqlQuery(db)	try:		QueryExec(query, "SELECT " + columns + " FROM " + table + " " + sql + " LIMIT 1")	except:		return False	return True # SQL table data model item class SQLTableItem(): 	def __init__(self, row, data):		self.row = row		self.data = data 	def getData(self, column):		return self.data[column] # SQL table data model class SQLTableModel(TableModel): 	progress = Signal(object) 	def __init__(self, glb, sql, column_headers, parent=None):		super(SQLTableModel, self).__init__(parent)		self.glb = glb		self.more = True		self.populated = 0		self.column_headers = column_headers		self.fetcher = SQLFetcher(glb, sql, lambda x, y=len(column_headers): self.SQLTableDataPrep(x, y), self.AddSample)		self.fetcher.done.connect(self.Update)		self.fetcher.Fetch(glb_chunk_sz) 	def DisplayData(self, item, index):		self.FetchIfNeeded(item.row)		return item.getData(index.column()) 	def AddSample(self, data):		child = SQLTableItem(self.populated, data)		self.child_items.append(child)		self.populated += 1 	def Update(self, fetched):		if not fetched:			self.more = False			self.progress.emit(0)		child_count = self.child_count		count = self.populated - child_count		if count > 0:			parent = QModelIndex()			self.beginInsertRows(parent, child_count, child_count + count - 1)			self.insertRows(child_count, count, parent)			self.child_count += count			self.endInsertRows()			self.progress.emit(self.child_count) 	def FetchMoreRecords(self, count):		current = self.child_count		if self.more:			self.fetcher.Fetch(count)		else:			self.progress.emit(0)		return current 	def HasMoreRecords(self):		return self.more 	def columnCount(self, parent=None):		return len(self.column_headers) 	def columnHeader(self, column):		return self.column_headers[column] 	def SQLTableDataPrep(self, query, count):		data = []		for i in xrange(count):			data.append(query.value(i))		return data # SQL automatic table data model class SQLAutoTableModel(SQLTableModel): 	def __init__(self, glb, table_name, parent=None):		sql = "SELECT * FROM " + table_name + " WHERE id > $$last_id$$ ORDER BY id LIMIT " + str(glb_chunk_sz)		if table_name == "comm_threads_view":			# For now, comm_threads_view has no id column			sql = "SELECT * FROM " + table_name + " WHERE comm_id > $$last_id$$ ORDER BY comm_id LIMIT " + str(glb_chunk_sz)		column_headers = []		query = QSqlQuery(glb.db)		if glb.dbref.is_sqlite3:			QueryExec(query, "PRAGMA table_info(" + table_name + ")")			while query.next():				column_headers.append(query.value(1))			if table_name == "sqlite_master":				sql = "SELECT * FROM " + table_name		else:			if table_name[:19] == "information_schema.":				sql = "SELECT * FROM " + table_name				select_table_name = table_name[19:]				schema = "information_schema"			else:				select_table_name = table_name				schema = "public"			QueryExec(query, "SELECT column_name FROM information_schema.columns WHERE table_schema = '" + schema + "' and table_name = '" + select_table_name + "'")			while query.next():				column_headers.append(query.value(0))		if pyside_version_1 and sys.version_info[0] == 3:			if table_name == "samples_view":				self.SQLTableDataPrep = self.samples_view_DataPrep			if table_name == "samples":				self.SQLTableDataPrep = self.samples_DataPrep		super(SQLAutoTableModel, self).__init__(glb, sql, column_headers, parent) 	def samples_view_DataPrep(self, query, count):		data = []		data.append(query.value(0))		# Workaround pyside failing to handle large integers (i.e. time) in python3 by converting to a string		data.append("{:>19}".format(query.value(1)))		for i in xrange(2, count):			data.append(query.value(i))		return data 	def samples_DataPrep(self, query, count):		data = []		for i in xrange(9):			data.append(query.value(i))		# Workaround pyside failing to handle large integers (i.e. time) in python3 by converting to a string		data.append("{:>19}".format(query.value(9)))		for i in xrange(10, count):			data.append(query.value(i))		return data # Base class for custom ResizeColumnsToContents class ResizeColumnsToContentsBase(QObject): 	def __init__(self, parent=None):		super(ResizeColumnsToContentsBase, self).__init__(parent) 	def ResizeColumnToContents(self, column, n):		# Using the view's resizeColumnToContents() here is extrememly slow		# so implement a crude alternative		font = self.view.font()		metrics = QFontMetrics(font)		max = 0		for row in xrange(n):			val = self.data_model.child_items[row].data[column]			len = metrics.width(str(val) + "MM")			max = len if len > max else max		val = self.data_model.columnHeader(column)		len = metrics.width(str(val) + "MM")		max = len if len > max else max		self.view.setColumnWidth(column, max) 	def ResizeColumnsToContents(self):		n = min(self.data_model.child_count, 100)		if n < 1:			# No data yet, so connect a signal to notify when there is			self.data_model.rowsInserted.connect(self.UpdateColumnWidths)			return		columns = self.data_model.columnCount()		for i in xrange(columns):			self.ResizeColumnToContents(i, n) 	def UpdateColumnWidths(self, *x):		# This only needs to be done once, so disconnect the signal now		self.data_model.rowsInserted.disconnect(self.UpdateColumnWidths)		self.ResizeColumnsToContents() # Convert value to CSV def ToCSValue(val):	if '"' in val:		val = val.replace('"', '""')	if "," in val or '"' in val:		val = '"' + val + '"'	return val # Key to sort table model indexes by row / column, assuming fewer than 1000 columns glb_max_cols = 1000 def RowColumnKey(a):	return a.row() * glb_max_cols + a.column() # Copy selected table cells to clipboard def CopyTableCellsToClipboard(view, as_csv=False, with_hdr=False):	indexes = sorted(view.selectedIndexes(), key=RowColumnKey)	idx_cnt = len(indexes)	if not idx_cnt:		return	if idx_cnt == 1:		with_hdr=False	min_row = indexes[0].row()	max_row = indexes[0].row()	min_col = indexes[0].column()	max_col = indexes[0].column()	for i in indexes:		min_row = min(min_row, i.row())		max_row = max(max_row, i.row())		min_col = min(min_col, i.column())		max_col = max(max_col, i.column())	if max_col > glb_max_cols:		raise RuntimeError("glb_max_cols is too low")	max_width = [0] * (1 + max_col - min_col)	for i in indexes:		c = i.column() - min_col		max_width[c] = max(max_width[c], len(str(i.data())))	text = ""	pad = ""	sep = ""	if with_hdr:		model = indexes[0].model()		for col in range(min_col, max_col + 1):			val = model.headerData(col, Qt.Horizontal, Qt.DisplayRole)			if as_csv:				text += sep + ToCSValue(val)				sep = ","			else:				c = col - min_col				max_width[c] = max(max_width[c], len(val))				width = max_width[c]				align = model.headerData(col, Qt.Horizontal, Qt.TextAlignmentRole)				if align & Qt.AlignRight:					val = val.rjust(width)				text += pad + sep + val				pad = " " * (width - len(val))				sep = "  "		text += "\n"		pad = ""		sep = ""	last_row = min_row	for i in indexes:		if i.row() > last_row:			last_row = i.row()			text += "\n"			pad = ""			sep = ""		if as_csv:			text += sep + ToCSValue(str(i.data()))			sep = ","		else:			width = max_width[i.column() - min_col]			if i.data(Qt.TextAlignmentRole) & Qt.AlignRight:				val = str(i.data()).rjust(width)			else:				val = str(i.data())			text += pad + sep + val			pad = " " * (width - len(val))			sep = "  "	QApplication.clipboard().setText(text) def CopyTreeCellsToClipboard(view, as_csv=False, with_hdr=False):	indexes = view.selectedIndexes()	if not len(indexes):		return 	selection = view.selectionModel() 	first = None	for i in indexes:		above = view.indexAbove(i)		if not selection.isSelected(above):			first = i			break 	if first is None:		raise RuntimeError("CopyTreeCellsToClipboard internal error") 	model = first.model()	row_cnt = 0	col_cnt = model.columnCount(first)	max_width = [0] * col_cnt 	indent_sz = 2	indent_str = " " * indent_sz 	expanded_mark_sz = 2	if sys.version_info[0] == 3:		expanded_mark = "\u25BC "		not_expanded_mark = "\u25B6 "	else:		expanded_mark = unicode(chr(0xE2) + chr(0x96) + chr(0xBC) + " ", "utf-8")		not_expanded_mark =  unicode(chr(0xE2) + chr(0x96) + chr(0xB6) + " ", "utf-8")	leaf_mark = "  " 	if not as_csv:		pos = first		while True:			row_cnt += 1			row = pos.row()			for c in range(col_cnt):				i = pos.sibling(row, c)				if c:					n = len(str(i.data()))				else:					n = len(str(i.data()).strip())					n += (i.internalPointer().level - 1) * indent_sz					n += expanded_mark_sz				max_width[c] = max(max_width[c], n)			pos = view.indexBelow(pos)			if not selection.isSelected(pos):				break 	text = ""	pad = ""	sep = ""	if with_hdr:		for c in range(col_cnt):			val = model.headerData(c, Qt.Horizontal, Qt.DisplayRole).strip()			if as_csv:				text += sep + ToCSValue(val)				sep = ","			else:				max_width[c] = max(max_width[c], len(val))				width = max_width[c]				align = model.headerData(c, Qt.Horizontal, Qt.TextAlignmentRole)				if align & Qt.AlignRight:					val = val.rjust(width)				text += pad + sep + val				pad = " " * (width - len(val))				sep = "   "		text += "\n"		pad = ""		sep = "" 	pos = first	while True:		row = pos.row()		for c in range(col_cnt):			i = pos.sibling(row, c)			val = str(i.data())			if not c:				if model.hasChildren(i):

Lines 3501–4000 of 5030. Previous lines