看一下shark_init.lua
这个文件(省去版权信息):
local uv = require("uv")
local ffi = require("ffi")
package.path = package.path .. ";./deps/?.lua"
package.cpath = package.cpath .. ";./deps/?.so"
-- microsecond precision
ffi.cdef[[
typedef long time_t;
typedef struct timeval {
time_t tv_sec;
time_t tv_usec;
} timeval;
int gettimeofday(struct timeval *t, void *tzp);
]]
local gettimeofday_struct = ffi.new("timeval")
shark.gettimeofday = function()
ffi.C.gettimeofday(gettimeofday_struct, nil)
return tonumber(gettimeofday_struct.tv_sec) * 1000000 +
tonumber(gettimeofday_struct.tv_usec)
end
set_interval = function(callback, interval)
local timer = uv.new_timer()
local function ontimeout()
callback(timer)
end
uv.timer_start(timer, interval, interval, ontimeout)
return timer
end
set_timeout = function(callback, timeout)
local timer = uv.new_timer()
local function ontimeout()
uv.timer_stop(timer)
uv.close(timer)
callback(timer)
end
uv.timer_start(timer, timeout, 0, ontimeout)
return timer
end
local shark_end_notify_list = {}
shark.add_end_notify = function(callback)
table.insert(shark_end_notify_list, callback)
end
shark.on_end = function(callback)
local function call_end()
--notify registered on_end function
for _, cb in pairs(shark_end_notify_list) do
cb()
end
callback()
os.exit(0)
end
local sigint = uv.new_signal()
uv.signal_start(sigint, "sigint", function()
call_end()
end)
local sigterm = uv.new_signal()
uv.signal_start(sigterm, "sigterm", function()
call_end()
end)
end
---------------------------------------------------------------
local function fill_line(n, max)
for i = 1, max do
if i < n then
io.write("*")
else
io.write(" ")
end
end
end
-- standard histogram print function
-- all type keys and number value
local __print_hist = function(t, cmp_func, mode)
local stdSum = 0
local array = {}
for k, v in pairs(t) do
stdSum = stdSum + v
if tostring(k) ~= "" then
array[#array + 1] = {k = k, v = v}
end
end
table.sort(array, function(v1, v2)
if cmp_func ~= nil then
return cmp_func(v1.v, v2.v)
else
if v1.v > v2.v then return true end
end
end)
if mode == "default" then
io.write(" value ---------- Distribution ---------- count\n")
end
for k, v in pairs(array) do
if mode == "default" then
io.write(string.format("%33s |", tostring(v.k)))
fill_line(v.v * 34 / stdSum, 34)
io.write(string.format("| %d\n", v.v))
else
io.write(string.format("%s\n%d\n", tostring(v.k), v.v))
end
end
end
function print_hist(t, cmp_func)
__print_hist(t, cmp_func, "default")
end
function print_hist_raw(t, cmp_func)
__print_hist(t, cmp_func, "raw")
end
shark.print_hist = print_hist
shark.print_hist_raw = print_hist_raw
(1)
local uv = require("uv")
local ffi = require("ffi")
package.path = package.path .. ";./deps/?.lua"
package.cpath = package.cpath .. ";./deps/?.so"
require("uv")
加载luv
模块(在main
函数中已经将luaopen_luv
注册进了package.preload table
),require("ffi")
加载luajit
中的ffi
模块。
然后修改package.path
和package.cpath
,这样可以找到shark
依赖的lua
文件和库。
(2)
-- microsecond precision
ffi.cdef[[
typedef long time_t;
typedef struct timeval {
time_t tv_sec;
time_t tv_usec;
} timeval;
int gettimeofday(struct timeval *t, void *tzp);
]]
local gettimeofday_struct = ffi.new("timeval")
shark.gettimeofday = function()
ffi.C.gettimeofday(gettimeofday_struct, nil)
return tonumber(gettimeofday_struct.tv_sec) * 1000000 +
tonumber(gettimeofday_struct.tv_usec)
end
ffi.new()
返回一个cdata
类型的值。shark.gettimeofday
返回的是当前时间的微秒(us
)值。
(3)
set_interval = function(callback, interval)
local timer = uv.new_timer()
local function ontimeout()
callback(timer)
end
uv.timer_start(timer, interval, interval, ontimeout)
return timer
end
set_timeout = function(callback, timeout)
local timer = uv.new_timer()
local function ontimeout()
uv.timer_stop(timer)
uv.close(timer)
callback(timer)
end
uv.timer_start(timer, timeout, 0, ontimeout)
return timer
end
set_interval
和set_timeout
利用了luv
模块中定时器相关函数。set_interval
函数会让callback
函数间隔interval
时间执行。而set_timeout
函数会让callback
函数在timeout
后执行,且执行一次。要注意这两个函数的时间单位是毫秒(ms
)。
(4)
local shark_end_notify_list = {}
shark.add_end_notify = function(callback)
table.insert(shark_end_notify_list, callback)
end
创建一个shark_end_notify_list
的table
,并且定义一个shark.add_end_notify
的函数。这个函数的作用是向shark_end_notify_list
添加回调函数(callback
),这个table
中的函数会在shark.on_end
这个函数中调用,也就是在脚本退出时执行收尾工作。
(5)
shark.on_end = function(callback)
local function call_end()
--notify registered on_end function
for _, cb in pairs(shark_end_notify_list) do
cb()
end
callback()
os.exit(0)
end
local sigint = uv.new_signal()
uv.signal_start(sigint, "sigint", function()
call_end()
end)
local sigterm = uv.new_signal()
uv.signal_start(sigterm, "sigterm", function()
call_end()
end)
end
shark.on_end
函数的参数是一个回调函数(callback
)。在shark.on_end
里定义了一个local
函数:call_end
,call_end
首先会遍历shark_end_notify_list
,并把其中的函数都执行一遍,最后调用shark.on_end
函数传入的回调函数(callback
)。 call_end
函数就是shark.on_end
函数为sigint
和sigterm
信号注册的信号处理函数。
(6)
local function fill_line(n, max)
for i = 1, max do
if i < n then
io.write("*")
else
io.write(" ")
end
end
end
fill_line
函数用来输出*
,用在接下来的__print_hist
函数中。
(7)
-- standard histogram print function
-- all type keys and number value
local __print_hist = function(t, cmp_func, mode)
local stdSum = 0
local array = {}
for k, v in pairs(t) do
stdSum = stdSum + v
if tostring(k) ~= "" then
array[#array + 1] = {k = k, v = v}
end
end
table.sort(array, function(v1, v2)
if cmp_func ~= nil then
return cmp_func(v1.v, v2.v)
else
if v1.v > v2.v then return true end
end
end)
if mode == "default" then
io.write(" value ---------- Distribution ---------- count\n")
end
for k, v in pairs(array) do
if mode == "default" then
io.write(string.format("%33s |", tostring(v.k)))
fill_line(v.v * 34 / stdSum, 34)
io.write(string.format("| %d\n", v.v))
else
io.write(string.format("%s\n%d\n", tostring(v.k), v.v))
end
end
end
__print_hist
函数用来打印柱状图。
local stdSum = 0
local array = {}
for k, v in pairs(t) do
stdSum = stdSum + v
if tostring(k) ~= "" then
array[#array + 1] = {k = k, v = v}
end
end
输入参数t
是一个table
。以上代码是遍历这个table
,并且生成一个新的“array table
”。这个array
的值又是一个table
:包含输入table
的key
和value
。
table.sort(array, function(v1, v2)
if cmp_func ~= nil then
return cmp_func(v1.v, v2.v)
else
if v1.v > v2.v then return true end
end
end)
以上代码是对array
进行排序。如果没有输入cmp_func
函数参数,就用默认的比较方式。
if mode == "default" then
io.write(" value ---------- Distribution ---------- count\n")
end
for k, v in pairs(array) do
if mode == "default" then
io.write(string.format("%33s |", tostring(v.k)))
fill_line(v.v * 34 / stdSum, 34)
io.write(string.format("| %d\n", v.v))
else
io.write(string.format("%s\n%d\n", tostring(v.k), v.v))
end
end
以上代码就是打印最后的柱状图了。输出结果类似:
value ---------- Distribution ---------- count
syscalls:sys_enter_gettimeofday |******** | 25940
syscalls:sys_exit_gettimeofday |******** | 25940
syscalls:sys_enter_epoll_wait |**** | 12977
syscalls:sys_exit_epoll_wait |**** | 12977
syscalls:sys_exit_alarm |* | 3917
(8)
function print_hist(t, cmp_func)
__print_hist(t, cmp_func, "default")
end
function print_hist_raw(t, cmp_func)
__print_hist(t, cmp_func, "raw")
end
shark.print_hist = print_hist
shark.print_hist_raw = print_hist_raw
最后就是把__print_hist
封装出shark.print_hist
和shark.print_hist_raw
两个函数供其它程序调用。