summaryrefslogtreecommitdiff
path: root/xmake/core/base/profiler.lua
diff options
context:
space:
mode:
authorruki <[email protected]>2016-03-27 21:38:05 +0800
committerruki <[email protected]>2016-03-27 21:38:05 +0800
commit6d429805c8699f6a27cf3e8d5297391e2c7b592c (patch)
tree2fc7040954ae4dddac1c6a1e6a7cad57a010ae34 /xmake/core/base/profiler.lua
parentf599ffc2ca8f452b70e2fb928816c5b78302ee1b (diff)
impl profiler
Diffstat (limited to 'xmake/core/base/profiler.lua')
-rw-r--r--xmake/core/base/profiler.lua134
1 files changed, 133 insertions, 1 deletions
diff --git a/xmake/core/base/profiler.lua b/xmake/core/base/profiler.lua
index b0f0b3cf8..31a2fd093 100644
--- a/xmake/core/base/profiler.lua
+++ b/xmake/core/base/profiler.lua
@@ -21,14 +21,146 @@
--
-- define module
-local profiler = profiler or {}
+local profiler = {}
-- load modules
local os = require("base/os")
+local path = require("base/path")
local table = require("base/table")
local utils = require("base/utils")
local string = require("base/string")
+-- get the function title
+function profiler:_func_title(funcinfo)
+
+ -- check
+ assert(funcinfo)
+
+ -- the function name
+ local name = funcinfo.name or 'anonymous'
+
+ -- the function line
+ local line = string.format("%d", funcinfo.linedefined or 0)
+
+ -- the function source
+ local source = funcinfo.short_src or 'C_FUNC'
+ if os.isfile(source) then
+ source = path.relative(source, xmake._PROGRAM_DIR)
+ end
+
+ -- make title
+ return string.format("%-30s: %s: %s", name, source, line)
+end
+
+-- get the function report
+function profiler:_func_report(funcinfo)
+
+ -- get the function title
+ local title = self:_func_title(funcinfo)
+
+ -- get the function report
+ local report = self._REPORTS_BY_TITLE[title]
+ if not report then
+
+ -- init report
+ report =
+ {
+ title = self:_func_title(funcinfo)
+ , callcount = 0
+ , totaltime = 0
+ }
+
+ -- save it
+ self._REPORTS_BY_TITLE[title] = report
+ table.insert(self._REPORTS, report)
+ end
+
+ -- ok?
+ return report
+end
+
+-- hook call
+function profiler:_hook_call(funcinfo)
+
+ -- get the function report
+ local report = self:_func_report(funcinfo)
+ assert(report)
+
+ -- save the call time
+ report.calltime = os.clock()
+
+ -- update the call count
+ report.callcount = report.callcount + 1
+
+end
+
+-- hook return
+function profiler:_hook_return(funcinfo)
+
+ -- get the stoptime
+ local stoptime = os.clock()
+
+ -- get the function report
+ local report = self:_func_report(funcinfo)
+ assert(report)
+
+ -- update the total time
+ if report.calltime then
+ report.totaltime = report.totaltime + (stoptime - report.calltime)
+ end
+end
+
+-- the hook handler
+function profiler._hook_handler(hooktype)
+
+ -- the function info
+ local funcinfo = debug.getinfo(2, 'nS')
+
+ -- dispatch it
+ if hooktype == "call" then
+ profiler:_hook_call(funcinfo)
+ elseif hooktype == "return" then
+ profiler:_hook_return(funcinfo)
+ end
+end
+
+-- start profiling
+function profiler:start()
+
+ -- init reports
+ self._REPORTS = {}
+ self._REPORTS_BY_TITLE = {}
+
+ -- save the start time
+ self._STARTIME = os.clock()
+
+ -- start to hook
+ debug.sethook(profiler._hook_handler, 'cr', 0)
+
+end
+
+-- stop profiling
+function profiler:stop()
+
+ -- save the stop time
+ self._STOPTIME = os.clock()
+
+ -- stop to hook
+ debug.sethook()
+
+ -- calculate the total time
+ local totaltime = self._STOPTIME - self._STARTIME
+
+ -- sort reports
+ table.sort(self._REPORTS, function(a, b)
+ return a.totaltime > b.totaltime
+ end)
+
+ -- show reports
+ for _, report in ipairs(self._REPORTS) do
+ utils.printf("%04.3f, %5.2f%%, %7d, %s", report.totaltime, (report.totaltime / totaltime) * 100, report.callcount, report.title)
+ end
+end
-- return module
return profiler