Skip to content

Expand API #57

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Dec 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,20 @@ This project uses [semantic versioning](http://semver.org/spec/v2.0.0.html). Ref
*[Semantic Versioning in Practice](https://www.jering.tech/articles/semantic-versioning-in-practice)*
for an overview of semantic versioning.

## [Unreleased](https://github.com/JeringTech/Javascript.NodeJS/compare/5.1.1...HEAD)
## [Unreleased](https://github.com/JeringTech/Javascript.NodeJS/compare/5.2.0...HEAD)

## [5.2.0](https://github.com/JeringTech/Javascript.NodeJS/compare/5.1.1...5.2.0) - Dec 4, 2019
### Fixes
- Expanded API. ([#57](https://github.com/JeringTech/Javascript.NodeJS/pull/57)). Added `INodeJSService` members for invocations without return values and
atomic/simplified caching-invoking:
- `Task InvokeFromFileAsync(string modulePath, string exportName = null, object[] args = null, CancellationToken cancellationToken = default);`
- `Task InvokeFromStringAsync(string moduleString, string newCacheIdentifier = null, string exportName = null, object[] args = null, CancellationToken cancellationToken = default);`
- `Task<T> InvokeFromStringAsync<T>(Func<string> moduleFactory, string cacheIdentifier, string exportName = null, object[] args = null, CancellationToken cancellationToken = default);`
- `Task InvokeFromStringAsync(Func<string> moduleFactory, string cacheIdentifier, string exportName = null, object[] args = null, CancellationToken cancellationToken = default);`
- `Task InvokeFromStreamAsync(Stream moduleStream, string newCacheIdentifier = null, string exportName = null, object[] args = null, CancellationToken cancellationToken = default);`
- `Task<T> InvokeFromStreamAsync<T>(Func<Stream> moduleFactory, string cacheIdentifier, string exportName = null, object[] args = null, CancellationToken cancellationToken = default);`
- `Task InvokeFromStreamAsync(Func<Stream> moduleFactory, string cacheIdentifier, string exportName = null, object[] args = null, CancellationToken cancellationToken = default);`
- `Task<bool> TryInvokeFromCacheAsync(string moduleCacheIdentifier, string exportName = null, object[] args = null, CancellationToken cancellationToken = default);`

## [5.1.1](https://github.com/JeringTech/Javascript.NodeJS/compare/5.1.0...5.1.1) - Nov 29, 2019
### Fixes
Expand Down
226 changes: 142 additions & 84 deletions ReadMe.md

Large diffs are not rendered by default.

20 changes: 10 additions & 10 deletions perf/NodeJS/ConcurrencyBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@

namespace Jering.Javascript.NodeJS.Performance
{
// TODO after adding invoke method with no return value (analagous to execute method in js engines), remove string type parameters
[MemoryDiagnoser]
public class ConcurrencyBenchmarks
{
private const string DUMMY_CONCURRENCY_MODULE = "dummyConcurrencyModule.js";
private const string DUMMY_WARMUP_MODULE = "module.exports = (callback) => callback()";
private const string DUMMY_CONCURRENCY_MODULE_FILE = "dummyConcurrencyModule.js";

private ServiceProvider _serviceProvider;
private INodeJSService _nodeJSService;
Expand All @@ -29,11 +29,11 @@ public void INodeJSService_Concurrency_MultiProcess_Setup()
_serviceProvider = services.BuildServiceProvider();
_nodeJSService = _serviceProvider.GetRequiredService<INodeJSService>();

// Warm up. First few runs start Node.js processes, so they take longer. If we don't manually warm up, BenchmarkDotNet erroneously complains
// Warmup. First few runs start Node.js processes, so they take longer. If we don't manually warm up, BenchmarkDotNet erroneously complains
// about iteration time being too low
for (int i = 0; i < Environment.ProcessorCount; i++)
{
_nodeJSService.InvokeFromStringAsync<string>("module.exports = (callback) => callback(null, null)", "warmup").GetAwaiter().GetResult();
_nodeJSService.InvokeFromStringAsync(DUMMY_WARMUP_MODULE).GetAwaiter().GetResult();
}
}

Expand All @@ -45,7 +45,7 @@ public async Task<string[]> INodeJSService_Concurrency_MultiProcess()
var results = new Task<string>[numTasks];
for (int i = 0; i < numTasks; i++)
{
results[i] = _nodeJSService.InvokeFromFileAsync<string>(DUMMY_CONCURRENCY_MODULE);
results[i] = _nodeJSService.InvokeFromFileAsync<string>(DUMMY_CONCURRENCY_MODULE_FILE);
}

return await Task.WhenAll(results);
Expand All @@ -60,8 +60,8 @@ public void INodeJSService_Concurrency_None_Setup()
_serviceProvider = services.BuildServiceProvider();
_nodeJSService = _serviceProvider.GetRequiredService<INodeJSService>();

// Warm up. First run starts a Node.js processes.
_nodeJSService.InvokeFromStringAsync<string>("module.exports = (callback) => callback(null, null)", "warmup").GetAwaiter().GetResult();
// Warmup. First run starts a Node.js processes.
_nodeJSService.InvokeFromStringAsync(DUMMY_WARMUP_MODULE).GetAwaiter().GetResult();
}

[Benchmark]
Expand All @@ -72,7 +72,7 @@ public async Task<string[]> INodeJSService_Concurrency_None()
var results = new Task<string>[numTasks];
for (int i = 0; i < numTasks; i++)
{
results[i] = _nodeJSService.InvokeFromFileAsync<string>(DUMMY_CONCURRENCY_MODULE);
results[i] = _nodeJSService.InvokeFromFileAsync<string>(DUMMY_CONCURRENCY_MODULE_FILE);
}

return await Task.WhenAll(results);
Expand All @@ -91,7 +91,7 @@ public void INodeServices_Concurrency_Setup()
_serviceProvider = services.BuildServiceProvider();
_nodeServices = _serviceProvider.GetRequiredService<INodeServices>();

// Warm up. First run starts a Node.js processes.
// Warmup. First run starts a Node.js processes.
_nodeServices.InvokeAsync<DummyResult>("dummyLatencyModule.js", 0).GetAwaiter().GetResult();
}

Expand All @@ -104,7 +104,7 @@ public async Task<string[]> INodeServices_Concurrency()
var results = new Task<string>[numTasks];
for (int i = 0; i < numTasks; i++)
{
results[i] = _nodeServices.InvokeAsync<string>(DUMMY_CONCURRENCY_MODULE);
results[i] = _nodeServices.InvokeAsync<string>(DUMMY_CONCURRENCY_MODULE_FILE);
}

return await Task.WhenAll(results);
Expand Down
28 changes: 16 additions & 12 deletions perf/NodeJS/LatencyBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ namespace Jering.Javascript.NodeJS.Performance
[MemoryDiagnoser]
public class LatencyBenchmarks
{
private const string DUMMY_LATENCY_MODULE = "dummyLatencyModule.js";
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 ServiceProvider _serviceProvider;
Expand All @@ -30,15 +31,14 @@ public void INodeJSService_Latency_InvokeFromFile_Setup()
_nodeJSService = _serviceProvider.GetRequiredService<INodeJSService>();
_counter = 0;

// Warm up. First run starts a Node.js process.
_nodeJSService.InvokeFromStringAsync<string>("module.exports = (callback) => callback(null, null)", "warmup").GetAwaiter().GetResult();
// Warmup. First run starts a Node.js process.
_nodeJSService.InvokeFromStringAsync(DUMMY_WARMUP_MODULE).GetAwaiter().GetResult();
}

[Benchmark]
public async Task<DummyResult> INodeJSService_Latency_InvokeFromFile()
{
DummyResult result = await _nodeJSService.InvokeFromFileAsync<DummyResult>(DUMMY_LATENCY_MODULE, args: new object[] { _counter++ });
return result;
return await _nodeJSService.InvokeFromFileAsync<DummyResult>(DUMMY_LATENCY_MODULE_FILE, args: new object[] { _counter++ });
}

[GlobalSetup(Target = nameof(INodeJSService_Latency_InvokeFromCache))]
Expand All @@ -50,15 +50,19 @@ public void INodeJSService_Latency_InvokeFromCache_Setup()
_nodeJSService = _serviceProvider.GetRequiredService<INodeJSService>();
_counter = 0;

// Cache module/warmup
_nodeJSService.InvokeFromStringAsync<DummyResult>("module.exports = (callback, result) => callback(null, { result: result });", DUMMY_MODULE_IDENTIFIER, args: new object[] { _counter++ }).GetAwaiter().GetResult();
// Warmup/cache.
_nodeJSService.InvokeFromStringAsync<DummyResult>(DummyModuleFactory, DUMMY_MODULE_IDENTIFIER, args: new object[] { _counter++ }).GetAwaiter().GetResult();
}

[Benchmark]
public async Task<DummyResult> INodeJSService_Latency_InvokeFromCache()
{
(bool _, DummyResult result) = await _nodeJSService.TryInvokeFromCacheAsync<DummyResult>(DUMMY_MODULE_IDENTIFIER, args: new object[] { _counter++ });
return result;
return await _nodeJSService.InvokeFromStringAsync<DummyResult>(DummyModuleFactory, DUMMY_MODULE_IDENTIFIER, args: new object[] { _counter++ });
}

private string DummyModuleFactory()
{
return File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(), "../../../..", DUMMY_LATENCY_MODULE_FILE));
}

[Obsolete]
Expand All @@ -75,15 +79,15 @@ public void INodeServices_Latency_Setup()
_nodeServices = _serviceProvider.GetRequiredService<INodeServices>();
_counter = 0;

// Warm up. First run starts a Node.js process.
_nodeServices.InvokeAsync<DummyResult>(DUMMY_LATENCY_MODULE, 0).GetAwaiter().GetResult();
// Warmup. First run starts a Node.js process.
_nodeServices.InvokeAsync<DummyResult>(DUMMY_LATENCY_MODULE_FILE, 0).GetAwaiter().GetResult();
}

[Obsolete]
[Benchmark]
public async Task<DummyResult> INodeServices_Latency()
{
DummyResult result = await _nodeServices.InvokeAsync<DummyResult>(DUMMY_LATENCY_MODULE, _counter++);
DummyResult result = await _nodeServices.InvokeAsync<DummyResult>(DUMMY_LATENCY_MODULE_FILE, _counter++);
return result;
}

Expand Down
18 changes: 12 additions & 6 deletions perf/NodeJS/RealWorkloadBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ namespace Jering.Javascript.NodeJS.Performance
[MemoryDiagnoser]
public class RealWorkloadBenchmarks
{
private const string DUMMY_REAL_WORKLOAD_MODULE = "dummyRealWorkloadModule.js";
private const string DUMMY_CACHE_IDENTIFIER = "dummyRealWorkloadModuleIdentifier";
private const string DUMMY_REAL_WORKLOAD_MODULE_FILE = "dummyRealWorkloadModule.js";
// Realistically, you aren't going to pass the same string for highlighting every time, so use a format that we alter slightly every interation
private const string DUMMY_CODE_FORMAT = @"public class HelloWorld
{{
Expand Down Expand Up @@ -39,11 +40,11 @@ public void INodeJSService_RealWorkload_Setup()
_nodeJSService = _serviceProvider.GetRequiredService<INodeJSService>();
_counter = 0;

// Warm up. First few runs start Node.js processes, so they take longer. If we don't manually warm up, BenchmarkDotNet erroneously complains
// Warmup/cache. First few runs start Node.js processes, so they take longer. If we don't manually warm up, BenchmarkDotNet erroneously complains
// about iteration time being too low
for (int i = 0; i < Environment.ProcessorCount; i++)
{
_nodeJSService.InvokeFromStringAsync<string>("module.exports = (callback) => callback(null, null)", "warmup").GetAwaiter().GetResult();
_nodeJSService.InvokeFromStringAsync(DummyModuleFactory, DUMMY_CACHE_IDENTIFIER, args: new object[] { string.Format(DUMMY_CODE_FORMAT, _counter++) }).GetAwaiter().GetResult();
}
}

Expand All @@ -56,12 +57,17 @@ public async Task<string[]> INodeJSService_RealWorkload()
for (int i = 0; i < numTasks; i++)
{
// The module uses Prism.js to perform syntax highlighting
results[i] = _nodeJSService.InvokeFromFileAsync<string>(DUMMY_REAL_WORKLOAD_MODULE, args: new object[] { string.Format(DUMMY_CODE_FORMAT, _counter++) });
results[i] = _nodeJSService.InvokeFromStringAsync<string>(DummyModuleFactory, DUMMY_CACHE_IDENTIFIER, args: new object[] { string.Format(DUMMY_CODE_FORMAT, _counter++) });
}

return await Task.WhenAll(results);
}

private string DummyModuleFactory()
{
return File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(), "../../../..", DUMMY_REAL_WORKLOAD_MODULE_FILE));
}

[Obsolete]
[GlobalSetup(Target = nameof(INodeServices_RealWorkload))]
public void INodeServices_RealWorkload_Setup()
Expand All @@ -76,7 +82,7 @@ public void INodeServices_RealWorkload_Setup()
_nodeServices = _serviceProvider.GetRequiredService<INodeServices>();
_counter = 0;

// Warm up. First run starts a Node.js process.
// Warmup. First run starts a Node.js process.
_nodeServices.InvokeAsync<DummyResult>("dummyLatencyModule.js", 0).GetAwaiter().GetResult(); // Doesn't support invoke from string, so this is the simplest/quickest
}

Expand All @@ -89,7 +95,7 @@ public async Task<string[]> INodeServices_RealWorkload()
var results = new Task<string>[numTasks];
for (int i = 0; i < numTasks; i++)
{
results[i] = _nodeServices.InvokeAsync<string>(DUMMY_REAL_WORKLOAD_MODULE, string.Format(DUMMY_CODE_FORMAT, _counter++));
results[i] = _nodeServices.InvokeAsync<string>(DUMMY_REAL_WORKLOAD_MODULE_FILE, string.Format(DUMMY_CODE_FORMAT, _counter++));
}

return await Task.WhenAll(results);
Expand Down
Loading