From af634efc800e8722d5c9aeb0e40c70b634b86df9 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Wed, 31 May 2023 13:56:10 +0200 Subject: [PATCH 1/2] [wasm][bench] Limit initial samples Try to limit initial samples measurement to 1 second. Currently some of string measurements with hybrid globalization turned on can take hundreds of seconds. This makes the browser stop the benchmark and the measurement job times out. This should limit the initial samples to take cca 1 second or take just one initial sample if it takes more time. Also increase the initial samples for string comparison, where it was on the edge and the times were flipping between cca 5 and 10 seconds. --- .../sample/wasm/browser-bench/BenchTask.cs | 41 ++++++++++++++----- src/mono/sample/wasm/browser-bench/String.cs | 2 + .../sample/wasm/browser-bench/WebSocket.cs | 14 +++---- 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/mono/sample/wasm/browser-bench/BenchTask.cs b/src/mono/sample/wasm/browser-bench/BenchTask.cs index d9da4502b2d16..e9c09dc9520aa 100644 --- a/src/mono/sample/wasm/browser-bench/BenchTask.cs +++ b/src/mono/sample/wasm/browser-bench/BenchTask.cs @@ -59,15 +59,16 @@ public virtual void RunStep() { } public virtual bool HasRunStepAsync => false; - protected virtual int CalculateSteps(int milliseconds, TimeSpan initTs) + protected virtual int CalculateSteps(int milliseconds, TimeSpan initTs, int initialSamples) { - return (int)(milliseconds * InitialSamples / Math.Max(1.0, initTs.TotalMilliseconds)); + return (int)(milliseconds * initialSamples / Math.Max(1.0, initTs.TotalMilliseconds)); } public async Task RunBatch(BenchTask task, int milliseconds) { DateTime start = DateTime.Now; DateTime end; + int initialSamples = InitialSamples; try { // run one to eliminate possible startup overhead and do GC collection @@ -79,15 +80,35 @@ public async Task RunBatch(BenchTask task, int milliseconds) GC.Collect(); start = DateTime.Now; - for (currentStep = 0; currentStep < InitialSamples; currentStep++) - if (HasRunStepAsync) - await RunStepAsync(); - else - RunStep(); + if (HasRunStepAsync) + await RunStepAsync(); + else + RunStep(); end = DateTime.Now; + // try to limit initial samples to 1s + var oneTs = end - start; + var maxInitMs = 1000; + if (oneTs.TotalMilliseconds > 0 && oneTs.TotalMilliseconds*InitialSamples > maxInitMs) + initialSamples = (int)(maxInitMs/oneTs.TotalMilliseconds); + + GC.Collect(); + + if (initialSamples > 1) { + start = DateTime.Now; + for (currentStep = 0; currentStep < initialSamples; currentStep++) + if (HasRunStepAsync) + await RunStepAsync(); + else + RunStep(); + end = DateTime.Now; + } else { + // we already have the 1st measurement + initialSamples = 1; + } + var initTs = end - start; - int steps = CalculateSteps(milliseconds, initTs); + int steps = CalculateSteps(milliseconds, initTs, initialSamples); start = DateTime.Now; for (currentStep = 0; currentStep < steps; currentStep++) @@ -101,14 +122,14 @@ public async Task RunBatch(BenchTask task, int milliseconds) var ts = end - start; - return new Result { span = ts + initTs, steps = steps + InitialSamples, taskName = task.Name, measurementName = Name }; + return new Result { span = ts + initTs, steps = steps + initialSamples, taskName = task.Name, measurementName = Name }; } catch (Exception ex) { end = DateTime.Now; var ts = end - start; Console.WriteLine(ex); - return new Result { span = ts, steps = currentStep + InitialSamples, taskName = task.Name, measurementName = Name + " " + ex.Message }; + return new Result { span = ts, steps = currentStep + initialSamples, taskName = task.Name, measurementName = Name + " " + ex.Message }; } } } diff --git a/src/mono/sample/wasm/browser-bench/String.cs b/src/mono/sample/wasm/browser-bench/String.cs index 2ac38b481d8e4..224604fd692a7 100644 --- a/src/mono/sample/wasm/browser-bench/String.cs +++ b/src/mono/sample/wasm/browser-bench/String.cs @@ -139,6 +139,8 @@ public class TextInfoToTitleCase : TextInfoMeasurement public abstract class StringsCompare : StringMeasurement { + public override int InitialSamples => 100; + protected string strAsciiSuffix; protected string strAsciiPrefix; protected string needleSameAsStrEnd; diff --git a/src/mono/sample/wasm/browser-bench/WebSocket.cs b/src/mono/sample/wasm/browser-bench/WebSocket.cs index d163537f7c593..9cc16ee09da31 100644 --- a/src/mono/sample/wasm/browser-bench/WebSocket.cs +++ b/src/mono/sample/wasm/browser-bench/WebSocket.cs @@ -88,7 +88,7 @@ public class PartialSend_1BMeasurement : WebSocketMeasurement public override int InitialSamples => 1000; ArraySegment buffer = new ArraySegment(new byte[1]); - protected override int CalculateSteps(int milliseconds, TimeSpan initTs) + protected override int CalculateSteps(int milliseconds, TimeSpan initTs, int initialSamples) { return 250_000; } @@ -112,7 +112,7 @@ public PartialSend_64KBMeasurement() buffer[i] = (byte)(i & 0xff); } } - protected override int CalculateSteps(int milliseconds, TimeSpan initTs) + protected override int CalculateSteps(int milliseconds, TimeSpan initTs, int initialSamples) { return 3000; } @@ -137,7 +137,7 @@ public PartialSend_1MBMeasurement() buffer[i] = (byte)(i & 0xff); } } - protected override int CalculateSteps(int milliseconds, TimeSpan initTs) + protected override int CalculateSteps(int milliseconds, TimeSpan initTs, int initialSamples) { return 100; } @@ -154,9 +154,9 @@ public class PartialReceive_1BMeasurement : WebSocketReceiveMeasurement { ArraySegment buffer = new ArraySegment(new byte[1]); - protected override int CalculateSteps(int milliseconds, TimeSpan initTs) + protected override int CalculateSteps(int milliseconds, TimeSpan initTs, int initialSamples) { - return MaxLength - InitialSamples - 100; + return MaxLength - initialSamples - 100; } public override void RunStep() @@ -177,7 +177,7 @@ public class PartialReceive_10KBMeasurement : WebSocketReceiveMeasurement public override int InitialSamples => 1; ArraySegment buffer = new ArraySegment(new byte[bufferSize]); - protected override int CalculateSteps(int milliseconds, TimeSpan initTs) + protected override int CalculateSteps(int milliseconds, TimeSpan initTs, int initialSamples) { return 500; } @@ -206,7 +206,7 @@ public class PartialReceive_100KBMeasurement : WebSocketReceiveMeasurement public override int InitialSamples => 1; ArraySegment buffer = new ArraySegment(new byte[bufferSize]); - protected override int CalculateSteps(int milliseconds, TimeSpan initTs) + protected override int CalculateSteps(int milliseconds, TimeSpan initTs, int initialSamples) { return MaxMessages - 1; } From cc8a4bf7357d98df81c5fb2666d6df60a2c0e93e Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Wed, 31 May 2023 14:41:27 +0200 Subject: [PATCH 2/2] Do GC collect only when doing initial samples --- src/mono/sample/wasm/browser-bench/BenchTask.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mono/sample/wasm/browser-bench/BenchTask.cs b/src/mono/sample/wasm/browser-bench/BenchTask.cs index e9c09dc9520aa..6a41030e44183 100644 --- a/src/mono/sample/wasm/browser-bench/BenchTask.cs +++ b/src/mono/sample/wasm/browser-bench/BenchTask.cs @@ -92,9 +92,9 @@ public async Task RunBatch(BenchTask task, int milliseconds) if (oneTs.TotalMilliseconds > 0 && oneTs.TotalMilliseconds*InitialSamples > maxInitMs) initialSamples = (int)(maxInitMs/oneTs.TotalMilliseconds); - GC.Collect(); - if (initialSamples > 1) { + GC.Collect(); + start = DateTime.Now; for (currentStep = 0; currentStep < initialSamples; currentStep++) if (HasRunStepAsync)