-- A timer that uses the rdtsc instruction to read the CPU timestamp counter. -- -- Requires DynAsm with Lua mode: https://github.com/luapower/dynasm -- -- Use it like this: -- -- local tsc_timer = require('tsc_timer') -- local t = tsc_timer.start() -- ... do some things ... -- t:stop() -- print(t:value()) -- -- value() returns the estimated number of milliseconds and the number of ticks elapsed -- local dynasm = require('dynasm') local ffi = require('ffi') local rdtsc = dynasm.loadstring [[ local ffi = require('ffi') local dasm = require('dasm') |.arch x64 |.actionlist actions local Dst = dasm.new(actions) | rdtsc | shl rdx, 32 | or rax, rdx | ret local code = Dst:build() return function() local _ = code return ffi.cast('uint64_t __cdecl (*)()', code)() end ]]() ffi.cdef [[ int usleep(uint32_t usec); ]] local _M = {} local mt = { __index = _M } function _M.initialize() if _M.ticks_per_sec ~= nil then return end local start_time = rdtsc() ffi.C.usleep(200000) local end_time = rdtsc() - start_time _M.ticks_per_sec = end_time * 5 end function _M.start() if _M.ticks_per_second == nil then _M.initialize() end return setmetatable({ start_time = rdtsc() }, mt) end function _M.stop(self) local end_time = rdtsc() if self.start_time == nil then error("timer has not been started") end if self.stop_time ~= nil then error("timer has already been stopped") end _M.end_time = end_time return _M.value(self) end function _M.value(self) return tonumber(self.end_time - self.start_time) / tonumber(self.ticks_per_sec) * 1000, tonumber(self.end_time - self.start_time) end return _M