Skip to content

Commit a55fe31

Browse files
authored
Merge pull request #305 from costleya/improve-dotnet-performance
feat(jsii-dotnet-runtime): Improve .NET Performance
2 parents 35934ad + 56340b4 commit a55fe31

File tree

10 files changed

+110
-84
lines changed

10 files changed

+110
-84
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
node_modules/
22
.BUILD_COMPLETED
3-
lerna-debug.log
3+
lerna-debug.log
4+
.DS_Store
5+
.idea
Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

3-
<PropertyGroup>
4-
<TargetFramework>netcoreapp2.0</TargetFramework>
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp2.0</TargetFramework>
55

6-
<IsPackable>false</IsPackable>
7-
</PropertyGroup>
6+
<IsPackable>false</IsPackable>
7+
</PropertyGroup>
88

9-
<ItemGroup>
10-
<PackageReference Include="Amazon.JSII.Tests.CalculatorPackageId" Version="$(JsiiVersion)" />
11-
</ItemGroup>
9+
<ItemGroup>
10+
<PackageReference Include="Amazon.JSII.Tests.CalculatorPackageId" Version="$(JsiiVersion)"/>
11+
</ItemGroup>
1212

13-
<ItemGroup>
14-
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.0" />
15-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
16-
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
17-
<PackageReference Include="xunit" Version="2.3.1" />
18-
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
19-
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
20-
</ItemGroup>
13+
<ItemGroup>
14+
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.0"/>
15+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0"/>
16+
<PackageReference Include="Newtonsoft.Json" Version="11.0.2"/>
17+
<PackageReference Include="xunit" Version="2.3.1"/>
18+
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1"/>
19+
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1"/>
20+
</ItemGroup>
21+
22+
<ItemGroup>
23+
<ProjectReference Include="..\..\..\jsii-dotnet-runtime\src\Amazon.JSII.Runtime\Amazon.JSII.Runtime.csproj"/>
24+
</ItemGroup>
2125

2226
</Project>

packages/jsii-dotnet-runtime-test/test/Amazon.JSII.Runtime.IntegrationTests/ComplianceTests.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Linq;
43
using Amazon.JSII.Runtime.Deputy;
54
using Amazon.JSII.Tests.CalculatorNamespace;
65
using Amazon.JSII.Tests.CalculatorNamespace.composition.CompositeOperation;
@@ -9,12 +8,14 @@
98
using Xunit;
109
using Xunit.Abstractions;
1110

11+
[assembly: CollectionBehavior(DisableTestParallelization = true)]
12+
1213
namespace Amazon.JSII.Runtime.IntegrationTests
1314
{
1415
/// <summary>
1516
/// Ported from packages/jsii-java-runtime/src/test/java/org/jsii/testing/ComplianceTest.java.
1617
/// </summary>
17-
public class ComplianceTests : IntegrationTestBase
18+
public class ComplianceTests : IClassFixture<ServiceContainerFixture>
1819
{
1920
class RuntimeException : Exception
2021
{
@@ -29,8 +30,9 @@ public RuntimeException(string message)
2930

3031
const string Prefix = nameof(IntegrationTests) + ".Compliance.";
3132

32-
public ComplianceTests(ITestOutputHelper output) : base(output)
33+
public ComplianceTests(ITestOutputHelper outputHelper, ServiceContainerFixture serviceContainerFixture)
3334
{
35+
serviceContainerFixture.SetOverride(outputHelper);
3436
}
3537

3638
[Fact(DisplayName = Prefix + nameof(PrimitiveTypes))]
@@ -858,7 +860,7 @@ public NumberReturner(double number)
858860
[JsiiProperty("numberProp", "{\"fqn\":\"@scope/jsii-calc-lib.Number\"}", true)]
859861
public Number NumberProp { get; }
860862

861-
[JsiiMethod("obtainNumber", "{\"fqn\":\"@scope/jsii-calc-lib.IDoublable\"}", "[]",true)]
863+
[JsiiMethod("obtainNumber", "{\"fqn\":\"@scope/jsii-calc-lib.IDoublable\"}", "[]", true)]
862864
public IIDoublable ObtainNumber()
863865
{
864866
return new Doublable(this.NumberProp);
@@ -871,7 +873,7 @@ public Doublable(Number number)
871873
this.DoubleValue = number.DoubleValue;
872874
}
873875

874-
[JsiiProperty("doubleValue","{\"primitive\":\"number\"}",true)]
876+
[JsiiProperty("doubleValue", "{\"primitive\":\"number\"}", true)]
875877
public Double DoubleValue { get; }
876878
}
877879
}

packages/jsii-dotnet-runtime-test/test/Amazon.JSII.Runtime.IntegrationTests/IntegrationTestBase.cs

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System;
2+
using Amazon.JSII.Runtime.Services;
3+
using Xunit.Abstractions;
4+
5+
namespace Amazon.JSII.Runtime.IntegrationTests
6+
{
7+
public class ServiceContainerFixture : IDisposable
8+
{
9+
public ServiceContainerFixture()
10+
{
11+
Environment.SetEnvironmentVariable("JSII_DEBUG", "true");
12+
}
13+
14+
public void SetOverride(ITestOutputHelper outputHelper)
15+
{
16+
if (ServiceContainer.ServiceProviderOverride == null)
17+
{
18+
ServiceContainer.ServiceProviderOverride = ServiceContainer.BuildServiceProvider(
19+
new XUnitLoggerFactory(outputHelper)
20+
);
21+
}
22+
}
23+
24+
public void Dispose()
25+
{
26+
ServiceContainer.ServiceProviderOverride = null;
27+
}
28+
}
29+
}

packages/jsii-dotnet-runtime/build.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ rsync -av node_modules/jsii-runtime/webpack/ ${bundle_dir}
1111
# up an old build from the cache if it exists. So we
1212
# explicitly clear the cache as a temporary workaround.
1313
dotnet nuget locals all --clear
14-
dotnet build -c Release ./src/Amazon.JSII.Runtime.sln
14+
15+
# Build just Runtime and it's dependencies instead of the
16+
# solution to avoid integration tests from trying to be
17+
# built before the calc packages are generated.
18+
dotnet build -c Release ./src/Amazon.JSII.Runtime
1519

1620
cp -f ./bin/Release/NuGet/*.nupkg .

packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{
1414
EndProject
1515
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Amazon.JSII.Runtime.UnitTests", "Amazon.JSII.Runtime.UnitTests\Amazon.JSII.Runtime.UnitTests.csproj", "{96CC0C0B-1D90-448F-9BFC-07CE93D2CE29}"
1616
EndProject
17+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amazon.JSII.Runtime.IntegrationTests", "..\..\jsii-dotnet-runtime-test\test\Amazon.JSII.Runtime.IntegrationTests\Amazon.JSII.Runtime.IntegrationTests.csproj", "{7BD15A18-BE3A-4729-9B8C-570BF214C4CE}"
18+
EndProject
1719
Global
1820
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1921
Debug|Any CPU = Debug|Any CPU
@@ -28,6 +30,10 @@ Global
2830
{96CC0C0B-1D90-448F-9BFC-07CE93D2CE29}.Debug|Any CPU.Build.0 = Debug|Any CPU
2931
{96CC0C0B-1D90-448F-9BFC-07CE93D2CE29}.Release|Any CPU.ActiveCfg = Release|Any CPU
3032
{96CC0C0B-1D90-448F-9BFC-07CE93D2CE29}.Release|Any CPU.Build.0 = Release|Any CPU
33+
{7BD15A18-BE3A-4729-9B8C-570BF214C4CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
34+
{7BD15A18-BE3A-4729-9B8C-570BF214C4CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
35+
{7BD15A18-BE3A-4729-9B8C-570BF214C4CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
36+
{7BD15A18-BE3A-4729-9B8C-570BF214C4CE}.Release|Any CPU.Build.0 = Release|Any CPU
3137
EndGlobalSection
3238
GlobalSection(SolutionProperties) = preSolution
3339
HideSolutionNode = FALSE

packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Deputy/JsiiTypeAttributeBase.cs

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
1-
using Amazon.JSII.Runtime.Services;
2-
using Microsoft.Extensions.DependencyInjection;
3-
using System;
4-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Concurrent;
53
using System.Linq;
64
using System.Reflection;
5+
using Amazon.JSII.Runtime.Services;
6+
using Microsoft.Extensions.DependencyInjection;
77

88
namespace Amazon.JSII.Runtime.Deputy
99
{
1010
public abstract class JsiiTypeAttributeBase : Attribute
1111
{
12+
// It's possible that a user is creating types in a multithreaded application.
13+
// This is not explicity supported, but making the list thread-safe to protect
14+
// against this possibility.
15+
private static readonly ConcurrentBag<string> ProcessedAssemblies =
16+
new ConcurrentBag<string>();
17+
1218
protected JsiiTypeAttributeBase(Type nativeType, string fullyQualifiedName)
1319
{
1420
nativeType = nativeType ?? throw new ArgumentNullException(nameof(nativeType));
@@ -17,27 +23,32 @@ protected JsiiTypeAttributeBase(Type nativeType, string fullyQualifiedName)
1723
Load(nativeType.Assembly);
1824
}
1925

20-
void Load(Assembly assembly)
26+
private static void Load(Assembly assembly)
2127
{
22-
IEnumerable<Assembly> dependencies = assembly.GetReferencedAssemblies()
23-
.Select(assemblyName => Assembly.Load(assemblyName));
28+
if (ProcessedAssemblies.Contains(GetAssemblyKey(assembly)))
29+
{
30+
return;
31+
}
2432

25-
JsiiAssemblyAttribute attribute = assembly.GetCustomAttribute<JsiiAssemblyAttribute>();
33+
var attribute = assembly.GetCustomAttribute<JsiiAssemblyAttribute>();
2634
if (attribute == null)
2735
{
36+
ProcessedAssemblies.Add(GetAssemblyKey(assembly));
2837
return;
2938
}
3039

31-
foreach (Assembly dependency in dependencies)
40+
foreach (var referencedAssembly in assembly.GetReferencedAssemblies())
3241
{
33-
Load(dependency);
42+
var loadedReference = Assembly.Load(referencedAssembly);
43+
Load(loadedReference);
3444
}
3545

3646
// find the .tgz resource
3747
var tarballResourceName = assembly.GetManifestResourceNames().FirstOrDefault(name => name.EndsWith(".tgz"));
3848
if (tarballResourceName == null)
3949
{
40-
throw new JsiiException("Cannot find embedded tarball resource in assembly " + assembly.GetName(), null);
50+
throw new JsiiException("Cannot find embedded tarball resource in assembly " + assembly.GetName(),
51+
null);
4152
}
4253

4354
IServiceProvider serviceProvider = ServiceContainer.ServiceProvider;
@@ -46,6 +57,10 @@ void Load(Assembly assembly)
4657

4758
IClient client = serviceProvider.GetRequiredService<IClient>();
4859
client.LoadPackage(attribute.Name, attribute.Version, tarballPath);
60+
61+
ProcessedAssemblies.Add(GetAssemblyKey(assembly));
62+
63+
string GetAssemblyKey(Assembly assemblyReference) => assemblyReference.GetName().FullName;
4964
}
5065

5166
public string FullyQualifiedName { get; }

packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/ReflectionUtils.cs

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
using Amazon.JSII.Runtime.Deputy;
2-
using System;
1+
using System;
32
using System.Linq;
43
using System.Reflection;
4+
using Amazon.JSII.Runtime.Deputy;
55

66
namespace Amazon.JSII.Runtime
77
{
@@ -35,7 +35,8 @@ public static MethodInfo GetNativeMethod(Type classType, string name)
3535

3636
if (methodInfo == null)
3737
{
38-
throw new ArgumentNullException($"Class {classType.Name} does not have a method called {name}", nameof(name));
38+
throw new ArgumentNullException($"Class {classType.Name} does not have a method called {name}",
39+
nameof(name));
3940
}
4041

4142
return methodInfo;
@@ -52,7 +53,8 @@ public static PropertyInfo GetNativeProperty(Type classType, string name)
5253

5354
if (propertyInfo == null)
5455
{
55-
throw new ArgumentNullException($"Class {classType.Name} does not have a property called {name}", nameof(name));
56+
throw new ArgumentNullException($"Class {classType.Name} does not have a property called {name}",
57+
nameof(name));
5658
}
5759

5860
return propertyInfo;
@@ -65,23 +67,13 @@ public static PropertyInfo GetIndexer(Type type)
6567

6668
public static JsiiClassAttribute GetClassAttribute(Type type)
6769
{
68-
Type current = type;
69-
70-
while (current != null)
70+
if (type == null)
7171
{
72-
// JsiiClassAttribute can't be inheritable, because we need to distinguish between JSII
73-
// types and native extensions of JSII types. So we have to search the inheritance tree
74-
// manually.
75-
JsiiClassAttribute classAttribute = current.GetCustomAttribute<JsiiClassAttribute>();
76-
if (classAttribute != null)
77-
{
78-
return classAttribute;
79-
}
80-
81-
current = current.BaseType;
72+
return null;
8273
}
8374

84-
return null;
75+
return type.GetCustomAttribute<JsiiClassAttribute>()
76+
?? GetClassAttribute(type.BaseType);
8577
}
8678
}
87-
}
79+
}

packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/Client.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
1-
using Amazon.JSII.JsonModel.Api;
1+
using System;
2+
using System.IO;
3+
using Amazon.JSII.JsonModel.Api;
24
using Amazon.JSII.JsonModel.Api.Request;
35
using Amazon.JSII.JsonModel.Api.Response;
46
using Amazon.JSII.JsonModel.FileSystem;
5-
using Amazon.JSII.JsonModel.Spec;
67
using Amazon.JSII.Runtime.Services.Converters;
78
using Microsoft.Extensions.Logging;
89
using Newtonsoft.Json;
910
using Newtonsoft.Json.Linq;
10-
using System;
11-
using System.IO;
12-
using System.Linq;
13-
using System.Reflection;
14-
using Assembly = Amazon.JSII.JsonModel.Spec.Assembly;
1511

1612
namespace Amazon.JSII.Runtime.Services
1713
{
@@ -171,7 +167,7 @@ public void LoadPackage(string package, string version, string tarballPath)
171167
_logger.LogDebug($"Loading package {package}@{version}...");
172168
_loadedPackages.Add(package);
173169

174-
LoadResponse response = Load(package, version, tarballPath);
170+
Load(package, version, tarballPath);
175171
}
176172

177173
public HelloResponse Hello()

0 commit comments

Comments
 (0)