-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathtimer.lua
More file actions
180 lines (150 loc) · 4.56 KB
/
Copy pathtimer.lua
File metadata and controls
180 lines (150 loc) · 4.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
--[[
I use this too often, so now it goes here
override T.getTime to change the timing function
override T.out to change the output file handle
--]]
local hasffi, ffi = pcall(require, 'ffi')
local T = {}
T.out = io.stderr
if not hasffi then
T.getTime = os.clock
elseif ffi.os == 'Windows' then
local assert = require 'ext.assert'
local profileapi = require 'ffi.req' 'c.profileapi'
local freq = ffi.new'LARGE_INTEGER'
assert.ne(profileapi.QueryPerformanceFrequency(freq), 0, 'QueryPerformanceFrequency failed')
local freqNum = tonumber(freq.QuadPart)
local startTime = ffi.new'LARGE_INTEGER'
profileapi.QueryPerformanceCounter(startTime)
local thisTime = ffi.new'LARGE_INTEGER'
function T.getTime()
profileapi.QueryPerformanceCounter(thisTime)
return tonumber(thisTime.QuadPart - startTime.QuadPart) / freqNum
end
local posix_time = require 'ffi.req' 'c.time'
local tm_1 = ffi.typeof'struct tm[1]'
function T.timegm(t)
local ts = tm_1()
ts[0].tm_year = (t.year or 1900) - 1900
ts[0].tm_mon = (t.month or 1) - 1
ts[0].tm_mday = t.day or 0
ts[0].tm_hour = t.hour or 12
ts[0].tm_min = t.min or 0
ts[0].tm_sec = t.sec or 0
ts[0].tm_isdst = t.isdst or false
return posix_time._mkgmtime(ts)
end
function T.time()
return posix_time.time(nil)
end
local time_t_1 = ffi.typeof'time_t[1]'
-- takes in UTC date info, spits out a timestamp
-- pass it unix timestamp, or nil for the current time
-- returns a date stucture with .year .month .day .hour .min .sec .isdst hopeully with the same range as Lua's os.date
function T.gmtime(t)
local tp = time_t_1()
tp[0] = t or T.time()
local ts = posix_time.gmtime(tp)
return {
year = ts[0].tm_year + 1900,
month = ts[0].tm_mon + 1,
day = ts[0].tm_mday,
hour = ts[0].tm_hour,
min = ts[0].tm_min,
sec = ts[0].tm_sec,
isdst = ts[0].tm_isdst ~= 0,
}
end
else
require 'ffi.req' 'c.time' -- timegm, gmtime
require 'ffi.req' 'c.sys.time' -- gettimeofday
require 'ffi.req' 'c.string' -- strerror
local errno = require 'ffi.req' 'c.errno'
local gettimeofday_tv = ffi.new'struct timeval[1]'
function T.getTime()
local result = ffi.C.gettimeofday(gettimeofday_tv, nil)
if result ~= 0 then
error(ffi.string(ffi.C.strerror(errno.errno())))
end
return tonumber(gettimeofday_tv[0].tv_sec) + tonumber(gettimeofday_tv[0].tv_usec) / 1000000
end
local tm_1 = ffi.typeof'struct tm[1]'
-- takes in a timestamp (your timezone? do timestamps consider timezone, or are they all UTC?)
-- spits out UTC date info
-- TODO add a first 'format' option that formats this... ?
-- TODO TODO either rename this to 'ext.time' or move it into its own ... repo? file? idk...
function T.timegm(t)
local ts = tm_1()
ts[0].tm_year = (t.year or 1900) - 1900
ts[0].tm_mon = (t.month or 1) - 1
ts[0].tm_mday = t.day or 0
ts[0].tm_hour = t.hour or 12
ts[0].tm_min = t.min or 0
ts[0].tm_sec = t.sec or 0
ts[0].tm_isdst = t.isdst or false
return ffi.C.timegm(ts)
end
function T.time()
return ffi.C.time(nil)
end
local time_t_1 = ffi.typeof'time_t[1]'
-- takes in UTC date info, spits out a timestamp
-- pass it unix timestamp, or nil for the current time
-- returns a date stucture with .year .month .day .hour .min .sec .isdst hopeully with the same range as Lua's os.date
function T.gmtime(t)
local tp = time_t_1()
tp[0] = t or T.time()
local ts = ffi.C.gmtime(tp)
return {
year = ts[0].tm_year + 1900,
month = ts[0].tm_mon + 1,
day = ts[0].tm_mday,
hour = ts[0].tm_hour,
min = ts[0].tm_min,
sec = ts[0].tm_sec,
isdst = ts[0].tm_isdst ~= 0,
}
end
end
T.depth = 0
T.tab = ' '
local function timerReturn(name, startTime, indent, ...)
local endTime = T.getTime()
local dt = endTime - startTime
-- this is all printing ...
T.depth = T.depth - 1
T.out:write(indent..'...done ')
if name then
T.out:write(name..' ')
end
T.out:write('('..dt..'s)\n')
T.out:flush()
return dt, ...
end
function T.timer(name, cb, ...)
local indent = T.tab:rep(T.depth)
if name then
T.out:write(indent..name..'...\n')
end
T.out:flush()
local startTime = T.getTime()
T.depth = T.depth + 1
return timerReturn(name, startTime, indent, cb(...))
end
-- same as above but without printing (and no name too cuz we're not printing)
local function timerReturnQuiet(startTime, ...)
local endTime = T.getTime()
local dt = endTime - startTime
return dt, ...
end
function T.timerQuiet(cb, ...)
local startTime = T.getTime()
return timerReturnQuiet(startTime, cb(...))
end
setmetatable(T, {
-- call forwards to timer:
__call = function(self, ...)
return self.timer(...)
end,
})
return T