Skip to content

Instantly share code, notes, and snippets.

@hodzanassredin
Created October 4, 2013 09:09
Show Gist options
  • Save hodzanassredin/6823148 to your computer and use it in GitHub Desktop.
Save hodzanassredin/6823148 to your computer and use it in GitHub Desktop.
Checking perf and memory usage disc unions vs custom struct with tag and bitconverter
//Results on my machine
//U1 Elapsed Time: 2541 Consumed memory: 81313836
//U2 Elapsed Time: 1835 Consumed memory: 58804716
//U1 Elapsed Time: 2144 Consumed memory: 80130316
//U2 Elapsed Time: 1682 Consumed memory: 57352372
//U1 Elapsed Time: 2109 Consumed memory: 81020952
//U2 Elapsed Time: 1672 Consumed memory: 58831224
open System
type U1 =
| F of float32
| C of char
| I of int
type U2Tag =
| F = 0uy
| C = 1uy
| I = 2uy
type U2 =
struct
val tag: U2Tag
val b0: byte
val b1: byte
val b2: byte
val b3: byte
new(x: float32) =
let arr = BitConverter.GetBytes(x)
{
tag = U2Tag.F;
b0 = arr.[0];
b1 = arr.[1];
b2 = arr.[2];
b3 = arr.[3];
}
new(x: int) =
let arr = BitConverter.GetBytes(x)
{
tag = U2Tag.I;
b0 = arr.[0];
b1 = arr.[1];
b2 = arr.[2];
b3 = arr.[3];
}
new(x: char) =
let arr = BitConverter.GetBytes(x)
{
tag = U2Tag.C;
b0 = arr.[0];
b1 = arr.[1];
b2 = 0uy;
b3 = 0uy;
}
member this.char =
if this.tag = U2Tag.C
then BitConverter.ToChar([|this.b0;this.b1|], 0)
else failwith "it is not a char"
member this.int =
if this.tag = U2Tag.I
then BitConverter.ToInt32([|this.b0;this.b1;this.b2;this.b3|], 0)
else failwith "it is not an int"
member this.float32 =
if this.tag = U2Tag.F
then BitConverter.ToSingle([|this.b0;this.b1;this.b2;this.b3|], 0)
else failwith "it is not a float"
end
let duration str f =
let timer = new System.Diagnostics.Stopwatch()
let memory = GC.GetTotalMemory(true)
timer.Start()
let returnValue = f()
timer.Stop()
let memoryUsage = GC.GetTotalMemory(false) - memory
printfn "%s Elapsed Time: %i Consumed memory: %d" str timer.ElapsedMilliseconds memoryUsage
returnValue
let max = 1000000
let test data =
let arr = Array.zeroCreate (max + 1)
for idx in 0..max do
let c,i,f = data(idx)
arr.[idx] <- [|c,i,f|]
arr
[<EntryPoint>]
let main argv =
let u1data i = (C('a'), I(i), F(float32 i))
let testu1() = test u1data
let u2data (i:int) = (new U2('a'), new U2(i), new U2(float32 i))
let testu2() = test u2data
for i in 0..10 do
duration "U1" testu1 |> ignore
duration "U2" testu2 |> ignore
printfn "%A" argv
0 // return an integer exit code
Copy link

ghost commented Oct 4, 2013

Hi,

How about this code (simpler, appears to have the same perf, fewer allocations for int/char cases)

type U2Tag =
        | F = 0uy
        | C = 1uy
        | I = 2uy

[<Struct>]
type U2(tag: U2Tag, bits: int32) = 
     new(x: float32) = 
        let arr = BitConverter.GetBytes(x)
        U2(U2Tag.F, int32 arr.[0] ||| (int32 arr.[1] <<< 8) ||| (int32 arr.[2] <<< 16) ||| (int32 arr.[3] <<< 24))
     new(x: int) = 
        U2(U2Tag.I, x)
     new(x: char) = 
        U2(U2Tag.C, int32 x)
     member this.char =
        if tag = U2Tag.C then char bits
        else failwith "it is not a char"
     member this.int =
        if tag = U2Tag.I then bits
        else failwith "it is not an int"
     member this.float32 =
        if tag = U2Tag.F then BitConverter.ToSingle ([| byte (bits &&& 0xFF);byte ((bits >>> 8) &&& 0xFF); byte ((bits >>> 16) &&& 0xFF); byte ((bits >>> 24) &&& 0xFF)|], 0)
        else failwith "it is not a float"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment