| // Copyright 2019 the V8 project authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | // A test utility for pinging objects back and forth among a pool of workers. | 
 | // Use by calling {RunWorkerPingTest} with a {config} object. | 
 | { | 
 | // Reference config object for demonstrating the interface. | 
 | let config = { | 
 |   numThings: 4,       // size of circular buffer | 
 |   numWorkers: 4,      // number of workers | 
 |   numMessages: 100,   // number of messages sent to each worker | 
 |   allocInterval: 11,  // interval for allocating new things per worker | 
 |   traceScript: false, // print the script | 
 |   traceAlloc: false,  // print each allocation attempt | 
 |   traceIteration: 10, // print diagnostics every so many iterations | 
 |   abortOnFail: false, // kill worker if allocation fails | 
 |  | 
 |   // Note that because the functions are appended to a worker script | 
 |   // *as source*, they need to be named properly. | 
 |  | 
 |   // The function that allocates things. Required. | 
 |   AllocThing: function AllocThing(id) { | 
 |     return new Array(2); | 
 |   }, | 
 |   // Before message send behavior. Optional. | 
 |   BeforeSend: function BeforeSend(msg) { }, | 
 |   // Before message reception behavior. Optional. | 
 |   BeforeReceive: function BeforeReceive(msg) { }, | 
 | } | 
 | } | 
 |  | 
 | function RunWorkerPingTest(config) { | 
 |   let workers = []; | 
 |   let beforeSend = (typeof config.BeforeSend == "function") ? | 
 |       config.BeforeSend : | 
 |       function BeforeSend(msg) { }; | 
 |   let beforeReceive = (typeof config.BeforeReceive == "function") ? | 
 |       config.BeforeReceive : | 
 |       function BeforeReceive(msg) { }; | 
 |  | 
 |   // Each worker has a circular buffer of size {config.numThings}, recording | 
 |   // received things into the buffer and responding with a previous thing. | 
 |   // Every {config.allocInterval}, a worker creates a new thing by | 
 |   // {config.AllocThing}. | 
 |  | 
 |   let script = | 
 | `const kNumThings = ${config.numThings}; | 
 |   const kAllocInterval = ${config.allocInterval}; | 
 |   let index = 0; | 
 |   let total = 0; | 
 |   let id = 0; | 
 |   let things = new Array(kNumThings); | 
 |   for (let i = 0; i < kNumThings; i++) { | 
 |     things[i] = TryAllocThing(); | 
 |   } | 
 |  | 
 |   function TryAllocThing() { | 
 |      try { | 
 |        let thing = AllocThing(id++); | 
 |        ${config.traceAlloc ? "print(\"alloc success\");" : ""} | 
 |        return thing; | 
 |      } catch(e) { | 
 |        ${config.abortOnFail ? "postMessage({error: e.toString()}); throw e;" : "" } | 
 |        ${config.traceAlloc ? "print(\"alloc fail: \" + e);" : ""} | 
 |      } | 
 |   } | 
 |  | 
 |   onmessage = function(msg) { | 
 |     BeforeReceive(msg); | 
 |     if (msg.thing !== undefined) { | 
 |       let reply = things[index]; | 
 |       if ((total % kAllocInterval) == 0) { | 
 |         reply = TryAllocThing(); | 
 |       } | 
 |       things[index] = msg.thing; | 
 |       postMessage({thing : reply}); | 
 |       index = (index + 1) % kNumThings; | 
 |       total++; | 
 |     } | 
 |   } | 
 |   ${config.AllocThing.toString()} | 
 |   ${beforeReceive.toString()} | 
 |   `; | 
 |  | 
 |   if (config.traceScript) { | 
 |     print("========== Worker script =========="); | 
 |     print(script); | 
 |     print("==================================="); | 
 |   } | 
 |  | 
 |   for (let i = 0; i < config.numWorkers; i++) { | 
 |     let worker = new Worker(script, {type : 'string'}); | 
 |     workers.push(worker); | 
 |   } | 
 |  | 
 |   let time = performance.now(); | 
 |  | 
 |   // The main thread posts {config.numMessages} messages to {config.numWorkers} | 
 |   // workers, with each message containing a "thing" created by {config.AllocThing}. | 
 |   let thing = config.AllocThing(-1); | 
 |   for (let i = 0; i < config.numMessages; i++) { | 
 |     if ((i % config.traceIteration) == 0) { | 
 |       let now = performance.now(); | 
 |       print(`iteration ${i}, Δ = ${(now - time).toFixed(3)} ms`); | 
 |       time = now; | 
 |     } | 
 |  | 
 |     for (let worker of workers) { | 
 |       let msg = {thing: thing}; | 
 |       beforeSend(msg); | 
 |       worker.postMessage(msg); | 
 |       msg = worker.getMessage(); | 
 |       if (msg.thing) { | 
 |         thing = msg.thing; | 
 |       } else if (msg.error) { | 
 |         print('Error in worker:', msg.error); | 
 |         worker.terminate(); | 
 |         throw msg.error; | 
 |       } | 
 |     } | 
 |   } | 
 |   print('Terminating workers.'); | 
 |   for (let worker of workers) { | 
 |     worker.terminate(); | 
 |   } | 
 |   print('Workers terminated.'); | 
 | } |