Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 #!/usr/bin/env python
3 """%prog [options] shellpath dirpath
5 Pulls performance data on parsing via the js shell.
6 Displays the average number of milliseconds it took to parse each file.
8 For comparison, something apparently approximating a t-test is performed:
9 "Faster" means that:
11 t_baseline_goodrun = (t_baseline_avg - t_baseline_stddev)
12 t_current_badrun = (t_current_avg + t_current_stddev)
13 t_current_badrun < t_baseline_goodrun
15 Effectively, a bad run from the current data is better than a good run from the
16 baseline data, we're probably faster. A similar computation is used for
17 determining the "slower" designation.
19 Arguments:
20 shellpath executable JavaScript shell
21 dirpath directory filled with parsilicious js files
22 """
24 import math
25 import optparse
26 import os
27 import subprocess as subp
28 import sys
29 from string import Template
31 try:
32 import compare_bench
33 except ImportError:
34 compare_bench = None
37 _DIR = os.path.dirname(__file__)
38 JS_CODE_TEMPLATE = Template("""
39 if (typeof snarf !== 'undefined') read = snarf
40 var contents = read("$filepath");
41 for (var i = 0; i < $warmup_run_count; i++)
42 parse(contents);
43 var results = [];
44 for (var i = 0; i < $real_run_count; i++) {
45 var start = new Date();
46 parse(contents);
47 var end = new Date();
48 results.push(end - start);
49 }
50 print(results);
51 """)
54 def gen_filepaths(dirpath, target_ext='.js'):
55 for filename in os.listdir(dirpath):
56 if filename.endswith(target_ext):
57 yield os.path.join(dirpath, filename)
60 def avg(seq):
61 return sum(seq) / len(seq)
64 def stddev(seq, mean):
65 diffs = ((float(item) - mean) ** 2 for item in seq)
66 return math.sqrt(sum(diffs) / len(seq))
69 def bench(shellpath, filepath, warmup_runs, counted_runs, stfu=False):
70 """Return a list of milliseconds for the counted runs."""
71 assert '"' not in filepath
72 code = JS_CODE_TEMPLATE.substitute(filepath=filepath,
73 warmup_run_count=warmup_runs, real_run_count=counted_runs)
74 proc = subp.Popen([shellpath, '-e', code], stdout=subp.PIPE)
75 stdout, _ = proc.communicate()
76 milliseconds = [float(val) for val in stdout.split(',')]
77 mean = avg(milliseconds)
78 sigma = stddev(milliseconds, mean)
79 if not stfu:
80 print 'Runs:', [int(ms) for ms in milliseconds]
81 print 'Mean:', mean
82 print 'Stddev: %.2f (%.2f%% of mean)' % (sigma, sigma / mean * 100)
83 return mean, sigma
86 def parsemark(filepaths, fbench, stfu=False):
87 """:param fbench: fbench(filename) -> float"""
88 bench_map = {} # {filename: (avg, stddev)}
89 for filepath in filepaths:
90 filename = os.path.split(filepath)[-1]
91 if not stfu:
92 print 'Parsemarking %s...' % filename
93 bench_map[filename] = fbench(filepath)
94 print '{'
95 for i, (filename, (avg, stddev)) in enumerate(bench_map.iteritems()):
96 assert '"' not in filename
97 fmt = ' %30s: {"average_ms": %6.2f, "stddev_ms": %6.2f}'
98 if i != len(bench_map) - 1:
99 fmt += ','
100 filename_str = '"%s"' % filename
101 print fmt % (filename_str, avg, stddev)
102 print '}'
103 return dict((filename, dict(average_ms=avg, stddev_ms=stddev))
104 for filename, (avg, stddev) in bench_map.iteritems())
107 def main():
108 parser = optparse.OptionParser(usage=__doc__.strip())
109 parser.add_option('-w', '--warmup-runs', metavar='COUNT', type=int,
110 default=5, help='used to minimize test instability [%default]')
111 parser.add_option('-c', '--counted-runs', metavar='COUNT', type=int,
112 default=50, help='timed data runs that count towards the average [%default]')
113 parser.add_option('-s', '--shell', metavar='PATH', help='explicit shell '
114 'location; when omitted, will look in likely places')
115 parser.add_option('-b', '--baseline', metavar='JSON_PATH',
116 dest='baseline_path', help='json file with baseline values to '
117 'compare against')
118 parser.add_option('-q', '--quiet', dest='stfu', action='store_true',
119 default=False, help='only print JSON to stdout [%default]')
120 options, args = parser.parse_args()
121 try:
122 shellpath = args.pop(0)
123 except IndexError:
124 parser.print_help()
125 print
126 print >> sys.stderr, 'error: shellpath required'
127 return -1
128 try:
129 dirpath = args.pop(0)
130 except IndexError:
131 parser.print_help()
132 print
133 print >> sys.stderr, 'error: dirpath required'
134 return -1
135 if not shellpath or not os.path.exists(shellpath):
136 print >> sys.stderr, 'error: could not find shell:', shellpath
137 return -1
138 if options.baseline_path:
139 if not os.path.isfile(options.baseline_path):
140 print >> sys.stderr, 'error: baseline file does not exist'
141 return -1
142 if not compare_bench:
143 print >> sys.stderr, 'error: JSON support is missing, cannot compare benchmarks'
144 return -1
145 benchfile = lambda filepath: bench(shellpath, filepath,
146 options.warmup_runs, options.counted_runs, stfu=options.stfu)
147 bench_map = parsemark(gen_filepaths(dirpath), benchfile, options.stfu)
148 if options.baseline_path:
149 compare_bench.compare_immediate(bench_map, options.baseline_path)
150 return 0
153 if __name__ == '__main__':
154 sys.exit(main())