aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/scripts/python/exported-sql-viewer.py
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2019-02-22 02:27:25 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2019-02-22 14:52:07 -0500
commit1c3ca1b3ae35d5cc6cedb85a03bc314699339874 (patch)
tree6a6a4fa5cc3aae3775fbe0389814c0cf275ebd97 /tools/perf/scripts/python/exported-sql-viewer.py
parent947cc38d47249bb83111b2607e1074b7d12338ba (diff)
perf scripts python: exported-sql-viewer.py: Create new dialog data item classes
Create new dialog data item classes to replace SQLTableDialogDataItem. This separates out different dialog data items and makes it easier to add new ones. SQLTableDialogDataItem is removed in a separate patch because it makes the diff more readable. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Cc: Jiri Olsa <jolsa@redhat.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/scripts/python/exported-sql-viewer.py')
-rwxr-xr-xtools/perf/scripts/python/exported-sql-viewer.py285
1 files changed, 272 insertions, 13 deletions
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
index ed39a0153dd3..63b14b80ebcd 100755
--- a/tools/perf/scripts/python/exported-sql-viewer.py
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -1702,6 +1702,265 @@ class SQLTableDialogDataItem():
1702 return False 1702 return False
1703 return True 1703 return True
1704 1704
1705# Line edit data item
1706
1707class LineEditDataItem(object):
1708
1709 def __init__(self, glb, label, placeholder_text, parent, id = ""):
1710 self.glb = glb
1711 self.label = label
1712 self.placeholder_text = placeholder_text
1713 self.parent = parent
1714 self.id = id
1715
1716 self.value = ""
1717
1718 self.widget = QLineEdit()
1719 self.widget.editingFinished.connect(self.Validate)
1720 self.widget.textChanged.connect(self.Invalidate)
1721 self.red = False
1722 self.error = ""
1723 self.validated = True
1724
1725 if placeholder_text:
1726 self.widget.setPlaceholderText(placeholder_text)
1727
1728 def TurnTextRed(self):
1729 if not self.red:
1730 palette = QPalette()
1731 palette.setColor(QPalette.Text,Qt.red)
1732 self.widget.setPalette(palette)
1733 self.red = True
1734
1735 def TurnTextNormal(self):
1736 if self.red:
1737 palette = QPalette()
1738 self.widget.setPalette(palette)
1739 self.red = False
1740
1741 def InvalidValue(self, value):
1742 self.value = ""
1743 self.TurnTextRed()
1744 self.error = self.label + " invalid value '" + value + "'"
1745 self.parent.ShowMessage(self.error)
1746
1747 def Invalidate(self):
1748 self.validated = False
1749
1750 def DoValidate(self, input_string):
1751 self.value = input_string.strip()
1752
1753 def Validate(self):
1754 self.validated = True
1755 self.error = ""
1756 self.TurnTextNormal()
1757 self.parent.ClearMessage()
1758 input_string = self.widget.text()
1759 if not len(input_string.strip()):
1760 self.value = ""
1761 return
1762 self.DoValidate(input_string)
1763
1764 def IsValid(self):
1765 if not self.validated:
1766 self.Validate()
1767 if len(self.error):
1768 self.parent.ShowMessage(self.error)
1769 return False
1770 return True
1771
1772 def IsNumber(self, value):
1773 try:
1774 x = int(value)
1775 except:
1776 x = 0
1777 return str(x) == value
1778
1779# Non-negative integer ranges dialog data item
1780
1781class NonNegativeIntegerRangesDataItem(LineEditDataItem):
1782
1783 def __init__(self, glb, label, placeholder_text, column_name, parent):
1784 super(NonNegativeIntegerRangesDataItem, self).__init__(glb, label, placeholder_text, parent)
1785
1786 self.column_name = column_name
1787
1788 def DoValidate(self, input_string):
1789 singles = []
1790 ranges = []
1791 for value in [x.strip() for x in input_string.split(",")]:
1792 if "-" in value:
1793 vrange = value.split("-")
1794 if len(vrange) != 2 or not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]):
1795 return self.InvalidValue(value)
1796 ranges.append(vrange)
1797 else:
1798 if not self.IsNumber(value):
1799 return self.InvalidValue(value)
1800 singles.append(value)
1801 ranges = [("(" + self.column_name + " >= " + r[0] + " AND " + self.column_name + " <= " + r[1] + ")") for r in ranges]
1802 if len(singles):
1803 ranges.append(self.column_name + " IN (" + ",".join(singles) + ")")
1804 self.value = " OR ".join(ranges)
1805
1806# Dialog data item converted and validated using a SQL table
1807
1808class SQLTableDataItem(LineEditDataItem):
1809
1810 def __init__(self, glb, label, placeholder_text, table_name, match_column, column_name1, column_name2, parent):
1811 super(SQLTableDataItem, self).__init__(glb, label, placeholder_text, parent)
1812
1813 self.table_name = table_name
1814 self.match_column = match_column
1815 self.column_name1 = column_name1
1816 self.column_name2 = column_name2
1817
1818 def ValueToIds(self, value):
1819 ids = []
1820 query = QSqlQuery(self.glb.db)
1821 stmt = "SELECT id FROM " + self.table_name + " WHERE " + self.match_column + " = '" + value + "'"
1822 ret = query.exec_(stmt)
1823 if ret:
1824 while query.next():
1825 ids.append(str(query.value(0)))
1826 return ids
1827
1828 def DoValidate(self, input_string):
1829 all_ids = []
1830 for value in [x.strip() for x in input_string.split(",")]:
1831 ids = self.ValueToIds(value)
1832 if len(ids):
1833 all_ids.extend(ids)
1834 else:
1835 return self.InvalidValue(value)
1836 self.value = self.column_name1 + " IN (" + ",".join(all_ids) + ")"
1837 if self.column_name2:
1838 self.value = "( " + self.value + " OR " + self.column_name2 + " IN (" + ",".join(all_ids) + ") )"
1839
1840# Sample time ranges dialog data item converted and validated using 'samples' SQL table
1841
1842class SampleTimeRangesDataItem(LineEditDataItem):
1843
1844 def __init__(self, glb, label, placeholder_text, column_name, parent):
1845 self.column_name = column_name
1846
1847 self.last_id = 0
1848 self.first_time = 0
1849 self.last_time = 2 ** 64
1850
1851 query = QSqlQuery(glb.db)
1852 QueryExec(query, "SELECT id, time FROM samples ORDER BY id DESC LIMIT 1")
1853 if query.next():
1854 self.last_id = int(query.value(0))
1855 self.last_time = int(query.value(1))
1856 QueryExec(query, "SELECT time FROM samples WHERE time != 0 ORDER BY id LIMIT 1")
1857 if query.next():
1858 self.first_time = int(query.value(0))
1859 if placeholder_text:
1860 placeholder_text += ", between " + str(self.first_time) + " and " + str(self.last_time)
1861
1862 super(SampleTimeRangesDataItem, self).__init__(glb, label, placeholder_text, parent)
1863
1864 def IdBetween(self, query, lower_id, higher_id, order):
1865 QueryExec(query, "SELECT id FROM samples WHERE id > " + str(lower_id) + " AND id < " + str(higher_id) + " ORDER BY id " + order + " LIMIT 1")
1866 if query.next():
1867 return True, int(query.value(0))
1868 else:
1869 return False, 0
1870
1871 def BinarySearchTime(self, lower_id, higher_id, target_time, get_floor):
1872 query = QSqlQuery(self.glb.db)
1873 while True:
1874 next_id = int((lower_id + higher_id) / 2)
1875 QueryExec(query, "SELECT time FROM samples WHERE id = " + str(next_id))
1876 if not query.next():
1877 ok, dbid = self.IdBetween(query, lower_id, next_id, "DESC")
1878 if not ok:
1879 ok, dbid = self.IdBetween(query, next_id, higher_id, "")
1880 if not ok:
1881 return str(higher_id)
1882 next_id = dbid
1883 QueryExec(query, "SELECT time FROM samples WHERE id = " + str(next_id))
1884 next_time = int(query.value(0))
1885 if get_floor:
1886 if target_time > next_time:
1887 lower_id = next_id
1888 else:
1889 higher_id = next_id
1890 if higher_id <= lower_id + 1:
1891 return str(higher_id)
1892 else:
1893 if target_time >= next_time:
1894 lower_id = next_id
1895 else:
1896 higher_id = next_id
1897 if higher_id <= lower_id + 1:
1898 return str(lower_id)
1899
1900 def ConvertRelativeTime(self, val):
1901 mult = 1
1902 suffix = val[-2:]
1903 if suffix == "ms":
1904 mult = 1000000
1905 elif suffix == "us":
1906 mult = 1000
1907 elif suffix == "ns":
1908 mult = 1
1909 else:
1910 return val
1911 val = val[:-2].strip()
1912 if not self.IsNumber(val):
1913 return val
1914 val = int(val) * mult
1915 if val >= 0:
1916 val += self.first_time
1917 else:
1918 val += self.last_time
1919 return str(val)
1920
1921 def ConvertTimeRange(self, vrange):
1922 if vrange[0] == "":
1923 vrange[0] = str(self.first_time)
1924 if vrange[1] == "":
1925 vrange[1] = str(self.last_time)
1926 vrange[0] = self.ConvertRelativeTime(vrange[0])
1927 vrange[1] = self.ConvertRelativeTime(vrange[1])
1928 if not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]):
1929 return False
1930 beg_range = max(int(vrange[0]), self.first_time)
1931 end_range = min(int(vrange[1]), self.last_time)
1932 if beg_range > self.last_time or end_range < self.first_time:
1933 return False
1934 vrange[0] = self.BinarySearchTime(0, self.last_id, beg_range, True)
1935 vrange[1] = self.BinarySearchTime(1, self.last_id + 1, end_range, False)
1936 return True
1937
1938 def AddTimeRange(self, value, ranges):
1939 n = value.count("-")
1940 if n == 1:
1941 pass
1942 elif n == 2:
1943 if value.split("-")[1].strip() == "":
1944 n = 1
1945 elif n == 3:
1946 n = 2
1947 else:
1948 return False
1949 pos = findnth(value, "-", n)
1950 vrange = [value[:pos].strip() ,value[pos+1:].strip()]
1951 if self.ConvertTimeRange(vrange):
1952 ranges.append(vrange)
1953 return True
1954 return False
1955
1956 def DoValidate(self, input_string):
1957 ranges = []
1958 for value in [x.strip() for x in input_string.split(",")]:
1959 if not self.AddTimeRange(value, ranges):
1960 return self.InvalidValue(value)
1961 ranges = [("(" + self.column_name + " >= " + r[0] + " AND " + self.column_name + " <= " + r[1] + ")") for r in ranges]
1962 self.value = " OR ".join(ranges)
1963
1705# Report Dialog Base 1964# Report Dialog Base
1706 1965
1707class ReportDialogBase(QDialog): 1966class ReportDialogBase(QDialog):
@@ -1716,7 +1975,7 @@ class ReportDialogBase(QDialog):
1716 self.setWindowTitle(title) 1975 self.setWindowTitle(title)
1717 self.setMinimumWidth(600) 1976 self.setMinimumWidth(600)
1718 1977
1719 self.data_items = [SQLTableDialogDataItem(glb, *x, parent=self) for x in items] 1978 self.data_items = [x(glb, self) for x in items]
1720 1979
1721 self.partial = partial 1980 self.partial = partial
1722 1981
@@ -1751,7 +2010,9 @@ class ReportDialogBase(QDialog):
1751 2010
1752 def Ok(self): 2011 def Ok(self):
1753 vars = self.report_vars 2012 vars = self.report_vars
1754 vars.name = self.data_items[0].value 2013 for d in self.data_items:
2014 if d.id == "REPORTNAME":
2015 vars.name = d.value
1755 if not vars.name: 2016 if not vars.name:
1756 self.ShowMessage("Report name is required") 2017 self.ShowMessage("Report name is required")
1757 return 2018 return
@@ -1785,17 +2046,15 @@ class SelectedBranchDialog(ReportDialogBase):
1785 2046
1786 def __init__(self, glb, parent=None): 2047 def __init__(self, glb, parent=None):
1787 title = "Selected Branches" 2048 title = "Selected Branches"
1788 items = ( 2049 items = (lambda g, p: LineEditDataItem(g, "Report name:", "Enter a name to appear in the window title bar", p, "REPORTNAME"),
1789 ("Report name:", "Enter a name to appear in the window title bar", "", "", "", ""), 2050 lambda g, p: SampleTimeRangesDataItem(g, "Time ranges:", "Enter time ranges", "samples.id", p),
1790 ("Time ranges:", "Enter time ranges", "<timeranges>", "", "samples.id", ""), 2051 lambda g, p: NonNegativeIntegerRangesDataItem(g, "CPUs:", "Enter CPUs or ranges e.g. 0,5-6", "cpu", p),
1791 ("CPUs:", "Enter CPUs or ranges e.g. 0,5-6", "<ranges>", "", "cpu", ""), 2052 lambda g, p: SQLTableDataItem(g, "Commands:", "Only branches with these commands will be included", "comms", "comm", "comm_id", "", p),
1792 ("Commands:", "Only branches with these commands will be included", "comms", "comm", "comm_id", ""), 2053 lambda g, p: SQLTableDataItem(g, "PIDs:", "Only branches with these process IDs will be included", "threads", "pid", "thread_id", "", p),
1793 ("PIDs:", "Only branches with these process IDs will be included", "threads", "pid", "thread_id", ""), 2054 lambda g, p: SQLTableDataItem(g, "TIDs:", "Only branches with these thread IDs will be included", "threads", "tid", "thread_id", "", p),
1794 ("TIDs:", "Only branches with these thread IDs will be included", "threads", "tid", "thread_id", ""), 2055 lambda g, p: SQLTableDataItem(g, "DSOs:", "Only branches with these DSOs will be included", "dsos", "short_name", "samples.dso_id", "to_dso_id", p),
1795 ("DSOs:", "Only branches with these DSOs will be included", "dsos", "short_name", "samples.dso_id", "to_dso_id"), 2056 lambda g, p: SQLTableDataItem(g, "Symbols:", "Only branches with these symbols will be included", "symbols", "name", "symbol_id", "to_symbol_id", p),
1796 ("Symbols:", "Only branches with these symbols will be included", "symbols", "name", "symbol_id", "to_symbol_id"), 2057 lambda g, p: LineEditDataItem(g, "Raw SQL clause: ", "Enter a raw SQL WHERE clause", p))
1797 ("Raw SQL clause: ", "Enter a raw SQL WHERE clause", "", "", "", ""),
1798 )
1799 super(SelectedBranchDialog, self).__init__(glb, title, items, True, parent) 2058 super(SelectedBranchDialog, self).__init__(glb, title, items, True, parent)
1800 2059
1801# Event list 2060# Event list