Skip to content

Instantly share code, notes, and snippets.

@tsafin
Last active August 15, 2021 20:46
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 tsafin/f7f21aad53f23801839b3b278cfac380 to your computer and use it in GitHub Desktop.
Save tsafin/f7f21aad53f23801839b3b278cfac380 to your computer and use it in GitHub Desktop.
datetime.secs vs secsf vs double. int64_t vs double
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
ffi.cdef [[
struct datetime_double {
/** seconds since epoch */
double secs;
/** nanoseconds if any */
int32_t nsec;
/** offset in minutes from UTC */
int32_t offset;
};
]]
local datetime_double_t = ffi.typeof('struct datetime_double')
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_raw_2(secs, nsec, offset)
local dt_obj = ffi.new(datetime_double_t)
dt_obj.secs = secs
dt_obj.nsec = nsec
dt_obj.offset = offset
return dt_obj
end
local function datetime_index(self, key)
if key == 'epoch' or key == 'unixtime' then
return self.secs
elseif key == 'secsf' then
return builtin.datetime_secs(self)
elseif key == 'ts' or key == 'timestamp' then
return tonumber(self.secs) + self.nsec / 1e9
elseif key == 'ns' or key == 'nanoseconds' then
return self.secs * 1e9 + self.nsec
elseif key == 'us' or key == 'microseconds' then
return self.secs * 1e6 + self.nsec / 1e3
elseif key == 'ms' or key == 'milliseconds' then
return self.secs * 1e3 + self.nsec / 1e6
elseif key == 's' or key == 'seconds' then
return tonumber(self.secs) + self.nsec / 1e9
elseif key == 'm' or key == 'min' or key == 'minutes' then
return (tonumber(self.secs) + self.nsec / 1e9) / 60
elseif key == 'hr' or key == 'hours' then
return (tonumber(self.secs) + self.nsec / 1e9) / (60 * 60)
elseif key == 'd' or key == 'days' then
return (tonumber(self.secs) + self.nsec / 1e9) / (24 * 60 * 60)
else
error(('unknown attribute %s'):format(key), 2)
end
end
local function datetime_newindex(self, key, value)
if key == 'epoch' or key == 'unixtime' then
self.secs = value
self.nsec, self.offset = 0, 0
else
error(('assigning to unknown attribute %s'):format(key), 2)
end
end
local datetime_mt = {
__index = datetime_index,
__newindex = datetime_newindex,
}
-- ffi.metatype(datetime_t, datetime_mt)
local _
local T
T = datetime_new_raw(60, 100000, 180)
print(ffi.typeof(T))
local start = clock.time()
for _ = 1, 1e6 do
_ = T.secs
end
print('date.secs', clock.time() - start)
collectgarbage()
collectgarbage()
print(ffi.typeof(T))
start = clock.time()
for _ = 1, 1e6 do
_ = T.secsf
end
print('date.secsf', clock.time() - start)
collectgarbage()
collectgarbage()
local N = datetime_new_raw_2(60, 100000, 180)
print(ffi.typeof(N))
start = clock.time()
for _ = 1, 1e6 do
_ = N.secs
end
print('date_double.secs', clock.time() - start)
diff --git a/extra/exports b/extra/exports
index 4100d500a..d34a54f62 100644
--- a/extra/exports
+++ b/extra/exports
@@ -152,6 +152,7 @@ datetime_asctime
datetime_ctime
datetime_now
datetime_pack
+datetime_secs
datetime_strftime
datetime_to_string
datetime_unpack
diff --git a/src/lib/core/datetime.c b/src/lib/core/datetime.c
index 7b65e28db..001f7e60f 100644
--- a/src/lib/core/datetime.c
+++ b/src/lib/core/datetime.c
@@ -75,6 +75,12 @@ datetime_now(struct datetime *now)
now->offset = tm.tm_gmtoff / 60;
}
+double
+datetime_secs(const struct datetime *t)
+{
+ return (double)t->secs;
+}
+
char *
datetime_asctime(const struct datetime *date, char *buf)
{
diff --git a/src/lua/datetime.lua b/src/lua/datetime.lua
index 5b1cbada9..c4d16028b 100644
--- a/src/lua/datetime.lua
+++ b/src/lua/datetime.lua
@@ -57,6 +57,8 @@ ffi.cdef [[
void
datetime_now(struct datetime * now);
+ double
+ datetime_secs(const struct datetime *t);
]]
local builtin = ffi.C
@@ -737,6 +739,8 @@ end
local function datetime_index(self, key)
if key == 'epoch' or key == 'unixtime' then
return self.secs
+ elseif key == 'secsf' then
+ return builtin.datetime_secs(self)
elseif key == 'ts' or key == 'timestamp' then
return tonumber(self.secs) + self.nsec / 1e9
elseif key == 'ns' or key == 'nanoseconds' then
✔ ~/datetime/tarantoolt/build [tsafin/gh-5941-datetime-v4 ↑·4|✚ 3…4⚑ 3]
23:40 $ ./src/tarantool ../../bench-hash-dt.lua
ctype<struct datetime>
date.secs 0.00035929679870605
ctype<struct datetime>
date.secsf 0.49544525146484
ctype<struct datetime_double>
date_double.secs 0.00042939186096191
✔ ~/datetime/tarantoolt/build [tsafin/gh-5941-datetime-v4 ↑·4|✚ 3…4⚑ 3]
23:40 $ ./src/tarantool ../../bench-hash-dt.lua
ctype<struct datetime>
date.secs 0.00034856796264648
ctype<struct datetime>
date.secsf 0.40926361083984
ctype<struct datetime_double>
date_double.secs 0.00043344497680664
✔ ~/datetime/tarantoolt/build [tsafin/gh-5941-datetime-v4 ↑·4|✚ 3…4⚑ 3]
23:40 $ ./src/tarantool ../../bench-hash-dt.lua
ctype<struct datetime>
date.secs 0.00034213066101074
ctype<struct datetime>
date.secsf 0.46818256378174
ctype<struct datetime_double>
date_double.secs 0.00037813186645508
✔ ~/datetime/tarantoolt/build [tsafin/gh-5941-datetime-v4 ↑·4|✚ 3…4⚑ 3]
23:40 $ ./src/tarantool ../../bench-hash-dt.lua
ctype<struct datetime>
date.secs 0.00051259994506836
ctype<struct datetime>
date.secsf 0.6695671081543
ctype<struct datetime_double>
date_double.secs 0.00048208236694336

jit.off()

✔ ~/datetime/tarantoolt/build [tsafin/msgpack-format L|✚ 1…6⚑ 3] 
14:47 $ ./src/tarantool ../../bench-hash-dt.lua 
ctype<struct datetime>
date.secs       0.25970935821533
ctype<struct datetime_double>
date_double.secs        0.15149474143982
✔ ~/datetime/tarantoolt/build [tsafin/msgpack-format L|✚ 1…6⚑ 3] 
14:48 $ ./src/tarantool ../../bench-hash-dt.lua 
ctype<struct datetime>
date.secs       0.33055567741394
ctype<struct datetime_double>
date_double.secs        0.18803310394287
✔ ~/datetime/tarantoolt/build [tsafin/msgpack-format L|✚ 1…6⚑ 3] 
14:48 $ ./src/tarantool ../../bench-hash-dt.lua 
ctype<struct datetime>
date.secs       0.29576468467712
ctype<struct datetime_double>
date_double.secs        0.15472149848938
✔ ~/datetime/tarantoolt/build [tsafin/msgpack-format L|✚ 1…6⚑ 3] 
14:48 $ ./src/tarantool ../../bench-hash-dt.lua 
ctype<struct datetime>
date.secs       0.2386200428009
ctype<struct datetime_double>
date_double.secs        0.1287829875946

jit.on()

✔ ~/datetime/tarantoolt/build [tsafin/msgpack-format L|✚ 1…6⚑ 3] 
14:46 $ ./src/tarantool ../../bench-hash-dt.lua 
ctype<struct datetime>
date.secs       0.0029795169830322
ctype<struct datetime_double>
date_double.secs        0.00043296813964844
✔ ~/datetime/tarantoolt/build [tsafin/msgpack-format L|✚ 1…6⚑ 3] 
14:47 $ ./src/tarantool ../../bench-hash-dt.lua 
ctype<struct datetime>
date.secs       0.00053858757019043
ctype<struct datetime_double>
date_double.secs        0.00038242340087891
✔ ~/datetime/tarantoolt/build [tsafin/msgpack-format L|✚ 1…6⚑ 3] 
14:47 $ ./src/tarantool ../../bench-hash-dt.lua 
ctype<struct datetime>
date.secs       0.00038433074951172
ctype<struct datetime_double>
date_double.secs        0.00033235549926758
✔ ~/datetime/tarantoolt/build [tsafin/msgpack-format L|✚ 1…6⚑ 3] 
14:47 $ ./src/tarantool ../../bench-hash-dt.lua 
ctype<struct datetime>
date.secs       0.0003509521484375
ctype<struct datetime_double>
date_double.secs        0.00031447410583496
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment