Moved from scripts into tools, and updated from 4.5 to 4.6 - Changed the tool title to SleepGraph - Reformatted the code so analyze_suspend can be used as a library - Reorganized all html/js/css handling code to be used by other tools - upgraded the -summary feature to work faster with better readability
Unified · Split
| @@ -12,10 +12,6 @@ · 11 unmodified lines | ||
| 12 | 12 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| 13 | 13 | # more details. |
| 14 | 14 | # |
| 15 | −# You should have received a copy of the GNU General Public License along with | |
| 16 | −# this program; if not, write to the Free Software Foundation, Inc., | |
| 17 | −# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | |
| 18 | −# | |
| 19 | 15 | # Authors: |
| 20 | 16 | # Todd Brandt <todd.e.brandt@linux.intel.com> |
| 21 | 17 | # |
| @@ -23,7 +19,7 @@ · 1 unmodified line | ||
| 23 | 19 | # Home Page |
| 24 | 20 | # https://01.org/suspendresume |
| 25 | 21 | # Source repo |
| 26 | −# https://github.com/01org/suspendresume | |
| 22 | +# https://github.com/01org/pm-graph | |
| 27 | 23 | # |
| 28 | 24 | # Description: |
| 29 | 25 | # This tool is designed to assist kernel and OS developers in optimizing |
| @@ -71,14 +67,16 @@ from subprocess import call, Popen, PIPE · 41 unmodified lines | ||
| 71 | 67 | # A global, single-instance container used to |
| 72 | 68 | # store system values and test parameters |
| 73 | 69 | class SystemValues: |
| 70 | + title = 'SleepGraph' | |
| 71 | + version = '4.6' | |
| 74 | 72 | ansi = False |
| 75 | − version = '4.5' | |
| 76 | 73 | verbose = False |
| 77 | 74 | addlogs = False |
| 78 | 75 | mindevlen = 0.0 |
| 79 | 76 | mincglen = 0.0 |
| 80 | 77 | cgphase = '' |
| 81 | 78 | cgtest = -1 |
| 79 | + max_graph_depth = 0 | |
| 82 | 80 | callloopmaxgap = 0.0001 |
| 83 | 81 | callloopmaxlen = 0.005 |
| 84 | 82 | srgap = 0 |
| @@ -106,8 +104,8 @@ class SystemValues: · 21 unmodified lines | ||
| 106 | 104 | ftracefile = '' |
| 107 | 105 | htmlfile = '' |
| 108 | 106 | embedded = False |
| 109 | − rtcwake = False | |
| 110 | − rtcwaketime = 10 | |
| 107 | + rtcwake = True | |
| 108 | + rtcwaketime = 15 | |
| 111 | 109 | rtcpath = '' |
| 112 | 110 | devicefilter = [] |
| 113 | 111 | stamp = 0 |
| @@ -235,6 +233,12 @@ class SystemValues: · 121 unmodified lines | ||
| 235 | 233 | self.rtcpath = rtc |
| 236 | 234 | if (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()): |
| 237 | 235 | self.ansi = True |
| 236 | + def rootUser(self, fatal=False): | |
| 237 | + if 'USER' in os.environ and os.environ['USER'] == 'root': | |
| 238 | + return True | |
| 239 | + if fatal: | |
| 240 | + doError('This command must be run as root') | |
| 241 | + return False | |
| 238 | 242 | def setPrecision(self, num): |
| 239 | 243 | if num < 0 or num > 6: |
| 240 | 244 | return |
| @@ -564,7 +568,7 @@ class SystemValues: · 323 unmodified lines | ||
| 564 | 568 | self.fsetVal('global', 'trace_clock') |
| 565 | 569 | # set trace buffer to a huge value |
| 566 | 570 | self.fsetVal('nop', 'current_tracer') |
| 567 | − self.fsetVal('100000', 'buffer_size_kb') | |
| 571 | + self.fsetVal('131073', 'buffer_size_kb') | |
| 568 | 572 | # go no further if this is just a status check |
| 569 | 573 | if testing: |
| 570 | 574 | return |
| @@ -583,7 +587,7 @@ class SystemValues: · 12 unmodified lines | ||
| 583 | 587 | self.fsetVal('nofuncgraph-overhead', 'trace_options') |
| 584 | 588 | self.fsetVal('context-info', 'trace_options') |
| 585 | 589 | self.fsetVal('graph-time', 'trace_options') |
| 586 | − self.fsetVal('0', 'max_graph_depth') | |
| 590 | + self.fsetVal('%d' % self.max_graph_depth, 'max_graph_depth') | |
| 587 | 591 | cf = ['dpm_run_callback'] |
| 588 | 592 | if(self.usetraceeventsonly): |
| 589 | 593 | cf += ['dpm_prepare', 'dpm_complete'] |
| @@ -639,6 +643,12 @@ class SystemValues: · 49 unmodified lines | ||
| 639 | 643 | return '\x1B[%d;40m%s\x1B[m' % (color, str) |
| 640 | 644 | |
| 641 | 645 | sysvals = SystemValues() |
| 646 | +suspendmodename = { | |
| 647 | + 'freeze': 'Freeze (S0)', | |
| 648 | + 'standby': 'Standby (S1)', | |
| 649 | + 'mem': 'Suspend (S3)', | |
| 650 | + 'disk': 'Hibernate (S4)' | |
| 651 | +} | |
| 642 | 652 | |
| 643 | 653 | # Class: DevProps |
| 644 | 654 | # Description: |
| @@ -1013,6 +1023,8 @@ class Data: · 368 unmodified lines | ||
| 1013 | 1023 | tmp = dict() |
| 1014 | 1024 | for devname in list: |
| 1015 | 1025 | dev = list[devname] |
| 1026 | + if dev['length'] == 0: | |
| 1027 | + continue | |
| 1016 | 1028 | tmp[dev['start']] = devname |
| 1017 | 1029 | for t in sorted(tmp): |
| 1018 | 1030 | slist.append(tmp[t]) |
| @@ -1477,12 +1489,14 @@ class FTraceLine: · 458 unmodified lines | ||
| 1477 | 1489 | # Each instance is tied to a single device in a single phase, and is |
| 1478 | 1490 | # comprised of an ordered list of FTraceLine objects |
| 1479 | 1491 | class FTraceCallGraph: |
| 1492 | + id = '' | |
| 1480 | 1493 | start = -1.0 |
| 1481 | 1494 | end = -1.0 |
| 1482 | 1495 | list = [] |
| 1483 | 1496 | invalid = False |
| 1484 | 1497 | depth = 0 |
| 1485 | 1498 | pid = 0 |
| 1499 | + name = '' | |
| 1486 | 1500 | def __init__(self, pid): |
| 1487 | 1501 | self.start = -1.0 |
| 1488 | 1502 | self.end = -1.0 |
| @@ -1631,9 +1645,17 @@ class FTraceCallGraph: · 142 unmodified lines | ||
| 1631 | 1645 | return True |
| 1632 | 1646 | return False |
| 1633 | 1647 | def postProcess(self, debug=False): |
| 1648 | + if len(self.list) > 0: | |
| 1649 | + self.name = self.list[0].name | |
| 1634 | 1650 | stack = dict() |
| 1635 | 1651 | cnt = 0 |
| 1652 | + last = 0 | |
| 1636 | 1653 | for l in self.list: |
| 1654 | + # ftrace bug: reported duration is not reliable | |
| 1655 | + # check each leaf and clip it at max possible length | |
| 1656 | + if(last and last.freturn and last.fcall): | |
| 1657 | + if last.length > l.time - last.time: | |
| 1658 | + last.length = l.time - last.time | |
| 1637 | 1659 | if(l.fcall and not l.freturn): |
| 1638 | 1660 | stack[l.depth] = l |
| 1639 | 1661 | cnt += 1 |
| @@ -1643,11 +1665,12 @@ class FTraceCallGraph: · 3 unmodified lines | ||
| 1643 | 1665 | print 'Post Process Error: Depth missing' |
| 1644 | 1666 | l.debugPrint() |
| 1645 | 1667 | return False |
| 1646 | − # transfer total time from return line to call line | |
| 1647 | − stack[l.depth].length = l.length | |
| 1668 | + # calculate call length from call/return lines | |
| 1669 | + stack[l.depth].length = l.time - stack[l.depth].time | |
| 1648 | 1670 | stack.pop(l.depth) |
| 1649 | 1671 | l.length = 0 |
| 1650 | 1672 | cnt -= 1 |
| 1673 | + last = l | |
| 1651 | 1674 | if(cnt == 0): |
| 1652 | 1675 | # trace caught the whole call tree |
| 1653 | 1676 | return True |
| @@ -1664,8 +1687,8 @@ class FTraceCallGraph: · 10 unmodified lines | ||
| 1664 | 1687 | 'dpm_prepare': 'suspend_prepare', |
| 1665 | 1688 | 'dpm_complete': 'resume_complete' |
| 1666 | 1689 | } |
| 1667 | − if(self.list[0].name in borderphase): | |
| 1668 | − p = borderphase[self.list[0].name] | |
| 1690 | + if(self.name in borderphase): | |
| 1691 | + p = borderphase[self.name] | |
| 1669 | 1692 | list = data.dmesg[p]['list'] |
| 1670 | 1693 | for devname in list: |
| 1671 | 1694 | dev = list[devname] |
| @@ -1690,7 +1713,7 @@ class FTraceCallGraph: · 18 unmodified lines | ||
| 1690 | 1713 | break |
| 1691 | 1714 | return found |
| 1692 | 1715 | def newActionFromFunction(self, data): |
| 1693 | − name = self.list[0].name | |
| 1716 | + name = self.name | |
| 1694 | 1717 | if name in ['dpm_run_callback', 'dpm_prepare', 'dpm_complete']: |
| 1695 | 1718 | return |
| 1696 | 1719 | fs = self.start |
| @@ -1710,7 +1733,7 @@ class FTraceCallGraph: · 13 unmodified lines | ||
| 1710 | 1733 | phase, myname = out |
| 1711 | 1734 | data.dmesg[phase]['list'][myname]['ftrace'] = self |
| 1712 | 1735 | def debugPrint(self): |
| 1713 | − print('[%f - %f] %s (%d)') % (self.start, self.end, self.list[0].name, self.pid) | |
| 1736 | + print('[%f - %f] %s (%d)') % (self.start, self.end, self.name, self.pid) | |
| 1714 | 1737 | for l in self.list: |
| 1715 | 1738 | if(l.freturn and l.fcall): |
| 1716 | 1739 | print('%f (%02d): %s(); (%.3f us)' % (l.time, \ |
| @@ -1738,7 +1761,7 @@ class DevItem: · 21 unmodified lines | ||
| 1738 | 1761 | # A container for a device timeline which calculates |
| 1739 | 1762 | # all the html properties to display it correctly |
| 1740 | 1763 | class Timeline: |
| 1741 | − html = {} | |
| 1764 | + html = '' | |
| 1742 | 1765 | height = 0 # total timeline height |
| 1743 | 1766 | scaleH = 20 # timescale (top) row height |
| 1744 | 1767 | rowH = 30 # device row height |
| @@ -1746,14 +1769,28 @@ class Timeline: · 1 unmodified line | ||
| 1746 | 1769 | rows = 0 # total timeline rows |
| 1747 | 1770 | rowlines = dict() |
| 1748 | 1771 | rowheight = dict() |
| 1772 | + html_tblock = '<div id="block{0}" class="tblock" style="left:{1}%;width:{2}%;"><div class="tback" style="height:{3}px"></div>\n' | |
| 1773 | + html_device = '<div id="{0}" title="{1}" class="thread{7}" style="left:{2}%;top:{3}px;height:{4}px;width:{5}%;{8}">{6}</div>\n' | |
| 1774 | + html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}px;height:{3}px;background:{4}">{5}</div>\n' | |
| 1775 | + html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n' | |
| 1749 | 1776 | def __init__(self, rowheight, scaleheight): |
| 1750 | 1777 | self.rowH = rowheight |
| 1751 | 1778 | self.scaleH = scaleheight |
| 1752 | − self.html = { | |
| 1753 | − 'header': '', | |
| 1754 | − 'timeline': '', | |
| 1755 | − 'legend': '', | |
| 1756 | − } | |
| 1779 | + self.html = '' | |
| 1780 | + def createHeader(self, sv, suppress=''): | |
| 1781 | + if(not sv.stamp['time']): | |
| 1782 | + return | |
| 1783 | + self.html += '<div class="version"><a href="https://01.org/suspendresume">%s v%s</a></div>' \ | |
| 1784 | + % (sv.title, sv.version) | |
| 1785 | + if sv.logmsg and 'log' not in suppress: | |
| 1786 | + self.html += '<button id="showtest" class="logbtn">log</button>' | |
| 1787 | + if sv.addlogs and 'dmesg' not in suppress: | |
| 1788 | + self.html += '<button id="showdmesg" class="logbtn">dmesg</button>' | |
| 1789 | + if sv.addlogs and sv.ftracefile and 'ftrace' not in suppress: | |
| 1790 | + self.html += '<button id="showftrace" class="logbtn">ftrace</button>' | |
| 1791 | + headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n' | |
| 1792 | + self.html += headline_stamp.format(sv.stamp['host'], sv.stamp['kernel'], | |
| 1793 | + sv.stamp['mode'], sv.stamp['time']) | |
| 1757 | 1794 | # Function: getDeviceRows |
| 1758 | 1795 | # Description: |
| 1759 | 1796 | # determine how may rows the device funcs will take |
| @@ -1880,10 +1917,8 @@ class Timeline: · 120 unmodified lines | ||
| 1880 | 1917 | break |
| 1881 | 1918 | top += self.rowheight[test][phase][i] |
| 1882 | 1919 | return top |
| 1883 | − # Function: calcTotalRows | |
| 1884 | − # Description: | |
| 1885 | − # Calculate the heights and offsets for the header and rows | |
| 1886 | 1920 | def calcTotalRows(self): |
| 1921 | + # Calculate the heights and offsets for the header and rows | |
| 1887 | 1922 | maxrows = 0 |
| 1888 | 1923 | standardphases = [] |
| 1889 | 1924 | for t in self.rowlines: |
| @@ -1901,6 +1936,20 @@ class Timeline: · 11 unmodified lines | ||
| 1901 | 1936 | for t, p in standardphases: |
| 1902 | 1937 | for i in sorted(self.rowheight[t][p]): |
| 1903 | 1938 | self.rowheight[t][p][i] = self.bodyH/len(self.rowlines[t][p]) |
| 1939 | + def createZoomBox(self, mode='command', testcount=1): | |
| 1940 | + # Create bounding box, add buttons | |
| 1941 | + html_zoombox = '<center><button id="zoomin">ZOOM IN +</button><button id="zoomout">ZOOM OUT -</button><button id="zoomdef">ZOOM 1:1</button></center>\n' | |
| 1942 | + html_timeline = '<div id="dmesgzoombox" class="zoombox">\n<div id="{0}" class="timeline" style="height:{1}px">\n' | |
| 1943 | + html_devlist1 = '<button id="devlist1" class="devlist" style="float:left;">Device Detail{0}</button>' | |
| 1944 | + html_devlist2 = '<button id="devlist2" class="devlist" style="float:right;">Device Detail2</button>\n' | |
| 1945 | + if mode != 'command': | |
| 1946 | + if testcount > 1: | |
| 1947 | + self.html += html_devlist2 | |
| 1948 | + self.html += html_devlist1.format('1') | |
| 1949 | + else: | |
| 1950 | + self.html += html_devlist1.format('') | |
| 1951 | + self.html += html_zoombox | |
| 1952 | + self.html += html_timeline.format('dmesg', self.height) | |
| 1904 | 1953 | # Function: createTimeScale |
| 1905 | 1954 | # Description: |
| 1906 | 1955 | # Create the timescale for a timeline block |
| @@ -1913,7 +1962,7 @@ class Timeline: · 6 unmodified lines | ||
| 1913 | 1962 | # The html code needed to display the time scale |
| 1914 | 1963 | def createTimeScale(self, m0, mMax, tTotal, mode): |
| 1915 | 1964 | timescale = '<div class="t" style="right:{0}%">{1}</div>\n' |
| 1916 | − rline = '<div class="t" style="left:0;border-left:1px solid black;border-right:0;">Resume</div>\n' | |
| 1965 | + rline = '<div class="t" style="left:0;border-left:1px solid black;border-right:0;">{0}</div>\n' | |
| 1917 | 1966 | output = '<div class="timescale">\n' |
| 1918 | 1967 | # set scale for timeline |
| 1919 | 1968 | mTotal = mMax - m0 |
| @@ -1926,21 +1975,20 @@ class Timeline: · 6 unmodified lines | ||
| 1926 | 1975 | divEdge = (mTotal - tS*(divTotal-1))*100/mTotal |
| 1927 | 1976 | for i in range(divTotal): |
| 1928 | 1977 | htmlline = '' |
| 1929 | − if(mode == 'resume'): | |
| 1930 | − pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal)) | |
| 1931 | − val = '%0.fms' % (float(i)*tS*1000) | |
| 1932 | − htmlline = timescale.format(pos, val) | |
| 1933 | − if(i == 0): | |
| 1934 | − htmlline = rline | |
| 1935 | − else: | |
| 1978 | + if(mode == 'suspend'): | |
| 1936 | 1979 | pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal) - divEdge) |
| 1937 | 1980 | val = '%0.fms' % (float(i-divTotal+1)*tS*1000) |
| 1938 | 1981 | if(i == divTotal - 1): |
| 1939 | − val = 'Suspend' | |
| 1982 | + val = mode | |
| 1983 | + htmlline = timescale.format(pos, val) | |
| 1984 | + else: | |
| 1985 | + pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal)) | |
| 1986 | + val = '%0.fms' % (float(i)*tS*1000) | |
| 1940 | 1987 | htmlline = timescale.format(pos, val) |
| 1988 | + if(i == 0): | |
| 1989 | + htmlline = rline.format(mode) | |
| 1941 | 1990 | output += htmlline |
| 1942 | − output += '</div>\n' | |
| 1943 | − return output | |
| 1991 | + self.html += output+'</div>\n' | |
| 1944 | 1992 | |
| 1945 | 1993 | # Class: TestProps |
| 1946 | 1994 | # Description: |
| @@ -2009,7 +2057,7 @@ class ProcessMonitor: · 62 unmodified lines | ||
| 2009 | 2057 | val['kern'] = kern |
| 2010 | 2058 | if ujiff > 0 or kjiff > 0: |
| 2011 | 2059 | running[pid] = ujiff + kjiff |
| 2012 | − result = process.wait() | |
| 2060 | + process.wait() | |
| 2013 | 2061 | out = '' |
| 2014 | 2062 | for pid in running: |
| 2015 | 2063 | jiffies = running[pid] |
| @@ -2071,26 +2119,6 @@ def parseStamp(line, data): · 55 unmodified lines | ||
| 2071 | 2119 | if not sysvals.stamp: |
| 2072 | 2120 | sysvals.stamp = data.stamp |
| 2073 | 2121 | |
| 2074 | −# Function: diffStamp | |
| 2075 | −# Description: | |
| 2076 | −# compare the host, kernel, and mode fields in 3 stamps | |
| 2077 | −# Arguments: | |
| 2078 | −# stamp1: string array with mode, kernel, and host | |
| 2079 | −# stamp2: string array with mode, kernel, and host | |
| 2080 | −# Return: | |
| 2081 | −# True if stamps differ, False if they're the same | |
| 2082 | −def diffStamp(stamp1, stamp2): | |
| 2083 | − if 'host' in stamp1 and 'host' in stamp2: | |
| 2084 | − if stamp1['host'] != stamp2['host']: | |
| 2085 | − return True | |
| 2086 | − if 'kernel' in stamp1 and 'kernel' in stamp2: | |
| 2087 | − if stamp1['kernel'] != stamp2['kernel']: | |
| 2088 | − return True | |
| 2089 | − if 'mode' in stamp1 and 'mode' in stamp2: | |
| 2090 | − if stamp1['mode'] != stamp2['mode']: | |
| 2091 | − return True | |
| 2092 | − return False | |
| 2093 | − | |
| 2094 | 2122 | # Function: doesTraceLogHaveTraceEvents |
| 2095 | 2123 | # Description: |
| 2096 | 2124 | # Quickly determine if the ftrace log has some or all of the trace events |
| @@ -2722,7 +2750,7 @@ def parseTraceLog(): · 625 unmodified lines | ||
| 2722 | 2750 | # create blocks for orphan cg data |
| 2723 | 2751 | for sortkey in sorted(sortlist): |
| 2724 | 2752 | cg = sortlist[sortkey] |
| 2725 | − name = cg.list[0].name | |
| 2753 | + name = cg.name | |
| 2726 | 2754 | if sysvals.isCallgraphFunc(name): |
| 2727 | 2755 | vprint('Callgraph found for task %d: %.3fms, %s' % (cg.pid, (cg.end - cg.start)*1000, name)) |
| 2728 | 2756 | cg.newActionFromFunction(data) |
| @@ -3100,149 +3128,154 @@ def parseKernelLog(data): · 371 unmodified lines | ||
| 3100 | 3128 | data.fixupInitcallsThatDidntReturn() |
| 3101 | 3129 | return True |
| 3102 | 3130 | |
| 3131 | +def callgraphHTML(sv, hf, num, cg, title, color, devid): | |
| 3132 | + html_func_top = '<article id="{0}" class="atop" style="background:{1}">\n<input type="checkbox" class="pf" id="f{2}" checked/><label for="f{2}">{3} {4}</label>\n' | |
| 3133 | + html_func_start = '<article>\n<input type="checkbox" class="pf" id="f{0}" checked/><label for="f{0}">{1} {2}</label>\n' | |
| 3134 | + html_func_end = '</article>\n' | |
| 3135 | + html_func_leaf = '<article>{0} {1}</article>\n' | |
| 3136 | + | |
| 3137 | + cgid = devid | |
| 3138 | + if cg.id: | |
| 3139 | + cgid += cg.id | |
| 3140 | + cglen = (cg.end - cg.start) * 1000 | |
| 3141 | + if cglen < sv.mincglen: | |
| 3142 | + return num | |
| 3143 | + | |
| 3144 | + fmt = '<r>(%.3f ms @ '+sv.timeformat+' to '+sv.timeformat+')</r>' | |
| 3145 | + flen = fmt % (cglen, cg.start, cg.end) | |
| 3146 | + hf.write(html_func_top.format(cgid, color, num, title, flen)) | |
| 3147 | + num += 1 | |
| 3148 | + for line in cg.list: | |
| 3149 | + if(line.length < 0.000000001): | |
| 3150 | + flen = '' | |
| 3151 | + else: | |
| 3152 | + fmt = '<n>(%.3f ms @ '+sv.timeformat+')</n>' | |
| 3153 | + flen = fmt % (line.length*1000, line.time) | |
| 3154 | + if(line.freturn and line.fcall): | |
| 3155 | + hf.write(html_func_leaf.format(line.name, flen)) | |
| 3156 | + elif(line.freturn): | |
| 3157 | + hf.write(html_func_end) | |
| 3158 | + else: | |
| 3159 | + hf.write(html_func_start.format(num, line.name, flen)) | |
| 3160 | + num += 1 | |
| 3161 | + hf.write(html_func_end) | |
| 3162 | + return num | |
| 3163 | + | |
| 3164 | +def addCallgraphs(sv, hf, data): | |
| 3165 | + hf.write('<section id="callgraphs" class="callgraph">\n') | |
| 3166 | + # write out the ftrace data converted to html | |
| 3167 | + num = 0 | |
| 3168 | + for p in data.phases: | |
| 3169 | + if sv.cgphase and p != sv.cgphase: | |
| 3170 | + continue | |
| 3171 | + list = data.dmesg[p]['list'] | |
| 3172 | + for devname in data.sortedDevices(p): | |
| 3173 | + dev = list[devname] | |
| 3174 | + color = 'white' | |
| 3175 | + if 'color' in data.dmesg[p]: | |
| 3176 | + color = data.dmesg[p]['color'] | |
| 3177 | + if 'color' in dev: | |
| 3178 | + color = dev['color'] | |
| 3179 | + name = devname | |
| 3180 | + if(devname in sv.devprops): | |
| 3181 | + name = sv.devprops[devname].altName(devname) | |
| 3182 | + if sv.suspendmode in suspendmodename: | |
| 3183 | + name += ' '+p | |
| 3184 | + if('ftrace' in dev): | |
| 3185 | + cg = dev['ftrace'] | |
| 3186 | + num = callgraphHTML(sv, hf, num, cg, | |
| 3187 | + name, color, dev['id']) | |
| 3188 | + if('ftraces' in dev): | |
| 3189 | + for cg in dev['ftraces']: | |
| 3190 | + num = callgraphHTML(sv, hf, num, cg, | |
| 3191 | + name+' → '+cg.name, color, dev['id']) | |
| 3192 | + | |
| 3193 | + hf.write('\n\n </section>\n') | |
| 3194 | + | |
| 3103 | 3195 | # Function: createHTMLSummarySimple |
| 3104 | 3196 | # Description: |
| 3105 | 3197 | # Create summary html file for a series of tests |
| 3106 | 3198 | # Arguments: |
| 3107 | 3199 | # testruns: array of Data objects from parseTraceLog |
| 3108 | −def createHTMLSummarySimple(testruns, htmlfile): | |
| 3109 | − # print out the basic summary of all the tests | |
| 3110 | − hf = open(htmlfile, 'w') | |
| 3111 | − | |
| 3200 | +def createHTMLSummarySimple(testruns, htmlfile, folder): | |
| 3112 | 3201 | # write the html header first (html head, css code, up to body start) |
| 3113 | 3202 | html = '<!DOCTYPE html>\n<html>\n<head>\n\ |
| 3114 | 3203 | <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ |
| 3115 | − <title>AnalyzeSuspend Summary</title>\n\ | |
| 3204 | + <title>SleepGraph Summary</title>\n\ | |
| 3116 | 3205 | <style type=\'text/css\'>\n\ |
| 3117 | − body {overflow-y: scroll;}\n\ | |
| 3118 | − .stamp {width: 100%;text-align:center;background-color:#495E09;line-height:30px;color:white;font: 25px Arial;}\n\ | |
| 3206 | + .stamp {width: 100%;text-align:center;background:#888;line-height:30px;color:white;font: 25px Arial;}\n\ | |
| 3119 | 3207 | table {width:100%;border-collapse: collapse;}\n\ |
| 3120 | − .summary {font: 22px Arial;border:1px solid;}\n\ | |
| 3121 | − th {border: 1px solid black;background-color:#A7C942;color:white;}\n\ | |
| 3122 | − td {text-align: center;}\n\ | |
| 3123 | − tr.alt td {background-color:#EAF2D3;}\n\ | |
| 3124 | − tr.avg td {background-color:#BDE34C;}\n\ | |
| 3125 | − a:link {color: #90B521;}\n\ | |
| 3126 | − a:visited {color: #495E09;}\n\ | |
| 3127 | − a:hover {color: #B1DF28;}\n\ | |
| 3128 | − a:active {color: #FFFFFF;}\n\ | |
| 3208 | + .summary {border:1px solid;}\n\ | |
| 3209 | + th {border: 1px solid black;background:#222;color:white;}\n\ | |
| 3210 | + td {font: 16px "Times New Roman";text-align: center;}\n\ | |
| 3211 | + tr.alt td {background:#ddd;}\n\ | |
| 3212 | + tr.avg td {background:#aaa;}\n\ | |
| 3129 | 3213 | </style>\n</head>\n<body>\n' |
| 3130 | 3214 | |
| 3131 | 3215 | # group test header |
| 3132 | − count = len(testruns) | |
| 3133 | − headline_stamp = '<div class="stamp">{0} {1} {2} {3} ({4} tests)</div>\n' | |
| 3134 | − html += headline_stamp.format(sysvals.stamp['host'], | |
| 3135 | − sysvals.stamp['kernel'], sysvals.stamp['mode'], | |
| 3136 | − sysvals.stamp['time'], count) | |
| 3137 | − | |
| 3138 | − # check to see if all the tests have the same value | |
| 3139 | − stampcolumns = False | |
| 3140 | − for data in testruns: | |
| 3141 | − if diffStamp(sysvals.stamp, data.stamp): | |
| 3142 | − stampcolumns = True | |
| 3143 | − break | |
| 3144 | − | |
| 3216 | + html += '<div class="stamp">%s (%d tests)</div>\n' % (folder, len(testruns)) | |
| 3145 | 3217 | th = '\t<th>{0}</th>\n' |
| 3146 | 3218 | td = '\t<td>{0}</td>\n' |
| 3147 | − tdlink = '\t<td><a href="{0}">Click Here</a></td>\n' | |
| 3219 | + tdlink = '\t<td><a href="{0}">html</a></td>\n' | |
| 3148 | 3220 | |
| 3149 | 3221 | # table header |
| 3150 | − html += '<table class="summary">\n<tr>\n' | |
| 3151 | − html += th.format("Test #") | |
| 3152 | − if stampcolumns: | |
| 3153 | − html += th.format("Hostname") | |
| 3154 | − html += th.format("Kernel Version") | |
| 3155 | − html += th.format("Suspend Mode") | |
| 3156 | − html += th.format("Test Time") | |
| 3157 | − html += th.format("Suspend Time") | |
| 3158 | − html += th.format("Resume Time") | |
| 3159 | − html += th.format("Detail") | |
| 3160 | − html += '</tr>\n' | |
| 3222 | + html += '<table class="summary">\n<tr>\n' + th.format('#') +\ | |
| 3223 | + th.format('Mode') + th.format('Host') + th.format('Kernel') +\ | |
| 3224 | + th.format('Test Time') + th.format('Suspend') + th.format('Resume') +\ | |
| 3225 | + th.format('Detail') + '</tr>\n' | |
| 3161 | 3226 | |
| 3162 | 3227 | # test data, 1 row per test |
| 3163 | − sTimeAvg = 0.0 | |
| 3164 | − rTimeAvg = 0.0 | |
| 3165 | − num = 1 | |
| 3166 | − for data in testruns: | |
| 3167 | − # data.end is the end of post_resume | |
| 3168 | − resumeEnd = data.dmesg['resume_complete']['end'] | |
| 3228 | + avg = '<tr class="avg"><td></td><td></td><td></td><td></td>'+\ | |
| 3229 | + '<td>Average of {0} {1} tests</td><td>{2}</td><td>{3}</td><td></td></tr>\n' | |
| 3230 | + sTimeAvg = rTimeAvg = 0.0 | |
| 3231 | + mode = '' | |
| 3232 | + num = 0 | |
| 3233 | + for data in sorted(testruns, key=lambda v:(v['mode'], v['host'], v['kernel'])): | |
| 3234 | + if mode != data['mode']: | |
| 3235 | + # test average line | |
| 3236 | + if(num > 0): | |
| 3237 | + sTimeAvg /= (num - 1) | |
| 3238 | + rTimeAvg /= (num - 1) | |
| 3239 | + html += avg.format('%d' % (num - 1), mode, | |
| 3240 | + '%3.3f ms' % sTimeAvg, '%3.3f ms' % rTimeAvg) | |
| 3241 | + sTimeAvg = rTimeAvg = 0.0 | |
| 3242 | + mode = data['mode'] | |
| 3243 | + num = 1 | |
| 3244 | + # alternate row color | |
| 3169 | 3245 | if num % 2 == 1: |
| 3170 | 3246 | html += '<tr class="alt">\n' |
| 3171 | 3247 | else: |
| 3172 | 3248 | html += '<tr>\n' |
| 3173 | − | |
| 3174 | − # test num | |
| 3175 | − html += td.format("test %d" % num) | |
| 3249 | + html += td.format("%d" % num) | |
| 3176 | 3250 | num += 1 |
| 3177 | − if stampcolumns: | |
| 3178 | − # host name | |
| 3179 | − val = "unknown" | |
| 3180 | − if('host' in data.stamp): | |
| 3181 | − val = data.stamp['host'] | |
| 3182 | − html += td.format(val) | |
| 3183 | − # host kernel | |
| 3251 | + # basic info | |
| 3252 | + for item in ['mode', 'host', 'kernel', 'time']: | |
| 3184 | 3253 | val = "unknown" |
| 3185 | − if('kernel' in data.stamp): | |
| 3186 | − val = data.stamp['kernel'] | |
| 3254 | + if(item in data): | |
| 3255 | + val = data[item] | |
| 3187 | 3256 | html += td.format(val) |
| 3188 | − # suspend mode | |
| 3189 | − val = "unknown" | |
| 3190 | − if('mode' in data.stamp): | |
| 3191 | − val = data.stamp['mode'] | |
| 3192 | − html += td.format(val) | |
| 3193 | − # test time | |
| 3194 | − val = "unknown" | |
| 3195 | − if('time' in data.stamp): | |
| 3196 | − val = data.stamp['time'] | |
| 3197 | − html += td.format(val) | |
| 3198 | 3257 | # suspend time |
| 3199 | − sTime = (data.tSuspended - data.start)*1000 | |
| 3258 | + sTime = float(data['suspend']) | |
| 3200 | 3259 | sTimeAvg += sTime |
| 3201 | − html += td.format("%3.3f ms" % sTime) | |
| 3260 | + html += td.format('%.3f ms' % sTime) | |
| 3202 | 3261 | # resume time |
| 3203 | − rTime = (resumeEnd - data.tResumed)*1000 | |
| 3262 | + rTime = float(data['resume']) | |
| 3204 | 3263 | rTimeAvg += rTime |
| 3205 | − html += td.format("%3.3f ms" % rTime) | |
| 3264 | + html += td.format('%.3f ms' % rTime) | |
| 3206 | 3265 | # link to the output html |
| 3207 | − html += tdlink.format(data.outfile) | |
| 3208 | − | |
| 3209 | − html += '</tr>\n' | |
| 3210 | − | |
| 3211 | − # last line: test average | |
| 3212 | − if(count > 0): | |
| 3213 | − sTimeAvg /= count | |
| 3214 | − rTimeAvg /= count | |
| 3215 | − html += '<tr class="avg">\n' | |
| 3216 | − html += td.format('Average') # name | |
| 3217 | − if stampcolumns: | |
| 3218 | − html += td.format('') # host | |
| 3219 | − html += td.format('') # kernel | |
| 3220 | − html += td.format('') # mode | |
| 3221 | − html += td.format('') # time | |
| 3222 | − html += td.format("%3.3f ms" % sTimeAvg) # suspend time | |
| 3223 | − html += td.format("%3.3f ms" % rTimeAvg) # resume time | |
| 3224 | − html += td.format('') # output link | |
| 3225 | − html += '</tr>\n' | |
| 3266 | + html += tdlink.format(data['url']) + '</tr>\n' | |
| 3267 | + # last test average line | |
| 3268 | + if(num > 0): | |
| 3269 | + sTimeAvg /= (num - 1) | |
| 3270 | + rTimeAvg /= (num - 1) | |
| 3271 | + html += avg.format('%d' % (num - 1), mode, | |
| 3272 | + '%3.3f ms' % sTimeAvg, '%3.3f ms' % rTimeAvg) | |
| 3226 | 3273 | |
| 3227 | 3274 | # flush the data to file |
| 3228 | − hf.write(html+'</table>\n') | |
| 3229 | − hf.write('</body>\n</html>\n') | |
| 3275 | + hf = open(htmlfile, 'w') | |
| 3276 | + hf.write(html+'</table>\n</body>\n</html>\n') | |
| 3230 | 3277 | hf.close() |
| 3231 | 3278 | |
| 3232 | −def htmlTitle(): | |
| 3233 | − modename = { | |
| 3234 | − 'freeze': 'Freeze (S0)', | |
| 3235 | − 'standby': 'Standby (S1)', | |
| 3236 | − 'mem': 'Suspend (S3)', | |
| 3237 | − 'disk': 'Hibernate (S4)' | |
| 3238 | − } | |
| 3239 | − kernel = sysvals.stamp['kernel'] | |
| 3240 | − host = sysvals.hostname[0].upper()+sysvals.hostname[1:] | |
| 3241 | − mode = sysvals.suspendmode | |
| 3242 | − if sysvals.suspendmode in modename: | |
| 3243 | − mode = modename[sysvals.suspendmode] | |
| 3244 | − return host+' '+mode+' '+kernel | |
| 3245 | − | |
| 3246 | 3279 | def ordinal(value): |
| 3247 | 3280 | suffix = 'th' |
| 3248 | 3281 | if value < 10 or value > 19: |
| @@ -3272,24 +3305,11 @@ def createHTML(testruns): · 23 unmodified lines | ||
| 3272 | 3305 | kerror = True |
| 3273 | 3306 | data.normalizeTime(testruns[-1].tSuspended) |
| 3274 | 3307 | |
| 3275 | − x2changes = ['', 'absolute'] | |
| 3276 | − if len(testruns) > 1: | |
| 3277 | − x2changes = ['1', 'relative'] | |
| 3278 | 3308 | # html function templates |
| 3279 | − headline_version = '<div class="version"><a href="https://01.org/suspendresume">AnalyzeSuspend v%s</a></div>' % sysvals.version | |
| 3280 | − headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n' | |
| 3281 | − html_devlist1 = '<button id="devlist1" class="devlist" style="float:left;">Device Detail%s</button>' % x2changes[0] | |
| 3282 | − html_zoombox = '<center><button id="zoomin">ZOOM IN +</button><button id="zoomout">ZOOM OUT -</button><button id="zoomdef">ZOOM 1:1</button></center>\n' | |
| 3283 | − html_devlist2 = '<button id="devlist2" class="devlist" style="float:right;">Device Detail2</button>\n' | |
| 3284 | − html_timeline = '<div id="dmesgzoombox" class="zoombox">\n<div id="{0}" class="timeline" style="height:{1}px">\n' | |
| 3285 | − html_tblock = '<div id="block{0}" class="tblock" style="left:{1}%;width:{2}%;"><div class="tback" style="height:{3}px"></div>\n' | |
| 3286 | − html_device = '<div id="{0}" title="{1}" class="thread{7}" style="left:{2}%;top:{3}px;height:{4}px;width:{5}%;{8}">{6}</div>\n' | |
| 3287 | 3309 | html_error = '<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">ERROR→</div>\n' |
| 3288 | 3310 | html_traceevent = '<div title="{0}" class="traceevent{6}" style="left:{1}%;top:{2}px;height:{3}px;width:{4}%;line-height:{3}px;{7}">{5}</div>\n' |
| 3289 | 3311 | html_cpuexec = '<div class="jiffie" style="left:{0}%;top:{1}px;height:{2}px;width:{3}%;background:{4};"></div>\n' |
| 3290 | − html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}px;height:{3}px;background-color:{4}">{5}</div>\n' | |
| 3291 | − html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n' | |
| 3292 | − html_legend = '<div id="p{3}" class="square" style="left:{0}%;background-color:{1}"> {2}</div>\n' | |
| 3312 | + html_legend = '<div id="p{3}" class="square" style="left:{0}%;background:{1}"> {2}</div>\n' | |
| 3293 | 3313 | html_timetotal = '<table class="time1">\n<tr>'\ |
| 3294 | 3314 | '<td class="green" title="{3}">{2} Suspend Time: <b>{0} ms</b></td>'\ |
| 3295 | 3315 | '<td class="yellow" title="{4}">{2} Resume Time: <b>{1} ms</b></td>'\ |
| @@ -3311,20 +3331,18 @@ def createHTML(testruns): · 15 unmodified lines | ||
| 3311 | 3331 | '</tr>\n</table>\n' |
| 3312 | 3332 | |
| 3313 | 3333 | # html format variables |
| 3314 | − hoverZ = 'z-index:8;' | |
| 3315 | − if sysvals.usedevsrc: | |
| 3316 | − hoverZ = '' | |
| 3317 | 3334 | scaleH = 20 |
| 3318 | − scaleTH = 20 | |
| 3319 | 3335 | if kerror: |
| 3320 | 3336 | scaleH = 40 |
| 3321 | − scaleTH = 60 | |
| 3322 | 3337 | |
| 3323 | 3338 | # device timeline |
| 3324 | 3339 | vprint('Creating Device Timeline...') |
| 3325 | 3340 | |
| 3326 | 3341 | devtl = Timeline(30, scaleH) |
| 3327 | 3342 | |
| 3343 | + # write the test title and general info header | |
| 3344 | + devtl.createHeader(sysvals) | |
| 3345 | + | |
| 3328 | 3346 | # Generate the header for this timeline |
| 3329 | 3347 | for data in testruns: |
| 3330 | 3348 | tTotal = data.end - data.start |
| @@ -3346,7 +3364,7 @@ def createHTML(testruns): · 15 unmodified lines | ||
| 3346 | 3364 | if(len(testruns) > 1): |
| 3347 | 3365 | testdesc = ordinal(data.testnumber+1)+' '+testdesc |
| 3348 | 3366 | thtml = html_timetotal3.format(run_time, testdesc) |
| 3349 | − devtl.html['header'] += thtml | |
| 3367 | + devtl.html += thtml | |
| 3350 | 3368 | elif data.fwValid: |
| 3351 | 3369 | suspend_time = '%.0f'%(sktime + (data.fwSuspend/1000000.0)) |
| 3352 | 3370 | resume_time = '%.0f'%(rktime + (data.fwResume/1000000.0)) |
| @@ -3363,10 +3381,10 @@ def createHTML(testruns): · 10 unmodified lines | ||
| 3363 | 3381 | else: |
| 3364 | 3382 | thtml = html_timetotal2.format(suspend_time, low_time, \ |
| 3365 | 3383 | resume_time, testdesc1, stitle, rtitle) |
| 3366 | − devtl.html['header'] += thtml | |
| 3384 | + devtl.html += thtml | |
| 3367 | 3385 | sftime = '%.3f'%(data.fwSuspend / 1000000.0) |
| 3368 | 3386 | rftime = '%.3f'%(data.fwResume / 1000000.0) |
| 3369 | − devtl.html['header'] += html_timegroups.format('%.3f'%sktime, \ | |
| 3387 | + devtl.html += html_timegroups.format('%.3f'%sktime, \ | |
| 3370 | 3388 | sftime, rftime, '%.3f'%rktime, testdesc2, sysvals.suspendmode) |
| 3371 | 3389 | else: |
| 3372 | 3390 | suspend_time = '%.3f' % sktime |
| @@ -3382,7 +3400,7 @@ def createHTML(testruns): · 9 unmodified lines | ||
| 3382 | 3400 | else: |
| 3383 | 3401 | thtml = html_timetotal2.format(suspend_time, low_time, \ |
| 3384 | 3402 | resume_time, testdesc, stitle, rtitle) |
| 3385 | − devtl.html['header'] += thtml | |
| 3403 | + devtl.html += thtml | |
| 3386 | 3404 | |
| 3387 | 3405 | # time scale for potentially multiple datasets |
| 3388 | 3406 | t0 = testruns[0].start |
| @@ -3429,15 +3447,8 @@ def createHTML(testruns): · 40 unmodified lines | ||
| 3429 | 3447 | devtl.getPhaseRows(threadlist, devtl.rows) |
| 3430 | 3448 | devtl.calcTotalRows() |
| 3431 | 3449 | |
| 3432 | − # create bounding box, add buttons | |
| 3433 | − if sysvals.suspendmode != 'command': | |
| 3434 | − devtl.html['timeline'] += html_devlist1 | |
| 3435 | − if len(testruns) > 1: | |
| 3436 | − devtl.html['timeline'] += html_devlist2 | |
| 3437 | − devtl.html['timeline'] += html_zoombox | |
| 3438 | − devtl.html['timeline'] += html_timeline.format('dmesg', devtl.height) | |
| 3439 | − | |
| 3440 | 3450 | # draw the full timeline |
| 3451 | + devtl.createZoomBox(sysvals.suspendmode, len(testruns)) | |
| 3441 | 3452 | phases = {'suspend':[],'resume':[]} |
| 3442 | 3453 | for phase in data.dmesg: |
| 3443 | 3454 | if 'resume' in phase: |
| @@ -3452,37 +3463,36 @@ def createHTML(testruns): · 8 unmodified lines | ||
| 3452 | 3463 | # draw suspend and resume blocks separately |
| 3453 | 3464 | bname = '%s%d' % (dir[0], data.testnumber) |
| 3454 | 3465 | if dir == 'suspend': |
| 3455 | − m0 = testruns[data.testnumber].start | |
| 3456 | − mMax = testruns[data.testnumber].tSuspended | |
| 3457 | − mTotal = mMax - m0 | |
| 3466 | + m0 = data.start | |
| 3467 | + mMax = data.tSuspended | |
| 3458 | 3468 | left = '%f' % (((m0-t0)*100.0)/tTotal) |
| 3459 | 3469 | else: |
| 3460 | − m0 = testruns[data.testnumber].tSuspended | |
| 3461 | − mMax = testruns[data.testnumber].end | |
| 3470 | + m0 = data.tSuspended | |
| 3471 | + mMax = data.end | |
| 3462 | 3472 | # in an x2 run, remove any gap between blocks |
| 3463 | 3473 | if len(testruns) > 1 and data.testnumber == 0: |
| 3464 | 3474 | mMax = testruns[1].start |
| 3465 | − mTotal = mMax - m0 | |
| 3466 | 3475 | left = '%f' % ((((m0-t0)*100.0)+sysvals.srgap/2)/tTotal) |
| 3476 | + mTotal = mMax - m0 | |
| 3467 | 3477 | # if a timeline block is 0 length, skip altogether |
| 3468 | 3478 | if mTotal == 0: |
| 3469 | 3479 | continue |
| 3470 | 3480 | width = '%f' % (((mTotal*100.0)-sysvals.srgap/2)/tTotal) |
| 3471 | − devtl.html['timeline'] += html_tblock.format(bname, left, width, devtl.scaleH) | |
| 3481 | + devtl.html += devtl.html_tblock.format(bname, left, width, devtl.scaleH) | |
| 3472 | 3482 | for b in sorted(phases[dir]): |
| 3473 | 3483 | # draw the phase color background |
| 3474 | 3484 | phase = data.dmesg[b] |
| 3475 | 3485 | length = phase['end']-phase['start'] |
| 3476 | 3486 | left = '%f' % (((phase['start']-m0)*100.0)/mTotal) |
| 3477 | 3487 | width = '%f' % ((length*100.0)/mTotal) |
| 3478 | − devtl.html['timeline'] += html_phase.format(left, width, \ | |
| 3488 | + devtl.html += devtl.html_phase.format(left, width, \ | |
| 3479 | 3489 | '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \ |
| 3480 | 3490 | data.dmesg[b]['color'], '') |
| 3481 | 3491 | for e in data.errorinfo[dir]: |
| 3482 | 3492 | # draw red lines for any kernel errors found |
| 3483 | 3493 | t, err = e |
| 3484 | 3494 | right = '%f' % (((mMax-t)*100.0)/mTotal) |
| 3485 | − devtl.html['timeline'] += html_error.format(right, err) | |
| 3495 | + devtl.html += html_error.format(right, err) | |
| 3486 | 3496 | for b in sorted(phases[dir]): |
| 3487 | 3497 | # draw the devices for this phase |
| 3488 | 3498 | phaselist = data.dmesg[b]['list'] |
| @@ -3496,7 +3506,7 @@ def createHTML(testruns): · 7 unmodified lines | ||
| 3496 | 3506 | if 'htmlclass' in dev: |
| 3497 | 3507 | xtraclass = dev['htmlclass'] |
| 3498 | 3508 | if 'color' in dev: |
| 3499 | − xtrastyle = 'background-color:%s;' % dev['color'] | |
| 3509 | + xtrastyle = 'background:%s;' % dev['color'] | |
| 3500 | 3510 | if(d in sysvals.devprops): |
| 3501 | 3511 | name = sysvals.devprops[d].altName(d) |
| 3502 | 3512 | xtraclass = sysvals.devprops[d].xtraClass() |
| @@ -3521,7 +3531,7 @@ def createHTML(testruns): · 18 unmodified lines | ||
| 3521 | 3531 | title += 'post_resume_process' |
| 3522 | 3532 | else: |
| 3523 | 3533 | title += b |
| 3524 | − devtl.html['timeline'] += html_device.format(dev['id'], \ | |
| 3534 | + devtl.html += devtl.html_device.format(dev['id'], \ | |
| 3525 | 3535 | title, left, top, '%.3f'%rowheight, width, \ |
| 3526 | 3536 | d+drv, xtraclass, xtrastyle) |
| 3527 | 3537 | if('cpuexec' in dev): |
| @@ -3535,7 +3545,7 @@ def createHTML(testruns): · 7 unmodified lines | ||
| 3535 | 3545 | left = '%f' % (((start-m0)*100)/mTotal) |
| 3536 | 3546 | width = '%f' % ((end-start)*100/mTotal) |
| 3537 | 3547 | color = 'rgba(255, 0, 0, %f)' % j |
| 3538 | − devtl.html['timeline'] += \ | |
| 3548 | + devtl.html += \ | |
| 3539 | 3549 | html_cpuexec.format(left, top, height, width, color) |
| 3540 | 3550 | if('src' not in dev): |
| 3541 | 3551 | continue |
| @@ -3548,20 +3558,20 @@ def createHTML(testruns): · 6 unmodified lines | ||
| 3548 | 3558 | xtrastyle = '' |
| 3549 | 3559 | if e.color: |
| 3550 | 3560 | xtrastyle = 'background:%s;' % e.color |
| 3551 | − devtl.html['timeline'] += \ | |
| 3561 | + devtl.html += \ | |
| 3552 | 3562 | html_traceevent.format(e.title(), \ |
| 3553 | 3563 | left, top, height, width, e.text(), '', xtrastyle) |
| 3554 | 3564 | # draw the time scale, try to make the number of labels readable |
| 3555 | − devtl.html['timeline'] += devtl.createTimeScale(m0, mMax, tTotal, dir) | |
| 3556 | − devtl.html['timeline'] += '</div>\n' | |
| 3565 | + devtl.createTimeScale(m0, mMax, tTotal, dir) | |
| 3566 | + devtl.html += '</div>\n' | |
| 3557 | 3567 | |
| 3558 | 3568 | # timeline is finished |
| 3559 | − devtl.html['timeline'] += '</div>\n</div>\n' | |
| 3569 | + devtl.html += '</div>\n</div>\n' | |
| 3560 | 3570 | |
| 3561 | 3571 | # draw a legend which describes the phases by color |
| 3562 | 3572 | if sysvals.suspendmode != 'command': |
| 3563 | 3573 | data = testruns[-1] |
| 3564 | − devtl.html['legend'] = '<div class="legend">\n' | |
| 3574 | + devtl.html += '<div class="legend">\n' | |
| 3565 | 3575 | pdelta = 100.0/len(data.phases) |
| 3566 | 3576 | pmargin = pdelta / 4.0 |
| 3567 | 3577 | for phase in data.phases: |
| @@ -3571,127 +3581,41 @@ def createHTML(testruns): · 3 unmodified lines | ||
| 3571 | 3581 | id += tmp[1][0] |
| 3572 | 3582 | order = '%.2f' % ((data.dmesg[phase]['order'] * pdelta) + pmargin) |
| 3573 | 3583 | name = string.replace(phase, '_', ' ') |
| 3574 | − devtl.html['legend'] += html_legend.format(order, \ | |
| 3584 | + devtl.html += html_legend.format(order, \ | |
| 3575 | 3585 | data.dmesg[phase]['color'], name, id) |
| 3576 | − devtl.html['legend'] += '</div>\n' | |
| 3586 | + devtl.html += '</div>\n' | |
| 3577 | 3587 | |
| 3578 | 3588 | hf = open(sysvals.htmlfile, 'w') |
| 3579 | 3589 | |
| 3580 | − if not sysvals.cgexp: | |
| 3581 | − cgchk = 'checked' | |
| 3582 | − cgnchk = 'not(:checked)' | |
| 3583 | − else: | |
| 3584 | − cgchk = 'not(:checked)' | |
| 3585 | − cgnchk = 'checked' | |
| 3586 | − | |
| 3587 | − # write the html header first (html head, css code, up to body start) | |
| 3588 | − html_header = '<!DOCTYPE html>\n<html>\n<head>\n\ | |
| 3589 | − <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ | |
| 3590 | − <title>'+htmlTitle()+'</title>\n\ | |
| 3591 | − <style type=\'text/css\'>\n\ | |
| 3592 | − body {overflow-y:scroll;}\n\ | |
| 3593 | − .stamp {width:100%;text-align:center;background-color:gray;line-height:30px;color:white;font:25px Arial;}\n\ | |
| 3594 | − .callgraph {margin-top:30px;box-shadow:5px 5px 20px black;}\n\ | |
| 3595 | − .callgraph article * {padding-left:28px;}\n\ | |
| 3596 | − h1 {color:black;font:bold 30px Times;}\n\ | |
| 3597 | − t0 {color:black;font:bold 30px Times;}\n\ | |
| 3598 | − t1 {color:black;font:30px Times;}\n\ | |
| 3599 | − t2 {color:black;font:25px Times;}\n\ | |
| 3600 | − t3 {color:black;font:20px Times;white-space:nowrap;}\n\ | |
| 3601 | − t4 {color:black;font:bold 30px Times;line-height:60px;white-space:nowrap;}\n\ | |
| 3602 | − cS {font:bold 13px Times;}\n\ | |
| 3603 | − table {width:100%;}\n\ | |
| 3604 | − .gray {background-color:rgba(80,80,80,0.1);}\n\ | |
| 3605 | − .green {background-color:rgba(204,255,204,0.4);}\n\ | |
| 3606 | − .purple {background-color:rgba(128,0,128,0.2);}\n\ | |
| 3607 | − .yellow {background-color:rgba(255,255,204,0.4);}\n\ | |
| 3608 | − .time1 {font:22px Arial;border:1px solid;}\n\ | |
| 3609 | − .time2 {font:15px Arial;border-bottom:1px solid;border-left:1px solid;border-right:1px solid;}\n\ | |
| 3610 | − td {text-align:center;}\n\ | |
| 3611 | − r {color:#500000;font:15px Tahoma;}\n\ | |
| 3612 | − n {color:#505050;font:15px Tahoma;}\n\ | |
| 3613 | − .tdhl {color:red;}\n\ | |
| 3614 | − .hide {display:none;}\n\ | |
| 3615 | − .pf {display:none;}\n\ | |
| 3616 | − .pf:'+cgchk+' + label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/><rect x="8" y="4" width="2" height="10" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\ | |
| 3617 | − .pf:'+cgnchk+' ~ label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\ | |
| 3618 | − .pf:'+cgchk+' ~ *:not(:nth-child(2)) {display:none;}\n\ | |
| 3619 | − .zoombox {position:relative;width:100%;overflow-x:scroll;-webkit-user-select:none;-moz-user-select:none;user-select:none;}\n\ | |
| 3620 | − .timeline {position:relative;font-size:14px;cursor:pointer;width:100%; overflow:hidden;background:linear-gradient(#cccccc, white);}\n\ | |
| 3621 | − .thread {position:absolute;height:0%;overflow:hidden;z-index:7;line-height:30px;font-size:14px;border:1px solid;text-align:center;white-space:nowrap;}\n\ | |
| 3622 | − .thread.ps {border-radius:3px;background:linear-gradient(to top, #ccc, #eee);}\n\ | |
| 3623 | − .thread:hover {background-color:white;border:1px solid red;'+hoverZ+'}\n\ | |
| 3624 | − .thread.sec,.thread.sec:hover {background-color:black;border:0;color:white;line-height:15px;font-size:10px;}\n\ | |
| 3625 | − .hover {background-color:white;border:1px solid red;'+hoverZ+'}\n\ | |
| 3626 | − .hover.sync {background-color:white;}\n\ | |
| 3627 | − .hover.bg,.hover.kth,.hover.sync,.hover.ps {background-color:white;}\n\ | |
| 3628 | − .jiffie {position:absolute;pointer-events: none;z-index:8;}\n\ | |
| 3629 | − .traceevent {position:absolute;font-size:10px;z-index:7;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,#CCC,#969696);}\n\ | |
| 3630 | − .traceevent:hover {color:white;font-weight:bold;border:1px solid white;}\n\ | |
| 3631 | − .phase {position:absolute;overflow:hidden;border:0px;text-align:center;}\n\ | |
| 3632 | − .phaselet {position:absolute;overflow:hidden;border:0px;text-align:center;height:100px;font-size:24px;}\n\ | |
| 3633 | − .t {position:absolute;line-height:'+('%d'%scaleTH)+'px;pointer-events:none;top:0;height:100%;border-right:1px solid black;z-index:6;}\n\ | |
| 3634 | − .err {position:absolute;top:0%;height:100%;border-right:3px solid red;color:red;font:bold 14px Times;line-height:18px;}\n\ | |
| 3635 | − .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\ | |
| 3636 | − .legend .square {position:absolute;cursor:pointer;top:10px; width:0px;height:20px;border:1px solid;padding-left:20px;}\n\ | |
| 3637 | − button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\ | |
| 3638 | − .logbtn {position:relative;float:right;height:25px;width:50px;margin-top:3px;margin-bottom:0;font-size:10px;text-align:center;}\n\ | |
| 3639 | − .devlist {position:'+x2changes[1]+';width:190px;}\n\ | |
| 3640 | − a:link {color:white;text-decoration:none;}\n\ | |
| 3641 | − a:visited {color:white;}\n\ | |
| 3642 | − a:hover {color:white;}\n\ | |
| 3643 | − a:active {color:white;}\n\ | |
| 3644 | − .version {position:relative;float:left;color:white;font-size:10px;line-height:30px;margin-left:10px;}\n\ | |
| 3645 | − #devicedetail {height:100px;box-shadow:5px 5px 20px black;}\n\ | |
| 3646 | − .tblock {position:absolute;height:100%;background-color:#ddd;}\n\ | |
| 3647 | − .tback {position:absolute;width:100%;background:linear-gradient(#ccc, #ddd);}\n\ | |
| 3648 | − .bg {z-index:1;}\n\ | |
| 3649 | − </style>\n</head>\n<body>\n' | |
| 3650 | − | |
| 3651 | 3590 | # no header or css if its embedded |
| 3652 | 3591 | if(sysvals.embedded): |
| 3653 | 3592 | hf.write('pass True tSus %.3f tRes %.3f tLow %.3f fwvalid %s tSus %.3f tRes %.3f\n' % |
| 3654 | 3593 | (data.tSuspended-data.start, data.end-data.tSuspended, data.tLow, data.fwValid, \ |
| 3655 | 3594 | data.fwSuspend/1000000, data.fwResume/1000000)) |
| 3656 | 3595 | else: |
| 3657 | − hf.write(html_header) | |
| 3658 | − | |
| 3659 | − # write the test title and general info header | |
| 3660 | − if(sysvals.stamp['time'] != ""): | |
| 3661 | − hf.write(headline_version) | |
| 3662 | − if sysvals.logmsg: | |
| 3663 | − hf.write('<button id="showtest" class="logbtn">log</button>') | |
| 3664 | − if sysvals.addlogs and sysvals.dmesgfile: | |
| 3665 | − hf.write('<button id="showdmesg" class="logbtn">dmesg</button>') | |
| 3666 | − if sysvals.addlogs and sysvals.ftracefile: | |
| 3667 | − hf.write('<button id="showftrace" class="logbtn">ftrace</button>') | |
| 3668 | − hf.write(headline_stamp.format(sysvals.stamp['host'], | |
| 3669 | − sysvals.stamp['kernel'], sysvals.stamp['mode'], \ | |
| 3670 | − sysvals.stamp['time'])) | |
| 3596 | + addCSS(hf, sysvals, len(testruns), kerror) | |
| 3671 | 3597 | |
| 3672 | 3598 | # write the device timeline |
| 3673 | − hf.write(devtl.html['header']) | |
| 3674 | − hf.write(devtl.html['timeline']) | |
| 3675 | − hf.write(devtl.html['legend']) | |
| 3599 | + hf.write(devtl.html) | |
| 3676 | 3600 | hf.write('<div id="devicedetailtitle"></div>\n') |
| 3677 | 3601 | hf.write('<div id="devicedetail" style="display:none;">\n') |
| 3678 | 3602 | # draw the colored boxes for the device detail section |
| 3679 | 3603 | for data in testruns: |
| 3680 | 3604 | hf.write('<div id="devicedetail%d">\n' % data.testnumber) |
| 3681 | 3605 | pscolor = 'linear-gradient(to top left, #ccc, #eee)' |
| 3682 | − hf.write(html_phaselet.format('pre_suspend_process', \ | |
| 3606 | + hf.write(devtl.html_phaselet.format('pre_suspend_process', \ | |
| 3683 | 3607 | '0', '0', pscolor)) |
| 3684 | 3608 | for b in data.phases: |
| 3685 | 3609 | phase = data.dmesg[b] |
| 3686 | 3610 | length = phase['end']-phase['start'] |
| 3687 | 3611 | left = '%.3f' % (((phase['start']-t0)*100.0)/tTotal) |
| 3688 | 3612 | width = '%.3f' % ((length*100.0)/tTotal) |
| 3689 | − hf.write(html_phaselet.format(b, left, width, \ | |
| 3613 | + hf.write(devtl.html_phaselet.format(b, left, width, \ | |
| 3690 | 3614 | data.dmesg[b]['color'])) |
| 3691 | − hf.write(html_phaselet.format('post_resume_process', \ | |
| 3615 | + hf.write(devtl.html_phaselet.format('post_resume_process', \ | |
| 3692 | 3616 | '0', '0', pscolor)) |
| 3693 | 3617 | if sysvals.suspendmode == 'command': |
| 3694 | − hf.write(html_phaselet.format('cmdexec', '0', '0', pscolor)) | |
| 3618 | + hf.write(devtl.html_phaselet.format('cmdexec', '0', '0', pscolor)) | |
| 3695 | 3619 | hf.write('</div>\n') |
| 3696 | 3620 | hf.write('</div>\n') |
| 3697 | 3621 | |
| @@ -3701,52 +3625,7 @@ def createHTML(testruns): · 3 unmodified lines | ||
| 3701 | 3625 | else: |
| 3702 | 3626 | data = testruns[-1] |
| 3703 | 3627 | if(sysvals.usecallgraph and not sysvals.embedded): |
| 3704 | − hf.write('<section id="callgraphs" class="callgraph">\n') | |
| 3705 | − # write out the ftrace data converted to html | |
| 3706 | − html_func_top = '<article id="{0}" class="atop" style="background-color:{1}">\n<input type="checkbox" class="pf" id="f{2}" checked/><label for="f{2}">{3} {4}</label>\n' | |
| 3707 | − html_func_start = '<article>\n<input type="checkbox" class="pf" id="f{0}" checked/><label for="f{0}">{1} {2}</label>\n' | |
| 3708 | − html_func_end = '</article>\n' | |
| 3709 | − html_func_leaf = '<article>{0} {1}</article>\n' | |
| 3710 | − num = 0 | |
| 3711 | − for p in data.phases: | |
| 3712 | − if sysvals.cgphase and p != sysvals.cgphase: | |
| 3713 | − continue | |
| 3714 | − list = data.dmesg[p]['list'] | |
| 3715 | − for devname in data.sortedDevices(p): | |
| 3716 | − if('ftrace' not in list[devname]): | |
| 3717 | − continue | |
| 3718 | − devid = list[devname]['id'] | |
| 3719 | − cg = list[devname]['ftrace'] | |
| 3720 | − clen = (cg.end - cg.start) * 1000 | |
| 3721 | − if clen < sysvals.mincglen: | |
| 3722 | − continue | |
| 3723 | − fmt = '<r>(%.3f ms @ '+sysvals.timeformat+' to '+sysvals.timeformat+')</r>' | |
| 3724 | − flen = fmt % (clen, cg.start, cg.end) | |
| 3725 | − name = devname | |
| 3726 | − if(devname in sysvals.devprops): | |
| 3727 | − name = sysvals.devprops[devname].altName(devname) | |
| 3728 | − if sysvals.suspendmode == 'command': | |
| 3729 | − ftitle = name | |
| 3730 | − else: | |
| 3731 | − ftitle = name+' '+p | |
| 3732 | − hf.write(html_func_top.format(devid, data.dmesg[p]['color'], \ | |
| 3733 | − num, ftitle, flen)) | |
| 3734 | − num += 1 | |
| 3735 | − for line in cg.list: | |
| 3736 | − if(line.length < 0.000000001): | |
| 3737 | − flen = '' | |
| 3738 | − else: | |
| 3739 | − fmt = '<n>(%.3f ms @ '+sysvals.timeformat+')</n>' | |
| 3740 | − flen = fmt % (line.length*1000, line.time) | |
| 3741 | − if(line.freturn and line.fcall): | |
| 3742 | − hf.write(html_func_leaf.format(line.name, flen)) | |
| 3743 | − elif(line.freturn): | |
| 3744 | − hf.write(html_func_end) | |
| 3745 | − else: | |
| 3746 | − hf.write(html_func_start.format(num, line.name, flen)) | |
| 3747 | − num += 1 | |
| 3748 | − hf.write(html_func_end) | |
| 3749 | − hf.write('\n\n </section>\n') | |
| 3628 | + addCallgraphs(sysvals, hf, data) | |
| 3750 | 3629 | |
| 3751 | 3630 | # add the test log as a hidden div |
| 3752 | 3631 | if sysvals.logmsg: |
| @@ -3788,6 +3667,100 @@ def createHTML(testruns): · 35 unmodified lines | ||
| 3788 | 3667 | hf.close() |
| 3789 | 3668 | return True |
| 3790 | 3669 | |
| 3670 | +def addCSS(hf, sv, testcount=1, kerror=False, extra=''): | |
| 3671 | + kernel = sv.stamp['kernel'] | |
| 3672 | + host = sv.hostname[0].upper()+sv.hostname[1:] | |
| 3673 | + mode = sv.suspendmode | |
| 3674 | + if sv.suspendmode in suspendmodename: | |
| 3675 | + mode = suspendmodename[sv.suspendmode] | |
| 3676 | + title = host+' '+mode+' '+kernel | |
| 3677 | + | |
| 3678 | + # various format changes by flags | |
| 3679 | + cgchk = 'checked' | |
| 3680 | + cgnchk = 'not(:checked)' | |
| 3681 | + if sv.cgexp: | |
| 3682 | + cgchk = 'not(:checked)' | |
| 3683 | + cgnchk = 'checked' | |
| 3684 | + | |
| 3685 | + hoverZ = 'z-index:8;' | |
| 3686 | + if sv.usedevsrc: | |
| 3687 | + hoverZ = '' | |
| 3688 | + | |
| 3689 | + devlistpos = 'absolute' | |
| 3690 | + if testcount > 1: | |
| 3691 | + devlistpos = 'relative' | |
| 3692 | + | |
| 3693 | + scaleTH = 20 | |
| 3694 | + if kerror: | |
| 3695 | + scaleTH = 60 | |
| 3696 | + | |
| 3697 | + # write the html header first (html head, css code, up to body start) | |
| 3698 | + html_header = '<!DOCTYPE html>\n<html>\n<head>\n\ | |
| 3699 | + <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ | |
| 3700 | + <title>'+title+'</title>\n\ | |
| 3701 | + <style type=\'text/css\'>\n\ | |
| 3702 | + body {overflow-y:scroll;}\n\ | |
| 3703 | + .stamp {width:100%;text-align:center;background:gray;line-height:30px;color:white;font:25px Arial;}\n\ | |
| 3704 | + .callgraph {margin-top:30px;box-shadow:5px 5px 20px black;}\n\ | |
| 3705 | + .callgraph article * {padding-left:28px;}\n\ | |
| 3706 | + h1 {color:black;font:bold 30px Times;}\n\ | |
| 3707 | + t0 {color:black;font:bold 30px Times;}\n\ | |
| 3708 | + t1 {color:black;font:30px Times;}\n\ | |
| 3709 | + t2 {color:black;font:25px Times;}\n\ | |
| 3710 | + t3 {color:black;font:20px Times;white-space:nowrap;}\n\ | |
| 3711 | + t4 {color:black;font:bold 30px Times;line-height:60px;white-space:nowrap;}\n\ | |
| 3712 | + cS {font:bold 13px Times;}\n\ | |
| 3713 | + table {width:100%;}\n\ | |
| 3714 | + .gray {background:rgba(80,80,80,0.1);}\n\ | |
| 3715 | + .green {background:rgba(204,255,204,0.4);}\n\ | |
| 3716 | + .purple {background:rgba(128,0,128,0.2);}\n\ | |
| 3717 | + .yellow {background:rgba(255,255,204,0.4);}\n\ | |
| 3718 | + .blue {background:rgba(169,208,245,0.4);}\n\ | |
| 3719 | + .time1 {font:22px Arial;border:1px solid;}\n\ | |
| 3720 | + .time2 {font:15px Arial;border-bottom:1px solid;border-left:1px solid;border-right:1px solid;}\n\ | |
| 3721 | + td {text-align:center;}\n\ | |
| 3722 | + r {color:#500000;font:15px Tahoma;}\n\ | |
| 3723 | + n {color:#505050;font:15px Tahoma;}\n\ | |
| 3724 | + .tdhl {color:red;}\n\ | |
| 3725 | + .hide {display:none;}\n\ | |
| 3726 | + .pf {display:none;}\n\ | |
| 3727 | + .pf:'+cgchk+' + label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/><rect x="8" y="4" width="2" height="10" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\ | |
| 3728 | + .pf:'+cgnchk+' ~ label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\ | |
| 3729 | + .pf:'+cgchk+' ~ *:not(:nth-child(2)) {display:none;}\n\ | |
| 3730 | + .zoombox {position:relative;width:100%;overflow-x:scroll;-webkit-user-select:none;-moz-user-select:none;user-select:none;}\n\ | |
| 3731 | + .timeline {position:relative;font-size:14px;cursor:pointer;width:100%; overflow:hidden;background:linear-gradient(#cccccc, white);}\n\ | |
| 3732 | + .thread {position:absolute;height:0%;overflow:hidden;z-index:7;line-height:30px;font-size:14px;border:1px solid;text-align:center;white-space:nowrap;}\n\ | |
| 3733 | + .thread.ps {border-radius:3px;background:linear-gradient(to top, #ccc, #eee);}\n\ | |
| 3734 | + .thread:hover {background:white;border:1px solid red;'+hoverZ+'}\n\ | |
| 3735 | + .thread.sec,.thread.sec:hover {background:black;border:0;color:white;line-height:15px;font-size:10px;}\n\ | |
| 3736 | + .hover {background:white;border:1px solid red;'+hoverZ+'}\n\ | |
| 3737 | + .hover.sync {background:white;}\n\ | |
| 3738 | + .hover.bg,.hover.kth,.hover.sync,.hover.ps {background:white;}\n\ | |
| 3739 | + .jiffie {position:absolute;pointer-events: none;z-index:8;}\n\ | |
| 3740 | + .traceevent {position:absolute;font-size:10px;z-index:7;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,#CCC,#969696);}\n\ | |
| 3741 | + .traceevent:hover {color:white;font-weight:bold;border:1px solid white;}\n\ | |
| 3742 | + .phase {position:absolute;overflow:hidden;border:0px;text-align:center;}\n\ | |
| 3743 | + .phaselet {float:left;overflow:hidden;border:0px;text-align:center;min-height:100px;font-size:24px;}\n\ | |
| 3744 | + .t {position:absolute;line-height:'+('%d'%scaleTH)+'px;pointer-events:none;top:0;height:100%;border-right:1px solid black;z-index:6;}\n\ | |
| 3745 | + .err {position:absolute;top:0%;height:100%;border-right:3px solid red;color:red;font:bold 14px Times;line-height:18px;}\n\ | |
| 3746 | + .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\ | |
| 3747 | + .legend .square {position:absolute;cursor:pointer;top:10px; width:0px;height:20px;border:1px solid;padding-left:20px;}\n\ | |
| 3748 | + button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\ | |
| 3749 | + .logbtn {position:relative;float:right;height:25px;width:50px;margin-top:3px;margin-bottom:0;font-size:10px;text-align:center;}\n\ | |
| 3750 | + .devlist {position:'+devlistpos+';width:190px;}\n\ | |
| 3751 | + a:link {color:white;text-decoration:none;}\n\ | |
| 3752 | + a:visited {color:white;}\n\ | |
| 3753 | + a:hover {color:white;}\n\ | |
| 3754 | + a:active {color:white;}\n\ | |
| 3755 | + .version {position:relative;float:left;color:white;font-size:10px;line-height:30px;margin-left:10px;}\n\ | |
| 3756 | + #devicedetail {min-height:100px;box-shadow:5px 5px 20px black;}\n\ | |
| 3757 | + .tblock {position:absolute;height:100%;background:#ddd;}\n\ | |
| 3758 | + .tback {position:absolute;width:100%;background:linear-gradient(#ccc, #ddd);}\n\ | |
| 3759 | + .bg {z-index:1;}\n\ | |
| 3760 | +'+extra+'\ | |
| 3761 | + </style>\n</head>\n<body>\n' | |
| 3762 | + hf.write(html_header) | |
| 3763 | + | |
| 3791 | 3764 | # Function: addScriptCode |
| 3792 | 3765 | # Description: |
| 3793 | 3766 | # Adds the javascript code to the output html |
| @@ -3809,7 +3782,7 @@ def addScriptCode(hf, testruns): · 15 unmodified lines | ||
| 3809 | 3782 | ' var resolution = -1;\n'\ |
| 3810 | 3783 | ' var dragval = [0, 0];\n'\ |
| 3811 | 3784 | ' function redrawTimescale(t0, tMax, tS) {\n'\ |
| 3812 | − ' var rline = \'<div class="t" style="left:0;border-left:1px solid black;border-right:0;"><cS>←R</cS></div>\';\n'\ | |
| 3785 | + ' var rline = \'<div class="t" style="left:0;border-left:1px solid black;border-right:0;">\';\n'\ | |
| 3813 | 3786 | ' var tTotal = tMax - t0;\n'\ |
| 3814 | 3787 | ' var list = document.getElementsByClassName("tblock");\n'\ |
| 3815 | 3788 | ' for (var i = 0; i < list.length; i++) {\n'\ |
| @@ -3824,19 +3797,23 @@ def addScriptCode(hf, testruns): · 8 unmodified lines | ||
| 3824 | 3797 | ' var pos = 0.0, val = 0.0;\n'\ |
| 3825 | 3798 | ' for (var j = 0; j < divTotal; j++) {\n'\ |
| 3826 | 3799 | ' var htmlline = "";\n'\ |
| 3827 | − ' if(list[i].id[5] == "r") {\n'\ | |
| 3828 | − ' pos = 100 - (((j)*tS*100)/mTotal);\n'\ | |
| 3829 | − ' val = (j)*tS;\n'\ | |
| 3830 | − ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ | |
| 3831 | − ' if(j == 0)\n'\ | |
| 3832 | − ' htmlline = rline;\n'\ | |
| 3833 | − ' } else {\n'\ | |
| 3800 | + ' var mode = list[i].id[5];\n'\ | |
| 3801 | + ' if(mode == "s") {\n'\ | |
| 3834 | 3802 | ' pos = 100 - (((j)*tS*100)/mTotal) - divEdge;\n'\ |
| 3835 | 3803 | ' val = (j-divTotal+1)*tS;\n'\ |
| 3836 | 3804 | ' if(j == divTotal - 1)\n'\ |
| 3837 | 3805 | ' htmlline = \'<div class="t" style="right:\'+pos+\'%"><cS>S→</cS></div>\';\n'\ |
| 3838 | 3806 | ' else\n'\ |
| 3839 | 3807 | ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ |
| 3808 | + ' } else {\n'\ | |
| 3809 | + ' pos = 100 - (((j)*tS*100)/mTotal);\n'\ | |
| 3810 | + ' val = (j)*tS;\n'\ | |
| 3811 | + ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ | |
| 3812 | + ' if(j == 0)\n'\ | |
| 3813 | + ' if(mode == "r")\n'\ | |
| 3814 | + ' htmlline = rline+"<cS>←R</cS></div>";\n'\ | |
| 3815 | + ' else\n'\ | |
| 3816 | + ' htmlline = rline+"<cS>0ms</div>";\n'\ | |
| 3840 | 3817 | ' }\n'\ |
| 3841 | 3818 | ' html += htmlline;\n'\ |
| 3842 | 3819 | ' }\n'\ |
| @@ -4002,12 +3979,80 @@ def addScriptCode(hf, testruns): · 159 unmodified lines | ||
| 4002 | 3979 | ' }\n'\ |
| 4003 | 3980 | ' }\n'\ |
| 4004 | 3981 | ' }\n'\ |
| 3982 | + ' if(typeof devstats !== \'undefined\')\n'\ | |
| 3983 | + ' callDetail(this.id, this.title);\n'\ | |
| 4005 | 3984 | ' var cglist = document.getElementById("callgraphs");\n'\ |
| 4006 | 3985 | ' if(!cglist) return;\n'\ |
| 4007 | 3986 | ' var cg = cglist.getElementsByClassName("atop");\n'\ |
| 4008 | 3987 | ' if(cg.length < 10) return;\n'\ |
| 4009 | 3988 | ' for (var i = 0; i < cg.length; i++) {\n'\ |
| 4010 | − ' if(idlist.indexOf(cg[i].id) >= 0) {\n'\ | |
| 3989 | + ' cgid = cg[i].id.split("x")[0]\n'\ | |
| 3990 | + ' if(idlist.indexOf(cgid) >= 0) {\n'\ | |
| 3991 | + ' cg[i].style.display = "block";\n'\ | |
| 3992 | + ' } else {\n'\ | |
| 3993 | + ' cg[i].style.display = "none";\n'\ | |
| 3994 | + ' }\n'\ | |
| 3995 | + ' }\n'\ | |
| 3996 | + ' }\n'\ | |
| 3997 | + ' function callDetail(devid, devtitle) {\n'\ | |
| 3998 | + ' if(!(devid in devstats) || devstats[devid].length < 1)\n'\ | |
| 3999 | + ' return;\n'\ | |
| 4000 | + ' var list = devstats[devid];\n'\ | |
| 4001 | + ' var tmp = devtitle.split(" ");\n'\ | |
| 4002 | + ' var name = tmp[0], phase = tmp[tmp.length-1];\n'\ | |
| 4003 | + ' var dd = document.getElementById(phase);\n'\ | |
| 4004 | + ' var total = parseFloat(tmp[1].slice(1));\n'\ | |
| 4005 | + ' var mlist = [];\n'\ | |
| 4006 | + ' var maxlen = 0;\n'\ | |
| 4007 | + ' var info = []\n'\ | |
| 4008 | + ' for(var i in list) {\n'\ | |
| 4009 | + ' if(list[i][0] == "@") {\n'\ | |
| 4010 | + ' info = list[i].split("|");\n'\ | |
| 4011 | + ' continue;\n'\ | |
| 4012 | + ' }\n'\ | |
| 4013 | + ' var tmp = list[i].split("|");\n'\ | |
| 4014 | + ' var t = parseFloat(tmp[0]), f = tmp[1], c = parseInt(tmp[2]);\n'\ | |
| 4015 | + ' var p = (t*100.0/total).toFixed(2);\n'\ | |
| 4016 | + ' mlist[mlist.length] = [f, c, t.toFixed(2), p+"%"];\n'\ | |
| 4017 | + ' if(f.length > maxlen)\n'\ | |
| 4018 | + ' maxlen = f.length;\n'\ | |
| 4019 | + ' }\n'\ | |
| 4020 | + ' var pad = 5;\n'\ | |
| 4021 | + ' if(mlist.length == 0) pad = 30;\n'\ | |
| 4022 | + ' var html = \'<div style="padding-top:\'+pad+\'px"><t3> <b>\'+name+\':</b>\';\n'\ | |
| 4023 | + ' if(info.length > 2)\n'\ | |
| 4024 | + ' html += " start=<b>"+info[1]+"</b>, end=<b>"+info[2]+"</b>";\n'\ | |
| 4025 | + ' if(info.length > 3)\n'\ | |
| 4026 | + ' html += ", length<i>(w/o overhead)</i>=<b>"+info[3]+" ms</b>";\n'\ | |
| 4027 | + ' if(info.length > 4)\n'\ | |
| 4028 | + ' html += ", return=<b>"+info[4]+"</b>";\n'\ | |
| 4029 | + ' html += "</t3></div>";\n'\ | |
| 4030 | + ' if(mlist.length > 0) {\n'\ | |
| 4031 | + ' html += \'<table class=fstat style="padding-top:\'+(maxlen*5)+\'px;"><tr><th>Function</th>\';\n'\ | |
| 4032 | + ' for(var i in mlist)\n'\ | |
| 4033 | + ' html += "<td class=vt>"+mlist[i][0]+"</td>";\n'\ | |
| 4034 | + ' html += "</tr><tr><th>Calls</th>";\n'\ | |
| 4035 | + ' for(var i in mlist)\n'\ | |
| 4036 | + ' html += "<td>"+mlist[i][1]+"</td>";\n'\ | |
| 4037 | + ' html += "</tr><tr><th>Time(ms)</th>";\n'\ | |
| 4038 | + ' for(var i in mlist)\n'\ | |
| 4039 | + ' html += "<td>"+mlist[i][2]+"</td>";\n'\ | |
| 4040 | + ' html += "</tr><tr><th>Percent</th>";\n'\ | |
| 4041 | + ' for(var i in mlist)\n'\ | |
| 4042 | + ' html += "<td>"+mlist[i][3]+"</td>";\n'\ | |
| 4043 | + ' html += "</tr></table>";\n'\ | |
| 4044 | + ' }\n'\ | |
| 4045 | + ' dd.innerHTML = html;\n'\ | |
| 4046 | + ' var height = (maxlen*5)+100;\n'\ | |
| 4047 | + ' dd.style.height = height+"px";\n'\ | |
| 4048 | + ' document.getElementById("devicedetail").style.height = height+"px";\n'\ | |
| 4049 | + ' }\n'\ | |
| 4050 | + ' function callSelect() {\n'\ | |
| 4051 | + ' var cglist = document.getElementById("callgraphs");\n'\ | |
| 4052 | + ' if(!cglist) return;\n'\ | |
| 4053 | + ' var cg = cglist.getElementsByClassName("atop");\n'\ | |
| 4054 | + ' for (var i = 0; i < cg.length; i++) {\n'\ | |
| 4055 | + ' if(this.id == cg[i].id) {\n'\ | |
| 4011 | 4056 | ' cg[i].style.display = "block";\n'\ |
| 4012 | 4057 | ' } else {\n'\ |
| 4013 | 4058 | ' cg[i].style.display = "none";\n'\ |
| @@ -4093,6 +4138,9 @@ def addScriptCode(hf, testruns): · 79 unmodified lines | ||
| 4093 | 4138 | ' dev[i].onmouseover = deviceHover;\n'\ |
| 4094 | 4139 | ' dev[i].onmouseout = deviceUnhover;\n'\ |
| 4095 | 4140 | ' }\n'\ |
| 4141 | + ' var dev = dmesg.getElementsByClassName("srccall");\n'\ | |
| 4142 | + ' for (var i = 0; i < dev.length; i++)\n'\ | |
| 4143 | + ' dev[i].onclick = callSelect;\n'\ | |
| 4096 | 4144 | ' zoomTimeline();\n'\ |
| 4097 | 4145 | ' });\n'\ |
| 4098 | 4146 | '</script>\n' |
| @@ -4675,7 +4723,7 @@ def rootCheck(fatal): · 576 unmodified lines | ||
| 4675 | 4723 | if(os.access(sysvals.powerfile, os.W_OK)): |
| 4676 | 4724 | return True |
| 4677 | 4725 | if fatal: |
| 4678 | − doError('This command must be run as root') | |
| 4726 | + doError('This command requires sysfs mount and root access') | |
| 4679 | 4727 | return False |
| 4680 | 4728 | |
| 4681 | 4729 | # Function: getArgInt |
| @@ -4767,51 +4815,62 @@ def runTest(subdir, testpath=''): · 85 unmodified lines | ||
| 4767 | 4815 | cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1' |
| 4768 | 4816 | call(cmd.format(os.environ['SUDO_USER'], sysvals.testdir), shell=True) |
| 4769 | 4817 | |
| 4818 | +def find_in_html(html, strs, div=False): | |
| 4819 | + for str in strs: | |
| 4820 | + l = len(str) | |
| 4821 | + i = html.find(str) | |
| 4822 | + if i >= 0: | |
| 4823 | + break | |
| 4824 | + if i < 0: | |
| 4825 | + return '' | |
| 4826 | + if not div: | |
| 4827 | + return re.search(r'[-+]?\d*\.\d+|\d+', html[i+l:i+l+50]).group() | |
| 4828 | + n = html[i+l:].find('</div>') | |
| 4829 | + if n < 0: | |
| 4830 | + return '' | |
| 4831 | + return html[i+l:i+l+n] | |
| 4832 | + | |
| 4770 | 4833 | # Function: runSummary |
| 4771 | 4834 | # Description: |
| 4772 | 4835 | # create a summary of tests in a sub-directory |
| 4773 | −def runSummary(subdir, output): | |
| 4774 | − # get a list of ftrace output files | |
| 4775 | − files = [] | |
| 4836 | +def runSummary(subdir, local=True): | |
| 4837 | + inpath = os.path.abspath(subdir) | |
| 4838 | + outpath = inpath | |
| 4839 | + if local: | |
| 4840 | + outpath = os.path.abspath('.') | |
| 4841 | + print('Generating a summary of folder "%s"' % inpath) | |
| 4842 | + testruns = [] | |
| 4776 | 4843 | for dirname, dirnames, filenames in os.walk(subdir): |
| 4777 | 4844 | for filename in filenames: |
| 4778 | − if(re.match('.*_ftrace.txt', filename)): | |
| 4779 | − files.append("%s/%s" % (dirname, filename)) | |
| 4780 | − | |
| 4781 | − # process the files in order and get an array of data objects | |
| 4782 | − testruns = [] | |
| 4783 | − for file in sorted(files): | |
| 4784 | − if output: | |
| 4785 | − print("Test found in %s" % os.path.dirname(file)) | |
| 4786 | − sysvals.ftracefile = file | |
| 4787 | − sysvals.dmesgfile = file.replace('_ftrace.txt', '_dmesg.txt') | |
| 4788 | − doesTraceLogHaveTraceEvents() | |
| 4789 | − sysvals.usecallgraph = False | |
| 4790 | − if not sysvals.usetraceeventsonly: | |
| 4791 | − if(not os.path.exists(sysvals.dmesgfile)): | |
| 4792 | − print("Skipping %s: not a valid test input" % file) | |
| 4845 | + if(not re.match('.*.html', filename)): | |
| 4793 | 4846 | continue |
| 4794 | − else: | |
| 4795 | − if output: | |
| 4796 | − f = os.path.basename(sysvals.ftracefile) | |
| 4797 | − d = os.path.basename(sysvals.dmesgfile) | |
| 4798 | − print("\tInput files: %s and %s" % (f, d)) | |
| 4799 | − testdata = loadKernelLog() | |
| 4800 | − data = testdata[0] | |
| 4801 | − parseKernelLog(data) | |
| 4802 | − testdata = [data] | |
| 4803 | − appendIncompleteTraceLog(testdata) | |
| 4804 | − else: | |
| 4805 | − if output: | |
| 4806 | − print("\tInput file: %s" % os.path.basename(sysvals.ftracefile)) | |
| 4807 | − testdata = parseTraceLog() | |
| 4808 | − data = testdata[0] | |
| 4809 | − data.normalizeTime(data.tSuspended) | |
| 4810 | − link = file.replace(subdir+'/', '').replace('_ftrace.txt', '.html') | |
| 4811 | − data.outfile = link | |
| 4812 | − testruns.append(data) | |
| 4813 | − | |
| 4814 | − createHTMLSummarySimple(testruns, subdir+'/summary.html') | |
| 4847 | + file = os.path.join(dirname, filename) | |
| 4848 | + html = open(file, 'r').read(10000) | |
| 4849 | + suspend = find_in_html(html, | |
| 4850 | + ['Kernel Suspend: ', 'Kernel Suspend Time: ']) | |
| 4851 | + resume = find_in_html(html, | |
| 4852 | + ['Kernel Resume: ', 'Kernel Resume Time: ']) | |
| 4853 | + line = find_in_html(html, ['<div class="stamp">'], True) | |
| 4854 | + stmp = line.split() | |
| 4855 | + if not suspend or not resume or len(stmp) < 4: | |
| 4856 | + continue | |
| 4857 | + data = { | |
| 4858 | + 'host': stmp[0], | |
| 4859 | + 'kernel': stmp[1], | |
| 4860 | + 'mode': stmp[2], | |
| 4861 | + 'time': string.join(stmp[3:], ' '), | |
| 4862 | + 'suspend': suspend, | |
| 4863 | + 'resume': resume, | |
| 4864 | + 'url': os.path.relpath(file, outpath), | |
| 4865 | + } | |
| 4866 | + if len(stmp) == 7: | |
| 4867 | + data['kernel'] = 'unknown' | |
| 4868 | + data['mode'] = stmp[1] | |
| 4869 | + data['time'] = string.join(stmp[2:], ' ') | |
| 4870 | + testruns.append(data) | |
| 4871 | + outfile = os.path.join(outpath, 'summary.html') | |
| 4872 | + print('Summary file: %s' % outfile) | |
| 4873 | + createHTMLSummarySimple(testruns, outfile, inpath) | |
| 4815 | 4874 | |
| 4816 | 4875 | # Function: checkArgBool |
| 4817 | 4876 | # Description: |
| @@ -4869,9 +4928,14 @@ def configFromFile(file): · 51 unmodified lines | ||
| 4869 | 4928 | sysvals.predelay = getArgInt('-predelay', value, 0, 60000, False) |
| 4870 | 4929 | elif(opt.lower() == 'postdelay'): |
| 4871 | 4930 | sysvals.postdelay = getArgInt('-postdelay', value, 0, 60000, False) |
| 4931 | + elif(opt.lower() == 'maxdepth'): | |
| 4932 | + sysvals.max_graph_depth = getArgInt('-maxdepth', value, 0, 1000, False) | |
| 4872 | 4933 | elif(opt.lower() == 'rtcwake'): |
| 4873 | − sysvals.rtcwake = True | |
| 4874 | − sysvals.rtcwaketime = getArgInt('-rtcwake', value, 0, 3600, False) | |
| 4934 | + if value.lower() == 'off': | |
| 4935 | + sysvals.rtcwake = False | |
| 4936 | + else: | |
| 4937 | + sysvals.rtcwake = True | |
| 4938 | + sysvals.rtcwaketime = getArgInt('-rtcwake', value, 0, 3600, False) | |
| 4875 | 4939 | elif(opt.lower() == 'timeprec'): |
| 4876 | 4940 | sysvals.setPrecision(getArgInt('-timeprec', value, 0, 6, False)) |
| 4877 | 4941 | elif(opt.lower() == 'mindev'): |
| @@ -4969,8 +5033,8 @@ def printHelp(): · 91 unmodified lines | ||
| 4969 | 5033 | modes = getModes() |
| 4970 | 5034 | |
| 4971 | 5035 | print('') |
| 4972 | − print('AnalyzeSuspend v%s' % sysvals.version) | |
| 4973 | − print('Usage: sudo analyze_suspend.py <options>') | |
| 5036 | + print('%s v%s' % (sysvals.title, sysvals.version)) | |
| 5037 | + print('Usage: sudo sleepgraph <options> <commands>') | |
| 4974 | 5038 | print('') |
| 4975 | 5039 | print('Description:') |
| 4976 | 5040 | print(' This tool is designed to assist kernel and OS developers in optimizing') |
| @@ -4981,22 +5045,22 @@ def printHelp(): · 4 unmodified lines | ||
| 4981 | 5045 | print(' a detailed view of which devices/subsystems are taking the most') |
| 4982 | 5046 | print(' time in suspend/resume.') |
| 4983 | 5047 | print('') |
| 5048 | + print(' If no specific command is given, the default behavior is to initiate') | |
| 5049 | + print(' a suspend/resume and capture the dmesg/ftrace output as an html timeline.') | |
| 5050 | + print('') | |
| 4984 | 5051 | print(' Generates output files in subdirectory: suspend-mmddyy-HHMMSS') |
| 4985 | 5052 | print(' HTML output: <hostname>_<mode>.html') |
| 4986 | 5053 | print(' raw dmesg output: <hostname>_<mode>_dmesg.txt') |
| 4987 | 5054 | print(' raw ftrace output: <hostname>_<mode>_ftrace.txt') |
| 4988 | 5055 | print('') |
| 4989 | 5056 | print('Options:') |
| 4990 | − print(' [general]') | |
| 4991 | 5057 | print(' -h Print this help text') |
| 4992 | 5058 | print(' -v Print the current tool version') |
| 4993 | 5059 | print(' -config fn Pull arguments and config options from file fn') |
| 4994 | 5060 | print(' -verbose Print extra information during execution and analysis') |
| 4995 | − print(' -status Test to see if the system is enabled to run this tool') | |
| 4996 | − print(' -modes List available suspend modes') | |
| 4997 | 5061 | print(' -m mode Mode to initiate for suspend %s (default: %s)') % (modes, sysvals.suspendmode) |
| 4998 | 5062 | print(' -o subdir Override the output subdirectory') |
| 4999 | − print(' -rtcwake t Use rtcwake to autoresume after <t> seconds (default: disabled)') | |
| 5063 | + print(' -rtcwake t Wakeup t seconds after suspend, set t to "off" to disable (default: 15)') | |
| 5000 | 5064 | print(' -addlogs Add the dmesg and ftrace logs to the html output') |
| 5001 | 5065 | print(' -srgap Add a visible gap in the timeline between sus/res (default: disabled)') |
| 5002 | 5066 | print(' [advanced]') |
| @@ -5012,23 +5076,25 @@ def printHelp(): · 9 unmodified lines | ||
| 5012 | 5076 | print(' be created in a new subdirectory with a summary page.') |
| 5013 | 5077 | print(' [debug]') |
| 5014 | 5078 | print(' -f Use ftrace to create device callgraphs (default: disabled)') |
| 5079 | + print(' -maxdepth N limit the callgraph data to N call levels (default: 0=all)') | |
| 5015 | 5080 | print(' -expandcg pre-expand the callgraph data in the html output (default: disabled)') |
| 5016 | − print(' -flist Print the list of functions currently being captured in ftrace') | |
| 5017 | − print(' -flistall Print all functions capable of being captured in ftrace') | |
| 5018 | 5081 | print(' -fadd file Add functions to be graphed in the timeline from a list in a text file') |
| 5019 | 5082 | print(' -filter "d1,d2,..." Filter out all but this comma-delimited list of device names') |
| 5020 | 5083 | print(' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)') |
| 5021 | 5084 | print(' -cgphase P Only show callgraph data for phase P (e.g. suspend_late)') |
| 5022 | 5085 | print(' -cgtest N Only show callgraph data for test N (e.g. 0 or 1 in an x2 run)') |
| 5023 | 5086 | print(' -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)') |
| 5024 | − print(' [utilities]') | |
| 5087 | + print(' [commands]') | |
| 5088 | + print(' -ftrace ftracefile Create HTML output using ftrace input (used with -dmesg)') | |
| 5089 | + print(' -dmesg dmesgfile Create HTML output using dmesg (used with -ftrace)') | |
| 5090 | + print(' -summary directory Create a summary of all test in this dir') | |
| 5091 | + print(' -modes List available suspend modes') | |
| 5092 | + print(' -status Test to see if the system is enabled to run this tool') | |
| 5025 | 5093 | print(' -fpdt Print out the contents of the ACPI Firmware Performance Data Table') |
| 5026 | 5094 | print(' -usbtopo Print out the current USB topology with power info') |
| 5027 | 5095 | print(' -usbauto Enable autosuspend for all connected USB devices') |
| 5028 | − print(' [re-analyze data from previous runs]') | |
| 5029 | − print(' -ftrace ftracefile Create HTML output using ftrace input') | |
| 5030 | − print(' -dmesg dmesgfile Create HTML output using dmesg (not needed for kernel >= 3.15)') | |
| 5031 | − print(' -summary directory Create a summary of all test in this dir') | |
| 5096 | + print(' -flist Print the list of functions currently being captured in ftrace') | |
| 5097 | + print(' -flistall Print all functions capable of being captured in ftrace') | |
| 5032 | 5098 | print('') |
| 5033 | 5099 | return True |
| 5034 | 5100 | |
| @@ -5076,9 +5142,18 @@ if __name__ == '__main__': · 41 unmodified lines | ||
| 5076 | 5142 | sysvals.useprocmon = True |
| 5077 | 5143 | elif(arg == '-dev'): |
| 5078 | 5144 | sysvals.usedevsrc = True |
| 5145 | + elif(arg == '-maxdepth'): | |
| 5146 | + sysvals.max_graph_depth = getArgInt('-maxdepth', args, 0, 1000) | |
| 5079 | 5147 | elif(arg == '-rtcwake'): |
| 5080 | − sysvals.rtcwake = True | |
| 5081 | − sysvals.rtcwaketime = getArgInt('-rtcwake', args, 0, 3600) | |
| 5148 | + try: | |
| 5149 | + val = args.next() | |
| 5150 | + except: | |
| 5151 | + doError('No rtcwake time supplied', True) | |
| 5152 | + if val.lower() == 'off': | |
| 5153 | + sysvals.rtcwake = False | |
| 5154 | + else: | |
| 5155 | + sysvals.rtcwake = True | |
| 5156 | + sysvals.rtcwaketime = getArgInt('-rtcwake', val, 0, 3600, False) | |
| 5082 | 5157 | elif(arg == '-timeprec'): |
| 5083 | 5158 | sysvals.setPrecision(getArgInt('-timeprec', args, 0, 6)) |
| 5084 | 5159 | elif(arg == '-mindev'): |
| @@ -5201,7 +5276,6 @@ if __name__ == '__main__': · 116 unmodified lines | ||
| 5201 | 5276 | elif(cmd == 'usbauto'): |
| 5202 | 5277 | setUSBDevicesAuto() |
| 5203 | 5278 | elif(cmd == 'summary'): |
| 5204 | − print("Generating a summary of folder \"%s\"" % cmdarg) | |
| 5205 | 5279 | runSummary(cmdarg, True) |
| 5206 | 5280 | sys.exit() |
| 5207 | 5281 | |