Skip to content

Commit 69b0019

Browse files
authored
Benchmarks for Alternative Implementations, Inline, and InlineIfLambda (#166)
* benchmarks * update gitignore * Remove artifacts * Adds InlineIfLambda variants * Adds additional variations on benchmark * revert Result.fs * Adds bind CE and bind same benchmarks * Adding Task and Async Result CE benchmarks * First pass at InlineIfLambda with backwards compatability * formatting async.fc * Convert AsyncOption.fs to use InlineIfLambda * get tests running for each netstandard * Gets all tests working with correct TFM split * Update FAKE to fix CI * formatting * update dotnet-fable * AsyncOptionCE using inlineiflambda * Update CI to install dotnet versions * global json woes? * formatting * AsyncResult InlineIfLambda * AsyncResultCE and Op InlineIfLambda * AsyncResultOption InlineIfLambda * Option InlineIfLambda * formatting * Result InlineIfLambda * Validation InlineIfLambda * ValueOption inlineiflambda * AsyncSeq InlineIfLambda * Speedily added InlineIfLambda to Taskresult * speedily add InlineIfLambda to JobResult * warning cleanups * That fun CI wackahole part 1 * That fun CI wackahole * That fun CI wackahole * Move fake build to console app * Paket targets * no more need for double underscore in classes
1 parent f5019f1 commit 69b0019

File tree

86 files changed

+4336
-1184
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+4336
-1184
lines changed

.config/dotnet-tools.json

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,14 @@
22
"version": 1,
33
"isRoot": true,
44
"tools": {
5-
"fake-cli": {
6-
"version": "5.20.4",
7-
"commands": [
8-
"fake"
9-
]
10-
},
115
"paket": {
126
"version": "6.2.1",
137
"commands": [
148
"paket"
159
]
1610
},
1711
"fable": {
18-
"version": "3.4.9",
12+
"version": "3.7.1",
1913
"commands": [
2014
"fable"
2115
]

.github/workflows/build.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ jobs:
1919
uses: actions/setup-dotnet@v1
2020
with:
2121
dotnet-version: '3.1.x'
22+
- name: Use .NET Core 5.x SDK
23+
uses: actions/setup-dotnet@v1
24+
with:
25+
dotnet-version: '5.0.x'
2226
# Not specifying a version will attempt to install via global.json
2327
- name: Use .NET Core global.json
2428
uses: actions/setup-dotnet@v1

.gitignore

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,6 @@ flycheck_*.el
156156
x64/
157157
x86/
158158
bld/
159-
build/
160159
[Bb]in/
161160
[Oo]bj/
162161
[Ll]og/
@@ -382,7 +381,6 @@ FakesAssemblies/
382381
_Pvt_Extensions
383382

384383
# Paket dependency manager
385-
.paket
386384
paket-files/
387385

388386
# FAKE - F# Make
@@ -399,4 +397,8 @@ paket-files/
399397
fable_modules
400398
.fable
401399
*.fs.js
402-
js-dist/
400+
js-dist/
401+
402+
403+
# Benchmarks
404+
benchmarks/BenchmarkDotNet.Artifacts/

.paket/Paket.Restore.targets

Lines changed: 557 additions & 0 deletions
Large diffs are not rendered by default.

FsToolkit.ErrorHandling.sln

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FsToolkit.ErrorHandling.Asy
2727
EndProject
2828
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FsToolkit.ErrorHandling.AsyncSeq.Tests", "tests\FsToolkit.ErrorHandling.AsyncSeq.Tests\FsToolkit.ErrorHandling.AsyncSeq.Tests.fsproj", "{5DED3CA8-B331-4B48-A6A2-2EE1410437CA}"
2929
EndProject
30+
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "benchmarks", "benchmarks\benchmarks.fsproj", "{C5DF6347-D612-466B-B038-69474A35B51E}"
31+
EndProject
32+
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "build", "build\build.fsproj", "{18220329-75D6-4C30-BEEF-9401325F85EC}"
33+
EndProject
3034
Global
3135
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3236
Debug|Any CPU = Debug|Any CPU
@@ -148,6 +152,42 @@ Global
148152
{5DED3CA8-B331-4B48-A6A2-2EE1410437CA}.Release|x64.Build.0 = Release|Any CPU
149153
{5DED3CA8-B331-4B48-A6A2-2EE1410437CA}.Release|x86.ActiveCfg = Release|Any CPU
150154
{5DED3CA8-B331-4B48-A6A2-2EE1410437CA}.Release|x86.Build.0 = Release|Any CPU
155+
{AE58E4D7-57CC-413A-B566-1EE78C768B7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
156+
{AE58E4D7-57CC-413A-B566-1EE78C768B7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
157+
{AE58E4D7-57CC-413A-B566-1EE78C768B7A}.Debug|x64.ActiveCfg = Debug|Any CPU
158+
{AE58E4D7-57CC-413A-B566-1EE78C768B7A}.Debug|x64.Build.0 = Debug|Any CPU
159+
{AE58E4D7-57CC-413A-B566-1EE78C768B7A}.Debug|x86.ActiveCfg = Debug|Any CPU
160+
{AE58E4D7-57CC-413A-B566-1EE78C768B7A}.Debug|x86.Build.0 = Debug|Any CPU
161+
{AE58E4D7-57CC-413A-B566-1EE78C768B7A}.Release|Any CPU.ActiveCfg = Release|Any CPU
162+
{AE58E4D7-57CC-413A-B566-1EE78C768B7A}.Release|Any CPU.Build.0 = Release|Any CPU
163+
{AE58E4D7-57CC-413A-B566-1EE78C768B7A}.Release|x64.ActiveCfg = Release|Any CPU
164+
{AE58E4D7-57CC-413A-B566-1EE78C768B7A}.Release|x64.Build.0 = Release|Any CPU
165+
{AE58E4D7-57CC-413A-B566-1EE78C768B7A}.Release|x86.ActiveCfg = Release|Any CPU
166+
{AE58E4D7-57CC-413A-B566-1EE78C768B7A}.Release|x86.Build.0 = Release|Any CPU
167+
{C5DF6347-D612-466B-B038-69474A35B51E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
168+
{C5DF6347-D612-466B-B038-69474A35B51E}.Debug|Any CPU.Build.0 = Debug|Any CPU
169+
{C5DF6347-D612-466B-B038-69474A35B51E}.Debug|x64.ActiveCfg = Debug|Any CPU
170+
{C5DF6347-D612-466B-B038-69474A35B51E}.Debug|x64.Build.0 = Debug|Any CPU
171+
{C5DF6347-D612-466B-B038-69474A35B51E}.Debug|x86.ActiveCfg = Debug|Any CPU
172+
{C5DF6347-D612-466B-B038-69474A35B51E}.Debug|x86.Build.0 = Debug|Any CPU
173+
{C5DF6347-D612-466B-B038-69474A35B51E}.Release|Any CPU.ActiveCfg = Release|Any CPU
174+
{C5DF6347-D612-466B-B038-69474A35B51E}.Release|Any CPU.Build.0 = Release|Any CPU
175+
{C5DF6347-D612-466B-B038-69474A35B51E}.Release|x64.ActiveCfg = Release|Any CPU
176+
{C5DF6347-D612-466B-B038-69474A35B51E}.Release|x64.Build.0 = Release|Any CPU
177+
{C5DF6347-D612-466B-B038-69474A35B51E}.Release|x86.ActiveCfg = Release|Any CPU
178+
{C5DF6347-D612-466B-B038-69474A35B51E}.Release|x86.Build.0 = Release|Any CPU
179+
{18220329-75D6-4C30-BEEF-9401325F85EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
180+
{18220329-75D6-4C30-BEEF-9401325F85EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
181+
{18220329-75D6-4C30-BEEF-9401325F85EC}.Debug|x64.ActiveCfg = Debug|Any CPU
182+
{18220329-75D6-4C30-BEEF-9401325F85EC}.Debug|x64.Build.0 = Debug|Any CPU
183+
{18220329-75D6-4C30-BEEF-9401325F85EC}.Debug|x86.ActiveCfg = Debug|Any CPU
184+
{18220329-75D6-4C30-BEEF-9401325F85EC}.Debug|x86.Build.0 = Debug|Any CPU
185+
{18220329-75D6-4C30-BEEF-9401325F85EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
186+
{18220329-75D6-4C30-BEEF-9401325F85EC}.Release|Any CPU.Build.0 = Release|Any CPU
187+
{18220329-75D6-4C30-BEEF-9401325F85EC}.Release|x64.ActiveCfg = Release|Any CPU
188+
{18220329-75D6-4C30-BEEF-9401325F85EC}.Release|x64.Build.0 = Release|Any CPU
189+
{18220329-75D6-4C30-BEEF-9401325F85EC}.Release|x86.ActiveCfg = Release|Any CPU
190+
{18220329-75D6-4C30-BEEF-9401325F85EC}.Release|x86.Build.0 = Release|Any CPU
151191
EndGlobalSection
152192
GlobalSection(NestedProjects) = preSolution
153193
{E0466000-F8E4-416B-B605-C65F7602367A} = {E28025A7-EF6A-45BF-8FA0-75E394D3D42B}

benchmarks/AsyncResultCE.fs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
namespace FsToolkit.ErrorHandling.Benchmarks
2+
3+
open System
4+
open BenchmarkDotNet
5+
open BenchmarkDotNet.Attributes
6+
open FsToolkit.ErrorHandling
7+
module AsyncResultCE =
8+
9+
10+
type AsyncResultInlinedLambdaBuilder() =
11+
12+
member _.Return(value: 'T) : Async<Result<'T, 'TError>> = async.Return <| result.Return value
13+
14+
member inline _.ReturnFrom(asyncResult: Async<Result<'T, 'TError>>) : Async<Result<'T, 'TError>> = asyncResult
15+
16+
member _.Zero() : Async<Result<unit, 'TError>> = async.Return <| result.Zero()
17+
18+
member inline _.Bind
19+
(
20+
asyncResult: Async<Result<'T, 'TError>>,
21+
[<InlineIfLambda>] binder: 'T -> Async<Result<'U, 'TError>>
22+
) : Async<Result<'U, 'TError>> =
23+
async.Bind(asyncResult, fun r ->
24+
match r with
25+
| Ok x -> binder x
26+
| Error e -> Error e |> async.Return
27+
)
28+
member inline _.Delay([<InlineIfLambda>] generator: unit -> Async<Result<'T, 'TError>>) : Async<Result<'T, 'TError>> =
29+
async.Delay generator
30+
31+
/// <summary>
32+
/// Method lets us transform data types into our internal representation. This is the identity method to recognize the self type.
33+
///
34+
/// See https://stackoverflow.com/questions/35286541/why-would-you-use-builder-source-in-a-custom-computation-expression-builder
35+
/// </summary>
36+
member inline _.Source(result: Async<Result<_, _>>) : Async<Result<_, _>> = result
37+
open AsyncResultCE
38+
39+
40+
41+
42+
[<AutoOpen>]
43+
// Having members as extensions gives them lower priority in
44+
// overload resolution and allows skipping more type annotations.
45+
module AsyncResultCEExtensions =
46+
47+
type AsyncResultInlinedLambdaBuilder with
48+
/// <summary>
49+
/// Needed to allow `for..in` and `for..do` functionality
50+
/// </summary>
51+
member inline _.Source(s: #seq<_>) = s
52+
53+
/// <summary>
54+
/// Method lets us transform data types into our internal representation.
55+
/// </summary>
56+
member inline _.Source(result: Result<_, _>) : Async<Result<_, _>> = Async.singleton result
57+
let rec fib n =
58+
if n < 2L then n
59+
else fib (n - 1L) + fib (n - 2L)
60+
61+
let rec afib (n, level) = async {
62+
if n < 0L then return Error "No"
63+
elif n < 2L then
64+
return Ok n
65+
elif n < level then
66+
return Ok (fib n)
67+
else
68+
let! n2a = afib (n-2L, level) |> Async.StartChild
69+
let! n1 = afib (n-1L, level)
70+
let! n2 = n2a
71+
match n1, n2 with
72+
| Ok n1, Ok n2 ->
73+
return Ok (n2 + n1)
74+
| Error e, _
75+
| _, Error e -> return Error e
76+
}
77+
let asyncResultInlinedIfLambda = AsyncResultInlinedLambdaBuilder()
78+
79+
[<MemoryDiagnoser>]
80+
type AsyncResult_BindCEBenchmarks () =
81+
82+
[<Benchmark(Baseline = true)>]
83+
member this.afib() =
84+
afib(10,5)
85+
|> Async.StartAsTask
86+
87+
[<Benchmark>]
88+
member this.Result_Normal_Bind_CE() =
89+
let action () = asyncResult {
90+
let! a = Ok 10
91+
let! b = Ok 5
92+
let! c = afib(a, b)
93+
return c
94+
}
95+
action ()
96+
|> Async.StartAsTask
97+
98+
99+
[<Benchmark>]
100+
member this.Result_Alt_Inlined_Bind_CE () =
101+
let action () = asyncResultInlinedIfLambda {
102+
let! a = Ok 10
103+
let! b = Ok 5
104+
let! c = afib(a, b)
105+
return c
106+
}
107+
action ()
108+
|> Async.StartAsTask

0 commit comments

Comments
 (0)