3588 lines · 112.0 KB · Python
RawDownload
	def __init__(self, glb, label, placeholder_text, parent, id = "", default = ""):		super(PositiveIntegerDataItem, self).__init__(glb, label, placeholder_text, parent, id, default) 	def DoValidate(self, input_string):		if not self.IsNumber(input_string.strip()):			return self.InvalidValue(input_string)		value = int(input_string.strip())		if value <= 0:			return self.InvalidValue(input_string)		self.value = str(value) # Dialog data item converted and validated using a SQL table class SQLTableDataItem(LineEditDataItem): 	def __init__(self, glb, label, placeholder_text, table_name, match_column, column_name1, column_name2, parent):		super(SQLTableDataItem, self).__init__(glb, label, placeholder_text, parent) 		self.table_name = table_name		self.match_column = match_column		self.column_name1 = column_name1		self.column_name2 = column_name2 	def ValueToIds(self, value):		ids = []		query = QSqlQuery(self.glb.db)		stmt = "SELECT id FROM " + self.table_name + " WHERE " + self.match_column + " = '" + value + "'"		ret = query.exec_(stmt)		if ret:			while query.next():				ids.append(str(query.value(0)))		return ids 	def DoValidate(self, input_string):		all_ids = []		for value in [x.strip() for x in input_string.split(",")]:			ids = self.ValueToIds(value)			if len(ids):				all_ids.extend(ids)			else:				return self.InvalidValue(value)		self.value = self.column_name1 + " IN (" + ",".join(all_ids) + ")"		if self.column_name2:			self.value = "( " + self.value + " OR " + self.column_name2 + " IN (" + ",".join(all_ids) + ") )" # Sample time ranges dialog data item converted and validated using 'samples' SQL table class SampleTimeRangesDataItem(LineEditDataItem): 	def __init__(self, glb, label, placeholder_text, column_name, parent):		self.column_name = column_name 		self.last_id = 0		self.first_time = 0		self.last_time = 2 ** 64 		query = QSqlQuery(glb.db)		QueryExec(query, "SELECT id, time FROM samples ORDER BY id DESC LIMIT 1")		if query.next():			self.last_id = int(query.value(0))			self.last_time = int(query.value(1))		QueryExec(query, "SELECT time FROM samples WHERE time != 0 ORDER BY id LIMIT 1")		if query.next():			self.first_time = int(query.value(0))		if placeholder_text:			placeholder_text += ", between " + str(self.first_time) + " and " + str(self.last_time) 		super(SampleTimeRangesDataItem, self).__init__(glb, label, placeholder_text, parent) 	def IdBetween(self, query, lower_id, higher_id, order):		QueryExec(query, "SELECT id FROM samples WHERE id > " + str(lower_id) + " AND id < " + str(higher_id) + " ORDER BY id " + order + " LIMIT 1")		if query.next():			return True, int(query.value(0))		else:			return False, 0 	def BinarySearchTime(self, lower_id, higher_id, target_time, get_floor):		query = QSqlQuery(self.glb.db)		while True:			next_id = int((lower_id + higher_id) / 2)			QueryExec(query, "SELECT time FROM samples WHERE id = " + str(next_id))			if not query.next():				ok, dbid = self.IdBetween(query, lower_id, next_id, "DESC")				if not ok:					ok, dbid = self.IdBetween(query, next_id, higher_id, "")					if not ok:						return str(higher_id)				next_id = dbid				QueryExec(query, "SELECT time FROM samples WHERE id = " + str(next_id))			next_time = int(query.value(0))			if get_floor:				if target_time > next_time:					lower_id = next_id				else:					higher_id = next_id				if higher_id <= lower_id + 1:					return str(higher_id)			else:				if target_time >= next_time:					lower_id = next_id				else:					higher_id = next_id				if higher_id <= lower_id + 1:					return str(lower_id) 	def ConvertRelativeTime(self, val):		mult = 1		suffix = val[-2:]		if suffix == "ms":			mult = 1000000		elif suffix == "us":			mult = 1000		elif suffix == "ns":			mult = 1		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)			if as_csv:				text += sep + ToCSValue(val)				sep = ","			else:				c = col - min_col

Lines 2001–2500 of 3588. Previous lines

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t