Add script injection when replaying with callstats.py
This allows benchmarking without --single-process and correctly gathering --runtime-call-stats numbers. Add optional parameter to %GetAndResetRuntimeCallStats - Without any parameter, it returns a string with the runtime call statistics (as before). - With one string parameter, it appends the statistics to the file with that file name. - With one integer parameter (which must be 1=stdout or 2=stderr), it prints the statistics to the output with of that file descriptor. The injected script is automatically generated. Also, callstats.py does not have a hardwired DEFAULT_SITES anymore. R=cbruni@chromium.org BUG= LOG=N Review-Url: https://codereview.chromium.org/1966193002 Cr-Commit-Position: refs/heads/master@{#36172}
This commit is contained in:
parent
52600c6b1c
commit
5fa1c61ee0
@ -497,13 +497,41 @@ RUNTIME_FUNCTION(Runtime_GetOrdinaryHasInstance) {
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_GetAndResetRuntimeCallStats) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(0, args.length());
|
||||
std::stringstream stats_stream;
|
||||
isolate->counters()->runtime_call_stats()->Print(stats_stream);
|
||||
Handle<String> result =
|
||||
isolate->factory()->NewStringFromAsciiChecked(stats_stream.str().c_str());
|
||||
isolate->counters()->runtime_call_stats()->Reset();
|
||||
return *result;
|
||||
if (args.length() == 0) {
|
||||
// Without arguments, the result is returned as a string.
|
||||
DCHECK_EQ(0, args.length());
|
||||
std::stringstream stats_stream;
|
||||
isolate->counters()->runtime_call_stats()->Print(stats_stream);
|
||||
Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(
|
||||
stats_stream.str().c_str());
|
||||
isolate->counters()->runtime_call_stats()->Reset();
|
||||
return *result;
|
||||
} else {
|
||||
DCHECK_EQ(1, args.length());
|
||||
std::FILE* f;
|
||||
if (args[0]->IsString()) {
|
||||
// With a string argument, the results are appended to that file.
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, arg0, 0);
|
||||
String::FlatContent flat = arg0->GetFlatContent();
|
||||
const char* filename =
|
||||
reinterpret_cast<const char*>(&(flat.ToOneByteVector()[0]));
|
||||
f = std::fopen(filename, "a");
|
||||
DCHECK_NOT_NULL(f);
|
||||
} else {
|
||||
// With an integer argument, the results are written to stdout/stderr.
|
||||
CONVERT_SMI_ARG_CHECKED(fd, 0);
|
||||
DCHECK(fd == 1 || fd == 2);
|
||||
f = fd == 1 ? stdout : stderr;
|
||||
}
|
||||
OFStream stats_stream(f);
|
||||
isolate->counters()->runtime_call_stats()->Print(stats_stream);
|
||||
isolate->counters()->runtime_call_stats()->Reset();
|
||||
if (args[0]->IsString())
|
||||
std::fclose(f);
|
||||
else
|
||||
std::fflush(f);
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_EnqueueMicrotask) {
|
||||
|
@ -315,7 +315,7 @@ namespace internal {
|
||||
F(CreateListFromArrayLike, 1, 1) \
|
||||
F(IncrementUseCounter, 1, 1) \
|
||||
F(GetOrdinaryHasInstance, 0, 1) \
|
||||
F(GetAndResetRuntimeCallStats, 0, 1) \
|
||||
F(GetAndResetRuntimeCallStats, -1 /* <= 1 */, 1) \
|
||||
F(EnqueueMicrotask, 1, 1) \
|
||||
F(RunMicrotasks, 0, 1) \
|
||||
F(WasmGetFunctionName, 2, 1)
|
||||
|
130
tools/callstats.py
Normal file → Executable file
130
tools/callstats.py
Normal file → Executable file
@ -34,46 +34,6 @@ from math import sqrt
|
||||
|
||||
# Run benchmarks.
|
||||
|
||||
DEFAULT_SITES = [
|
||||
# top websites (http://alexa.com/topsites): --------------------
|
||||
"https://www.google.de/search?q=v8",
|
||||
"https://www.youtube.com",
|
||||
"https://www.facebook.com/shakira",
|
||||
"http://www.baidu.com/s?wd=v8",
|
||||
"http://www.yahoo.co.jp",
|
||||
"http://www.amazon.com/s/?field-keywords=v8",
|
||||
"http://hi.wikipedia.org/wiki/" \
|
||||
"%E0%A4%AE%E0%A5%81%E0%A4%96%E0%A4%AA%E0%A5%83%E0%A4%B7%E0%A5%8D%E0%A4%A0",
|
||||
"http://www.qq.com",
|
||||
"http://www.twitter.com/taylorswift13",
|
||||
"http://www.reddit.com",
|
||||
"http://www.ebay.fr/sch/i.html?_nkw=v8",
|
||||
"http://edition.cnn.com",
|
||||
"http://world.taobao.com",
|
||||
"http://www.instagram.com/archdigest",
|
||||
"https://www.linkedin.com/pub/dir/?first=john&last=doe&search=search",
|
||||
"http://www.msn.com/ar-ae",
|
||||
"http://www.bing.com/search?q=v8+engine",
|
||||
"http://www.pinterest.com/categories/popular",
|
||||
"http://www.sina.com.cn",
|
||||
"http://weibo.com",
|
||||
"http://yandex.ru/search/?text=v8",
|
||||
# framework driven decisions: -----------------------------------
|
||||
# wikipedia content + angularjs
|
||||
"http://www.wikiwand.com/en/hill",
|
||||
# ember website
|
||||
"http://meta.discourse.org",
|
||||
# backbone js
|
||||
"http://reddit.musicplayer.io",
|
||||
# gwt application
|
||||
"http://inbox.google.com",
|
||||
# webgl / algorithmic case
|
||||
"http://maps.google.co.jp/maps/search/restaurant+tokyo",
|
||||
# whatever framework adwords uses
|
||||
"https://adwords.google.com",
|
||||
]
|
||||
|
||||
|
||||
def print_command(cmd_args):
|
||||
def fix_for_printing(arg):
|
||||
m = re.match(r'^--([^=]+)=(.*)$', arg)
|
||||
@ -85,7 +45,11 @@ def print_command(cmd_args):
|
||||
print " ".join(map(fix_for_printing, cmd_args))
|
||||
|
||||
|
||||
def start_replay_server(args):
|
||||
def start_replay_server(args, sites):
|
||||
with tempfile.NamedTemporaryFile(prefix='callstats-inject-', suffix='.js',
|
||||
mode='wt', delete=False) as f:
|
||||
injection = f.name
|
||||
generate_injection(f, sites)
|
||||
cmd_args = [
|
||||
args.replay_bin,
|
||||
"--port=4080",
|
||||
@ -93,6 +57,7 @@ def start_replay_server(args):
|
||||
"--no-dns_forwarding",
|
||||
"--use_closest_match",
|
||||
"--no-diff_unknown_requests",
|
||||
"--inject_scripts=deterministic.js,{}".format(injection),
|
||||
args.replay_wpr,
|
||||
]
|
||||
print "=" * 80
|
||||
@ -101,12 +66,51 @@ def start_replay_server(args):
|
||||
server = subprocess.Popen(cmd_args, stdout=null, stderr=null)
|
||||
print "RUNNING REPLAY SERVER: %s with PID=%s" % (args.replay_bin, server.pid)
|
||||
print "=" * 80
|
||||
return server
|
||||
return {'process': server, 'injection': injection}
|
||||
|
||||
|
||||
def stop_replay_server(server):
|
||||
print("SHUTTING DOWN REPLAY SERVER %s" % server.pid)
|
||||
server.terminate()
|
||||
print("SHUTTING DOWN REPLAY SERVER %s" % server['process'].pid)
|
||||
server['process'].terminate()
|
||||
os.remove(server['injection'])
|
||||
|
||||
|
||||
def generate_injection(f, sites):
|
||||
print >> f, """\
|
||||
(function() {
|
||||
function match(url, item) {
|
||||
if ('regexp' in item) return url.match(item.regexp) !== null;
|
||||
let url_wanted = item.url;
|
||||
// Allow automatic redirections from http to https.
|
||||
if (url_wanted.startsWith("http://") && url.startsWith("https://")) {
|
||||
url_wanted = "https://" + url_wanted.substr(7);
|
||||
}
|
||||
return url.startsWith(url_wanted);
|
||||
};
|
||||
|
||||
function onLoad(e) {
|
||||
let url = e.target.URL;
|
||||
for (let item of sites) {
|
||||
if (!match(url, item)) continue;
|
||||
let timeout = 'timeline' in item ? 2500 * item.timeline + 3000
|
||||
: 'timeout' in item ? 1000 * (item.timeout - 3)
|
||||
: 10000;
|
||||
console.log("Setting time out of " + timeout + " for: " + url);
|
||||
window.setTimeout(function () {
|
||||
console.log("Time is out for: " + url);
|
||||
%GetAndResetRuntimeCallStats(1);
|
||||
}, timeout);
|
||||
return;
|
||||
}
|
||||
console.log("Ignoring: " + url);
|
||||
};
|
||||
|
||||
let sites =
|
||||
""", json.dumps(sites), """;
|
||||
|
||||
console.log("Event listenner added for: " + window.location.href);
|
||||
window.addEventListener("load", onLoad);
|
||||
})();"""
|
||||
|
||||
|
||||
def run_site(site, domain, args, timeout=None):
|
||||
@ -115,6 +119,8 @@ def run_site(site, domain, args, timeout=None):
|
||||
print "="*80
|
||||
result_template = "{domain}#{count}.txt" if args.repeat else "{domain}.txt"
|
||||
count = 0
|
||||
if timeout is None: timeout = args.timeout
|
||||
if args.replay_wpr: timeout += 1
|
||||
while count == 0 or args.repeat is not None and count < args.repeat:
|
||||
count += 1
|
||||
result = result_template.format(domain=domain, count=count)
|
||||
@ -122,15 +128,17 @@ def run_site(site, domain, args, timeout=None):
|
||||
while args.retries is None or retries < args.retries:
|
||||
retries += 1
|
||||
try:
|
||||
temp_user_data_dir = args.user_data_dir is None
|
||||
if temp_user_data_dir:
|
||||
if args.user_data_dir:
|
||||
user_data_dir = args.user_data_dir
|
||||
else:
|
||||
user_data_dir = tempfile.mkdtemp(prefix="chr_")
|
||||
js_flags = "--runtime-call-stats"
|
||||
if args.replay_wpr: js_flags += " --allow-natives-syntax"
|
||||
if args.js_flags: js_flags += " " + args.js_flags
|
||||
chrome_flags = [
|
||||
"--no-default-browser-check",
|
||||
"--disable-translate",
|
||||
"--single-process",
|
||||
"--disable-seccomp-sandbox",
|
||||
"--no-sandbox",
|
||||
"--js-flags={}".format(js_flags),
|
||||
"--no-first-run",
|
||||
@ -146,9 +154,12 @@ def run_site(site, domain, args, timeout=None):
|
||||
"--reduce-security-for-testing",
|
||||
"--allow-insecure-localhost",
|
||||
]
|
||||
else:
|
||||
chrome_flags += [
|
||||
"--single-process",
|
||||
]
|
||||
if args.chrome_flags:
|
||||
chrome_flags += args.chrome_flags.split()
|
||||
if timeout is None: timeout = args.timeout
|
||||
cmd_args = [
|
||||
"timeout", str(timeout),
|
||||
args.with_chrome
|
||||
@ -171,9 +182,10 @@ def run_site(site, domain, args, timeout=None):
|
||||
print >> f
|
||||
print >> f, "URL: {}".format(site)
|
||||
break
|
||||
if retries <= 5: timeout += 1
|
||||
print("EMPTY RESULT, REPEATING RUN");
|
||||
finally:
|
||||
if temp_user_data_dir:
|
||||
if not args.user_data_dir:
|
||||
shutil.rmtree(user_data_dir)
|
||||
|
||||
|
||||
@ -204,10 +216,8 @@ def do_run(args):
|
||||
# Determine the websites to benchmark.
|
||||
if args.sites_file:
|
||||
sites = read_sites_file(args)
|
||||
elif args.sites:
|
||||
sites = [{'url': site, 'timeout': args.timeout} for site in args.sites]
|
||||
else:
|
||||
sites = [{'url': site, 'timeout': args.timeout} for site in DEFAULT_SITES]
|
||||
sites = [{'url': site, 'timeout': args.timeout} for site in args.sites]
|
||||
# Disambiguate domains, if needed.
|
||||
L = []
|
||||
domains = {}
|
||||
@ -228,8 +238,7 @@ def do_run(args):
|
||||
domains[domain] += 1
|
||||
entry[2] = domains[domain]
|
||||
L.append(entry)
|
||||
if args.replay_wpr:
|
||||
replay_server = start_replay_server(args);
|
||||
replay_server = start_replay_server(args, sites) if args.replay_wpr else None
|
||||
try:
|
||||
# Run them.
|
||||
for site, domain, count, timeout in L:
|
||||
@ -427,6 +436,10 @@ def do_help(parser, subparsers, args):
|
||||
|
||||
# Main program, parse command line and execute.
|
||||
|
||||
def coexist(*l):
|
||||
given = sum(1 for x in l if x)
|
||||
return given == 0 or given == len(l)
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
subparser_adder = parser.add_subparsers(title="commands", dest="command",
|
||||
@ -511,11 +524,12 @@ def main():
|
||||
help="command for which to display help")
|
||||
# Execute the command.
|
||||
args = parser.parse_args()
|
||||
if args.command == "run" and args.sites_file and args.sites:
|
||||
args.error("if --sites-file is used, no site URLS must be given")
|
||||
setattr(args, 'script_path', os.path.dirname(sys.argv[0]))
|
||||
if args.command == "run" and coexist(args.sites_file, args.sites):
|
||||
args.error("use either option --sites-file or site URLs")
|
||||
sys.exit(1)
|
||||
elif args.command == "run" and args.replay_wpr and not args.replay_bin:
|
||||
args.error("if --replay-wpr is used, --replay-bin must be given")
|
||||
elif args.command == "run" and not coexist(args.replay_wpr, args.replay_bin):
|
||||
args.error("options --replay-wpr and --replay-bin must be used together")
|
||||
sys.exit(1)
|
||||
else:
|
||||
args.func(args)
|
||||
|
Loading…
Reference in New Issue
Block a user