Bench #14

Merged
patrick merged 1 commits from bench into main 2023-12-12 21:03:51 +00:00
6 changed files with 402 additions and 9 deletions

View File

@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="Run.fs" />
<Compile Include="Inputs.fs" />
<Compile Include="Program.fs"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.11" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AdventOfCode2023.FSharp.Lib\AdventOfCode2023.FSharp.Lib.fsproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,19 @@
namespace AdventOfCode2023
open System.IO
open System.Reflection
[<RequireQualifiedAccess>]
module Inputs =
let days =
let mutable dir = Assembly.GetEntryAssembly().Location |> FileInfo |> _.Directory
while not (dir.EnumerateDirectories () |> Seq.exists (fun i -> i.Name = "inputs")) do
dir <- dir.Parent
if isNull dir then
failwith "reached root of filesystem without finding inputs dir"
Array.init 12 (fun day -> Path.Combine (dir.FullName, "inputs", $"day%i{day + 1}.txt") |> File.ReadAllText)
let inline day (i : int) = days.[i - 1]

View File

@@ -0,0 +1,70 @@
namespace AdventOfCode2023
open BenchmarkDotNet.Attributes
open BenchmarkDotNet.Configs
open BenchmarkDotNet.Running
module Benchmarks =
type Benchmark1To5 () =
[<GlobalSetup>]
member _.Setup () = Run.shouldWrite <- false
[<Params(1, 2, 3, 4, 5)>]
member val Day = 0 with get, set
[<Params(false, true)>]
member val IsPartOne = false with get, set
[<Benchmark>]
member this.Benchmark () : unit =
Run.allRuns.[this.Day - 1] (not this.IsPartOne) (Inputs.day this.Day)
[<GlobalCleanup>]
member _.Cleanup () = Run.shouldWrite <- true
type Benchmark6To10 () =
[<GlobalSetup>]
member _.Setup () = Run.shouldWrite <- false
[<Params(6, 7, 8, 9, 10)>]
member val Day = 0 with get, set
[<Params(false, true)>]
member val IsPartOne = false with get, set
[<Benchmark>]
member this.Benchmark () : unit =
Run.allRuns.[this.Day - 1] (not this.IsPartOne) (Inputs.day this.Day)
[<GlobalCleanup>]
member _.Cleanup () = Run.shouldWrite <- true
type Benchmark11To15 () =
[<GlobalSetup>]
member _.Setup () = Run.shouldWrite <- false
[<Params(11, 12)>]
member val Day = 0 with get, set
[<Params(false, true)>]
member val IsPartOne = false with get, set
[<Benchmark>]
member this.Benchmark () : unit =
Run.allRuns.[this.Day - 1] (not this.IsPartOne) (Inputs.day this.Day)
[<GlobalCleanup>]
member _.Cleanup () = Run.shouldWrite <- true
module Program =
[<EntryPoint>]
let main args =
let config =
ManualConfig.Create(DefaultConfig.Instance).WithOptions ConfigOptions.DisableOptimizationsValidator
let _summary = BenchmarkRunner.Run<Benchmarks.Benchmark1To5> config
let _summary = BenchmarkRunner.Run<Benchmarks.Benchmark6To10> config
let _summary = BenchmarkRunner.Run<Benchmarks.Benchmark11To15> config
0

View File

@@ -0,0 +1,190 @@
namespace AdventOfCode2023
#if DEBUG
#else
#nowarn "9"
#endif
open System
[<RequireQualifiedAccess>]
module Run =
let mutable shouldWrite = true
let day1 (partTwo : bool) (input : string) =
if not partTwo then
let output = Day1.part1 input
if shouldWrite then
Console.WriteLine output
else
let output = Day1.part2 input
if shouldWrite then
Console.WriteLine output
let day2 (partTwo : bool) (input : string) =
if not partTwo then
let output = Day2.part1 input
if shouldWrite then
Console.WriteLine output
else
let output = Day2.part2 input
if shouldWrite then
Console.WriteLine output
let day3 (partTwo : bool) (input : string) =
let resultArr, len, lineCount = Day3.parse (input.ToCharArray () |> Array.map byte)
#if DEBUG
let contents =
{
Elements = Array.take len resultArr
Width = len / lineCount
}
#else
use ptr = fixed resultArr
let contents =
{
Elements = ptr
Length = len
Width = len / lineCount
}
#endif
if not partTwo then
let output = Day3.part1 contents
if shouldWrite then
Console.WriteLine output
else
let output = Day3.part2 contents
if shouldWrite then
Console.WriteLine output
let day4 (partTwo : bool) (input : string) =
if not partTwo then
let output = Day4.part1 input
if shouldWrite then
Console.WriteLine output
else
let output = Day4.part2 input
if shouldWrite then
Console.WriteLine output
let day5 (partTwo : bool) (input : string) =
if not partTwo then
let output = Day5.part1 input
if shouldWrite then
Console.WriteLine output
else
let output = Day5.part2 input
if shouldWrite then
Console.WriteLine output
let day6 (partTwo : bool) (input : string) =
if not partTwo then
let output = Day6.part1 input
if shouldWrite then
Console.WriteLine output
else
let output = Day6.part2 input
if shouldWrite then
Console.WriteLine output
let day7 (partTwo : bool) (input : string) =
if not partTwo then
let output = Day7.part1 input
if shouldWrite then
Console.WriteLine output
else
let output = Day7.part2 input
if shouldWrite then
Console.WriteLine output
let day8 (partTwo : bool) (input : string) =
if not partTwo then
let output = Day8.part1 input
if shouldWrite then
Console.WriteLine output
else
let output = Day8.part2 input
if shouldWrite then
Console.WriteLine output
let day9 (partTwo : bool) (input : string) =
if not partTwo then
let output = Day9.part1 input
if shouldWrite then
Console.WriteLine output
else
let output = Day9.part2 input
if shouldWrite then
Console.WriteLine output
let day10 (partTwo : bool) (input : string) =
if not partTwo then
let output = Day10.part1 input
if shouldWrite then
Console.WriteLine output
else
let output = Day10.part2 input
if shouldWrite then
Console.WriteLine output
let day11 (partTwo : bool) (input : string) =
if not partTwo then
let output = Day11.part1 input
if shouldWrite then
Console.WriteLine output
else
let output = Day11.part2 input
if shouldWrite then
Console.WriteLine output
let day12 (partTwo : bool) (input : string) =
if not partTwo then
let output = Day12.part1 input
if shouldWrite then
Console.WriteLine output
else
let output = Day12.part2 input
if shouldWrite then
Console.WriteLine output
let allRuns =
[|
day1
day2
day3
day4
day5
day6
day7
day8
day9
day10
day11
day12
|]

View File

@@ -6,6 +6,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Test", "Test\Test.fsproj",
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "AdventOfCode2023.FSharp.Lib", "AdventOfCode2023.FSharp.Lib\AdventOfCode2023.FSharp.Lib.fsproj", "{95CE0568-3D1A-4060-BB54-52460FB1E399}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "AdventOfCode2023.FSharp.Bench", "AdventOfCode2023.FSharp.Bench\AdventOfCode2023.FSharp.Bench.fsproj", "{5FD3221D-2C90-4173-8FC0-90553CEE1D4A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -24,5 +26,9 @@ Global
{95CE0568-3D1A-4060-BB54-52460FB1E399}.Debug|Any CPU.Build.0 = Debug|Any CPU
{95CE0568-3D1A-4060-BB54-52460FB1E399}.Release|Any CPU.ActiveCfg = Release|Any CPU
{95CE0568-3D1A-4060-BB54-52460FB1E399}.Release|Any CPU.Build.0 = Release|Any CPU
{5FD3221D-2C90-4173-8FC0-90553CEE1D4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5FD3221D-2C90-4173-8FC0-90553CEE1D4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5FD3221D-2C90-4173-8FC0-90553CEE1D4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5FD3221D-2C90-4173-8FC0-90553CEE1D4A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

104
README.md
View File

@@ -7,23 +7,109 @@
Ahead-of-time compiled with `PublishAot`, M1 Max.
The format is: "answer part1\ntime\nanswer part2\ntime\n...", with possible extra lines indicating how long it took to parse the input if I happen to have split that out.
After day 3:
BenchmarkDotNet:
```
| Day | IsPartOne | Mean | Error | StdDev |
|---- |---------- |----------:|---------:|---------:|
| 1 | True | 10.23 us | 0.036 us | 0.032 us |
| 1 | False | 17.93 us | 0.203 us | 0.180 us |
| 2 | True | 17.39 us | 0.080 us | 0.075 us |
| 2 | False | 25.42 us | 0.155 us | 0.145 us |
| 3 | True | 65.60 us | 0.393 us | 0.328 us |
| 3 | False | 145.52 us | 0.256 us | 0.200 us |
| 4 | True | 109.78 us | 0.236 us | 0.209 us |
| 4 | False | 110.34 us | 0.081 us | 0.063 us |
| 5 | True | 13.44 us | 0.045 us | 0.042 us |
| 5 | False | 61.70 us | 0.199 us | 0.177 us |
| Day | IsPartOne | Mean | Error | StdDev |
|---- |---------- |---------------:|------------:|------------:|
| 6 | True | 314.7 ns | 1.87 ns | 1.65 ns |
| 6 | False | 316.3 ns | 0.31 ns | 0.26 ns |
| 7 | True | 89,256.3 ns | 578.24 ns | 540.88 ns |
| 7 | False | 95,062.7 ns | 921.75 ns | 862.21 ns |
| 8 | True | 423,461.0 ns | 7,218.95 ns | 6,752.61 ns |
| 8 | False | 2,045,302.1 ns | 4,338.61 ns | 3,846.06 ns |
| 9 | True | 1,390,976.2 ns | 2,171.39 ns | 1,813.21 ns |
| 9 | False | 2,173,468.1 ns | 3,171.04 ns | 2,647.96 ns |
| 10 | True | 57,460.7 ns | 1,135.45 ns | 2,160.31 ns |
| 10 | False | 694,553.9 ns | 2,935.74 ns | 2,746.09 ns |
| Day | IsPartOne | Mean | Error | StdDev | Median |
|---- |---------- |----------:|----------:|----------:|----------:|
| 11 | True | 39.085 ms | 0.0355 ms | 0.0297 ms | 39.082 ms |
| 11 | False | 38.608 ms | 0.0270 ms | 0.0211 ms | 38.617 ms |
| 12 | True | 1.846 ms | 0.0044 ms | 0.0041 ms | 1.845 ms |
| 12 | False | 18.692 ms | 0.3676 ms | 0.3775 ms | 18.962 ms |
```
After day 12, a single run of the ahead-of-time compiled version:
```
=====Day 1=====
54304
0.549458ms
3.418417ms
54418
0.710375ms
0.317958ms
=====Day 2=====
2727
0.119959ms
0.079917ms
56580
0.155708ms
0.1395ms parse
0.107292ms
=====Day 3=====
0.140292ms parse
540131
0.1395ms
0.140292ms
86879020
0.840791ms
4.144166ms total
0.664416ms
=====Day 4=====
27454
0.390541ms
6857330
0.360375ms
=====Day 5=====
806029445
0.161917ms
59370572
0.249708ms
=====Day 6=====
32076
0.002917ms
34278221
0.001667ms
=====Day 7=====
250058342
0.409792ms
250506580
0.431167ms
=====Day 8=====
19199
1.192792ms
13663968099527
5.276083ms
=====Day 9=====
1898776583
3.775667ms
1100
5.365875ms
=====Day 10=====
6842
0.201208ms
393
2.226042ms
=====Day 11=====
0.11225ms parse
9947476
48.423ms
519939907614
34.836125ms
=====Day 12=====
7402
4.704375ms
3384337640277
31.825583ms
151.644334ms total
```
# Building yourself