Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 // Explanation of minItemsTestingThreshold:
6 //
7 // If the volume of input items in a test is small, then all of them
8 // may be processed during warmup alone, and the parallel-invocation
9 // will trivially succeed even if we are intentionally trying to
10 // detect a failure.
11 //
12 // The maximum number of items processed by sequential warmups for
13 // ArrayBuildPar is:
14 // maxSeqItems = maxBailouts * numSlices * CHUNK_SIZE
15 //
16 // For maxBailouts = 3, maxSeqItems == 3 * 8 * 32 == 768
17 // For maxBailouts = 5, maxSeqItems == 5 * 8 * 32 == 1280
18 //
19 // Our test code does not have access to the values of these constants
20 // (maxBailouts, numSlices, CHUNK_SIZE). Therefore, the value of
21 // minItemsTestingThreshold should be kept in sync with some value
22 // greater than maxSeqItems as calculated above.
23 //
24 // This is still imperfect since it assumes numSlices <= 8, but
25 // numSlices is machine-dependent.
26 // (TODO: consider exposing numSlices via builtin/TestingFunctions.cpp)
28 var minItemsTestingThreshold = 1024;
30 // The standard sequence of modes to test.
31 // First mode compiles for parallel exec.
32 // Second mode checks that parallel exec does not bail.
33 // Final mode tests the sequential fallback path.
34 var MODE_STRINGS = ["compile", "par", "seq"];
35 var MODES = MODE_STRINGS.map(s => ({mode: s}));
37 var INVALIDATE_MODE_STRINGS = ["seq", "compile", "par", "seq"];
38 var INVALIDATE_MODES = INVALIDATE_MODE_STRINGS.map(s => ({mode: s}));
40 function build(n, f) {
41 var result = [];
42 for (var i = 0; i < n; i++)
43 result.push(f(i));
44 return result;
45 }
47 function range(n, m) {
48 // Returns an array with [n..m] (include on n, exclusive on m)
50 var result = [];
51 for (var i = n; i < m; i++)
52 result.push(i);
53 return result;
54 }
56 function seq_scan(array, f) {
57 // Simple sequential version of scan() that operates over an array
59 var result = [];
60 result[0] = array[0];
61 for (var i = 1; i < array.length; i++) {
62 result[i] = f(result[i-1], array[i]);
63 }
64 return result;
65 }
67 function assertAlmostEq(v1, v2) {
68 if (v1 === v2)
69 return true;
70 // + and other fp ops can vary somewhat when run in parallel!
71 assertEq(typeof v1, "number");
72 assertEq(typeof v2, "number");
73 var diff = Math.abs(v1 - v2);
74 var percent = diff / v1 * 100.0;
75 print("v1 = " + v1);
76 print("v2 = " + v2);
77 print("% diff = " + percent);
78 assertEq(percent < 1e-10, true); // off by an less than 1e-10%...good enough.
79 }
81 function assertStructuralEq(e1, e2) {
82 if (e1 instanceof Array && e2 instanceof Array) {
83 assertEqArray(e1, e2);
84 } else if (e1 instanceof Object && e2 instanceof Object) {
85 assertEq(e1.__proto__, e2.__proto__);
86 for (prop in e1) {
87 if (e1.hasOwnProperty(prop)) {
88 assertEq(e2.hasOwnProperty(prop), true);
89 assertStructuralEq(e1[prop], e2[prop]);
90 }
91 }
92 } else {
93 assertEq(e1, e2);
94 }
95 }
97 function assertEqArray(a, b) {
98 assertEq(a.length, b.length);
99 for (var i = 0, l = a.length; i < l; i++) {
100 try {
101 assertStructuralEq(a[i], b[i]);
102 } catch (e) {
103 print("...in index", i, "of", l);
104 throw e;
105 }
106 }
107 }
109 // Checks that whenever we execute this in parallel mode,
110 // it bails out. `opFunction` should be a closure that takes a
111 // mode parameter and performs some parallel array operation.
112 // This closure will be invoked repeatedly.
113 //
114 // Here is an example of the expected usage:
115 //
116 // assertParallelExecWillBail(function(m) {
117 // Array.buildPar(..., m)
118 // });
119 //
120 // where the `Array.buildPar(...)` is a stand-in
121 // for some parallel array operation.
122 function assertParallelExecWillBail(opFunction) {
123 opFunction({mode:"compile"}); // get the script compiled
124 opFunction({mode:"bailout"}); // check that it bails when executed
125 }
127 // Checks that when we execute this in parallel mode,
128 // some bailouts will occur but we will recover and
129 // return to parallel execution mode. `opFunction` is a closure
130 // that expects a mode, just as in `assertParallelExecWillBail`.
131 function assertParallelExecWillRecover(opFunction) {
132 opFunction({mode:"compile"}); // get the script compiled
133 opFunction({mode:"recover"}); // check that it bails when executed
134 }
136 // Checks that we will (eventually) be able to compile and exection
137 // `opFunction` in parallel mode. Invokes `cmpFunction` with the
138 // result. For some tests, it takes many compile rounds to reach a TI
139 // fixed point. So this function will repeatedly attempt to invoke
140 // `opFunction` with `compile` and then `par` mode until getting a
141 // successful `par` run. After enough tries, of course, we give up
142 // and declare a test failure.
143 function assertParallelExecSucceeds(opFunction, cmpFunction) {
144 var failures = 0;
145 while (true) {
146 print("Attempting compile #", failures);
147 var result = opFunction({mode:"compile"});
148 cmpFunction(result);
150 try {
151 print("Attempting parallel run #", failures);
152 var result = opFunction({mode:"par"});
153 cmpFunction(result);
154 break;
155 } catch (e) {
156 failures++;
157 if (failures > 5) {
158 throw e; // doesn't seem to be reaching a fixed point!
159 } else {
160 print(e);
161 }
162 }
163 }
165 print("Attempting sequential run");
166 var result = opFunction({mode:"seq"});
167 cmpFunction(result);
168 }
170 // Compares an Array constructed in parallel against one constructed
171 // sequentially. `func` should be the closure to provide as argument. For
172 // example:
173 //
174 // assertArraySeqParResultsEq([1, 2, 3], "map", i => i + 1)
175 //
176 // would check that `[1, 2, 3].map(i => i+1)` and `[1, 2, 3].mapPar(i => i+1)`
177 // yield the same result.
178 //
179 // Based on `assertParallelExecSucceeds`
180 function assertArraySeqParResultsEq(arr, op, func, cmpFunc) {
181 if (!cmpFunc)
182 cmpFunc = assertStructuralEq;
183 var expected = arr[op].apply(arr, [func]);
184 assertParallelExecSucceeds(
185 function (m) { return arr[op + "Par"].apply(arr, [func, m]); },
186 function (r) { cmpFunc(expected, r); });
187 }
189 // Similar to `compareAgainstArray`, but for the `scan` method which
190 // does not appear on array.
191 function testArrayScanPar(jsarray, func, cmpFunction) {
192 if (!cmpFunction)
193 cmpFunction = assertStructuralEq;
194 var expected = seq_scan(jsarray, func);
196 // Unfortunately, it sometimes happens that running 'par' twice in a
197 // row causes bailouts and other unfortunate things!
199 assertParallelExecSucceeds(
200 function(m) {
201 print(m.mode + " " + m.expect);
202 var p = jsarray.scanPar(func, m);
203 return p;
204 },
205 function(r) {
206 cmpFunction(expected, r);
207 });
208 }
210 // Checks that `opFunction`, when run with each of the modes
211 // in `modes`, returns the same value each time.
212 function assertParallelModesCommute(modes, opFunction) {
213 var expected = undefined;
214 var acc = opFunction(modes[0]);
215 assertParallelExecSucceeds(
216 opFunction,
217 function(r) {
218 if (expected === undefined)
219 expected = r;
220 else
221 assertStructuralEq(expected, r);
222 });
223 }