Skip to content

Instantly share code, notes, and snippets.

@will
Last active August 29, 2015 14:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save will/1b0ee6865472b8b30b46 to your computer and use it in GitHub Desktop.
Save will/1b0ee6865472b8b30b46 to your computer and use it in GitHub Desktop.
more postgres time benchmarks
/tmp ➤ crystal build timebm.cr --release
/tmp ➤ ./timebm
2015-05-01 20:10:01 UTC
2015-05-01 20:10:01 UTC
2015-05-01 20:10:01 UTC
text 18636833.84 (± 1002412.33) 10.69× slower
binary span 60320068.97 (± 4530921.68) 3.30× slower
binary int 199241301.90 (± 17951824.75) fastest
class TimeDecoderText
def initialize
super
@curr = Pointer(UInt8).new(0)
end
def decode(value_ptr)
@curr = value_ptr + 0
year = get_next_int
month = get_next_int
day = get_next_int
hour = get_next_int
minute = get_next_int
second = get_next_int
fraction = (@curr-1).value == '.'.ord ? get_next_int : 0
sign = (@curr-1).value == '-'.ord ? -1 : 1
offset = get_next_int * sign
milisecond = fraction_to_mili(fraction)
t = Time.new(year, month, day, hour, minute, second, milisecond, Time::Kind::Utc)
return apply_offset(t, offset)
end
private def get_next_int
return 0 if @curr.value == 0
int = 0
while @curr.value >= 48 && @curr.value <= 57
int = (int*10) + (@curr.value - 48)
@curr += 1
end
@curr += 1 unless @curr.value == 0
return int
end
private def fraction_to_mili(frac)
if frac < 10
frac * 100
elsif frac < 100
frac * 10
elsif frac > 1000
frac / 1000
else
frac
end
end
private def apply_offset(t, offset)
if offset == 0
t
else
t - TimeSpan.new(offset,0,0)
end
end
end
abstract class Decoder
def decode(value_ptr) end
private def swap64(ptr : UInt8*) : UInt64
(((((((((((((((( 0_u64
) | ptr[0] ) << 8
) | ptr[1] ) << 8
) | ptr[2] ) << 8
) | ptr[3] ) << 8
) | ptr[4] ) << 8
) | ptr[5] ) << 8
) | ptr[6] ) << 8
) | ptr[7] )
end
end
class TimeDecoderSpan < Decoder
def decode(value_ptr)
v = swap64(value_ptr).to_i64 / 1000
Time.new(2000,1,1, kind: Time::Kind::Utc) + TimeSpan.new(0,0,0,0,v)
end
end
JAN_1_2K_TICKS = Time.new(2000,1,1, kind: Time::Kind::Utc).ticks
class TimeDecoderInt < Decoder
def decode(value_ptr)
v = swap64(value_ptr).to_i64 / 1000
#Time.new(630822816000000000_i64 + (TimeSpan::TicksPerMillisecond * v), kind: Time::Kind::Utc)
Time.new(JAN_1_2K_TICKS + (TimeSpan::TicksPerMillisecond * v), kind: Time::Kind::Utc)
end
end
ptr = "2015-05-01 13:10:01.23442-07".cstr
#bytes = {0_u8, 1_u8, 184_u8, 9_u8, 144_u8, 219_u8, 139_u8, 244_u8}
#bptr = pointerof(bytes) as UInt8*
pgdate = -825324695007526656_i64
bptr = pointerof(pgdate) as UInt8*
tdt = TimeDecoderText.new
tds = TimeDecoderSpan.new
tdi = TimeDecoderInt.new
p tdt.decode(ptr)
p tds.decode(bptr)
p tdi.decode(bptr)
require "benchmark"
Benchmark.ips do |x|
x.report("text") { tdt.decode(ptr) }
x.report("binary span") { tds.decode(bptr) }
x.report("binary int") { tdi.decode(bptr) }
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment