js/src/jit-test/lib/parallelarray-helpers.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

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.

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

mercurial