Have a CLI version of JetStream 2 to run on watchOS
https://bugs.webkit.org/show_bug.cgi?id=202998
<rdar://problem/56208554>

Reviewed by Tadeu Zagallo.

This patch adds a CLI version of JS2 to run on watchOS. We run most subtests
from the browser version of JS2, but skip a few tests that are particularly
long running, like WSL and some of WTB. We also don't run the Wasm tests
as we don't JIT on watchOS. Each test runs for fewer iterations in the watch
version. 15 is the default iteration count. This benchmark runs in 7 minutes on
a Series 4 watch.

* JetStream2/JetStreamDriver.js:
(getIterationCount):
(getWorstCaseCount):
(Driver.prototype.async.start):
(Driver.prototype.resultsJSON):
(Driver.prototype.dumpJSONResultsIfNeeded):
(Driver.prototype.async.reportScoreToRunBenchmarkRunner):
(DefaultBenchmark):
* JetStream2/RexBench/UniPoker/benchmark.js:
(Benchmark.prototype.validate):
(Benchmark):
* JetStream2/watch-cli.js: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@251265 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/PerformanceTests/ChangeLog b/PerformanceTests/ChangeLog
index fe4d355..0950122 100644
--- a/PerformanceTests/ChangeLog
+++ b/PerformanceTests/ChangeLog
@@ -1,3 +1,31 @@
+2019-10-17  Saam Barati  <sbarati@apple.com>
+
+        Have a CLI version of JetStream 2 to run on watchOS
+        https://bugs.webkit.org/show_bug.cgi?id=202998
+        <rdar://problem/56208554>
+
+        Reviewed by Tadeu Zagallo.
+
+        This patch adds a CLI version of JS2 to run on watchOS. We run most subtests
+        from the browser version of JS2, but skip a few tests that are particularly
+        long running, like WSL and some of WTB. We also don't run the Wasm tests
+        as we don't JIT on watchOS. Each test runs for fewer iterations in the watch
+        version. 15 is the default iteration count. This benchmark runs in 7 minutes on
+        a Series 4 watch.
+
+        * JetStream2/JetStreamDriver.js:
+        (getIterationCount):
+        (getWorstCaseCount):
+        (Driver.prototype.async.start):
+        (Driver.prototype.resultsJSON):
+        (Driver.prototype.dumpJSONResultsIfNeeded):
+        (Driver.prototype.async.reportScoreToRunBenchmarkRunner):
+        (DefaultBenchmark):
+        * JetStream2/RexBench/UniPoker/benchmark.js:
+        (Benchmark.prototype.validate):
+        (Benchmark):
+        * JetStream2/watch-cli.js: Added.
+
 2019-10-17  Adrian Perez de Castro  <aperez@igalia.com>
 
         [Linux] Avoid usage of <sys/sysctl.h> in MallocBench
diff --git a/PerformanceTests/JetStream2/JetStreamDriver.js b/PerformanceTests/JetStream2/JetStreamDriver.js
index 221d200..dd7fae9 100644
--- a/PerformanceTests/JetStream2/JetStreamDriver.js
+++ b/PerformanceTests/JetStream2/JetStreamDriver.js
@@ -34,6 +34,15 @@
 if (typeof testIterationCount === "undefined")
     var testIterationCount = undefined;
 
+if (typeof testIterationCountMap === "undefined")
+    var testIterationCountMap = new Map;
+
+if (typeof testWorstCaseCountMap === "undefined")
+    var testWorstCaseCountMap = new Map;
+
+if (typeof dumpJSONResults === "undefined")
+    var dumpJSONResults = false;
+
 // Used for the promise representing the current benchmark run.
 this.currentResolve = null;
 this.currentReject = null;
@@ -55,6 +64,24 @@
     categoryScores = null;
 }
 
+function getIterationCount(plan) {
+    if (testIterationCountMap.has(plan.name))
+        return testIterationCountMap.get(plan.name);
+    if (testIterationCount)
+        return testIterationCount;
+    if (plan.iterations)
+        return plan.iterations;
+    return defaultIterationCount;
+}
+
+function getWorstCaseCount(plan) {
+    if (testWorstCaseCountMap.has(plan.name))
+        return testWorstCaseCountMap.get(plan.name);
+    if (plan.worstCaseCount)
+        return plan.worstCaseCount;
+    return defaultWorstCaseCount;
+}
+
 if (isInBrowser) {
     document.onkeydown = (keyboardEvent) => {
         let key = keyboardEvent.key;
@@ -250,6 +277,7 @@
         }
 
         this.reportScoreToRunBenchmarkRunner();
+        this.dumpJSONResultsIfNeeded();
     }
 
     runCode(string)
@@ -355,14 +383,8 @@
         }
     }
 
-    async reportScoreToRunBenchmarkRunner()
+    resultsJSON()
     {
-        if (!isInBrowser)
-            return;
-
-        if (window.location.search !== '?report=true')
-            return;
-
         let results = {};
         for (let benchmark of this.benchmarks) {
             const subResults = {}
@@ -381,7 +403,27 @@
 
         results = {"JetStream2.0": {"metrics" : {"Score" : ["Geometric"]}, "tests" : results}};
 
-        const content = JSON.stringify(results);
+        return JSON.stringify(results);
+    }
+
+    dumpJSONResultsIfNeeded()
+    {
+        if (dumpJSONResults) {
+            print("\n");
+            print(this.resultsJSON());
+            print("\n");
+        }
+    }
+
+    async reportScoreToRunBenchmarkRunner()
+    {
+        if (!isInBrowser)
+            return;
+
+        if (window.location.search !== '?report=true')
+            return;
+
+        const content = this.resultsJSON();
         await fetch("/report", {
             method: "POST",
             heeaders: {
@@ -398,7 +440,7 @@
     constructor(plan)
     {
         this.plan = plan;
-        this.iterations = testIterationCount || plan.iterations || defaultIterationCount;
+        this.iterations = getIterationCount(plan);
         this.isAsync = !!plan.isAsync;
 
         this.scripts = null;
@@ -623,7 +665,7 @@
     constructor(...args) {
         super(...args);
 
-        this.worstCaseCount = this.plan.worstCaseCount || defaultWorstCaseCount;
+        this.worstCaseCount = getWorstCaseCount(this.plan);
         this.firstIteration = null;
         this.worst4 = null;
         this.average = null;
diff --git a/PerformanceTests/JetStream2/RexBench/UniPoker/benchmark.js b/PerformanceTests/JetStream2/RexBench/UniPoker/benchmark.js
index f87b06e..cbcbe0b 100644
--- a/PerformanceTests/JetStream2/RexBench/UniPoker/benchmark.js
+++ b/PerformanceTests/JetStream2/RexBench/UniPoker/benchmark.js
@@ -43,8 +43,9 @@
     {
         if (this._players.length != playerExpectations.length)
             throw "Expect " + playerExpectations.length + ", but actually have " + this._players.length;
-
-        for (let playerIdx = 0; playerIdx < playerExpectations.length; playerIdx++)
-            playerExpectations[playerIdx].validate(this._players[playerIdx]);
+        if (isInBrowser) {
+            for (let playerIdx = 0; playerIdx < playerExpectations.length; playerIdx++)
+                playerExpectations[playerIdx].validate(this._players[playerIdx]);
+        }
     }
 }
diff --git a/PerformanceTests/JetStream2/watch-cli.js b/PerformanceTests/JetStream2/watch-cli.js
new file mode 100644
index 0000000..49a399d
--- /dev/null
+++ b/PerformanceTests/JetStream2/watch-cli.js
@@ -0,0 +1,65 @@
+dumpJSONResults = true;
+
+testIterationCount = 15;
+
+testList = [
+    {name: "FlightPlanner"},
+    {name: "UniPoker"},
+    {name: "Air"},
+    {name: "Basic"},
+    {name: "ML", iterations: 7, worstCaseCount: 2},
+    {name: "Babylon"},
+    {name: "cdjs", iterations: 10, worstCaseCount: 2},
+    {name: "first-inspector-code-load"},
+    {name: "multi-inspector-code-load"},
+    {name: "Box2D"},
+    {name: "octane-code-load"},
+    {name: "crypto"},
+    {name: "delta-blue"},
+    {name: "earley-boyer"},
+    {name: "gbemu", iterations: 10, worstCaseCount: 2},
+    {name: "navier-stokes"},
+    {name: "pdfjs"},
+    {name: "raytrace"},
+    {name: "regexp"},
+    {name: "richards"},
+    {name: "splay"},
+    {name: "ai-astar"},
+    {name: "gaussian-blur", iterations: 10, worstCaseCount: 2},
+    {name: "stanford-crypto-aes"},
+    {name: "stanford-crypto-pbkdf2"},
+    {name: "stanford-crypto-sha256"},
+    {name: "json-stringify-inspector"},
+    {name: "json-parse-inspector"},
+    {name: "async-fs", iterations: 8, worstCaseCount: 2},
+    {name: "hash-map", iterations: 12, worstCaseCount: 3},
+    {name: "3d-cube-SP"},
+    {name: "3d-raytrace-SP"},
+    {name: "base64-SP"},
+    {name: "crypto-aes-SP"},
+    {name: "crypto-md5-SP"},
+    {name: "crypto-sha1-SP"},
+    {name: "date-format-tofte-SP"},
+    {name: "date-format-xparb-SP"},
+    {name: "n-body-SP"},
+    {name: "regex-dna-SP"},
+    {name: "string-unpack-code-SP"},
+    {name: "tagcloud-SP"},
+    {name: "chai-wtb", iterations: 5, worstCaseCount: 2},
+    {name: "jshint-wtb", iterations: 5, worstCaseCount: 2},
+    {name: "prepack-wtb", iterations: 5, worstCaseCount: 2}
+];
+
+testIterationCountMap = new Map;
+testWorstCaseCountMap = new Map;
+for (let test of testList) {
+    if (test.iterations)
+        testIterationCountMap.set(test.name, test.iterations);
+    if (test.worstCaseCount)
+        testWorstCaseCountMap.set(test.name, test.worstCaseCount);
+}
+
+
+testList = testList.map(x => x.name);
+
+load("./cli.js");