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 8c3d95d
Show file tree
Hide file tree
Showing 16 changed files with 126 additions and 55 deletions.
36 changes: 36 additions & 0 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# This is a basic workflow to help you get started with Actions

name: Benchmark
on:
workflow_dispatch:

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
9.x.x
- name: Prepare Node
uses: actions/setup-node@v4
with:
node-version: "lts/*"

- name: Install dependencies
run: npm ci

- name: Test
run: npm run benchmark
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
dotnet-version: |
7.x.x
8.x.x
9.x.x
- name: Install dependencies
run: npm ci
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ jobs:
dotnet-version: |
7.x.x
8.x.x
9.x.x
- name: install
run: npm ci
- name: Lint
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/semantic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ jobs:
dotnet-version: |
7.x.x
8.x.x
9.x.x
- name: Prepare Node
uses: actions/setup-node@v4
Expand All @@ -41,7 +42,7 @@ jobs:
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
coverageLocations: ${{github.workspace}}/test/Codibre.EnumerableExtensions.Branching.Test/coverage/lcov.net9.0.info:lcov

- name: Semantic Release
run: npm i -g @semantic-release/changelog @semantic-release/commit-analyzer @semantic-release/git @semantic-release/github @semantic-release/exec @droidsolutions-oss/semantic-release-nuget @semantic-release/release-notes-generator semantic-release @semantic-release/error
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This is a basic workflow to help you get started with Actions

name: test
name: Test
on:
pull_request:
branches: [main]
Expand All @@ -23,6 +23,7 @@ jobs:
dotnet-version: |
7.x.x
8.x.x
9.x.x
- name: Prepare Node
uses: actions/setup-node@v4
Expand All @@ -43,4 +44,4 @@ jobs:
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
coverageLocations: ${{github.workspace}}/test/Codibre.EnumerableExtensions.Branching.Test/coverage/lcov.net9.0.info:lcov
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 @@ -6,15 +6,15 @@ namespace Codibre.EnumerableExtensions.Branching.Internal;
internal sealed record BranchContext<T>(Func<BranchContext<T>, ValueTask<LinkedNode<T>?>> GetNext, int _branchCount)
{
private ushort _count = 0;
private readonly ushort _limit = (ushort)int.Min(_branchCount << 14, ushort.MaxValue / 2);
private readonly ushort _limit = 1024;

internal async ValueTask<LinkedNode<T>?> FillNext()
internal ValueTask<LinkedNode<T>?> FillNext()
=> ++_count <= _limit ? GetNext(this) : GetYielded();

private async ValueTask<LinkedNode<T>?> GetYielded()
{
if (++_count > _limit)
{
_count = 0;
await Task.Yield();
}
_count = 0;
await Task.Yield();
return await GetNext(this);
}
}
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);
}
32 changes: 16 additions & 16 deletions test/Codibre.EnumerableExtensions.Branching.Benchmark/Benchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,30 @@ public static IEnumerable<int> AddOps(this IEnumerable<int> source, int value)

public class Benchmarks
{
[Params(100)] //, 1000, 10000)]
[Params(100, 1000, 10000)]
public int _size = 100;
private IEnumerable<int> GetBaseEnumerable()
=> Enumerable.Range(0, _size)
.AddOps(2)
.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 8c3d95d

Please sign in to comment.