Skip to content

Commit

Permalink
fix: minor performance improvements
Browse files Browse the repository at this point in the history
Some small changes to make performance closer
to vanilla one
  • Loading branch information
Farenheith committed Nov 15, 2024
1 parent be4998b commit 54cd48f
Show file tree
Hide file tree
Showing 13 changed files with 126 additions and 64 deletions.
46 changes: 46 additions & 0 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# This is a basic workflow to help you get started with Actions

name: Benchmark
on:
pull_request:
branches: [main]

env:
ConnectionStrings__SqlConnection: ${{ secrets.CONNECTIONSTRINGS__SQLCONNECTION }}

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: "lts/*"
# Install the .NET SDK indicated in the global.json file
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
7.x.x
8.x.x
- name: Prepare Node
uses: actions/setup-node@v4
with:
node-version: "lts/*"

- name: Install dependencies
run: npm ci

# - name: Docker build
# run: npm run docker:build
# - name: Docker run
# run: npm run docker:run

- name: Test
uses: paambaati/[email protected]
env:
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
with:
coverageCommand: dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./coverage/lcov.info
coverageLocations: ${{github.workspace}}/test/Codibre.EnumerableExtensions.Branching.Test/coverage/lcov.net8.0.info:lcov
15 changes: 2 additions & 13 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

name: test
on:
pull_request:
branches: [main]
workflow_dispatch:

env:
ConnectionStrings__SqlConnection: ${{ secrets.CONNECTIONSTRINGS__SQLCONNECTION }}
Expand Down Expand Up @@ -32,15 +31,5 @@ jobs:
- name: Install dependencies
run: npm ci

# - name: Docker build
# run: npm run docker:build
# - name: Docker run
# run: npm run docker:run

- name: Test
uses: paambaati/[email protected]
env:
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
with:
coverageCommand: dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./coverage/lcov.info
coverageLocations: ${{github.workspace}}/test/Codibre.EnumerableExtensions.Branching.Test/coverage/lcov.net8.0.info:lcov
run: npm run benchmark
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
namespace Codibre.EnumerableExtensions.Branching;
public sealed class AsyncBranchingBuilder<T>(IAsyncEnumerable<T> source) : BaseBranchingBuilder<T>
{
private static readonly LinkedNode<T>? _null = null;
internal override LinkedNode<T> Iterate(int branchCount)
{
var enumerator = source.GetAsyncEnumerator();
return new(enumerator.Current, new(
async (c) => await enumerator.MoveNextAsync() ? new(enumerator.Current, c) : null,
async (c) => await enumerator.MoveNextAsync() ? new(enumerator.Current, c) : _null,
branchCount
));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ public sealed class BranchingBuilder<T>(IEnumerable<T> source) : BaseBranchingBu
internal override LinkedNode<T> Iterate(int branchCount)
{
var enumerator = source.GetEnumerator();
return new LinkedNode<T>(default!, new(
(c) => ValueTask.FromResult<LinkedNode<T>?>(enumerator.MoveNext() ? new(enumerator.Current, c) : null),
return new(default!, new(
(c) => new(enumerator.MoveNext() ? new LinkedNode<T>(enumerator.Current, c) : null),
branchCount
));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,5 @@ public static BaseBranchingBuilder<T> Add<T, R>(this BaseBranchingBuilder<T> bui
}

public static BaseBranchingBuilder<T> Add<T, R>(this BaseBranchingBuilder<T> builder, Func<IAsyncEnumerable<T>, ValueTask<R>> branch)
=> builder.Add(async (x) => await branch(x).AsTask());
public static BaseBranchingBuilder<T> Add<T, R>(this BaseBranchingBuilder<T> builder, Func<IAsyncEnumerable<T>, Task<R>> branch, out BranchResult<R> result)
{
var refResult = result = new();
return builder.Add(async (x) => refResult.Result = await branch(x));
}

public static BaseBranchingBuilder<T> Add<T, R>(this BaseBranchingBuilder<T> builder, Func<IAsyncEnumerable<T>, Task<R>> branch)
=> builder.Add(async (x) => await branch(x));
=> builder.Add((x) => branch(x).AsTask());
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
<TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>12</LangVersion>
<LangVersion>13</LangVersion>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/codibre/dotnet-enumerable.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,10 @@ internal sealed record BranchContext<T>(Func<BranchContext<T>, ValueTask<LinkedN
private ushort _count = 0;
private readonly ushort _limit = (ushort)int.Min(_branchCount << 14, ushort.MaxValue / 2);

internal async ValueTask<LinkedNode<T>?> FillNext()
internal ValueTask<LinkedNode<T>?> FillNext()
{
if (++_count > _limit)
{
_count = 0;
await Task.Yield();
}
return await GetNext(this);
if (++_count <= _limit) return GetNext(this);
_count = 0;
return new(Task.Run(() => GetNext(this).AsTask()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mime;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

namespace Codibre.EnumerableExtensions.Branching.Internal;

internal class BranchedEnumerable<T> : IAsyncEnumerable<T>
{
private readonly BranchedEnumerator<T> _enumerator;
public BranchedEnumerable(LinkedNode<T> root) => _enumerator = new(root);

public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default) => _enumerator;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mime;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

namespace Codibre.EnumerableExtensions.Branching.Internal;

internal class BranchedEnumerator<T> : IAsyncEnumerator<T>
{
private LinkedNode<T>? _node;
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
public BranchedEnumerator(LinkedNode<T> root) => _node = root;
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
public T Current { get; set; }

public ValueTask DisposeAsync() => ValueTask.CompletedTask;

public async ValueTask<bool> MoveNextAsync()
{
if (_node is null) return false;
_node = await _node.Next.Value;
if (_node is null) return false;
Current = _node.Value;
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,6 @@ namespace Codibre.EnumerableExtensions.Branching.Internal;

internal static class BranchingHelper
{
internal static async IAsyncEnumerable<T> GetBranchedIterable<T>(this LinkedNode<T> root)
{
var node = await root.Next.Value;
while (node is not null)
{
yield return node.Value;
node = await node.Next.Value;
}
}
internal static IAsyncEnumerable<T> GetBranchedIterable<T>(this LinkedNode<T> root)
=> new BranchedEnumerable<T>(root);
}
30 changes: 15 additions & 15 deletions test/Codibre.EnumerableExtensions.Branching.Benchmark/Benchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,22 @@ private IEnumerable<int> GetBaseEnumerable()
.AddOps(3)
.AddOps(4);

// [Benchmark]
// public void Separate()
// {
// GetBaseEnumerable().Min();
// GetBaseEnumerable().Max();
// GetBaseEnumerable().Average();
// }
[Benchmark]
public void Separate()
{
GetBaseEnumerable().Min();
GetBaseEnumerable().Max();
GetBaseEnumerable().Average();
}

// [Benchmark]
// public void ManualBranch()
// {
// var baseEnum = GetBaseEnumerable();
// baseEnum.Min();
// baseEnum.Max();
// baseEnum.Average();
// }
[Benchmark]
public void ManualBranch()
{
var baseEnum = GetBaseEnumerable();
baseEnum.Min();
baseEnum.Max();
baseEnum.Average();
}

[Benchmark]
public Task Branching() => GetBaseEnumerable()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
<TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<LangVersion>12</LangVersion>
<LangVersion>13</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2" />
<PackageReference Include="coverlet.msbuild" Version="6.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
<PackageReference Include="coverlet.msbuild" Version="6.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="6.12.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
Expand Down

0 comments on commit 54cd48f

Please sign in to comment.