1b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor#!/usr/bin/python 2b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor# 3b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor# Copyright (C) 2010 The Android Open Source Project 4b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor# 5b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor# Licensed under the Apache License, Version 2.0 (the "License"); 6b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor# you may not use this file except in compliance with the License. 7b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor# You may obtain a copy of the License at 8b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor# 9b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor# http://www.apache.org/licenses/LICENSE-2.0 10b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor# 11b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor# Unless required by applicable law or agreed to in writing, software 12b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor# distributed under the License is distributed on an "AS IS" BASIS, 13b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor# See the License for the specific language governing permissions and 15b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor# limitations under the License. 16b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 17b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnorimport cgi 18b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnorimport csv 19b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnorimport json 20b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnorimport math 21b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnorimport os 22b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnorimport re 23b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnorimport sys 24b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnorimport time 25b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnorimport urllib 26b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 27b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor"""Interpret output from procstatlog and write an HTML report file.""" 28b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 29b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 30b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor# TODO: Rethink dygraph-combined.js source URL? 31b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan EgnorPAGE_BEGIN = """ 32b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor<html><head> 33b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor<title>%(filename)s</title> 34b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor<script type="text/javascript" src="http://www.corp.google.com/~egnor/no_crawl/dygraph-combined.js"></script> 35b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor<script> 36b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnorvar allCharts = []; 37b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnorvar inDrawCallback = false; 38b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 39b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan EgnorOnDraw = function(me, initial) { 40b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if (inDrawCallback || initial) return; 41b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor inDrawCallback = true; 42b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor var range = me.xAxisRange(); 43b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor for (var j = 0; j < allCharts.length; j++) { 44b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if (allCharts[j] == me) continue; 45b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor allCharts[j].updateOptions({dateWindow: range}); 46b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor } 47b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor inDrawCallback = false; 48b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor} 49b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 50b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan EgnorMakeChart = function(id, filename, options) { 51b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor options.width = "75%%"; 52b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor options.xTicker = Dygraph.dateTicker; 53b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor options.xValueFormatter = Dygraph.dateString_; 54b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor options.xAxisLabelFormatter = Dygraph.dateAxisFormatter; 55b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor options.drawCallback = OnDraw; 56b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor allCharts.push(new Dygraph(document.getElementById(id), filename, options)); 57b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor} 58b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor</script> 59b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor</head><body> 60b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor<p> 61b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor<span style="font-size: 150%%">%(filename)s</span> 62b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor- stat report generated by %(user)s on %(date)s</p> 63b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor<table cellpadding=0 cellspacing=0 margin=0 border=0> 64b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor""" 65b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 66b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan EgnorCHART = """ 67b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor<tr> 68b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor<td valign=top width=25%%>%(label_html)s</td> 69b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor<td id="%(id)s"> </td> 70b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor</tr> 71b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor<script> 72b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan EgnorMakeChart(%(id_js)s, %(filename_js)s, %(options_js)s) 73b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 74b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor</script> 75b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor""" 76b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 77b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan EgnorSPACER = """ 78b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor<tr><td colspan=2 height=20> </td></tr> 79b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor""" 80b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 81b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan EgnorTOTAL_CPU_LABEL = """ 82b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor<b style="font-size: 150%%">Total CPU</b><br> 83b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnorjiffies: <nobr>%(sys)d sys</nobr>, <nobr>%(user)d user</nobr> 84b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor""" 85b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 86376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan EgnorCPU_SPEED_LABEL = """ 87376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor<nobr>average CPU speed</nobr> 88376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor""" 89376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 90b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan EgnorCONTEXT_LABEL = """ 91b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnorcontext: <nobr>%(switches)d switches</nobr> 92b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor""" 93b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 94b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan EgnorFAULTS_LABEL = """ 95b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor<nobr>page faults:</nobr> <nobr>%(major)d major</nobr> 96b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor""" 97b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 98376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan EgnorBINDER_LABEL = """ 99376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnorbinder: <nobr>%(calls)d calls</nobr> 100376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor""" 101376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 102b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan EgnorPROC_CPU_LABEL = """ 103b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor<span style="font-size: 150%%">%(process)s</span> (%(pid)d)<br> 104b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnorjiffies: <nobr>%(sys)d sys</nobr>, <nobr>%(user)d user</nobr> 105b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor</div> 106b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor""" 107b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 108b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan EgnorYAFFS_LABEL = """ 109376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor<span style="font-size: 150%%">yaffs: %(partition)s</span><br> 110b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnorpages: <nobr>%(nPageReads)d read</nobr>, 111b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor<nobr>%(nPageWrites)d written</nobr><br> 112b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnorblocks: <nobr>%(nBlockErasures)d erased</nobr> 113b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor""" 114b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 115b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan EgnorDISK_LABEL = """ 116b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor<span style="font-size: 150%%">disk: %(device)s</span><br> 117b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnorsectors: <nobr>%(reads)d read</nobr>, <nobr>%(writes)d written</nobr> 118b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor""" 119b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor 120b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan EgnorDISK_TIME_LABEL = """ 121b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnormsec: <nobr>%(msec)d waiting</nobr> 122b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor""" 123b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor 124376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan EgnorNET_LABEL = """ 125376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor<span style="font-size: 150%%">net: %(interface)s</span><br> 126376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnorbytes: <nobr>%(tx)d tx</nobr>, 127b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor<nobr>%(rx)d rx</nobr> 128376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor""" 129376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 130b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan EgnorPAGE_END = """ 131b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor</table></body></html> 132b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor""" 133b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 134b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 135b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnordef WriteChartData(titles, datasets, filename): 136b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor writer = csv.writer(file(filename, "w")) 137b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor writer.writerow(["Time"] + titles) 138b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 139b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor merged_rows = {} 140b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor for set_num, data in enumerate(datasets): 141b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor for when, datum in data.iteritems(): 142b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if type(datum) == tuple: datum = "%d/%d" % datum 143b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor merged_rows.setdefault(when, {})[set_num] = datum 144b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 145b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor num_cols = len(datasets) 146b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor for when, values in sorted(merged_rows.iteritems()): 147b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor msec = "%d" % (when * 1000) 148b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor writer.writerow([msec] + [values.get(n, "") for n in range(num_cols)]) 149b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 150b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 151b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnordef WriteOutput(history, log_filename, filename): 152b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor out = [] 153b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 154b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor out.append(PAGE_BEGIN % { 155b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "filename": cgi.escape(log_filename), 156b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "user": cgi.escape(os.environ.get("USER", "unknown")), 157b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "date": cgi.escape(time.ctime()), 158b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor }) 159b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 160b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor files_dir = "%s_files" % os.path.splitext(filename)[0] 161b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor files_url = os.path.basename(files_dir) 162b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if not os.path.isdir(files_dir): os.makedirs(files_dir) 163b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 164b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor sorted_history = sorted(history.iteritems()) 165376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor date_window = [1000 * sorted_history[1][0], 1000 * sorted_history[-1][0]] 166b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 167b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor # 168b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor # Output total CPU statistics 169b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor # 170b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 171b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor sys_jiffies = {} 172b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor sys_user_jiffies = {} 173b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor all_jiffies = {} 174b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor total_sys = total_user = 0 175b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 176b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor last_state = {} 177b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor for when, state in sorted_history: 178b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor last = last_state.get("/proc/stat:cpu", "").split() 179b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor next = state.get("/proc/stat:cpu", "").split() 180b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if last and next: 181b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor stime = sum([int(next[x]) - int(last[x]) for x in [2, 5, 6]]) 182b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor utime = sum([int(next[x]) - int(last[x]) for x in [0, 1]]) 183b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor idle = sum([int(next[x]) - int(last[x]) for x in [3, 4]]) 184b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor all = stime + utime + idle 185b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor total_sys += stime 186b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor total_user += utime 187b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 188b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor sys_jiffies[when] = (stime, all) 189b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor sys_user_jiffies[when] = (stime + utime, all) 190b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor all_jiffies[when] = all 191b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 192b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor last_state = state 193b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 194b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor WriteChartData( 195b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor ["sys", "sys+user"], 196b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor [sys_jiffies, sys_user_jiffies], 197b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor os.path.join(files_dir, "total_cpu.csv")) 198b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 199b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor out.append(CHART % { 200b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "id": cgi.escape("total_cpu"), 201b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "id_js": json.write("total_cpu"), 202b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "label_html": TOTAL_CPU_LABEL % {"sys": total_sys, "user": total_user}, 203b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "filename_js": json.write(files_url + "/total_cpu.csv"), 204b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "options_js": json.write({ 205b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "colors": ["blue", "green"], 206b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "dateWindow": date_window, 207b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "fillGraph": True, 208b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "fractions": True, 209b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "height": 100, 210b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "valueRange": [0, 110], 211b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor }), 212b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor }) 213b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 214b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor # 215376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor # Output CPU speed statistics 216376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor # 217376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 218376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor cpu_speed = {} 219376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor speed_key = "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state:" 220376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 221376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor last_state = {} 222376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor for when, state in sorted_history: 223376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor total_time = total_cycles = 0 224376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor for key in state: 225376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if not key.startswith(speed_key): continue 226376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 227376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor last = int(last_state.get(key, -1)) 228376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor next = int(state.get(key, -1)) 229376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if last != -1 and next != -1: 230376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor speed = int(key[len(speed_key):]) 231376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor total_time += next - last 232376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor total_cycles += (next - last) * speed 233376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 234376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if total_time > 0: cpu_speed[when] = total_cycles / total_time 235376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor last_state = state 236376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 237376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor WriteChartData( 238376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor ["kHz"], [cpu_speed], 239376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor os.path.join(files_dir, "cpu_speed.csv")) 240376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 241376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor out.append(CHART % { 242376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "id": cgi.escape("cpu_speed"), 243376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "id_js": json.write("cpu_speed"), 244376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "label_html": CPU_SPEED_LABEL, 245376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "filename_js": json.write(files_url + "/cpu_speed.csv"), 246376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "options_js": json.write({ 247376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "colors": ["navy"], 248376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "dateWindow": date_window, 249376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "fillGraph": True, 250376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "height": 50, 251376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "includeZero": True, 252376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor }), 253376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor }) 254376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 255376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor # 256b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor # Output total context switch statistics 257b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor # 258b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 259376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor context_switches = {} 260b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 261b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor last_state = {} 262b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor for when, state in sorted_history: 263b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor last = int(last_state.get("/proc/stat:ctxt", -1)) 264b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor next = int(state.get("/proc/stat:ctxt", -1)) 265376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if last != -1 and next != -1: context_switches[when] = next - last 266b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor last_state = state 267b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 268b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor WriteChartData( 269376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor ["switches"], [context_switches], 270b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor os.path.join(files_dir, "context_switches.csv")) 271b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 272376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor total_switches = sum(context_switches.values()) 273b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor out.append(CHART % { 274b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "id": cgi.escape("context_switches"), 275b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "id_js": json.write("context_switches"), 276376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "label_html": CONTEXT_LABEL % {"switches": total_switches}, 277b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "filename_js": json.write(files_url + "/context_switches.csv"), 278b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "options_js": json.write({ 279b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "colors": ["blue"], 280b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "dateWindow": date_window, 281b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "fillGraph": True, 282b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "height": 50, 283376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "includeZero": True, 284b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor }), 285b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor }) 286b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 287b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor # 288b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor # Collect (no output yet) per-process CPU and major faults 289b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor # 290b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 291b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor process_name = {} 292b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor process_start = {} 293b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor process_sys = {} 294b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor process_sys_user = {} 295b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 296b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor process_faults = {} 297b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor total_faults = {} 298b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor max_faults = 0 299b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 300b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor last_state = {} 301b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor zero_stat = "0 (zero) Z 0 0 0 0 0 0 0 0 0 0 0 0" 302b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor for when, state in sorted_history: 303b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor for key in state: 304b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if not key.endswith("/stat"): continue 305b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 306b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor last = last_state.get(key, zero_stat).split() 307b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor next = state.get(key, "").split() 308b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if not next: continue 309b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 310b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor pid = int(next[0]) 311b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor process_start.setdefault(pid, when) 312b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor process_name[pid] = next[1][1:-1] 313b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 314b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor all = all_jiffies.get(when, 0) 315b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if not all: continue 316b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 317b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor faults = int(next[11]) - int(last[11]) 318b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor process_faults.setdefault(pid, {})[when] = faults 319b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor tf = total_faults[when] = total_faults.get(when, 0) + faults 320b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor max_faults = max(max_faults, tf) 321b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 322b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor stime = int(next[14]) - int(last[14]) 323b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor utime = int(next[13]) - int(last[13]) 324b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor process_sys.setdefault(pid, {})[when] = (stime, all) 325b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor process_sys_user.setdefault(pid, {})[when] = (stime + utime, all) 326b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 327b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor last_state = state 328b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 329b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor # 330b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor # Output total major faults (sum over all processes) 331b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor # 332b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 333b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor WriteChartData( 334376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor ["major"], [total_faults], 335b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor os.path.join(files_dir, "total_faults.csv")) 336b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 337b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor out.append(CHART % { 338b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "id": cgi.escape("total_faults"), 339b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "id_js": json.write("total_faults"), 340b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "label_html": FAULTS_LABEL % {"major": sum(total_faults.values())}, 341b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "filename_js": json.write(files_url + "/total_faults.csv"), 342b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "options_js": json.write({ 343b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "colors": ["gray"], 344b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "dateWindow": date_window, 345b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "fillGraph": True, 346b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "height": 50, 347b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "valueRange": [0, max_faults * 11 / 10], 348b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor }), 349b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor }) 350b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 351b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor # 352376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor # Output binder transaactions 353b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor # 354b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 355376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor binder_calls = {} 356376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 357376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor last_state = {} 358376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor for when, state in sorted_history: 359376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor last = int(last_state.get("/proc/binder/stats:BC_TRANSACTION", -1)) 360376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor next = int(state.get("/proc/binder/stats:BC_TRANSACTION", -1)) 361376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if last != -1 and next != -1: binder_calls[when] = next - last 362376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor last_state = state 363376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 364376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor WriteChartData( 365376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor ["calls"], [binder_calls], 366376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor os.path.join(files_dir, "binder_calls.csv")) 367376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 368376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor out.append(CHART % { 369376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "id": cgi.escape("binder_calls"), 370376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "id_js": json.write("binder_calls"), 371376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "label_html": BINDER_LABEL % {"calls": sum(binder_calls.values())}, 372376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "filename_js": json.write(files_url + "/binder_calls.csv"), 373376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "options_js": json.write({ 374376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "colors": ["green"], 375376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "dateWindow": date_window, 376376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "fillGraph": True, 377376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "height": 50, 378376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "includeZero": True, 379376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor }) 380376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor }) 381376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 382376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor # 383376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor # Output network interface statistics 384376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor # 385376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 386376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if out[-1] != SPACER: out.append(SPACER) 387376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 388376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor interface_rx = {} 389376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor interface_tx = {} 390376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor max_bytes = 0 391376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 392376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor last_state = {} 393376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor for when, state in sorted_history: 394376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor for key in state: 395376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if not key.startswith("/proc/net/dev:"): continue 396376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 397376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor last = last_state.get(key, "").split() 398376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor next = state.get(key, "").split() 399376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if not (last and next): continue 400376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 401376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor rx = int(next[0]) - int(last[0]) 402376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor tx = int(next[8]) - int(last[8]) 403376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor max_bytes = max(max_bytes, rx, tx) 404376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 405376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor net, interface = key.split(":", 1) 406376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor interface_rx.setdefault(interface, {})[when] = rx 407376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor interface_tx.setdefault(interface, {})[when] = tx 408376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 409376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor last_state = state 410376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 411376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor for num, interface in enumerate(sorted(interface_rx.keys())): 412376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor rx, tx = interface_rx[interface], interface_tx[interface] 413376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor total_rx, total_tx = sum(rx.values()), sum(tx.values()) 414376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if not (total_rx or total_tx): continue 415376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 416376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor WriteChartData( 417376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor ["rx", "tx"], [rx, tx], 418376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor os.path.join(files_dir, "net%d.csv" % num)) 419376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 420376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor out.append(CHART % { 421376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "id": cgi.escape("net%d" % num), 422376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "id_js": json.write("net%d" % num), 423376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "label_html": NET_LABEL % { 424376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "interface": cgi.escape(interface), 425376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "rx": total_rx, 426376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "tx": total_tx 427376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor }, 428376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "filename_js": json.write("%s/net%d.csv" % (files_url, num)), 429376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "options_js": json.write({ 430376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "colors": ["black", "purple"], 431376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "dateWindow": date_window, 432376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "fillGraph": True, 433376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "height": 75, 434376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "valueRange": [0, max_bytes * 11 / 10], 435376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor }) 436376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor }) 437376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 438376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor # 439376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor # Output YAFFS statistics 440376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor # 441376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 442376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if out[-1] != SPACER: out.append(SPACER) 443b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 444b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor yaffs_vars = ["nBlockErasures", "nPageReads", "nPageWrites"] 445b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor partition_ops = {} 446b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 447b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor last_state = {} 448b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor for when, state in sorted_history: 449b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor for key in state: 450b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if not key.startswith("/proc/yaffs:"): continue 451b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 452b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor last = int(last_state.get(key, -1)) 453b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor next = int(state.get(key, -1)) 454b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if last == -1 or next == -1: continue 455b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 456b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor value = next - last 457376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor yaffs, partition, var = key.split(":", 2) 458b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor ops = partition_ops.setdefault(partition, {}) 459b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if var in yaffs_vars: 460b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor ops.setdefault(var, {})[when] = value 461b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 462b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor last_state = state 463b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 464b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor for num, (partition, ops) in enumerate(sorted(partition_ops.iteritems())): 465b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor totals = [sum(ops.get(var, {}).values()) for var in yaffs_vars] 466b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if not sum(totals): continue 467b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 468b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor WriteChartData( 469b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor yaffs_vars, 470b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor [ops.get(var, {}) for var in yaffs_vars], 471b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor os.path.join(files_dir, "yaffs%d.csv" % num)) 472b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 473b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor values = {"partition": partition} 474b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor values.update(zip(yaffs_vars, totals)) 475b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor out.append(CHART % { 476b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "id": cgi.escape("yaffs%d" % num), 477b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "id_js": json.write("yaffs%d" % num), 478b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "label_html": YAFFS_LABEL % values, 479b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "filename_js": json.write("%s/yaffs%d.csv" % (files_url, num)), 480b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "options_js": json.write({ 481b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "colors": ["maroon", "gray", "teal"], 482b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "dateWindow": date_window, 483b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "fillGraph": True, 484b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "height": 75, 485376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "includeZero": True, 486b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor }) 487b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor }) 488b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 489b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor # 490b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor # Output non-YAFFS statistics 491b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor # 492b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor 493b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor disk_reads = {} 494b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor disk_writes = {} 495b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor disk_msec = {} 496b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor total_io = max_io = max_msec = 0 497b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor 498b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor last_state = {} 499b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor for when, state in sorted_history: 500b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor for key in state: 501b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor if not key.startswith("/proc/diskstats:"): continue 502b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor 503b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor last = last_state.get(key, "").split() 504b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor next = state.get(key, "").split() 505b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor if not (last and next): continue 506b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor 507b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor reads = int(next[2]) - int(last[2]) 508b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor writes = int(next[6]) - int(last[6]) 509b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor msec = int(next[10]) - int(last[10]) 510b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor total_io += reads + writes 511b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor max_io = max(max_io, reads, writes) 512b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor max_msec = max(max_msec, msec) 513b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor 514b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor diskstats, device = key.split(":", 1) 515b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor disk_reads.setdefault(device, {})[when] = reads 516b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor disk_writes.setdefault(device, {})[when] = writes 517b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor disk_msec.setdefault(device, {})[when] = msec 518b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor 519b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor last_state = state 520b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor 521b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor io_cutoff = total_io / 100 522b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor for num, device in enumerate(sorted(disk_reads.keys())): 523b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor if [d for d in disk_reads.keys() 524b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor if d.startswith(device) and d != device]: continue 525b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor 526b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor reads, writes = disk_reads[device], disk_writes[device] 527b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor total_reads, total_writes = sum(reads.values()), sum(writes.values()) 528b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor if total_reads + total_writes <= io_cutoff: continue 529b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor 530b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor WriteChartData( 531b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor ["reads", "writes"], [reads, writes], 532b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor os.path.join(files_dir, "disk%d.csv" % num)) 533b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor 534b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor out.append(CHART % { 535b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "id": cgi.escape("disk%d" % num), 536b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "id_js": json.write("disk%d" % num), 537b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "label_html": DISK_LABEL % { 538b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "device": cgi.escape(device), 539b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "reads": total_reads, 540b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "writes": total_writes, 541b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor }, 542b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "filename_js": json.write("%s/disk%d.csv" % (files_url, num)), 543b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "options_js": json.write({ 544b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "colors": ["gray", "teal"], 545b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "dateWindow": date_window, 546b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "fillGraph": True, 547b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "height": 75, 548b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "valueRange": [0, max_io * 11 / 10], 549b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor }), 550b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor }) 551b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor 552b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor msec = disk_msec[device] 553b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor 554b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor WriteChartData( 555b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor ["msec"], [msec], 556b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor os.path.join(files_dir, "disk%d_time.csv" % num)) 557b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor 558b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor out.append(CHART % { 559b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "id": cgi.escape("disk%d_time" % num), 560b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "id_js": json.write("disk%d_time" % num), 561b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "label_html": DISK_TIME_LABEL % {"msec": sum(msec.values())}, 562b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "filename_js": json.write("%s/disk%d_time.csv" % (files_url, num)), 563b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "options_js": json.write({ 564b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "colors": ["blue"], 565b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "dateWindow": date_window, 566b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "fillGraph": True, 567b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "height": 50, 568b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor "valueRange": [0, max_msec * 11 / 10], 569b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor }), 570b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor }) 571b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor 572b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor # 573b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor # Output per-process CPU and page faults collected earlier 574b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor # 575b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 576b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor cpu_cutoff = (total_sys + total_user) / 200 577b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor faults_cutoff = sum(total_faults.values()) / 100 578b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor for start, pid in sorted([(s, p) for p, s in process_start.iteritems()]): 579b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor sys = sum([n for n, d in process_sys.get(pid, {}).values()]) 580b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor sys_user = sum([n for n, d in process_sys_user.get(pid, {}).values()]) 581b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if sys_user <= cpu_cutoff: continue 582b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 583376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if out[-1] != SPACER: out.append(SPACER) 584b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 585b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor WriteChartData( 586b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor ["sys", "sys+user"], 587b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor [process_sys.get(pid, {}), process_sys_user.get(pid, {})], 588b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor os.path.join(files_dir, "proc%d.csv" % pid)) 589b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 590b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor out.append(CHART % { 591b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "id": cgi.escape("proc%d" % pid), 592b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "id_js": json.write("proc%d" % pid), 593b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "label_html": PROC_CPU_LABEL % { 594b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "pid": pid, 595b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "process": cgi.escape(process_name.get(pid, "(unknown)")), 596b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "sys": sys, 597b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "user": sys_user - sys, 598b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor }, 599b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "filename_js": json.write("%s/proc%d.csv" % (files_url, pid)), 600b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "options_js": json.write({ 601b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "colors": ["blue", "green"], 602b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "dateWindow": date_window, 603b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "fillGraph": True, 604b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "fractions": True, 605b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "height": 75, 606b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "valueRange": [0, 110], 607b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor }), 608b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor }) 609b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 610b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor faults = sum(process_faults.get(pid, {}).values()) 611b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if faults <= faults_cutoff: continue 612b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 613b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor WriteChartData( 614376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor ["major"], [process_faults.get(pid, {})], 615b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor os.path.join(files_dir, "proc%d_faults.csv" % pid)) 616b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 617b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor out.append(CHART % { 618b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "id": cgi.escape("proc%d_faults" % pid), 619b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "id_js": json.write("proc%d_faults" % pid), 620b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "label_html": FAULTS_LABEL % {"major": faults}, 621b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "filename_js": json.write("%s/proc%d_faults.csv" % (files_url, pid)), 622b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "options_js": json.write({ 623b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "colors": ["gray"], 624b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "dateWindow": date_window, 625b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "fillGraph": True, 626b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "height": 50, 627b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor "valueRange": [0, max_faults * 11 / 10], 628b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor }), 629b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor }) 630b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 631b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor out.append(PAGE_END) 632b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor file(filename, "w").write("\n".join(out)) 633b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 634b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 635b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnordef main(argv): 636b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if len(argv) != 3: 637b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor print >>sys.stderr, "usage: procstatreport.py procstat.log output.html" 638376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor return 2 639b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 640b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor history = {} 641b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor current_state = {} 642b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor scan_time = 0.0 643b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 644b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor for line in file(argv[1]): 645376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if not line.endswith("\n"): continue 646376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 647b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor parts = line.split(None, 2) 648b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if len(parts) < 2 or parts[1] not in "+-=": 649b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor print >>sys.stderr, "Invalid input:", line 650b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor sys.exit(1) 651b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 652b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor name, op = parts[:2] 653b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 654b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if name == "T" and op == "+": # timestamp: scan about to begin 655b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor scan_time = float(line[4:]) 656b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor continue 657b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 658b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if name == "T" and op == "-": # timestamp: scan complete 659b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor time = (scan_time + float(line[4:])) / 2.0 660b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor history[time] = dict(current_state) 661b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 662b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor elif op == "-": 663b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor if name in current_state: del current_state[name] 664b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 665b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor else: 666b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor current_state[name] = "".join(parts[2:]).strip() 667b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 668376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if len(history) < 2: 669376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor print >>sys.stderr, "error: insufficient history to chart" 670376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor return 1 671376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 672b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor WriteOutput(history, argv[1], argv[2]) 673b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 674b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor 675b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnorif __name__ == "__main__": 676b1ccdd258e9efdd9dfa9e2c110e70348d20d3a31Dan Egnor sys.exit(main(sys.argv)) 677