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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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 }

mercurial