Skip to content

Commit

Permalink
Parallelisation of metadata definition
Browse files Browse the repository at this point in the history
  • Loading branch information
NikolayPianikov committed Jun 6, 2024
1 parent 31c8f55 commit 6c32f16
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 28 deletions.
22 changes: 8 additions & 14 deletions src/Pure.DI.Core/Core/ApiInvocationProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ internal class ApiInvocationProcessor(
: IApiInvocationProcessor
{
private static readonly char[] TypeNamePartsSeparators = ['.'];
private readonly Hints _hints = new();

public void ProcessInvocation(
IMetadataVisitor metadataVisitor,
Expand Down Expand Up @@ -92,7 +91,7 @@ public void ProcessInvocation(
var hintArgs = arguments.GetArgs(invocation.ArgumentList, "hint", "value");
if (hintArgs is [{ Expression: { } hintNameExpression }, { Expression: { } hintValueExpression }])
{
_hints[semanticModel.GetConstantValue<Hint>(hintNameExpression)] = semanticModel.GetRequiredConstantValue<string>(hintValueExpression);
metadataVisitor.VisitHint(new MdHint(semanticModel.GetConstantValue<Hint>(hintNameExpression), semanticModel.GetRequiredConstantValue<string>(hintValueExpression)));
}

break;
Expand All @@ -116,14 +115,19 @@ public void ProcessInvocation(
setupCompositionTypeName = baseType.Identifier.Text;
}

foreach (var hint in comments.GetHints(invocationComments))
{
metadataVisitor.VisitHint(new MdHint(hint.Key, hint.Value));
}

metadataVisitor.VisitSetup(
new MdSetup(
semanticModel,
invocation.ArgumentList,
CreateCompositionName(setupCompositionTypeName, @namespace, invocation.ArgumentList),
ImmutableArray<MdUsingDirectives>.Empty,
setupKind,
ApplyHints(invocationComments),
new Hints(),
ImmutableArray<MdBinding>.Empty,
ImmutableArray<MdRoot>.Empty,
ImmutableArray<MdDependsOn>.Empty,
Expand Down Expand Up @@ -507,16 +511,6 @@ private static void VisitUsingDirectives(
}
}

private IHints ApplyHints(IEnumerable<string> invocationComments)
{
foreach (var hint in comments.GetHints(invocationComments))
{
_hints[hint.Key] = hint.Value;
}

return _hints;
}

// ReSharper disable once SuggestBaseTypeForParameter
private static void NotSupported(InvocationExpressionSyntax invocation)
{
Expand All @@ -539,7 +533,7 @@ private static ImmutableArray<MdTag> BuildTags(SemanticModel semanticModel, IEnu
.Select((tag, i) => new MdTag(i, tag))
.ToImmutableArray();
}

private static CompositionName CreateCompositionName(string name, string ns, SyntaxNode source)
{
string className;
Expand Down
4 changes: 3 additions & 1 deletion src/Pure.DI.Core/Core/IMetadataVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal interface IMetadataVisitor

void VisitFactory(in MdFactory factory);

void VisitResolve(MdResolver resolver);
void VisitResolve(in MdResolver resolver);

void VisitDefaultLifetime(in MdDefaultLifetime defaultLifetime);

Expand All @@ -36,6 +36,8 @@ internal interface IMetadataVisitor
void VisitTag(in MdTag tag);

void VisitAccumulator(in MdAccumulator accumulator);

void VisitHint(in MdHint hint);

void VisitFinish();
}
94 changes: 94 additions & 0 deletions src/Pure.DI.Core/Core/InvocationVisitor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
namespace Pure.DI.Core;

internal readonly record struct InvocationVisitor(
SemanticModel SemanticModel,
InvocationExpressionSyntax Invocation,
IMetadataVisitor BaseVisitor,
CancellationToken CancellationToken)
: IMetadataVisitor
{
private readonly List<IRunnable> _actions = [];

public void Apply()
{
foreach (var action in _actions)
{
CancellationToken.ThrowIfCancellationRequested();
action.Run();
}
}

public void VisitSetup(in MdSetup setup) =>
AddAction((visitor, i) => visitor.VisitSetup(i), BaseVisitor, setup);

public void VisitUsingDirectives(in MdUsingDirectives usingDirectives) =>
AddAction((visitor, i) => visitor.VisitUsingDirectives(i), BaseVisitor, usingDirectives);

public void VisitBinding(in MdBinding binding) =>
AddAction((visitor, i) => visitor.VisitBinding(i), BaseVisitor, binding);

public void VisitContract(in MdContract contract) =>
AddAction((visitor, i) => visitor.VisitContract(i), BaseVisitor, contract);

public void VisitImplementation(in MdImplementation implementation) =>
AddAction((visitor, i) => visitor.VisitImplementation(i), BaseVisitor, implementation);

public void VisitFactory(in MdFactory factory) =>
AddAction((visitor, i) => visitor.VisitFactory(i), BaseVisitor, factory);

public void VisitResolve(in MdResolver resolver) =>
AddAction((visitor, i) => visitor.VisitResolve(i), BaseVisitor, resolver);

public void VisitDefaultLifetime(in MdDefaultLifetime defaultLifetime) =>
AddAction((visitor, i) => visitor.VisitDefaultLifetime(i), BaseVisitor, defaultLifetime);

public void VisitDependsOn(in MdDependsOn dependsOn) =>
AddAction((visitor, i) => visitor.VisitDependsOn(i), BaseVisitor, dependsOn);

public void VisitArg(in MdArg arg) =>
AddAction((visitor, i) => visitor.VisitArg(i), BaseVisitor, arg);

public void VisitRoot(in MdRoot root) =>
AddAction((visitor, i) => visitor.VisitRoot(i), BaseVisitor, root);

public void VisitTypeAttribute(in MdTypeAttribute typeAttribute) =>
AddAction((visitor, i) => visitor.VisitTypeAttribute(i), BaseVisitor, typeAttribute);

public void VisitTagAttribute(in MdTagAttribute tagAttribute) =>
AddAction((visitor, i) => visitor.VisitTagAttribute(i), BaseVisitor, tagAttribute);

public void VisitOrdinalAttribute(in MdOrdinalAttribute ordinalAttribute) =>
AddAction((visitor, i) => visitor.VisitOrdinalAttribute(i), BaseVisitor, ordinalAttribute);

public void VisitLifetime(in MdLifetime lifetime) =>
AddAction((visitor, i) => visitor.VisitLifetime(i), BaseVisitor, lifetime);

public void VisitTag(in MdTag tag) =>
AddAction((visitor, i) => visitor.VisitTag(i), BaseVisitor, tag);

public void VisitAccumulator(in MdAccumulator accumulator) =>
AddAction((visitor, i) => visitor.VisitAccumulator(i), BaseVisitor, accumulator);

public void VisitHint(in MdHint hint) =>
AddAction((visitor, i) => visitor.VisitHint(i), BaseVisitor, hint);

public void VisitFinish() =>
AddAction((visitor, _) => visitor.VisitFinish(), BaseVisitor, 0);

private void AddAction<T>(Action<IMetadataVisitor, T> action, IMetadataVisitor visitor, in T state) =>
_actions.Add(new VisitorAction<T>(action, visitor, state));

private interface IRunnable
{
void Run();
}

private class VisitorAction<T>(
Action<IMetadataVisitor, T> action,
IMetadataVisitor visitor,
T state)
: IRunnable
{
public void Run() => action(visitor, state);
}
}
34 changes: 24 additions & 10 deletions src/Pure.DI.Core/Core/MetadataSyntaxWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ internal sealed class MetadataSyntaxWalker(
public void Visit(IMetadataVisitor metadataVisitor, in SyntaxUpdate update)
{
Visit(update.Node);
var invocations = new Stack<InvocationExpressionSyntax>();
var visitors = new List<InvocationVisitor>();
while (_invocations.TryPop(out var invocation))
{
invocations.Push(invocation);
visitors.Add(new InvocationVisitor(update.SemanticModel, invocation, metadataVisitor, cancellationToken));
_isMetadata = true;
try
{
Expand All @@ -38,14 +38,28 @@ public void Visit(IMetadataVisitor metadataVisitor, in SyntaxUpdate update)
}
}

while (invocations.TryPop(out var invocation))
if (visitors.Count == 0)
{
invocationProcessor.ProcessInvocation(metadataVisitor, update.SemanticModel, invocation, _namespace);
return;
}


visitors.Reverse();
#if DEBUG
visitors.ForEach(i => ProcessInvocation(i));
#else
Parallel.ForEach(invocations, i => ProcessInvocation(i));

Check failure on line 50 in src/Pure.DI.Core/Core/MetadataSyntaxWalker.cs

View workflow job for this annotation

GitHub Actions / deploy-examples

The name 'invocations' does not exist in the current context
#endif
foreach (var visitor in visitors)
{
visitor.Apply();
}

metadataVisitor.VisitFinish();
}


private void ProcessInvocation(in InvocationVisitor visitor) =>
invocationProcessor.ProcessInvocation(visitor, visitor.SemanticModel, visitor.Invocation, _namespace);

// ReSharper disable once CognitiveComplexity
public override void VisitInvocationExpression(InvocationExpressionSyntax invocation)
{
Expand All @@ -67,7 +81,7 @@ public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax namesp
_namespace = namespaceDeclaration.Name.ToString().Trim();
base.VisitNamespaceDeclaration(namespaceDeclaration);
}

private static string GetInvocationName(InvocationExpressionSyntax invocation) => GetName(invocation.Expression, 2);

private static string GetName(ExpressionSyntax expression, int deepness = int.MaxValue)
Expand All @@ -76,7 +90,7 @@ private static string GetName(ExpressionSyntax expression, int deepness = int.Ma
{
case IdentifierNameSyntax identifierNameSyntax:
return identifierNameSyntax.Identifier.Text;

case MemberAccessExpressionSyntax memberAccess when memberAccess.IsKind(SyntaxKind.SimpleMemberAccessExpression):
{
var name = memberAccess.Name.Identifier.Text;
Expand All @@ -88,12 +102,12 @@ private static string GetName(ExpressionSyntax expression, int deepness = int.Ma

return name;
}

default:
return string.Empty;
}
}

[SuppressMessage("ReSharper", "SuggestBaseTypeForParameter")]
private static bool IsMetadata(InvocationExpressionSyntax invocation) =>
invocation
Expand Down
6 changes: 5 additions & 1 deletion src/Pure.DI.Core/Core/MetadataWalkerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public virtual void VisitRoot(in MdRoot root)
}
}

public virtual void VisitResolve(MdResolver resolver)
public virtual void VisitResolve(in MdResolver resolver)
{
if (resolver.Tag is {} tag)
{
Expand Down Expand Up @@ -154,6 +154,10 @@ public virtual void VisitAccumulator(in MdAccumulator accumulator)
{
}

public virtual void VisitHint(in MdHint hint)
{
}

public virtual void VisitFinish()
{
}
Expand Down
3 changes: 3 additions & 0 deletions src/Pure.DI.Core/Core/Models/MdHint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Pure.DI.Core.Models;

internal readonly record struct MdHint(Hint Key, string Value);
10 changes: 8 additions & 2 deletions src/Pure.DI.Core/Core/SetupsBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ internal sealed class SetupsBuilder(
private readonly List<MdAccumulator> _accumulators = [];
private IBindingBuilder _bindingBuilder = bindingBuilderFactory();
private MdSetup? _setup;
private Hints _hints = new();

public IEnumerable<MdSetup> Build(SyntaxUpdate update)
{
Expand Down Expand Up @@ -69,7 +70,7 @@ public void VisitArg(in MdArg arg)
FinishBinding();
}

public void VisitResolve(MdResolver resolver)
public void VisitResolve(in MdResolver resolver)
{
}

Expand Down Expand Up @@ -98,6 +99,9 @@ public void VisitLifetime(in MdLifetime lifetime) =>
public void VisitAccumulator(in MdAccumulator accumulator) =>
_accumulators.Add(accumulator);

public void VisitHint(in MdHint hint) =>
_hints[hint.Key] = hint.Value;

public void VisitFinish() => FinishSetup();

private void FinishBinding() =>
Expand All @@ -113,6 +117,7 @@ private void FinishSetup()
_setups.Add(
setup with
{
Hints = _hints,
Bindings = _bindings.Select(i => i with { SourceSetup = setup }).ToImmutableArray(),
Roots = _roots.ToImmutableArray(),
DependsOn = _dependsOn.ToImmutableArray(),
Expand All @@ -122,7 +127,8 @@ setup with
UsingDirectives = _usingDirectives.ToImmutableArray(),
Accumulators = _accumulators.Distinct().ToImmutableArray()
});


_hints = new Hints();
_bindings.Clear();
_roots.Clear();
_dependsOn.Clear();
Expand Down

0 comments on commit 6c32f16

Please sign in to comment.