Skip to content

Commit

Permalink
Improved performance
Browse files Browse the repository at this point in the history
  • Loading branch information
NikolayPianikov committed Apr 27, 2024
1 parent 68c2c07 commit 453a713
Show file tree
Hide file tree
Showing 12 changed files with 87 additions and 55 deletions.
26 changes: 25 additions & 1 deletion src/Pure.DI.Core/Core/Code/BlockCodeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,31 @@ variable.Node.Lifetime is Lifetime.Singleton or Lifetime.Scoped
finally
{
info.HasCode = true;
ctx.Code.AppendLines(info.Code.Lines);
// ctx.Code.AppendLines(info.Code.Lines);
if (block.Parent is not null
&& info is { PerBlockRefCount: > 2, Code.Lines.Count: > 3 })
{
var localFunctionsCode = ctx.LocalFunctionsCode;
var localMethodName = $"{Names.LocalMethodPrefix}{variable.VariableName}{Names.EnsureExistsMethodNamePostfix}";
if (variable.Node.Binding.SemanticModel.Compilation.GetLanguageVersion() >= LanguageVersion.CSharp9)
{
localFunctionsCode.AppendLine($"[{Names.MethodImplAttribute}(({Names.MethodImplOptions})0x100)]");
}

localFunctionsCode.AppendLine($"void {localMethodName}()");
localFunctionsCode.AppendLine("{");
using (localFunctionsCode.Indent())
{
localFunctionsCode.AppendLines(info.Code.Lines);
}

localFunctionsCode.AppendLine("}");
ctx.Code.AppendLine($"{localMethodName}();");
}
else
{
ctx.Code.AppendLines(info.Code.Lines);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/Pure.DI.Core/Core/Code/BuildContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ internal record BuildContext(
DependencyGraph DependencyGraph,
Variable Variable,
LinesBuilder Code,
LinesBuilder LocalFunctionsCode,
object? ContextTag,
bool? LockIsRequired,
ImmutableArray<Accumulator> Accumulators);
2 changes: 2 additions & 0 deletions src/Pure.DI.Core/Core/Code/CompositionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public CompositionCode Build(DependencyGraph graph)
graph,
rootBlock.Current,
new LinesBuilder(),
new LinesBuilder(),
root.Injection.Tag != MdTag.ContextTag ? root.Injection.Tag : default,
default,
root.Node.Accumulators.ToImmutableArray());
Expand All @@ -46,6 +47,7 @@ public CompositionCode Build(DependencyGraph graph)

blockBuilder.Build(ctx, rootBlock);
ctx.Code.AppendLine($"return {buildTools.OnInjected(ctx, rootBlock.Current)};");
ctx.Code.AppendLines(ctx.LocalFunctionsCode.Lines);

var args = GetRootArgs(map.Values).ToImmutableArray();
var processedRoot = root with
Expand Down
7 changes: 6 additions & 1 deletion src/Pure.DI.Core/Core/Code/VariableInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,25 @@

internal class VariableInfo
{
private readonly HashSet<int> _perBlockRefCounts = [];
public readonly HashSet<Block> Owners = [];
public bool IsCreated;
public bool HasCode;
public LinesBuilder Code = new();

public int RefCount { get; private set; } = 1;

public void AddRef()
public int PerBlockRefCount => _perBlockRefCounts.Count;

public void AddRef(Block parentBlock)
{
RefCount++;
_perBlockRefCounts.Add(parentBlock.Id);
}

public void Reset()
{
_perBlockRefCounts.Clear();
Owners.Clear();
RefCount = 1;
IsCreated = false;
Expand Down
10 changes: 7 additions & 3 deletions src/Pure.DI.Core/Core/Code/VariablesBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,17 @@ public Block Build(
var counter = 0;
while (blocks.TryPop(out var currentBlock))
{
if (cancellationToken.IsCancellationRequested)
{
break;
}

var stack = new Stack<IStatement>(currentBlock.Statements);
while (stack.TryPop(out var currentStatement))
{
cancellationToken.ThrowIfCancellationRequested();
if (counter++ > Const.MaxIterationsCount)
{
throw new CompileErrorException("Cyclic dependency has been found.", rootNode.Binding.Source.GetLocation(), LogId.ErrorCyclicDependency);
throw new CompileErrorException($"The composition is too large. Stopped on the #{counter} instance.", rootNode.Binding.Source.GetLocation(), LogId.ErrorInvalidMetadata);
}

switch (currentStatement)
Expand Down Expand Up @@ -219,7 +223,7 @@ private Variable GetVariable(

if (map.TryGetValue(node.Binding, out var variable))
{
variable.Info.AddRef();
variable.Info.AddRef(parentBlock);
return variable with
{
Parent = parentBlock,
Expand Down
10 changes: 2 additions & 8 deletions src/Pure.DI.Core/Core/CodeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,8 @@ public Unit Build(MdSetup setup)
composition = classBuilder.Build(composition);

cancellationToken.ThrowIfCancellationRequested();
var code = new StringBuilder(composition.Code.Sum(i => i.Length + 2));
foreach (var line in composition.Code)
{
code.AppendLine(line);
}

cancellationToken.ThrowIfCancellationRequested();
sources.AddSource($"{setup.Name.FullName}.g.cs", SourceText.From(code.ToString(), Encoding.UTF8));
using var rent = composition.Code.SaveToArray(Encoding.UTF8, out var buffer, out var size);
sources.AddSource($"{setup.Name.FullName}.g.cs", SourceText.From(buffer, size, Encoding.UTF8, SourceHashAlgorithm.Sha1, false, true));
return Unit.Shared;
}
}
2 changes: 1 addition & 1 deletion src/Pure.DI.Core/Core/Const.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

public static class Const
{
public const int MaxIterationsCount = 0xffff;
public const int MaxIterationsCount = 0x8FFFF;
}
2 changes: 1 addition & 1 deletion src/Pure.DI.Core/Core/DependencyGraphBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public IEnumerable<DependencyNode> TryBuild(
cancellationToken.ThrowIfCancellationRequested();
if (counter++ > Const.MaxIterationsCount)
{
throw new CompileErrorException("Cyclic dependency has been found.", setup.Source.GetLocation(), LogId.ErrorCyclicDependency);
throw new CompileErrorException($"The composition is too large. Stopped on the #{counter} dependency.", setup.Source.GetLocation(), LogId.ErrorInvalidMetadata);
}

var targetNode = node.Node;
Expand Down
7 changes: 4 additions & 3 deletions src/Pure.DI.Core/Core/Formatting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ namespace Pure.DI.Core;

internal static class Formatting
{
public const int IndentSize = 2;
private const int IndentsCount = 5;
public const int IndentSize = 1;
private const int IndentsCount = 256;
private static readonly string[] Indents;

static Formatting()
Expand All @@ -26,5 +26,6 @@ public static string IndentPrefix(Indent indent) =>
_ => IndentInternal(indent.Value)
};

private static string IndentInternal(int count = 1) => new(' ', count * IndentSize);
private static string IndentInternal(int count = 1) =>
string.Intern(new string('\t', count * IndentSize));
}
14 changes: 3 additions & 11 deletions src/Pure.DI.Core/Core/Indent.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
namespace Pure.DI.Core;

internal sealed class Indent
internal readonly struct Indent(int value)
{
private readonly string _str;

public Indent(int value)
{
Value = value;
_str = Formatting.IndentPrefix(this);
}

public int Value { get; set; }
public int Value { get; } = value;

public static implicit operator Indent(int value) => new(value);

public override string ToString() => _str;
public override string ToString() => Formatting.IndentPrefix(this);
}
60 changes: 34 additions & 26 deletions src/Pure.DI.Core/Core/LinesBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,13 @@
// ReSharper disable ReturnTypeCanBeEnumerable.Global
namespace Pure.DI.Core;

using System.Buffers;

internal sealed class LinesBuilder: IEnumerable<string>
{
private static readonly string[] Indents = new string[64];
private readonly StringBuilder _sb = new();
private readonly List<Line> _lines = [];
private readonly Indent _indent;

static LinesBuilder()
{
for (var i = 0; i < Indents.Length; i++)
{
Indents[i] = new Indent(i).ToString();
}
}
private Indent _indent;

public LinesBuilder(Indent indent) => _indent = new Indent(indent.Value - 1);

Expand Down Expand Up @@ -72,13 +65,13 @@ public IDisposable Indent(int value = 1)
public void IncIndent(int value = 1)
{
FlushLines();
_indent.Value += value;
_indent = new Indent(_indent.Value + 1);
}

public void DecIndent(int value = 1)
{
FlushLines();
_indent.Value -= value;
_indent = new Indent(_indent.Value - 1);
}

public IEnumerator<string> GetEnumerator()
Expand All @@ -87,28 +80,43 @@ public IEnumerator<string> GetEnumerator()
return _lines.Select(i => $"{GetIndent(i.Indent)}{i.Text}").GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

private void FlushLines()
public IDisposable SaveToArray(Encoding encoding, out byte[] buffer, out int size)
{
if (_sb.Length > 0)
var charCount = 0;
var newLine = Environment.NewLine;
foreach (var line in _lines)
{
AppendLine();
charCount += GetIndent(line.Indent).Length;
charCount += line.Text.Length;
charCount += newLine.Length;
}
}

private static string GetIndent(int indent)
{
if (indent < 1)
size = encoding.GetMaxByteCount(charCount);
var rent = ArrayPool<byte>.Shared.Rent(size);
buffer = rent;
var position = 0;
foreach (var line in _lines)
{
return string.Empty;
var indent = GetIndent(line.Indent);
position += encoding.GetBytes(indent, 0, indent.Length, buffer, position);
position += encoding.GetBytes(line.Text, 0, line.Text.Length, buffer, position);
position += encoding.GetBytes(newLine, 0, newLine.Length, buffer, position);
}

size = position;
return Disposables.Create(() => ArrayPool<byte>.Shared.Return(rent));
}

if (indent < Indents.Length)
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

private void FlushLines()
{
if (_sb.Length > 0)
{
return Indents[indent];
AppendLine();
}

return new Indent(indent).ToString();
}

private static string GetIndent(int indent) =>
new Indent(indent).ToString();
}
1 change: 1 addition & 0 deletions src/Pure.DI.Core/Core/Names.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ internal static class Names

// Local methods
public const string LocalMethodPrefix = "Local";
public const string EnsureExistsMethodNamePostfix = "EnsureExists";

// Fields
public static readonly string BucketsFieldName = $"_buckets{Salt}";
Expand Down

0 comments on commit 453a713

Please sign in to comment.