Skip to content

Commit

Permalink
Merge pull request #57 from JeringTech/improve-api
Browse files Browse the repository at this point in the history
Expanded API.
  • Loading branch information
JeremyTCD authored Dec 4, 2019
2 parents b2666f1 + aa5b806 commit 2cd5d66
Show file tree
Hide file tree
Showing 25 changed files with 2,587 additions and 749 deletions.
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

0 comments on commit 2cd5d66

Please sign in to comment.