Created
July 6, 2014 19:57
-
-
Save csfrancis/9068d7168f6614bbdb41 to your computer and use it in GitHub Desktop.
Using Luajit's DynAsm to read the timestamp counter using inline assembly in Lua
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment