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

Fastpath #7

Merged
merged 2 commits into from
Jun 20, 2024
Merged

Fastpath #7

merged 2 commits into from
Jun 20, 2024

Conversation

alanmcgovern
Copy link
Owner

@alanmcgovern alanmcgovern commented Jun 20, 2024

When a ReusableTask continues from another ReusableTask we can
pass the StateMachineCache object directly as the continuation
to avoid creating an Action which points to the StateMachineCache.

This optimisation works for ReusableTask -> ReusableTask as well as ReusableTask<T> -> ReusableTask and ReusableTask -> ReusableTask<T>.

Additionally, this makes a bunch of Cache objects a little bit smaller
as they don't have to hold an Action object.

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22631
AMD Ryzen 5 5600U with Radeon Graphics, 1 CPU, 12 logical and 6 physical cores
.NET SDK=8.0.300
[Host] : .NET 6.0.30 (6.0.3024.21525), X64 RyuJIT
DefaultJob : .NET 6.0.30 (6.0.3024.21525), X64 RyuJIT

Before

Method Concurrency Depth Iterations Mean Error StdDev Median Gen 0 Gen 1 Allocated
ReusableTask 1 500 1000 64.40 ms 4.009 ms 11.757 ms 61.14 ms - - 32 KB
ReusableTaskInt 1 500 1000 40.76 ms 3.133 ms 8.733 ms 37.86 ms - - 32 KB
ValueTaskInt 1 500 1000 65.22 ms 1.281 ms 2.140 ms 65.50 ms 6300.0000 100.0000 51,452 KB
ReusableTask 4 500 1000 91.19 ms 3.628 ms 10.698 ms 92.22 ms - - 32 KB
ReusableTaskInt 4 500 1000 57.23 ms 2.273 ms 6.630 ms 57.10 ms - - 127 KB
ValueTaskInt 4 500 1000 154.20 ms 3.067 ms 5.835 ms 154.74 ms 22250.0000 1000.0000 182,428 KB

After

Method Concurrency Depth Iterations Mean Error StdDev Median Gen 0 Gen 1 Allocated
ReusableTask 1 500 1000 41.91 ms 1.705 ms 4.667 ms 41.04 ms - - 32 KB
ReusableTaskInt 1 500 1000 34.96 ms 5.059 ms 14.917 ms 33.78 ms - - 32 KB
ValueTaskInt 1 500 1000 61.91 ms 3.413 ms 9.738 ms 56.92 ms 6000.0000 - 49,869 KB
ReusableTask 4 500 1000 55.24 ms 2.077 ms 6.124 ms 54.68 ms - - 32 KB
ReusableTaskInt 4 500 1000 51.82 ms 2.425 ms 7.111 ms 51.74 ms - - 127 KB
ValueTaskInt 4 500 1000 157.49 ms 3.112 ms 8.199 ms 157.46 ms 22500.0000 1000.0000 182,908 KB

When a ReusableTask continues from another ReusableTask we can
pass the StateMachineCache object directly as the continuation
to avoid creating an Action which points to the StateMachineCache.

Additionally, this makes a bunch of Cache objects a little bit smaller
as they don't have to hold an Action object.

Before

// * Summary *

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22631
AMD Ryzen 5 5600U with Radeon Graphics, 1 CPU, 12 logical and 6 physical cores
.NET SDK=8.0.300
  [Host]     : .NET 6.0.30 (6.0.3024.21525), X64 RyuJIT
  DefaultJob : .NET 6.0.30 (6.0.3024.21525), X64 RyuJIT

|          Method | Concurrency | Depth | Iterations |      Mean |    Error |    StdDev |    Median |      Gen 0 |     Gen 1 |  Allocated |
|---------------- |------------ |------ |----------- |----------:|---------:|----------:|----------:|-----------:|----------:|-----------:|
|    ReusableTask |           1 |   500 |       1000 |  64.40 ms | 4.009 ms | 11.757 ms |  61.14 ms |          - |         - |      32 KB |
| ReusableTaskInt |           1 |   500 |       1000 |  40.76 ms | 3.133 ms |  8.733 ms |  37.86 ms |          - |         - |      32 KB |
|    ValueTaskInt |           1 |   500 |       1000 |  65.22 ms | 1.281 ms |  2.140 ms |  65.50 ms |  6300.0000 |  100.0000 |  51,452 KB |
|    ReusableTask |           4 |   500 |       1000 |  91.19 ms | 3.628 ms | 10.698 ms |  92.22 ms |          - |         - |      32 KB |
| ReusableTaskInt |           4 |   500 |       1000 |  57.23 ms | 2.273 ms |  6.630 ms |  57.10 ms |          - |         - |     127 KB |
|    ValueTaskInt |           4 |   500 |       1000 | 154.20 ms | 3.067 ms |  5.835 ms | 154.74 ms | 22250.0000 | 1000.0000 | 182,428 KB |

After

// * Summary *

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22631
AMD Ryzen 5 5600U with Radeon Graphics, 1 CPU, 12 logical and 6 physical cores
.NET SDK=8.0.300
  [Host]     : .NET 6.0.30 (6.0.3024.21525), X64 RyuJIT
  DefaultJob : .NET 6.0.30 (6.0.3024.21525), X64 RyuJIT

|          Method | Concurrency | Depth | Iterations |      Mean |    Error |    StdDev |    Median |      Gen 0 |     Gen 1 |  Allocated |
|---------------- |------------ |------ |----------- |----------:|---------:|----------:|----------:|-----------:|----------:|-----------:|
|    ReusableTask |           1 |   500 |       1000 |  41.91 ms | 1.705 ms |  4.667 ms |  41.04 ms |          - |         - |      32 KB |
| ReusableTaskInt |           1 |   500 |       1000 |  34.96 ms | 5.059 ms | 14.917 ms |  33.78 ms |          - |         - |      32 KB |
|    ValueTaskInt |           1 |   500 |       1000 |  61.91 ms | 3.413 ms |  9.738 ms |  56.92 ms |  6000.0000 |         - |  49,869 KB |
|    ReusableTask |           4 |   500 |       1000 |  55.24 ms | 2.077 ms |  6.124 ms |  54.68 ms |          - |         - |      32 KB |
| ReusableTaskInt |           4 |   500 |       1000 |  51.82 ms | 2.425 ms |  7.111 ms |  51.74 ms |          - |         - |     127 KB |
|    ValueTaskInt |           4 |   500 |       1000 | 157.49 ms | 3.112 ms |  8.199 ms | 157.46 ms | 22500.0000 | 1000.0000 | 182,908 KB |
AsyncVoidMethodBuilder has been updated to hide more of the
internal implementation, and allow for a fastpath to be implemented.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant