Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize Tasks collections in .Net 9 #7585

Merged
merged 25 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
bd29127
Switch to .NET 9
rubo Sep 14, 2024
35bcaac
Update packages
rubo Sep 19, 2024
8d2f24b
Merge branch 'master' into feature/dotnet9-migration
rubo Sep 21, 2024
f9455ea
Update Docker files
rubo Sep 26, 2024
2a30f62
Merge branch 'master' into feature/dotnet9-migration
rubo Sep 26, 2024
35976d5
Merge branch 'master' into feature/dotnet9-migration
rubo Sep 30, 2024
bd43063
Update tools' target framework
rubo Oct 7, 2024
a83afee
Merge branch 'master' into feature/dotnet9-migration
rubo Oct 7, 2024
e5eac31
Merge branch 'master' into feature/dotnet9-migration
rubo Oct 10, 2024
ea2f47c
Add `Directory.Build.props` to tools
rubo Oct 10, 2024
4e7b370
Merge branch 'master' into feature/dotnet9-migration
rubo Oct 10, 2024
2e6d4c5
Optimize Tasks collections in .Net 9
LukaszRozmej Oct 10, 2024
351b80a
use in test
LukaszRozmej Oct 10, 2024
e000fe0
Remove redundant `$TARGETPLATFORM`
rubo Oct 11, 2024
082149f
Update packages
rubo Oct 14, 2024
e08e3f6
Merge remote-tracking branch 'origin/master' into feature/dotnet9-mig…
asdacap Oct 17, 2024
cbf6204
Remove to array
asdacap Oct 18, 2024
c867b90
Merge remote-tracking branch 'origin/master' into feature/dotnet9-mig…
asdacap Oct 18, 2024
3558986
Merge branch 'feature/dotnet9-migration' into feature/dotnet9-migrati…
asdacap Oct 18, 2024
da5da85
Use span
asdacap Oct 18, 2024
3eb0e3b
Fix build
asdacap Oct 18, 2024
54f79c0
Merge remote-tracking branch 'origin/master' into feature/dotnet9-mig…
LukaszRozmej Nov 19, 2024
526371c
fix merge
LukaszRozmej Nov 20, 2024
8ff1fd7
one more pooled list from enumerable
LukaszRozmej Nov 20, 2024
1f84821
Merge branch 'master' into feature/dotnet9-migration-optimize-tasks
LukaszRozmej Nov 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
# SPDX-License-Identifier: LGPL-3.0-only

FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-noble AS build
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:9.0-noble AS build

ARG BUILD_CONFIG=release
ARG BUILD_TIMESTAMP
Expand All @@ -18,7 +18,7 @@ RUN arch=$([ "$TARGETARCH" = "amd64" ] && echo "x64" || echo "$TARGETARCH") && \
# A temporary symlink to support the old executable name
RUN ln -s -r /publish/nethermind /publish/Nethermind.Runner

FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/aspnet:8.0-noble
FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/aspnet:9.0-noble

WORKDIR /nethermind

Expand Down
4 changes: 2 additions & 2 deletions Dockerfile.chiseled
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
# SPDX-License-Identifier: LGPL-3.0-only

FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-noble AS build
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:9.0-noble AS build

ARG BUILD_CONFIG=release
ARG BUILD_TIMESTAMP
Expand All @@ -21,7 +21,7 @@ RUN cd /publish && \
mkdir logs && \
mkdir nethermind_db

FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/aspnet:8.0-noble-chiseled
FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/aspnet:9.0-noble-chiseled

WORKDIR /nethermind

Expand Down
4 changes: 2 additions & 2 deletions Dockerfile.diag
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
# SPDX-License-Identifier: LGPL-3.0-only

FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-noble AS build
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:9.0-noble AS build

ARG BUILD_CONFIG=release
ARG BUILD_TIMESTAMP
Expand All @@ -22,7 +22,7 @@ RUN dotnet tool install -g dotnet-dump && \
dotnet tool install -g dotnet-trace && \
dotnet tool install -g JetBrains.dotTrace.GlobalTools

FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/aspnet:8.0-noble
FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/aspnet:9.0-noble

WORKDIR /nethermind

Expand Down
4 changes: 2 additions & 2 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"sdk": {
"version": "8.0.0",
"allowPrerelease": false,
"version": "9.0.0",
"allowPrerelease": true,
"rollForward": "latestFeature"
}
}
4 changes: 2 additions & 2 deletions src/Nethermind/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
<ContinuousIntegrationBuild Condition="'$(CI)' == 'true'">true</ContinuousIntegrationBuild>
<LangVersion>latest</LangVersion>
<TargetFramework>net8.0</TargetFramework>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<TargetFramework>net9.0</TargetFramework>
<!--<TreatWarningsAsErrors>true</TreatWarningsAsErrors>-->
<UseArtifactsOutput>true</UseArtifactsOutput>
</PropertyGroup>

Expand Down
16 changes: 8 additions & 8 deletions src/Nethermind/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
<PackageVersion Include="HexMate" Version="0.0.3" />
<PackageVersion Include="Jint" Version="2.11.58" />
<PackageVersion Include="MathNet.Numerics.FSharp" Version="5.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection" Version="8.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection.Extensions" Version="8.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection.Extensions" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.Build.Tasks.Git" Version="8.0.0" />
<PackageVersion Include="Microsoft.ClearScript.V8" Version="7.4.5" />
<PackageVersion Include="Microsoft.ClearScript.V8.Native.linux-arm64" Version="7.4.5" />
Expand All @@ -37,9 +37,9 @@
<PackageVersion Include="Microsoft.ClearScript.V8.Native.win-x64" Version="7.4.5" />
<PackageVersion Include="McMaster.Extensions.CommandLineUtils" Version="4.1.1" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.ObjectPool" Version="8.0.7" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.ObjectPool" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.0.1" />
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
Expand Down Expand Up @@ -72,10 +72,10 @@
<PackageVersion Include="SCrypt" Version="2.0.0.2" />
<PackageVersion Include="Shouldly" Version="4.2.1" />
<PackageVersion Include="Snappier" Version="1.1.6" />
<PackageVersion Include="System.Configuration.ConfigurationManager" Version="8.0.0" />
<PackageVersion Include="System.IO.Pipelines" Version="8.0.0" />
<PackageVersion Include="System.Configuration.ConfigurationManager" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="System.IO.Pipelines" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="System.Linq.Async" Version="6.0.1" />
<PackageVersion Include="System.Security.Cryptography.ProtectedData" Version="8.0.0" />
<PackageVersion Include="System.Security.Cryptography.ProtectedData" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="TestableIO.System.IO.Abstractions.TestingHelpers" Version="21.0.29" />
<PackageVersion Include="TestableIO.System.IO.Abstractions.Wrappers" Version="21.0.29" />
<PackageVersion Include="Websocket.Client" Version="5.1.2" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ public async Task StopAsync(bool processRemainingBlocks = false)
_blockQueue.CompleteAdding();
}

await Task.WhenAll((_recoveryTask ?? Task.CompletedTask), (_processorTask ?? Task.CompletedTask));
await Task.WhenAll(_recoveryTask ?? Task.CompletedTask, _processorTask ?? Task.CompletedTask);
if (_logger.IsInfo) _logger.Info("Blockchain Processor shutdown complete.. please wait for all components to close");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Threading;
using System.Threading.Tasks;
using Nethermind.Core;
using Nethermind.Core.Collections;
using Nethermind.Evm.Tracing;
using Nethermind.Logging;

Expand All @@ -32,23 +33,20 @@ protected MultipleBlockProducer(
public async Task<Block?> BuildBlock(BlockHeader? parentHeader, IBlockTracer? blockTracer = null,
PayloadAttributes? payloadAttributes = null, CancellationToken? token = null)
{
Task<Block?>[] produceTasks = new Task<Block?>[_blockProducers.Length];
using ArrayPoolList<Task<Block>> produceTasks = new(_blockProducers.Length);
for (int i = 0; i < _blockProducers.Length; i++)
{
T blockProducerInfo = _blockProducers[i];
if (!blockProducerInfo.Condition.CanProduce(parentHeader))
{
produceTasks[i] = Task.FromResult<Block?>(null);
continue;
}
produceTasks[i] = blockProducerInfo.BlockProducer.BuildBlock(parentHeader, blockProducerInfo.BlockTracer, cancellationToken: token);
produceTasks.Add(!blockProducerInfo.Condition.CanProduce(parentHeader!)
? Task.FromResult<Block?>(null)
: blockProducerInfo.BlockProducer.BuildBlock(parentHeader, blockProducerInfo.BlockTracer, cancellationToken: token));
}

IEnumerable<(Block? Block, T BlockProducer)> blocksWithProducers;

try
{
Block?[] blocks = await Task.WhenAll(produceTasks);
Block?[] blocks = await Task.WhenAll<Block?>(produceTasks.AsSpan());
blocksWithProducers = blocks.Zip(_blockProducers);
}
catch (OperationCanceledException)
Expand Down
13 changes: 6 additions & 7 deletions src/Nethermind/Nethermind.Core.Test/Encoding/TxDecoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Threading.Tasks;
using FluentAssertions;
using FluentAssertions.Numeric;
using Nethermind.Core.Collections;
using Nethermind.Core.Crypto;
using Nethermind.Core.Eip2930;
using Nethermind.Core.Extensions;
Expand Down Expand Up @@ -68,7 +69,7 @@ public class TxDecoderTests

[TestCaseSource(nameof(TestCaseSource))]
[Repeat(10)] // Might wanna increase this to double check when changing logic as on lower value, it does not reproduce.
public void CanCorrectlyCalculateTxHash_when_called_concurrently((Transaction Tx, string Description) testCase)
public async Task CanCorrectlyCalculateTxHash_when_called_concurrently((Transaction Tx, string Description) testCase)
{
Transaction tx = testCase.Tx;

Expand All @@ -80,14 +81,12 @@ public void CanCorrectlyCalculateTxHash_when_called_concurrently((Transaction Tx

decodedTx.SetPreHash(rlp.Bytes);

IEnumerable<Task<AndConstraint<ComparableTypeAssertions<Hash256>>>> tasks = Enumerable
using ArrayPoolList<Task<AndConstraint<ComparableTypeAssertions<Hash256>>>> tasks = Enumerable
.Range(0, 32)
.Select((_) =>
Task.Factory
.StartNew(() => decodedTx.Hash.Should().Be(expectedHash),
TaskCreationOptions.RunContinuationsAsynchronously));
.Select(_ => Task.Factory.StartNew(() => decodedTx.Hash.Should().Be(expectedHash), TaskCreationOptions.RunContinuationsAsynchronously))
.ToPooledList(32);

Task.WaitAll(tasks.ToArray());
await Task.WhenAll<AndConstraint<ComparableTypeAssertions<Hash256>>>(tasks.AsSpan());
}

[TestCaseSource(nameof(TestCaseSource))]
Expand Down
22 changes: 8 additions & 14 deletions src/Nethermind/Nethermind.Core/PubSub/CompositePublisher.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,28 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Threading.Tasks;
using Nethermind.Core.Collections;

namespace Nethermind.Core.PubSub
{
public class CompositePublisher : IPublisher
public class CompositePublisher(params IPublisher[] publishers) : IPublisher
{
private readonly IPublisher[] _publishers;

public CompositePublisher(params IPublisher[] publishers)
{
_publishers = publishers;
}

public async Task PublishAsync<T>(T data) where T : class
{
// TODO: .Net 9 stackalloc
Task[] tasks = new Task[_publishers.Length];
for (int i = 0; i < _publishers.Length; i++)
using ArrayPoolList<Task> tasks = new(publishers.Length);
for (int i = 0; i < publishers.Length; i++)
{
tasks[i] = _publishers[i].PublishAsync(data);
tasks.Add(publishers[i].PublishAsync(data));
}

await Task.WhenAll(tasks);
await Task.WhenAll(tasks.AsSpan());
}

public void Dispose()
{
foreach (IPublisher publisher in _publishers)
foreach (IPublisher publisher in publishers)
{
publisher.Dispose();
}
Expand Down
7 changes: 4 additions & 3 deletions src/Nethermind/Nethermind.Db/RocksDbInitializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Nethermind.Core.Collections;

namespace Nethermind.Db
{
Expand Down Expand Up @@ -68,13 +69,13 @@ protected void InitAll()

protected async Task InitAllAsync()
{
HashSet<Task> allInitializers = new();
foreach (var registration in _registrations)
using ArrayPoolList<Task> allInitializers = new(_registrations.Count);
foreach (Action registration in _registrations)
{
allInitializers.Add(Task.Run(() => registration.Invoke()));
}

await Task.WhenAll(allInitializers);
await Task.WhenAll(allInitializers.AsSpan());
}

protected static string GetTitleDbName(string dbName) => char.ToUpper(dbName[0]) + dbName[1..];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace Nethermind.Evm.Test.Tracing;
[TestFixture]
public class GethLikeCallTracerTests : VirtualMachineTestsBase
{
private static readonly JsonSerializerOptions SerializerOptions = EthereumJsonSerializer.JsonOptionsIndented;
private static readonly JsonSerializerOptions SerializerOptions = new(EthereumJsonSerializer.JsonOptionsIndented) { NewLine = "\n" };
private const string? WithLog = """{"withLog":true}""";
private const string? OnlyTopCall = """{"onlyTopCall":true}""";
private const string? WithLogAndOnlyTopCall = """{"withLog":true,"onlyTopCall":true}""";
Expand All @@ -27,14 +27,8 @@ private string ExecuteCallTrace(byte[] code, string? tracerConfig = null)
(_, Transaction tx) = PrepareTx(MainnetSpecProvider.CancunActivation, 100000, code);
NativeCallTracer tracer = new(tx, GetGethTraceOptions(tracerConfig));

GethLikeTxTrace callTrace = Execute(
tracer,
code,
MainnetSpecProvider.CancunActivation)
.BuildResult();
return JsonSerializer.Serialize(callTrace.CustomTracerResult?.Value, SerializerOptions)
// fix for windows, can be done better in .NET 9: https://github.com/dotnet/runtime/issues/84117
.ReplaceLineEndings("\n");
GethLikeTxTrace callTrace = Execute(tracer, code, MainnetSpecProvider.CancunActivation).BuildResult();
return JsonSerializer.Serialize(callTrace.CustomTracerResult?.Value, SerializerOptions);
}

private static GethTraceOptions GetGethTraceOptions(string? config) => GethTraceOptions.Default with
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
Expand Down
6 changes: 4 additions & 2 deletions src/Nethermind/Nethermind.Network.Discovery/NodesLocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

using System.Text;
using Nethermind.Core;
using Nethermind.Core.Collections;
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
using Nethermind.Logging;
using Nethermind.Network.Discovery.Lifecycle;
using Nethermind.Network.Discovery.Messages;
Expand Down Expand Up @@ -128,8 +130,8 @@ public async Task LocateNodesAsync(byte[]? searchedNodeId, CancellationToken can
int count = failRequestCount > 0 ? failRequestCount : _discoveryConfig.Concurrency;
IEnumerable<Node> nodesToSend = tryCandidates.Skip(nodesTriedCount).Take(count);

IEnumerable<Task<Result>> sendFindNodeTasks = SendFindNodes(searchedNodeId, nodesToSend, alreadyTriedNodes);
Result?[] results = await Task.WhenAll(sendFindNodeTasks);
using ArrayPoolList<Task<Result>> sendFindNodeTasks = SendFindNodes(searchedNodeId, nodesToSend, alreadyTriedNodes).ToPooledList(count);
Result[] results = await Task.WhenAll<Result>(sendFindNodeTasks.AsSpan());

if (results.Length == 0)
{
Expand Down
9 changes: 5 additions & 4 deletions src/Nethermind/Nethermind.Network/CompositeNodeSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using Nethermind.Core.Collections;
using Nethermind.Core.Extensions;
using Nethermind.Stats.Model;

namespace Nethermind.Network;
Expand All @@ -20,14 +22,13 @@ public async IAsyncEnumerable<Node> DiscoverNodes([EnumeratorCancellation] Cance
{
Channel<Node> ch = Channel.CreateBounded<Node>(1);

// TODO: .Net 9 stackalloc
Task[] feedTasks = _nodeSources.Select(async innerSource =>
using ArrayPoolList<Task> feedTasks = _nodeSources.Select(async innerSource =>
{
await foreach (Node node in innerSource.DiscoverNodes(cancellationToken))
{
await ch.Writer.WriteAsync(node, cancellationToken);
}
}).ToArray();
}).ToPooledList(_nodeSources.Length * 16);

try
{
Expand All @@ -38,7 +39,7 @@ public async IAsyncEnumerable<Node> DiscoverNodes([EnumeratorCancellation] Cance
}
finally
{
await Task.WhenAll(feedTasks);
await Task.WhenAll(feedTasks.AsSpan());
}
}

Expand Down
8 changes: 5 additions & 3 deletions src/Nethermind/Nethermind.Network/PeerManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
using FastEnumUtility;
using Nethermind.Core;
using Nethermind.Core.Attributes;
using Nethermind.Core.Collections;
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
using Nethermind.Logging;
using Nethermind.Network.Config;
using Nethermind.Network.P2P;
Expand Down Expand Up @@ -206,7 +208,7 @@ private class CandidateSelection
private async Task RunPeerUpdateLoop()
{
Channel<Peer> taskChannel = Channel.CreateBounded<Peer>(1);
List<Task>? tasks = Enumerable.Range(0, _outgoingConnectParallelism).Select(async (idx) =>
using ArrayPoolList<Task> tasks = Enumerable.Range(0, _outgoingConnectParallelism).Select(async idx =>
{
await foreach (Peer peer in taskChannel.Reader.ReadAllAsync(_cancellationTokenSource.Token))
{
Expand All @@ -226,7 +228,7 @@ private async Task RunPeerUpdateLoop()
}
}
if (_logger.IsDebug) _logger.Debug($"Connect worker {idx} completed");
}).ToList();
}).ToPooledList(_outgoingConnectParallelism);

int loopCount = 0;
long previousActivePeersCount = 0;
Expand Down Expand Up @@ -359,7 +361,7 @@ private async Task RunPeerUpdateLoop()
}

taskChannel.Writer.Complete();
await Task.WhenAll(tasks);
await Task.WhenAll(tasks.AsSpan());
}

private bool EnsureAvailableActivePeerSlot()
Expand Down
Loading