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.
Showing the changes to tools/perf/scripts/python (1 of 1 file). Show all
Unified · Split
| @@ -1702,6 +1702,265 @@ class SQLTableDialogDataItem(): · 1701 unmodified lines | ||
| 1702 | 1702 | return False |
| 1703 | 1703 | return True |
| 1704 | 1704 | |
| 1705 | +# Line edit data item | |
| 1706 | + | |
| 1707 | +class 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 | + | |
| 1781 | +class 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 | + | |
| 1808 | +class 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 | + | |
| 1842 | +class 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 | 1964 | # Report Dialog Base |
| 1706 | 1965 | |
| 1707 | 1966 | class ReportDialogBase(QDialog): |
| @@ -1716,7 +1975,7 @@ class ReportDialogBase(QDialog): · 8 unmodified lines | ||
| 1716 | 1975 | self.setWindowTitle(title) |
| 1717 | 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 | 1980 | self.partial = partial |
| 1722 | 1981 | |
| @@ -1751,7 +2010,9 @@ class ReportDialogBase(QDialog): · 28 unmodified lines | ||
| 1751 | 2010 | |
| 1752 | 2011 | def Ok(self): |
| 1753 | 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 | 2016 | if not vars.name: |
| 1756 | 2017 | self.ShowMessage("Report name is required") |
| 1757 | 2018 | return |
| @@ -1785,17 +2046,15 @@ class SelectedBranchDialog(ReportDialogBase): · 27 unmodified lines | ||
| 1785 | 2046 | |
| 1786 | 2047 | def __init__(self, glb, parent=None): |
| 1787 | 2048 | title = "Selected Branches" |
| 1788 | − items = ( | |
| 1789 | − ("Report name:", "Enter a name to appear in the window title bar", "", "", "", ""), | |
| 1790 | − ("Time ranges:", "Enter time ranges", "<timeranges>", "", "samples.id", ""), | |
| 1791 | − ("CPUs:", "Enter CPUs or ranges e.g. 0,5-6", "<ranges>", "", "cpu", ""), | |
| 1792 | − ("Commands:", "Only branches with these commands will be included", "comms", "comm", "comm_id", ""), | |
| 1793 | − ("PIDs:", "Only branches with these process IDs will be included", "threads", "pid", "thread_id", ""), | |
| 1794 | − ("TIDs:", "Only branches with these thread IDs will be included", "threads", "tid", "thread_id", ""), | |
| 1795 | − ("DSOs:", "Only branches with these DSOs will be included", "dsos", "short_name", "samples.dso_id", "to_dso_id"), | |
| 1796 | − ("Symbols:", "Only branches with these symbols will be included", "symbols", "name", "symbol_id", "to_symbol_id"), | |
| 1797 | − ("Raw SQL clause: ", "Enter a raw SQL WHERE clause", "", "", "", ""), | |
| 1798 | − ) | |
| 2049 | + items = (lambda g, p: LineEditDataItem(g, "Report name:", "Enter a name to appear in the window title bar", p, "REPORTNAME"), | |
| 2050 | + lambda g, p: SampleTimeRangesDataItem(g, "Time ranges:", "Enter time ranges", "samples.id", p), | |
| 2051 | + lambda g, p: NonNegativeIntegerRangesDataItem(g, "CPUs:", "Enter CPUs or ranges e.g. 0,5-6", "cpu", p), | |
| 2052 | + lambda g, p: SQLTableDataItem(g, "Commands:", "Only branches with these commands will be included", "comms", "comm", "comm_id", "", p), | |
| 2053 | + lambda g, p: SQLTableDataItem(g, "PIDs:", "Only branches with these process IDs will be included", "threads", "pid", "thread_id", "", p), | |
| 2054 | + lambda g, p: SQLTableDataItem(g, "TIDs:", "Only branches with these thread IDs will be included", "threads", "tid", "thread_id", "", p), | |
| 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), | |
| 2056 | + lambda g, p: SQLTableDataItem(g, "Symbols:", "Only branches with these symbols will be included", "symbols", "name", "symbol_id", "to_symbol_id", p), | |
| 2057 | + lambda g, p: LineEditDataItem(g, "Raw SQL clause: ", "Enter a raw SQL WHERE clause", p)) | |
| 1799 | 2058 | super(SelectedBranchDialog, self).__init__(glb, title, items, True, parent) |
| 1800 | 2059 | |
| 1801 | 2060 | # Event list |