OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2016 the V8 project authors. All rights reserved. | 2 # Copyright 2016 the V8 project 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 Usage: callstats.py [-h] <command> ... | 6 Usage: callstats.py [-h] <command> ... |
7 | 7 |
8 Optional arguments: | 8 Optional arguments: |
9 -h, --help show this help message and exit | 9 -h, --help show this help message and exit |
10 | 10 |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
116 }, timeout); | 116 }, timeout); |
117 return; | 117 return; |
118 } | 118 } |
119 console.log("Ignoring: " + url); | 119 console.log("Ignoring: " + url); |
120 }; | 120 }; |
121 var sites = | 121 var sites = |
122 """, json.dumps(sites), """; | 122 """, json.dumps(sites), """; |
123 onLoad(window.location.href); | 123 onLoad(window.location.href); |
124 })();""" | 124 })();""" |
125 | 125 |
126 def get_chrome_flags(js_flags="'--runtime-calls-stats --allow-natives-syntax'", | |
127 user_data_dir="/var/tmp/`date +%S`"): | |
nickie
2016/09/28 09:08:09
The default parameter here is probably not recomme
Camillo Bruni
2016/09/28 10:36:34
Will push the tmp dir flag to there.
| |
128 return [ | |
129 "--no-default-browser-check", | |
130 "--no-sandbox", | |
131 "--disable-translate", | |
132 "--enable-benchmarking", | |
133 "--js-flags={}".format(js_flags), | |
134 "--no-first-run", | |
135 "--user-data-dir={}".format(user_data_dir), | |
136 ] | |
137 | |
138 def get_chrome_replay_args(args): | |
139 http_port = 4080 + args.port_offset | |
140 https_port = 4443 + args.port_offset | |
141 return [ | |
142 "--host-resolver-rules=MAP *:80 localhost:%s, " \ | |
143 "MAP *:443 localhost:%s, " \ | |
144 "EXCLUDE localhost" % ( | |
145 http_port, https_port), | |
146 "--ignore-certificate-errors", | |
147 "--disable-seccomp-sandbox", | |
148 "--disable-web-security", | |
149 "--reduce-security-for-testing", | |
150 "--allow-insecure-localhost", | |
151 ] | |
126 | 152 |
127 def run_site(site, domain, args, timeout=None): | 153 def run_site(site, domain, args, timeout=None): |
128 print "="*80 | 154 print "="*80 |
129 print "RUNNING DOMAIN %s" % domain | 155 print "RUNNING DOMAIN %s" % domain |
130 print "="*80 | 156 print "="*80 |
131 result_template = "{domain}#{count}.txt" if args.repeat else "{domain}.txt" | 157 result_template = "{domain}#{count}.txt" if args.repeat else "{domain}.txt" |
132 count = 0 | 158 count = 0 |
133 if timeout is None: timeout = args.timeout | 159 if timeout is None: timeout = args.timeout |
134 if args.replay_wpr: | 160 if args.replay_wpr: |
135 timeout *= 1 + args.refresh | 161 timeout *= 1 + args.refresh |
136 timeout += 1 | 162 timeout += 1 |
137 retries_since_good_run = 0 | 163 retries_since_good_run = 0 |
138 while count == 0 or args.repeat is not None and count < args.repeat: | 164 while count == 0 or args.repeat is not None and count < args.repeat: |
139 count += 1 | 165 count += 1 |
140 result = result_template.format(domain=domain, count=count) | 166 result = result_template.format(domain=domain, count=count) |
141 retries = 0 | 167 retries = 0 |
142 while args.retries is None or retries < args.retries: | 168 while args.retries is None or retries < args.retries: |
143 retries += 1 | 169 retries += 1 |
144 try: | 170 try: |
145 if args.user_data_dir: | 171 if args.user_data_dir: |
146 user_data_dir = args.user_data_dir | 172 user_data_dir = args.user_data_dir |
147 else: | 173 else: |
148 user_data_dir = tempfile.mkdtemp(prefix="chr_") | 174 user_data_dir = tempfile.mkdtemp(prefix="chr_") |
149 js_flags = "--runtime-call-stats" | 175 js_flags = "--runtime-call-stats" |
150 if args.replay_wpr: js_flags += " --allow-natives-syntax" | 176 if args.replay_wpr: js_flags += " --allow-natives-syntax" |
151 if args.js_flags: js_flags += " " + args.js_flags | 177 if args.js_flags: js_flags += " " + args.js_flags |
152 chrome_flags = [ | 178 chrome_flags = get_chrome_flags(js_flags, user_data_dir) |
153 "--no-default-browser-check", | |
154 "--no-sandbox", | |
155 "--disable-translate", | |
156 "--enable-benchmarking", | |
157 "--js-flags={}".format(js_flags), | |
158 "--no-first-run", | |
159 "--user-data-dir={}".format(user_data_dir), | |
160 ] | |
161 if args.replay_wpr: | 179 if args.replay_wpr: |
162 http_port = 4080 + args.port_offset | 180 chrome_flags += get_chrome_replay_flags(args.port_offset) |
163 https_port = 4443 + args.port_offset | |
164 chrome_flags += [ | |
165 "--host-resolver-rules=MAP *:80 localhost:%s, " \ | |
166 "MAP *:443 localhost:%s, " \ | |
167 "EXCLUDE localhost" % ( | |
168 http_port, https_port), | |
169 "--ignore-certificate-errors", | |
170 "--disable-seccomp-sandbox", | |
171 "--disable-web-security", | |
172 "--reduce-security-for-testing", | |
173 "--allow-insecure-localhost", | |
174 ] | |
175 else: | 181 else: |
176 chrome_flags += [ | 182 chrome_flags += [ "--single-process", ] |
177 "--single-process", | |
178 ] | |
179 if args.chrome_flags: | 183 if args.chrome_flags: |
180 chrome_flags += args.chrome_flags.split() | 184 chrome_flags += args.chrome_flags.split() |
181 cmd_args = [ | 185 cmd_args = [ |
182 "timeout", str(timeout), | 186 "timeout", str(timeout), |
183 args.with_chrome | 187 args.with_chrome |
184 ] + chrome_flags + [ site ] | 188 ] + chrome_flags + [ site ] |
185 print "- " * 40 | 189 print "- " * 40 |
186 print_command(cmd_args) | 190 print_command(cmd_args) |
187 print "- " * 40 | 191 print "- " * 40 |
188 with open(result, "wt") as f: | 192 with open(result, "wt") as f: |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
228 for line in f: | 232 for line in f: |
229 line = line.strip() | 233 line = line.strip() |
230 if not line or line.startswith('#'): continue | 234 if not line or line.startswith('#'): continue |
231 sites.append({'url': line, 'timeout': args.timeout}) | 235 sites.append({'url': line, 'timeout': args.timeout}) |
232 return sites | 236 return sites |
233 except IOError as e: | 237 except IOError as e: |
234 args.error("Cannot read from {}. {}.".format(args.sites_file, e.strerror)) | 238 args.error("Cannot read from {}. {}.".format(args.sites_file, e.strerror)) |
235 sys.exit(1) | 239 sys.exit(1) |
236 | 240 |
237 | 241 |
238 def do_run(args): | 242 def read_sites(args): |
239 # Determine the websites to benchmark. | 243 # Determine the websites to benchmark. |
240 if args.sites_file: | 244 if args.sites_file: |
241 sites = read_sites_file(args) | 245 return read_sites_file(args) |
242 else: | 246 return [{'url': site, 'timeout': args.timeout} for site in args.sites] |
243 sites = [{'url': site, 'timeout': args.timeout} for site in args.sites] | 247 |
248 def do_run(args): | |
249 sites = read_sites(args) | |
250 replay_server = start_replay_server(args, sites) if args.replay_wpr else None | |
244 # Disambiguate domains, if needed. | 251 # Disambiguate domains, if needed. |
245 L = [] | 252 L = [] |
246 domains = {} | 253 domains = {} |
247 for item in sites: | 254 for item in sites: |
248 site = item['url'] | 255 site = item['url'] |
249 domain = None | 256 domain = None |
250 if args.domain: | 257 if args.domain: |
251 domain = args.domain | 258 domain = args.domain |
252 elif 'domain' in item: | 259 elif 'domain' in item: |
253 domain = item['domain'] | 260 domain = item['domain'] |
254 else: | 261 else: |
255 m = re.match(r'^(https?://)?([^/]+)(/.*)?$', site) | 262 m = re.match(r'^(https?://)?([^/]+)(/.*)?$', site) |
256 if not m: | 263 if not m: |
257 args.error("Invalid URL {}.".format(site)) | 264 args.error("Invalid URL {}.".format(site)) |
258 continue | 265 continue |
259 domain = m.group(2) | 266 domain = m.group(2) |
260 entry = [site, domain, None, item['timeout']] | 267 entry = [site, domain, None, item['timeout']] |
261 if domain not in domains: | 268 if domain not in domains: |
262 domains[domain] = entry | 269 domains[domain] = entry |
263 else: | 270 else: |
264 if not isinstance(domains[domain], int): | 271 if not isinstance(domains[domain], int): |
265 domains[domain][2] = 1 | 272 domains[domain][2] = 1 |
266 domains[domain] = 1 | 273 domains[domain] = 1 |
267 domains[domain] += 1 | 274 domains[domain] += 1 |
268 entry[2] = domains[domain] | 275 entry[2] = domains[domain] |
269 L.append(entry) | 276 L.append(entry) |
270 replay_server = start_replay_server(args, sites) if args.replay_wpr else None | |
271 try: | 277 try: |
272 # Run them. | 278 # Run them. |
273 for site, domain, count, timeout in L: | 279 for site, domain, count, timeout in L: |
274 if count is not None: domain = "{}%{}".format(domain, count) | 280 if count is not None: domain = "{}%{}".format(domain, count) |
275 print site, domain, timeout | 281 print(site, domain, timeout) |
276 run_site(site, domain, args, timeout) | 282 run_site(site, domain, args, timeout) |
277 finally: | 283 finally: |
278 if replay_server: | 284 if replay_server: |
279 stop_replay_server(replay_server) | 285 stop_replay_server(replay_server) |
280 | 286 |
281 | 287 |
288 def do_run_replay_server(args): | |
289 sites = read_sites(args) | |
290 print("- " * 40) | |
291 print("Launch chromium with the following commands for debugging:") | |
292 print(" $CHROMIUM_DIR/out/Release/chomium") | |
293 print(" " + | |
294 (" \\\n ".join(get_chrome_flags()+get_chrome_replay_args(args))) + | |
nickie
2016/09/28 09:08:09
Here the users will see the /var/tmp/`date` temp d
Camillo Bruni
2016/09/28 10:36:34
right, made this more obvious by pushing down the
| |
295 " \\") | |
296 print(" <URL>") | |
297 print("- " * 40) | |
298 replay_server = start_replay_server(args, sites) | |
299 try: | |
300 replay_server['process'].wait() | |
301 finally: | |
302 stop_replay_server(replay_server) | |
303 | |
304 | |
282 # Calculate statistics. | 305 # Calculate statistics. |
283 | 306 |
284 def statistics(data): | 307 def statistics(data): |
285 N = len(data) | 308 N = len(data) |
286 average = numpy.average(data) | 309 average = numpy.average(data) |
287 median = numpy.median(data) | 310 median = numpy.median(data) |
288 low = numpy.min(data) | 311 low = numpy.min(data) |
289 high= numpy.max(data) | 312 high= numpy.max(data) |
290 if N > 1: | 313 if N > 1: |
291 # evaluate sample variance by setting delta degrees of freedom (ddof) to | 314 # evaluate sample variance by setting delta degrees of freedom (ddof) to |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
528 given = sum(1 for x in l if x) | 551 given = sum(1 for x in l if x) |
529 return given == 0 or given == len(l) | 552 return given == 0 or given == len(l) |
530 | 553 |
531 def main(): | 554 def main(): |
532 parser = argparse.ArgumentParser() | 555 parser = argparse.ArgumentParser() |
533 subparser_adder = parser.add_subparsers(title="commands", dest="command", | 556 subparser_adder = parser.add_subparsers(title="commands", dest="command", |
534 metavar="<command>") | 557 metavar="<command>") |
535 subparsers = {} | 558 subparsers = {} |
536 # Command: run. | 559 # Command: run. |
537 subparsers["run"] = subparser_adder.add_parser( | 560 subparsers["run"] = subparser_adder.add_parser( |
538 "run", help="run --help") | 561 "run", help="Replay websites and collect runtime stats data.") |
539 subparsers["run"].set_defaults( | 562 subparsers["run"].set_defaults( |
540 func=do_run, error=subparsers["run"].error) | 563 func=do_run, error=subparsers["run"].error) |
541 subparsers["run"].add_argument( | 564 subparsers["run"].add_argument( |
542 "--chrome-flags", type=str, default="", | 565 "--chrome-flags", type=str, default="", |
543 help="specify additional chrome flags") | 566 help="specify additional chrome flags") |
544 subparsers["run"].add_argument( | 567 subparsers["run"].add_argument( |
545 "--js-flags", type=str, default="", | 568 "--js-flags", type=str, default="", |
546 help="specify additional V8 flags") | 569 help="specify additional V8 flags") |
547 subparsers["run"].add_argument( | 570 subparsers["run"].add_argument( |
548 "--domain", type=str, default="", | |
549 help="specify the output file domain name") | |
550 subparsers["run"].add_argument( | |
551 "--no-url", dest="print_url", action="store_false", default=True, | |
552 help="do not include url in statistics file") | |
553 subparsers["run"].add_argument( | |
554 "-n", "--repeat", type=int, metavar="<num>", | |
555 help="specify iterations for each website (default: once)") | |
556 subparsers["run"].add_argument( | |
557 "-k", "--refresh", type=int, metavar="<num>", default=0, | |
558 help="specify refreshes for each iteration (default: 0)") | |
559 subparsers["run"].add_argument( | |
560 "--replay-wpr", type=str, metavar="<path>", | |
561 help="use the specified web page replay (.wpr) archive") | |
562 subparsers["run"].add_argument( | |
563 "--replay-bin", type=str, metavar="<path>", | |
564 help="specify the replay.py script typically located in " \ | |
565 "$CHROMIUM/src/third_party/webpagereplay/replay.py") | |
566 subparsers["run"].add_argument( | |
567 "-r", "--retries", type=int, metavar="<num>", | |
568 help="specify retries if website is down (default: forever)") | |
569 subparsers["run"].add_argument( | |
570 "-f", "--sites-file", type=str, metavar="<path>", | |
571 help="specify file containing benchmark websites") | |
572 subparsers["run"].add_argument( | |
573 "-t", "--timeout", type=int, metavar="<seconds>", default=60, | |
574 help="specify seconds before chrome is killed") | |
575 subparsers["run"].add_argument( | |
576 "-p", "--port-offset", type=int, metavar="<offset>", default=0, | |
577 help="specify the offset for the replay server's default ports") | |
578 subparsers["run"].add_argument( | |
579 "-u", "--user-data-dir", type=str, metavar="<path>", | 571 "-u", "--user-data-dir", type=str, metavar="<path>", |
580 help="specify user data dir (default is temporary)") | 572 help="specify user data dir (default is temporary)") |
581 subparsers["run"].add_argument( | 573 subparsers["run"].add_argument( |
582 "-c", "--with-chrome", type=str, metavar="<path>", | 574 "-c", "--with-chrome", type=str, metavar="<path>", |
583 default="/usr/bin/google-chrome", | 575 default="/usr/bin/google-chrome", |
584 help="specify chrome executable to use") | 576 help="specify chrome executable to use") |
585 subparsers["run"].add_argument( | 577 subparsers["run"].add_argument( |
586 "-l", "--log-stderr", type=str, metavar="<path>", | 578 "-r", "--retries", type=int, metavar="<num>", |
587 help="specify where chrome's stderr should go (default: /dev/null)") | 579 help="specify retries if website is down (default: forever)") |
588 subparsers["run"].add_argument( | 580 subparsers["run"].add_argument( |
589 "sites", type=str, metavar="<URL>", nargs="*", | 581 "--no-url", dest="print_url", action="store_false", default=True, |
590 help="specify benchmark website") | 582 help="do not include url in statistics file") |
583 subparsers["run"].add_argument( | |
584 "--domain", type=str, default="", | |
585 help="specify the output file domain name") | |
586 subparsers["run"].add_argument( | |
587 "-n", "--repeat", type=int, metavar="<num>", | |
588 help="specify iterations for each website (default: once)") | |
589 | |
590 def add_replay_args(subparser): | |
591 subparser.add_argument( | |
592 "-k", "--refresh", type=int, metavar="<num>", default=0, | |
593 help="specify refreshes for each iteration (default: 0)") | |
594 subparser.add_argument( | |
595 "--replay-wpr", type=str, metavar="<path>", | |
596 help="use the specified web page replay (.wpr) archive") | |
597 subparser.add_argument( | |
598 "--replay-bin", type=str, metavar="<path>", | |
599 help="specify the replay.py script typically located in " \ | |
600 "$CHROMIUM/src/third_party/webpagereplay/replay.py") | |
601 subparser.add_argument( | |
602 "-f", "--sites-file", type=str, metavar="<path>", | |
603 help="specify file containing benchmark websites") | |
604 subparser.add_argument( | |
605 "-t", "--timeout", type=int, metavar="<seconds>", default=60, | |
606 help="specify seconds before chrome is killed") | |
607 subparser.add_argument( | |
608 "-p", "--port-offset", type=int, metavar="<offset>", default=0, | |
609 help="specify the offset for the replay server's default ports") | |
610 subparser.add_argument( | |
611 "-l", "--log-stderr", type=str, metavar="<path>", | |
612 help="specify where chrome's stderr should go (default: /dev/null)") | |
613 subparser.add_argument( | |
614 "sites", type=str, metavar="<URL>", nargs="*", | |
615 help="specify benchmark website") | |
616 add_replay_args(subparsers["run"]) | |
617 | |
618 # Command: replay-server | |
619 subparsers["replay"] = subparser_adder.add_parser( | |
620 "replay", help="Run the replay server for debugging purposes") | |
621 subparsers["replay"].set_defaults( | |
622 func=do_run_replay_server, error=subparsers["replay"].error) | |
623 add_replay_args(subparsers["replay"]) | |
624 | |
591 # Command: stats. | 625 # Command: stats. |
592 subparsers["stats"] = subparser_adder.add_parser( | 626 subparsers["stats"] = subparser_adder.add_parser( |
593 "stats", help="stats --help") | 627 "stats", help="Analize the results file create by the 'run' command.") |
594 subparsers["stats"].set_defaults( | 628 subparsers["stats"].set_defaults( |
595 func=do_stats, error=subparsers["stats"].error) | 629 func=do_stats, error=subparsers["stats"].error) |
596 subparsers["stats"].add_argument( | 630 subparsers["stats"].add_argument( |
597 "-l", "--limit", type=int, metavar="<num>", default=0, | 631 "-l", "--limit", type=int, metavar="<num>", default=0, |
598 help="limit how many items to print (default: none)") | 632 help="limit how many items to print (default: none)") |
599 subparsers["stats"].add_argument( | 633 subparsers["stats"].add_argument( |
600 "-s", "--sort", choices=["asc", "desc"], default="asc", | 634 "-s", "--sort", choices=["asc", "desc"], default="asc", |
601 help="specify sorting order (default: ascending)") | 635 help="specify sorting order (default: ascending)") |
602 subparsers["stats"].add_argument( | 636 subparsers["stats"].add_argument( |
603 "-n", "--no-total", dest="totals", action="store_false", default=True, | 637 "-n", "--no-total", dest="totals", action="store_false", default=True, |
604 help="do not print totals") | 638 help="do not print totals") |
605 subparsers["stats"].add_argument( | 639 subparsers["stats"].add_argument( |
606 "logfiles", type=str, metavar="<logfile>", nargs="*", | 640 "logfiles", type=str, metavar="<logfile>", nargs="*", |
607 help="specify log files to parse") | 641 help="specify log files to parse") |
608 subparsers["stats"].add_argument( | 642 subparsers["stats"].add_argument( |
609 "--aggregate", dest="aggregate", action="store_true", default=False, | 643 "--aggregate", dest="aggregate", action="store_true", default=False, |
610 help="Create aggregated entries. Adds Group-* entries at the toplevel. " + | 644 help="Create aggregated entries. Adds Group-* entries at the toplevel. " \ |
611 "Additionally creates a Total page with all entries.") | 645 "Additionally creates a Total page with all entries.") |
646 | |
612 # Command: json. | 647 # Command: json. |
613 subparsers["json"] = subparser_adder.add_parser( | 648 subparsers["json"] = subparser_adder.add_parser( |
614 "json", help="json --help") | 649 "json", help="Collect results file created by the 'run' command into" \ |
650 "a single json file.") | |
615 subparsers["json"].set_defaults( | 651 subparsers["json"].set_defaults( |
616 func=do_json, error=subparsers["json"].error) | 652 func=do_json, error=subparsers["json"].error) |
617 subparsers["json"].add_argument( | 653 subparsers["json"].add_argument( |
618 "logdirs", type=str, metavar="<logdir>", nargs="*", | 654 "logdirs", type=str, metavar="<logdir>", nargs="*", |
619 help="specify directories with log files to parse") | 655 help="specify directories with log files to parse") |
620 subparsers["json"].add_argument( | 656 subparsers["json"].add_argument( |
621 "--aggregate", dest="aggregate", action="store_true", default=False, | 657 "--aggregate", dest="aggregate", action="store_true", default=False, |
622 help="Create aggregated entries. Adds Group-* entries at the toplevel. " + | 658 help="Create aggregated entries. Adds Group-* entries at the toplevel. " \ |
623 "Additionally creates a Total page with all entries.") | 659 "Additionally creates a Total page with all entries.") |
660 | |
624 # Command: help. | 661 # Command: help. |
625 subparsers["help"] = subparser_adder.add_parser( | 662 subparsers["help"] = subparser_adder.add_parser( |
626 "help", help="help information") | 663 "help", help="help information") |
627 subparsers["help"].set_defaults( | 664 subparsers["help"].set_defaults( |
628 func=lambda args: do_help(parser, subparsers, args), | 665 func=lambda args: do_help(parser, subparsers, args), |
629 error=subparsers["help"].error) | 666 error=subparsers["help"].error) |
630 subparsers["help"].add_argument( | 667 subparsers["help"].add_argument( |
631 "help_cmd", type=str, metavar="<command>", nargs="?", | 668 "help_cmd", type=str, metavar="<command>", nargs="?", |
632 help="command for which to display help") | 669 help="command for which to display help") |
670 | |
633 # Execute the command. | 671 # Execute the command. |
634 args = parser.parse_args() | 672 args = parser.parse_args() |
635 setattr(args, 'script_path', os.path.dirname(sys.argv[0])) | 673 setattr(args, 'script_path', os.path.dirname(sys.argv[0])) |
636 if args.command == "run" and coexist(args.sites_file, args.sites): | 674 if args.command == "run" and coexist(args.sites_file, args.sites): |
637 args.error("use either option --sites-file or site URLs") | 675 args.error("use either option --sites-file or site URLs") |
638 sys.exit(1) | 676 sys.exit(1) |
639 elif args.command == "run" and not coexist(args.replay_wpr, args.replay_bin): | 677 elif args.command == "run" and not coexist(args.replay_wpr, args.replay_bin): |
640 args.error("options --replay-wpr and --replay-bin must be used together") | 678 args.error("options --replay-wpr and --replay-bin must be used together") |
641 sys.exit(1) | 679 sys.exit(1) |
642 else: | 680 else: |
643 args.func(args) | 681 args.func(args) |
644 | 682 |
645 if __name__ == "__main__": | 683 if __name__ == "__main__": |
646 sys.exit(main()) | 684 sys.exit(main()) |
OLD | NEW |