profiler.lua.txt 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. -- Tencent is pleased to support the open source community by making xLua available.
  2. -- Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
  3. -- Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
  4. -- http://opensource.org/licenses/MIT
  5. -- Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
  6. local get_time = os.clock
  7. local sethook = xlua.sethook or debug.sethook
  8. local func_info_map = nil
  9. local start_time
  10. local function create_func_info(db_info)
  11. return {
  12. db_info = db_info,
  13. count = 0,
  14. total_time = 0
  15. }
  16. end
  17. local function on_hook(event, func_info_id, source)
  18. local func_info = func_info_map[func_info_id]
  19. if not func_info then
  20. func_info = create_func_info(debug.getinfo( 2, 'nS' ))
  21. func_info_map[func_info_id] = func_info
  22. end
  23. if event == "call" then
  24. func_info.call_time = get_time()
  25. func_info.count = func_info.count + 1
  26. func_info.return_time = nil
  27. elseif event == "return" or event == 'tail return' then
  28. local now = get_time()
  29. if func_info.call_time then
  30. func_info.total_time = func_info.total_time + (now - func_info.call_time)
  31. func_info.call_time = nil
  32. else
  33. func_info.total_time = func_info.total_time + (now - (func_info.return_time or now))
  34. func_info.count = func_info.count + 1
  35. end
  36. func_info.return_time = now
  37. if source and func_info.count == 1 then
  38. func_info.db_info.short_src = source
  39. end
  40. end
  41. end
  42. local function start()
  43. func_info_map = {}
  44. start_time = get_time()
  45. sethook(on_hook, 'cr')
  46. end
  47. local function pause()
  48. sethook()
  49. end
  50. local function resume()
  51. sethook(on_hook, 'cr')
  52. end
  53. local function stop()
  54. sethook()
  55. func_info_map = nil
  56. start_time = nil
  57. end
  58. local function report_output_line(rp, stat_interval)
  59. local source = rp.db_info.short_src or '[NA]'
  60. local linedefined = (rp.db_info.linedefined and rp.db_info.linedefined >= 0) and string.format(":%i", rp.db_info.linedefined) or ''
  61. source = source .. linedefined
  62. local name = rp.db_info.name or '[anonymous]'
  63. local total_time = string.format("%04.3f", rp.total_time * 1000)
  64. local average_time = string.format("%04.3f", rp.total_time / rp.count * 1000)
  65. local relative_time = string.format("%03.2f%%", (rp.total_time / stat_interval) * 100 )
  66. local count = string.format("%7i", rp.count)
  67. return string.format("|%-40.40s: %-50.50s: %-12s: %-12s: %-12s: %-12s|\n", name, source, total_time, average_time, relative_time, count)
  68. end
  69. local sort_funcs = {
  70. TOTAL = function(a, b) return a.total_time > b.total_time end,
  71. AVERAGE = function(a, b) return a.average > b.average end,
  72. CALLED = function(a, b) return a.count > b.count end
  73. }
  74. local function report(sort_by)
  75. sethook()
  76. local sort_func = type(sort_by) == 'function' and sort_by or sort_funcs[sort_by]
  77. local FORMAT_HEADER_LINE = "|%-40s: %-50s: %-12s: %-12s: %-12s: %-12s|\n"
  78. local header = string.format( FORMAT_HEADER_LINE, "FUNCTION", "SOURCE", "TOTAL(MS)", "AVERAGE(MS)", "RELATIVE", "CALLED" )
  79. local stat_interval = get_time() - (start_time or get_time())
  80. local report_list = {}
  81. for _, rp in pairs(func_info_map) do
  82. table.insert(report_list, {
  83. total_time = rp.total_time,
  84. count = rp.count,
  85. average = rp.total_time / rp.count,
  86. output = report_output_line(rp, stat_interval)
  87. })
  88. end
  89. table.sort(report_list, sort_func or sort_funcs.TOTAL)
  90. local output = header
  91. for i, rp in ipairs(report_list) do
  92. output = output .. rp.output
  93. end
  94. sethook(on_hook, 'cr')
  95. return output
  96. end
  97. return {
  98. --开始统计
  99. start = start,
  100. --获取报告,start和stop之间可以多次调用,参数sort_by类型是string,可以是'TOTAL','AVERAGE', 'CALLED'
  101. report = report,
  102. --停止统计
  103. stop = stop
  104. }