Skip to content

Instantly share code, notes, and snippets.

@tsafin
Last active August 18, 2021 09:40
Show Gist options
  • Save tsafin/31cc9b0872b6015904fcc90d97740770 to your computer and use it in GitHub Desktop.
Save tsafin/31cc9b0872b6015904fcc90d97740770 to your computer and use it in GitHub Desktop.
local ffi = require('ffi')
local clock = require('clock')
local builtin = ffi.C
local datetime_t = ffi.typeof('struct datetime')
local SECS_PER_DAY = 86400
local DT_EPOCH_1970_OFFSET = 719163LL
local function datetime_new_raw(secs, nsec, offset)
local dt_obj = ffi.new(datetime_t)
dt_obj.secs = secs
dt_obj.nsec = nsec
dt_obj.offset = offset
return dt_obj
end
local function datetime_new_dt(dt, secs, frac, offset)
local epochV = dt ~= nil and (builtin.tnt_dt_rdn(dt) - DT_EPOCH_1970_OFFSET) *
SECS_PER_DAY or 0
local secsV = secs ~= nil and secs or 0
local fracV = frac ~= nil and frac or 0
local ofsV = offset ~= nil and offset or 0
return datetime_new_raw(epochV + secsV - ofsV * 60, fracV, ofsV)
end
-- create datetime given attribute values from obj
local function datetime_new(obj)
if obj == nil then
return datetime_new_raw(0, 0, 0)
end
local secs = 0
local nsec = 0
local offset = 0
local easy_way = false
local y = 0
local M = 0
local d = 0
local ymd = false
local h = 0
local m = 0
local s = 0
local frac = 0
local hms = false
local dt = 0
local handlers = {
secs = function(_, v)
secs = v
easy_way = true
end,
nsec = function(_, v)
nsec = v
easy_way = true
end,
offset = function (_, v)
offset = v
easy_way = true
end,
year = function(k, v)
y = v
ymd = true
end,
month = function(k, v)
M = v
ymd = true
end,
day = function(k, v)
d = v
ymd = true
end,
hour = function(k, v)
h = v
hms = true
end,
minute = function(k, v)
m = v
hms = true
end,
second = function(k, v)
s, frac = math_modf(v)
frac = frac * 1e9 -- convert fraction to nanoseconds
hms = true
end,
-- tz offset in minutes
tz = function(k, v)
offset = v
end
}
for key, value in pairs(obj) do
handlers[key](key, value)
end
-- .sec, .nsec, .offset
if easy_way then
return datetime_new_raw(secs, nsec, offset)
end
-- .year, .month, .day
if ymd then
dt = dt + builtin.tnt_dt_from_ymd(y, M, d)
end
-- .hour, .minute, .second
if hms then
secs = h * 3600 + m * 60 + s
end
return datetime_new_dt(dt, secs, frac, offset)
end
-- create datetime given attribute values from obj
local function datetime_new_2(obj)
if obj == nil then
return datetime_new_raw(0, 0, 0)
end
local secs = 0
local nsec = 0
local offset = 0
local easy_way = false
local y = 0
local M = 0
local d = 0
local ymd = false
local h = 0
local m = 0
local s = 0
local frac = 0
local hms = false
local dt = 0
for key, value in pairs(obj) do
if key == 'secs' then
secs = value
easy_way = true
elseif key == 'nsec' then
nsec = value
easy_way = true
elseif key == 'offset' then
offset = value
easy_way = true
elseif key == 'year' then
y = value
ymd = true
elseif key == 'month' then
M = value
ymd = true
elseif key == 'day' then
d = value
ymd = true
elseif key == 'hour' then
h = value
hms = true
elseif key == 'minute' then
m = value
hms = true
elseif key == 'second' then
s, frac = math_modf(value)
frac = frac * 1e9 -- convert fraction to nanoseconds
hms = true
elseif key == 'tz' then
offset = value
end
end
-- .sec, .nsec, .offset
if easy_way then
return datetime_new_raw(secs, nsec, offset)
end
-- .year, .month, .day
if ymd then
dt = dt + builtin.tnt_dt_from_ymd(y, M, d)
end
-- .hour, .minute, .second
if hms then
secs = h * 3600 + m * 60 + s
end
return datetime_new_dt(dt, secs, frac, offset)
end
local _
local start = clock.time()
for _ = 1, 1e6 do
_ = datetime_new_dt(DT_EPOCH_1970_OFFSET, 60, 100000, 180)
end
print('datetime_new_dt', clock.time() - start)
collectgarbage()
collectgarbage()
start = clock.time()
for _ = 1, 1e6 do
_ = datetime_new{ secs = 60, nsec = 100000, offset = 180}
end
print('datetime_new', clock.time() - start)
collectgarbage()
collectgarbage()
local o = { secs = 60, nsec = 100000, offset = 180}
start = clock.time()
for _ = 1, 1e6 do
_ = datetime_new(o)
end
print('datetime_new(precreated)', clock.time() - start)
collectgarbage()
collectgarbage()
start = clock.time()
for _ = 1, 1e6 do
_ = datetime_new_2(o)
end
print('datetime_new_2(ifs)', clock.time() - start)
✔ ~/datetime/tarantoolt/build [tsafin/gh-5941-datetime-v4 ↓·8↑·24|✚ 3…8⚑ 3]
12:39 $ ./src/tarantool ../../bench-hash-0.lua
datetime_new_dt 0.0030450820922852
datetime_new 9.1180400848389
datetime_new(precreated) 7.1469388008118
datetime_new_2(ifs) 0.38320755958557
✔ ~/datetime/tarantoolt/build [tsafin/gh-5941-datetime-v4 ↓·8↑·24|✚ 3…8⚑ 3]
12:39 $ ./src/tarantool ../../bench-hash-0.lua
datetime_new_dt 0.0036327838897705
datetime_new 7.5975275039673
datetime_new(precreated) 6.8448140621185
datetime_new_2(ifs) 0.49595499038696
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment