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