Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Side by Side Diff: tools/perf/measurements/loading_measurement_analyzer.py

Issue 19925002: Update loading_measurement_analyzer to display CPU vs Network breakdowns. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2013 The Chromium Authors. All rights reserved. 2 # Copyright 2013 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Parses CSV output from the loading_measurement and outputs interesting stats. 6 """Parses CSV output from the loading_measurement and outputs interesting stats.
7 7
8 Example usage: 8 Example usage:
9 $ tools/perf/run_measurement --browser=release \ 9 $ tools/perf/run_measurement --browser=release \
10 --output-format=csv --output=/path/to/loading_measurement_output.csv \ 10 --output-format=csv --output=/path/to/loading_measurement_output.csv \
(...skipping 11 matching lines...) Expand all
22 import sys 22 import sys
23 23
24 24
25 class LoadingMeasurementAnalyzer(object): 25 class LoadingMeasurementAnalyzer(object):
26 26
27 def __init__(self, input_file, options): 27 def __init__(self, input_file, options):
28 self.ranks = {} 28 self.ranks = {}
29 self.totals = collections.defaultdict(list) 29 self.totals = collections.defaultdict(list)
30 self.maxes = collections.defaultdict(list) 30 self.maxes = collections.defaultdict(list)
31 self.avgs = collections.defaultdict(list) 31 self.avgs = collections.defaultdict(list)
32 self.load_times = []
33 self.cpu_times = []
34 self.network_percents = []
32 self.num_rows_parsed = 0 35 self.num_rows_parsed = 0
33 self.num_slowest_urls = options.num_slowest_urls 36 self.num_slowest_urls = options.num_slowest_urls
34 if options.rank_csv_file: 37 if options.rank_csv_file:
35 self._ParseRankCsvFile(os.path.expanduser(options.rank_csv_file)) 38 self._ParseRankCsvFile(os.path.expanduser(options.rank_csv_file))
36 self._ParseInputFile(input_file, options) 39 self._ParseInputFile(input_file, options)
37 40
38 def _ParseInputFile(self, input_file, options): 41 def _ParseInputFile(self, input_file, options):
39 with open(input_file, 'r') as csvfile: 42 with open(input_file, 'r') as csvfile:
40 row_dict = csv.DictReader(csvfile) 43 row_dict = csv.DictReader(csvfile)
41 for row in row_dict: 44 for row in row_dict:
42 if (options.rank_limit and 45 if (options.rank_limit and
43 self._GetRank(row['url']) > options.rank_limit): 46 self._GetRank(row['url']) > options.rank_limit):
44 continue 47 continue
48 cpu_time = 0
49 load_time = float(row['load_time (ms)'])
50 if load_time < 0:
51 print 'Skipping %s due to negative load time' % row['url']
52 continue
45 for key, value in row.iteritems(): 53 for key, value in row.iteritems():
46 if key in ('url', 'dom_content_loaded_time (ms)', 'load_time (ms)'): 54 if key in ('url', 'load_time (ms)', 'dom_content_loaded_time (ms)'):
47 continue 55 continue
48 if not value or value == '-': 56 if not value or value == '-':
49 continue 57 continue
58 value = float(value)
50 if '_avg' in key: 59 if '_avg' in key:
51 self.avgs[key].append((float(value), row['url'])) 60 self.avgs[key].append((value, row['url']))
52 elif '_max' in key: 61 elif '_max' in key:
53 self.maxes[key].append((float(value), row['url'])) 62 self.maxes[key].append((value, row['url']))
54 else: 63 else:
55 self.totals[key].append((float(value), row['url'])) 64 self.totals[key].append((value, row['url']))
nduca 2013/07/22 23:37:00 so you define network time as the unaccounted-for
65 cpu_time += value
66 self.load_times.append((load_time, row['url']))
67 self.cpu_times.append((cpu_time, row['url']))
68 if options.show_network:
69 network_time = load_time - cpu_time
70 self.totals['Network (ms)'].append((network_time, row['url']))
71 self.network_percents.append((network_time / load_time, row['url']))
56 self.num_rows_parsed += 1 72 self.num_rows_parsed += 1
57 if options.max_rows and self.num_rows_parsed == int(options.max_rows): 73 if options.max_rows and self.num_rows_parsed == int(options.max_rows):
58 break 74 break
59 75
60 def _ParseRankCsvFile(self, input_file): 76 def _ParseRankCsvFile(self, input_file):
61 with open(input_file, 'r') as csvfile: 77 with open(input_file, 'r') as csvfile:
62 for row in csv.reader(csvfile): 78 for row in csv.reader(csvfile):
63 assert len(row) == 2 79 assert len(row) == 2
64 self.ranks[row[1]] = int(row[0]) 80 self.ranks[row[1]] = int(row[0])
65 81
66 def _GetRank(self, url): 82 def _GetRank(self, url):
67 url = url.replace('http://', '') 83 url = url.replace('http://', '')
68 if url in self.ranks: 84 if url in self.ranks:
69 return self.ranks[url] 85 return self.ranks[url]
70 return len(self.ranks) 86 return len(self.ranks)
71 87
72 def PrintSummary(self): 88 def PrintSummary(self):
73 sum_totals = {} 89 sum_totals = {}
74 for key, values in self.totals.iteritems(): 90 for key, values in self.totals.iteritems():
75 sum_totals[key] = sum([v[0] for v in values]) 91 sum_totals[key] = sum([v[0] for v in values])
76 total_time = sum(sum_totals.values()) 92 total_cpu_time = sum([v[0] for v in self.cpu_times])
93 total_page_load_time = sum([v[0] for v in self.load_times])
77 94
78 print 95 print
79 print 'Total URLs: ', self.num_rows_parsed 96 print 'Total URLs: ', self.num_rows_parsed
80 print 'Total time: %ds' % int(round(total_time / 1000)) 97 print 'Total CPU time: %ds' % int(round(total_cpu_time / 1000))
98 print 'Total page load time: %ds' % int(round(total_page_load_time / 1000))
99 print 'Average CPU time: %dms' % int(round(
100 total_cpu_time / self.num_rows_parsed))
101 print 'Average page load time: %dms' % int(round(
102 total_page_load_time / self.num_rows_parsed))
81 print 103 print
82 for key, value in sorted(sum_totals.iteritems(), reverse=True, 104 for key, value in sorted(sum_totals.iteritems(), reverse=True,
83 key=lambda i: i[1]): 105 key=lambda i: i[1]):
84 output_key = '%30s: ' % key.replace(' (ms)', '') 106 output_key = '%30s: ' % key.replace(' (ms)', '')
85 output_value = '%10ds ' % (value / 1000) 107 output_value = '%10ds ' % (value / 1000)
86 output_percent = '%.1f%%' % (100 * value / total_time) 108 output_percent = '%.1f%%' % (100 * value / total_page_load_time)
87 print output_key, output_value, output_percent 109 print output_key, output_value, output_percent
88 110
89 if not self.num_slowest_urls: 111 if not self.num_slowest_urls:
90 return 112 return
91 113
92 for key, values in sorted(self.totals.iteritems(), reverse=True, 114 for key, values in sorted(self.totals.iteritems(), reverse=True,
93 key=lambda i: sum_totals[i[0]]): 115 key=lambda i: sum_totals[i[0]]):
94 print 116 print
95 print 'Top %d slowest %s:' % (self.num_slowest_urls, 117 print 'Top %d slowest %s:' % (self.num_slowest_urls,
96 key.replace(' (ms)', '')) 118 key.replace(' (ms)', ''))
97 slowest = heapq.nlargest(self.num_slowest_urls, values) 119 slowest = heapq.nlargest(self.num_slowest_urls, values)
98 for value, url in slowest: 120 for value, url in slowest:
99 print '\t', '%dms\t' % value, url, '(#%s)' % self._GetRank(url) 121 print '\t', '%dms\t' % value, url, '(#%s)' % self._GetRank(url)
100 122
123 if self.network_percents:
124 print
125 print 'Top %d highest network to CPU time ratios:' % self.num_slowest_urls
126 for percent, url in sorted(
127 self.network_percents, reverse=True)[:self.num_slowest_urls]:
128 percent *= 100
129 print '\t', '%.1f%%' % percent, url, '(#%s)' % self._GetRank(url)
130
131
101 def main(argv): 132 def main(argv):
102 prog_desc = 'Parses CSV output from the loading_measurement' 133 prog_desc = 'Parses CSV output from the loading_measurement'
103 parser = optparse.OptionParser(usage=('%prog [options]' + '\n\n' + prog_desc)) 134 parser = optparse.OptionParser(usage=('%prog [options]' + '\n\n' + prog_desc))
104 135
105 parser.add_option('--max-rows', type='int', 136 parser.add_option('--max-rows', type='int',
106 help='Only process this many rows') 137 help='Only process this many rows')
107 parser.add_option('--num-slowest-urls', type='int', 138 parser.add_option('--num-slowest-urls', type='int',
108 help='Output this many slowest URLs for each category') 139 help='Output this many slowest URLs for each category')
109 parser.add_option('--rank-csv-file', help='A CSV file of <rank,url>') 140 parser.add_option('--rank-csv-file', help='A CSV file of <rank,url>')
110 parser.add_option('--rank-limit', type='int', 141 parser.add_option('--rank-limit', type='int',
111 help='Only process pages higher than this rank') 142 help='Only process pages higher than this rank')
143 parser.add_option('--show-network', action='store_true',
144 help='Whether to display Network as a category')
112 145
113 options, args = parser.parse_args(argv[1:]) 146 options, args = parser.parse_args(argv[1:])
114 147
115 assert len(args) == 1, 'Must pass exactly one CSV file to analyze' 148 assert len(args) == 1, 'Must pass exactly one CSV file to analyze'
116 if options.rank_limit and not options.rank_csv_file: 149 if options.rank_limit and not options.rank_csv_file:
117 print 'Must pass --rank-csv-file with --rank-limit' 150 print 'Must pass --rank-csv-file with --rank-limit'
118 return 1 151 return 1
119 152
120 LoadingMeasurementAnalyzer(args[0], options).PrintSummary() 153 LoadingMeasurementAnalyzer(args[0], options).PrintSummary()
121 154
122 return 0 155 return 0
123 156
124 157
125 if __name__ == '__main__': 158 if __name__ == '__main__':
126 sys.exit(main(sys.argv)) 159 sys.exit(main(sys.argv))
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698