Skip to content

Commit

Permalink
added struct enumerator to ReferenceCountingSet + changed internal st…
Browse files Browse the repository at this point in the history
…ore to use struct tuples
  • Loading branch information
luithefirst committed Sep 3, 2024
1 parent 3cf2145 commit fb8da22
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ open FSharp.Data.Adaptive
type ReferenceCountingSet<'a>(initial : seq<'a>) =
let mutable nullCount = 0
let mutable version = 0
let mutable store = Dictionary<obj, 'a * ref<int>>(1)
let mutable store = Dictionary<obj, struct('a * ref<int>)>(1)


static let rec checkDeltas (l : list<SetOperation<'a>>) =
Expand Down Expand Up @@ -65,7 +65,7 @@ type ReferenceCountingSet<'a>(initial : seq<'a>) =
r := !r + 1
false
| _ ->
let r = v, ref 1
let r = struct(v, ref 1)
store.[v] <- r
hasChanged()
true
Expand Down Expand Up @@ -340,6 +340,7 @@ type ReferenceCountingSet<'a>(initial : seq<'a>) =
member x.Overlaps other = x.Overlaps other
member x.SetEquals other = x.SetEquals other

member x.GetEnumerator() = new ReferenceCountingSetEnumerator<'a>(nullCount > 0, store)

interface IEnumerable with
member x.GetEnumerator() =
Expand All @@ -350,33 +351,48 @@ type ReferenceCountingSet<'a>(initial : seq<'a>) =
new ReferenceCountingSetEnumerator<'a>(nullCount > 0, store) :> IEnumerator<'a>

// define an Enumerator enumerating all (distinct) elements in the set
and private ReferenceCountingSetEnumerator<'a>(containsNull : bool, store : Dictionary<obj, 'a * ref<int>>) =
let mutable emitNull = containsNull
let mutable e = store.GetEnumerator() :> IEnumerator<KeyValuePair<obj, 'a * ref<int>>>
let mutable currentIsNull = Unchecked.defaultof<bool> // does not matter here

member x.Current =
if currentIsNull then
Unchecked.defaultof<_>
else
e.Current.Value |> fst

interface IEnumerator with
and ReferenceCountingSetEnumerator<'a> =
struct
val mutable internal containsNull : bool
val mutable internal emitNull : bool
val mutable internal currentIsNull : bool
val mutable internal e : Dictionary<obj, struct('a * ref<int>)>.Enumerator

member x.Current =
if x.currentIsNull then
Unchecked.defaultof<_>
else
x.e.Current.Value |> fstv

member x.MoveNext() =
if emitNull then
emitNull <- false
currentIsNull <- true
if x.emitNull then
x.emitNull <- false
x.currentIsNull <- true
true
else
currentIsNull <- false
e.MoveNext()
x.currentIsNull <- false
x.e.MoveNext()

interface IEnumerator with
member x.MoveNext() =
x.MoveNext()

member x.Reset() =
x.emitNull <- x.containsNull
(x.e :> IEnumerator).Reset()

member x.Current = x.Current :> obj

member x.Reset() =
emitNull <- containsNull
e.Reset()
interface IEnumerator<'a> with
member x.Current = x.Current
member x.Dispose() = x.e.Dispose()

member x.Current = x.Current :> obj
internal new(containsNull2 : bool, store : Dictionary<obj, struct('a * ref<int>)>) =
{
containsNull = containsNull2
emitNull = containsNull2
currentIsNull = false
e = store.GetEnumerator()
}

interface IEnumerator<'a> with
member x.Current = x.Current
member x.Dispose() = e.Dispose()
end
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
<Compile Include="TensorMathBench.fs" />
<Compile Include="DynamicDispatchBench.fs" />
<Compile Include="TypePatternsBench.fs" />
<Compile Include="ReferenceCountingSetBench.fs" />
<Compile Include="Program.fs" />
</ItemGroup>
<ItemGroup>
Expand Down
5 changes: 4 additions & 1 deletion src/Tests/Aardvark.Base.FSharp.Benchmarks/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,8 @@ module Program =
let job = Job.ShortRun.WithToolchain(InProcess.Emit.InProcessEmitToolchain.Instance)
ManualConfig.Create(DefaultConfig.Instance).WithOptions(ConfigOptions.DisableOptimizationsValidator).AddJob(job)

BenchmarkSwitcher.FromAssembly(typeof<ZipFloatArrays>.Assembly).Run(argv, cfg) |> ignore;
BenchmarkSwitcher.FromAssembly(typeof<ZipFloatArrays>.Assembly).Run(argv, cfg) |> ignore

//BenchmarkRunner.Run<RefCountingSet>(cfg) |> ignore

0
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
namespace Aardvark.Base.FSharp.Benchmarks

open Aardvark.Base
open BenchmarkDotNet.Attributes
open System

//BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.4780/22H2/2022Update)
//AMD Ryzen 9 7900, 1 CPU, 24 logical and 12 physical cores
//.NET SDK 8.0.400
// [Host] : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI DEBUG

//Job=ShortRun Toolchain=InProcessEmitToolchain IterationCount=3
//LaunchCount=1 WarmupCount=3

//| Method | Count | Mean | Error | StdDev | Gen0 | Allocated |
//|---------- |------ |------------:|------------:|-----------:|-------:|----------:|
//| Enumerate | 1 | 25.37 ns | 11.08 ns | 0.607 ns | 0.0052 | 88 B |
//| Enumerate | 10 | 125.34 ns | 30.77 ns | 1.686 ns | 0.0052 | 88 B |
//| Enumerate | 100 | 1,033.09 ns | 289.20 ns | 15.852 ns | 0.0038 | 88 B |
//| Enumerate | 1000 | 9,871.15 ns | 1,857.34 ns | 101.807 ns | - | 88 B |

// struct enumerator
//| Method | Count | Mean | Error | StdDev | Allocated |
//|---------- |------ |-------------:|------------:|----------:|----------:|
//| Enumerate | 1 | 2.789 ns | 0.0885 ns | 0.0049 ns | - |
//| Enumerate | 10 | 17.053 ns | 0.3215 ns | 0.0176 ns | - |
//| Enumerate | 100 | 154.362 ns | 10.5647 ns | 0.5791 ns | - |
//| Enumerate | 1000 | 1,560.785 ns | 122.1086 ns | 6.6932 ns | - |

// struct enumerator + struct tuple store
//| Method | Count | Mean | Error | StdDev | Allocated |
//|---------- |------ |-------------:|-----------:|----------:|----------:|
//| Enumerate | 1 | 2.738 ns | 0.4081 ns | 0.0224 ns | - |
//| Enumerate | 10 | 17.059 ns | 0.9612 ns | 0.0527 ns | - |
//| Enumerate | 100 | 155.314 ns | 9.7062 ns | 0.5320 ns | - |
//| Enumerate | 1000 | 1,560.410 ns | 92.5061 ns | 5.0706 ns | - |

[<MemoryDiagnoser>]
type RefCountingSet() =

let mutable refSet : ReferenceCountingSet<Object> = Unchecked.defaultof<_>
let mutable cnt = 0

[<Params(1, 10, 100, 1000)>]
member x.Count
with get() = cnt
and set v = cnt <- v

[<GlobalSetup>]
member x.Setup() =

let stuff = Array.init x.Count (fun i -> Object())
refSet <- ReferenceCountingSet<Object>(stuff)

[<Benchmark>]
member x.Enumerate() : int =
let mutable xx = 0
for x in refSet do
xx <- xx ^^^ x.GetHashCode()
xx

0 comments on commit fb8da22

Please sign in to comment.