-
Notifications
You must be signed in to change notification settings - Fork 43
/
LatencyBenchmarks.cs
136 lines (119 loc) · 5.77 KB
/
LatencyBenchmarks.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Diagnosers;
using Microsoft.AspNetCore.NodeServices;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.IO;
using System.Threading.Tasks;
namespace Jering.Javascript.NodeJS.Performance
{
[MemoryDiagnoser]
public class LatencyBenchmarks
{
private const string DUMMY_WARMUP_MODULE = "module.exports = (callback) => callback()";
private const string DUMMY_LATENCY_MODULE_FILE = "dummyLatencyModule.js";
private const string DUMMY_MODULE_IDENTIFIER = "dummyLatencyModuleIdentifier";
private static readonly string _projectPath = Path.Combine(Directory.GetCurrentDirectory(), "../../../../../../../Javascript"); // BenchmarkDotNet creates a project nested deep in bin
private ServiceProvider? _serviceProvider;
private int _counter;
private readonly object[] _args = new object[1];
private INodeJSService? _nodeJSService;
[Obsolete]
private INodeServices? _nodeServices;
[GlobalSetup(Target = nameof(INodeJSService_Latency_InvokeFromFile))]
public void INodeJSService_Latency_InvokeFromFile_Setup()
{
var services = new ServiceCollection();
services.AddNodeJS();
services.Configure<NodeJSProcessOptions>(options => options.ProjectPath = _projectPath);
_serviceProvider = services.BuildServiceProvider();
_nodeJSService = _serviceProvider.GetRequiredService<INodeJSService>();
_counter = 0;
// Warmup. First run starts a Node.js process.
_nodeJSService.InvokeFromStringAsync(DUMMY_WARMUP_MODULE).GetAwaiter().GetResult();
}
[Benchmark]
public async Task<DummyResult?> INodeJSService_Latency_InvokeFromFile()
{
_args[0] = _counter++;
return await _nodeJSService!.InvokeFromFileAsync<DummyResult>(DUMMY_LATENCY_MODULE_FILE, args: _args).ConfigureAwait(false);
}
// If file watching is enabled but graceful shutdown is disabled, latency is the same as if file watching is disabled,
// so don't need a separate benchmark for that scenario. There is slightly higher latency when file watching and
// graceful shutdown are both enabled though.
[GlobalSetup(Target = nameof(INodeJSService_Latency_InvokeFromFile_GracefulShutdownEnabled))]
public void INodeJSService_Latency_InvokeFromFile_GracefulShutdownEnabled_Setup()
{
var services = new ServiceCollection();
services.AddNodeJS();
services.Configure<NodeJSProcessOptions>(options => options.ProjectPath = _projectPath);
services.Configure<OutOfProcessNodeJSServiceOptions>(options => options.EnableFileWatching = true);
_serviceProvider = services.BuildServiceProvider();
_nodeJSService = _serviceProvider.GetRequiredService<INodeJSService>();
_counter = 0;
// Warmup. First run starts a Node.js process.
_nodeJSService.InvokeFromStringAsync(DUMMY_WARMUP_MODULE).GetAwaiter().GetResult();
}
[Benchmark]
public async Task<DummyResult?> INodeJSService_Latency_InvokeFromFile_GracefulShutdownEnabled()
{
_args[0] = _counter++;
return await _nodeJSService!.InvokeFromFileAsync<DummyResult>(DUMMY_LATENCY_MODULE_FILE, args: _args).ConfigureAwait(false);
}
[GlobalSetup(Target = nameof(INodeJSService_Latency_InvokeFromCache))]
public void INodeJSService_Latency_InvokeFromCache_Setup()
{
var services = new ServiceCollection();
services.AddNodeJS();
_serviceProvider = services.BuildServiceProvider();
_nodeJSService = _serviceProvider.GetRequiredService<INodeJSService>();
_counter = 0;
// Warmup/cache.
_args[0] = _counter++;
_nodeJSService.InvokeFromStringAsync<DummyResult>(DummyModuleFactory, DUMMY_MODULE_IDENTIFIER, args: _args).GetAwaiter().GetResult();
}
[Benchmark]
public async Task<DummyResult?> INodeJSService_Latency_InvokeFromCache()
{
_args[0] = _counter++;
return await _nodeJSService!.InvokeFromStringAsync<DummyResult>(DummyModuleFactory, DUMMY_MODULE_IDENTIFIER, args: _args).ConfigureAwait(false);
}
private string DummyModuleFactory()
{
return File.ReadAllText(Path.Combine(_projectPath, DUMMY_LATENCY_MODULE_FILE));
}
[Obsolete("NodeServices is obsolete")]
[GlobalSetup(Target = nameof(INodeServices_Latency))]
public void INodeServices_Latency_Setup()
{
var services = new ServiceCollection();
services.AddNodeServices(options =>
{
options.ProjectPath = _projectPath;
options.WatchFileExtensions = null;
});
_serviceProvider = services.BuildServiceProvider();
_nodeServices = _serviceProvider.GetRequiredService<INodeServices>();
_counter = 0;
// Warmup. First run starts a Node.js process.
_nodeServices.InvokeAsync<DummyResult>(DUMMY_LATENCY_MODULE_FILE, 0).GetAwaiter().GetResult();
}
[Obsolete("NodeServices is obsolete")]
[Benchmark]
public async Task<DummyResult> INodeServices_Latency()
{
_args[0] = _counter++;
DummyResult result = await _nodeServices!.InvokeAsync<DummyResult>(DUMMY_LATENCY_MODULE_FILE, _args).ConfigureAwait(false);
return result;
}
[GlobalCleanup]
public void Cleanup()
{
_serviceProvider?.Dispose();
}
public class DummyResult
{
public int Result { get; set; }
}
}
}