Skip to content

Commit ecd6bbc

Browse files
authored
[wasm] few simple test for JavaScript interop (#74419)
1 parent 03c2146 commit ecd6bbc

File tree

4 files changed

+275
-8
lines changed

4 files changed

+275
-8
lines changed

src/mono/sample/wasm/browser-bench/BenchTask.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public class Result
4141

4242
public abstract class Measurement
4343
{
44+
protected int currentStep = 0;
4445
public abstract string Name { get; }
4546

4647
public virtual int InitialSamples { get { return 10; } }
@@ -64,7 +65,6 @@ public async Task<Result> RunBatch(BenchTask task, int milliseconds)
6465
{
6566
DateTime start = DateTime.Now;
6667
DateTime end;
67-
int i = 0;
6868
try
6969
{
7070
// run one to eliminate possible startup overhead and do GC collection
@@ -76,7 +76,7 @@ public async Task<Result> RunBatch(BenchTask task, int milliseconds)
7676
GC.Collect();
7777

7878
start = DateTime.Now;
79-
for (i = 0; i < InitialSamples; i++)
79+
for (currentStep = 0; currentStep < InitialSamples; currentStep++)
8080
if (HasRunStepAsync)
8181
await RunStepAsync();
8282
else
@@ -87,7 +87,7 @@ public async Task<Result> RunBatch(BenchTask task, int milliseconds)
8787
int steps = CalculateSteps(milliseconds, initTs);
8888

8989
start = DateTime.Now;
90-
for (i = 0; i < steps; i++)
90+
for (currentStep = 0; currentStep < steps; currentStep++)
9191
{
9292
if (HasRunStepAsync)
9393
await RunStepAsync();
@@ -105,7 +105,7 @@ public async Task<Result> RunBatch(BenchTask task, int milliseconds)
105105
end = DateTime.Now;
106106
var ts = end - start;
107107
Console.WriteLine(ex);
108-
return new Result { span = ts, steps = i + InitialSamples, taskName = task.Name, measurementName = Name + " " + ex.Message };
108+
return new Result { span = ts, steps = currentStep + InitialSamples, taskName = task.Name, measurementName = Name + " " + ex.Message };
109109
}
110110
}
111111
}
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Net.WebSockets;
8+
using System.Runtime.CompilerServices;
9+
using System.Runtime.InteropServices.JavaScript;
10+
using System.Text;
11+
using System.Threading;
12+
using System.Threading.Tasks;
13+
14+
namespace Sample
15+
{
16+
// http://localhost:8000/?task=JSInterop
17+
class JSInteropTask : BenchTask
18+
{
19+
public override string Name => "JSInterop";
20+
public override Measurement[] Measurements => measurements;
21+
public override bool BrowserOnly => false;
22+
23+
Measurement[] measurements;
24+
public JSInteropTask()
25+
{
26+
measurements = new Measurement[] {
27+
new LegacyExportIntMeasurement(),
28+
new JSExportIntMeasurement(),
29+
new LegacyExportStringMeasurement(),
30+
new JSExportStringMeasurement(),
31+
new JSImportIntMeasurement(),
32+
new JSImportStringMeasurement(),
33+
new JSImportTaskMeasurement(),
34+
new JSImportTaskFailMeasurement(),
35+
new JSImportFailMeasurement(),
36+
};
37+
}
38+
39+
public class LegacyExportIntMeasurement : BenchTask.Measurement
40+
{
41+
public override int InitialSamples => 10;
42+
public override string Name => "LegacyExportInt";
43+
public override void RunStep()
44+
{
45+
ImportsExportsHelper.RunLegacyExportInt(10000);
46+
}
47+
}
48+
49+
public class JSExportIntMeasurement : BenchTask.Measurement
50+
{
51+
public override int InitialSamples => 10;
52+
public override string Name => "JSExportInt";
53+
public override void RunStep()
54+
{
55+
ImportsExportsHelper.RunJSExportInt(10000);
56+
}
57+
}
58+
59+
public class LegacyExportStringMeasurement : BenchTask.Measurement
60+
{
61+
public override int InitialSamples => 10;
62+
public override string Name => "LegacyExportString";
63+
public override void RunStep()
64+
{
65+
ImportsExportsHelper.RunLegacyExportString(10000);
66+
}
67+
}
68+
69+
public class JSExportStringMeasurement : BenchTask.Measurement
70+
{
71+
public override int InitialSamples => 10;
72+
public override string Name => "JSExportString";
73+
public override void RunStep()
74+
{
75+
ImportsExportsHelper.RunJSExportString(10000);
76+
}
77+
}
78+
79+
public class JSImportIntMeasurement : BenchTask.Measurement
80+
{
81+
public override int InitialSamples => 10;
82+
public override string Name => "JSImportInt";
83+
public override void RunStep()
84+
{
85+
ImportsExportsHelper.ImportTargetInt(10000);
86+
}
87+
}
88+
89+
public class JSImportStringMeasurement : BenchTask.Measurement
90+
{
91+
public override int InitialSamples => 10;
92+
public override string Name => "JSImportString";
93+
public override void RunStep()
94+
{
95+
ImportsExportsHelper.ImportTargetString("A" + currentStep);
96+
}
97+
}
98+
99+
public class JSImportTaskMeasurement : BenchTask.Measurement
100+
{
101+
public override int InitialSamples => 10;
102+
public override string Name => "JSImportTask";
103+
public override async Task RunStepAsync()
104+
{
105+
TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
106+
var promise = ImportsExportsHelper.ImportTargetTask(tcs.Task);
107+
tcs.SetResult(currentStep);
108+
await promise;
109+
}
110+
}
111+
112+
public class JSImportTaskFailMeasurement : BenchTask.Measurement
113+
{
114+
public override int InitialSamples => 10;
115+
public override string Name => "JSImportTaskFail";
116+
public override async Task RunStepAsync()
117+
{
118+
TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
119+
var promise = ImportsExportsHelper.ImportTargetTask(tcs.Task);
120+
tcs.SetException(new Exception("test"));
121+
try
122+
{
123+
await promise;
124+
}
125+
catch (Exception)
126+
{
127+
// no action
128+
}
129+
}
130+
}
131+
132+
public class JSImportFailMeasurement : BenchTask.Measurement
133+
{
134+
public override int InitialSamples => 10;
135+
public override string Name => "JSImportFail";
136+
public override void RunStep()
137+
{
138+
try
139+
{
140+
ImportsExportsHelper.ImportTargetThrows(currentStep);
141+
}
142+
catch (Exception)
143+
{
144+
// no action
145+
}
146+
}
147+
}
148+
}
149+
150+
partial class ImportsExportsHelper
151+
{
152+
[JSImport("Sample.Test.runLegacyExportInt", "main.js")]
153+
public static partial void RunLegacyExportInt(int count);
154+
155+
[JSImport("Sample.Test.runJSExportInt", "main.js")]
156+
public static partial void RunJSExportInt(int count);
157+
158+
[JSImport("Sample.Test.runLegacyExportString", "main.js")]
159+
public static partial void RunLegacyExportString(int count);
160+
161+
[JSImport("Sample.Test.runJSExportString", "main.js")]
162+
public static partial void RunJSExportString(int count);
163+
164+
[JSImport("Sample.Test.importTargetInt", "main.js")]
165+
public static partial int ImportTargetInt(int value);
166+
167+
[JSImport("Sample.Test.importTargetString", "main.js")]
168+
public static partial string ImportTargetString(string value);
169+
170+
[JSImport("Sample.Test.importTargetTask", "main.js")]
171+
public static partial Task<int> ImportTargetTask(Task<int> value);
172+
173+
[JSImport("Sample.Test.importTargetThrows", "main.js")]
174+
public static partial void ImportTargetThrows(int value);
175+
176+
[MethodImpl(MethodImplOptions.NoInlining)]
177+
public static int LegacyExportTargetInt(int value)
178+
{
179+
return value + 1;
180+
}
181+
182+
[JSExport]
183+
public static int JSExportTargetInt(int value)
184+
{
185+
return value + 1;
186+
}
187+
188+
[MethodImpl(MethodImplOptions.NoInlining)]
189+
public static string LegacyExportTargetString(string value)
190+
{
191+
return value + "A";
192+
}
193+
194+
[JSExport]
195+
public static string JSExportTargetString(string value)
196+
{
197+
return value + "A";
198+
}
199+
}
200+
}

src/mono/sample/wasm/browser-bench/Program.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ public partial class Test
2424
new ExceptionsTask(),
2525
new JsonTask(),
2626
new VectorTask(),
27-
new WebSocketTask()
27+
new JSInteropTask(),
28+
new WebSocketTask(),
2829
};
2930
static Test instance = new Test();
3031
Formatter formatter = new HTMLFormatter();
@@ -206,7 +207,7 @@ class JsonResultsData
206207
public DateTime timeStamp;
207208
}
208209

209-
string GetJsonResults ()
210+
string GetJsonResults()
210211
{
211212
var options = new JsonSerializerOptions { IncludeFields = true, WriteIndented = true };
212213
var jsonObject = new JsonResultsData { results = results, minTimes = minTimes, timeStamp = DateTime.UtcNow };
@@ -216,7 +217,7 @@ string GetJsonResults ()
216217
private void PrintJsonResults()
217218
{
218219
Console.WriteLine("=== json results start ===");
219-
Console.WriteLine(GetJsonResults ());
220+
Console.WriteLine(GetJsonResults());
220221
Console.WriteLine("=== json results end ===");
221222
}
222223
}

src/mono/sample/wasm/browser-bench/main.js

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,80 @@ import { dotnet, exit } from './dotnet.js'
88
let runBenchmark;
99
let setTasks;
1010
let getFullJsonResults;
11+
let legacyExportTargetInt;
12+
let jsExportTargetInt;
13+
let legacyExportTargetString;
14+
let jsExportTargetString;
15+
16+
function runLegacyExportInt(count) {
17+
for (let i = 0; i < count; i++) {
18+
legacyExportTargetInt(i);
19+
}
20+
}
21+
22+
function runJSExportInt(count) {
23+
for (let i = 0; i < count; i++) {
24+
jsExportTargetInt(i);
25+
}
26+
}
27+
28+
function runLegacyExportString(count) {
29+
for (let i = 0; i < count; i++) {
30+
legacyExportTargetString("A" + i);
31+
}
32+
}
33+
34+
function runJSExportString(count) {
35+
for (let i = 0; i < count; i++) {
36+
jsExportTargetString("A" + i);
37+
}
38+
}
39+
40+
function importTargetInt(value) {
41+
return value + 1;
42+
}
43+
44+
function importTargetString(value) {
45+
return value + "A";
46+
}
47+
48+
async function importTargetTask(value) {
49+
await value;
50+
return;
51+
}
52+
53+
function importTargetThrows(value) {
54+
throw new Error("test" + value);
55+
}
1156

1257
class MainApp {
13-
async init({ getAssemblyExports }) {
58+
async init({ getAssemblyExports, setModuleImports, BINDING }) {
1459
const exports = await getAssemblyExports("Wasm.Browser.Bench.Sample.dll");
1560
runBenchmark = exports.Sample.Test.RunBenchmark;
1661
setTasks = exports.Sample.Test.SetTasks;
1762
getFullJsonResults = exports.Sample.Test.GetFullJsonResults;
1863

64+
legacyExportTargetInt = BINDING.bind_static_method("[Wasm.Browser.Bench.Sample]Sample.ImportsExportsHelper:LegacyExportTargetInt");
65+
jsExportTargetInt = exports.Sample.ImportsExportsHelper.JSExportTargetInt;
66+
legacyExportTargetString = BINDING.bind_static_method("[Wasm.Browser.Bench.Sample]Sample.ImportsExportsHelper:LegacyExportTargetString");
67+
jsExportTargetString = exports.Sample.ImportsExportsHelper.JSExportTargetString;
68+
69+
setModuleImports("main.js", {
70+
Sample: {
71+
Test: {
72+
runLegacyExportInt,
73+
runJSExportInt,
74+
runLegacyExportString,
75+
runJSExportString,
76+
importTargetInt,
77+
importTargetString,
78+
importTargetTask,
79+
importTargetThrows,
80+
}
81+
}
82+
});
83+
84+
1985
var url = new URL(decodeURI(window.location));
2086
let tasks = url.searchParams.getAll('task');
2187
if (tasks != '') {

0 commit comments

Comments
 (0)