CapsAdmin

Untitled

Sep 18th, 2013
134
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.37 KB | None | 0 0
  1. local profiler = _G.profiler or {}
  2.  
  3. profiler.type = "instrumental"
  4. profiler.default_zone = "no zone"
  5. profiler.enabled = true
  6.  
  7. local clock = os.clock -- see SetClockFunction
  8.  
  9. local function fix_path(path)
  10.     return path:gsub("\\", "/"):gsub("(/+)", "/"):gsub("^%s*(.-)%s*$", "%1" )
  11. end
  12.  
  13. local function getparams(func)
  14.     local params = {}
  15.    
  16.     for i = 1, math.huge do
  17.         local key = debug.getlocal(func, i)
  18.         if key then
  19.             table.insert(params, key)
  20.         else
  21.             break
  22.         end
  23.     end
  24.  
  25.     return params
  26. end
  27.  
  28. profiler.data = profiler.data or {}
  29.  
  30. local active = false
  31. local zone = profiler.default_zone
  32. local data = profiler.data
  33. local read_file
  34.  
  35.  
  36. if jit.version_num >= 20100 then
  37.     profiler.jitpf = require("jit.profile")
  38.     profiler.default_mode = "l"
  39.     profiler.dump_depth = 10
  40.     profiler.dump_format = "pl\n"
  41. end
  42.  
  43. if glfw then
  44.     clock = glfw.GetTime
  45.     read_file = vfs.Read
  46. elseif gmod then
  47.     clock = SysTime
  48. end
  49.  
  50. -- call this with glfw.GetTime or something after glfw is loaded
  51. function profiler.SetClockFunction(func)
  52.     time = func
  53.     profiler.Restart()
  54. end
  55.  
  56. do
  57.     local function statistical_callback(thread, samples, vmstate)
  58.         if not active or not profiler.enabled then
  59.             profiler.Stop()
  60.         return end
  61.        
  62.         profiler.jitpf.dumpstack(thread, profiler.dump_format, profiler.dump_depth):gsub("(.-):(%d+)", function(path, line)
  63.            
  64.             data[zone] = data[zone] or {}
  65.             data[zone][path] = data[zone][path] or {}
  66.             data[zone][path][line] = data[zone][path][line] or {total_time = 0, samples = 0}
  67.            
  68.             data[zone][path][line].samples = data[zone][path][line].samples + samples
  69.             data[zone][path][line].start_time = data[zone][path][line].start_time or clock()
  70.            
  71.         end)
  72.     end
  73.    
  74.     local function instrumental_callback(type)
  75.         if not active or not profiler.enabled then
  76.             profiler.Stop()
  77.         return end
  78.    
  79.         local info = debug.getinfo(2)
  80.        
  81.         if info.linedefined <= 0 then return end
  82.        
  83.         local path = info.source
  84.         local line = info.linedefined
  85.                
  86.         data[zone] = data[zone] or {}
  87.         data[zone][path] = data[zone][path] or {}
  88.         data[zone][path][line] = data[zone][path][line] or {total_time = 0, samples = 0, total_garbage = 0, func = info.func, func_name = info.name}
  89.        
  90.         data[zone][path][line].samples = data[zone][path][line].samples + 1
  91.         data[zone][path][line].start_time = data[zone][path][line].start_time or clock()
  92.        
  93.         if type == "call" then
  94.             data[zone][path][line].call_time = clock()
  95.             data[zone][path][line].call_garbage = collectgarbage("count")
  96.         elseif type == "return" and data[zone][path][line].call_time then
  97.             data[zone][path][line].total_time = data[zone][path][line].total_time + (clock() - data[zone][path][line].call_time)
  98.             data[zone][path][line].total_garbage = data[zone][path][line].total_garbage + (collectgarbage("count") - data[zone][path][line].call_garbage)
  99.         end
  100.     end
  101.  
  102.     function profiler.Start(zone)
  103.         if not profiler.enabled then return end
  104.                
  105.         if not zone then
  106.             local info = debug.getinfo(2)
  107.             if info then
  108.                 zone = info.name
  109.             end
  110.         end
  111.        
  112.         zone = zone or profiler.default_zone
  113.        
  114.         if profiler.type == "statistical" then
  115.             profiler.jitpf.start(profiler.default_mode, statistical_callback)
  116.         elseif profiler.type == "instrumental" then
  117.             debug.sethook(instrumental_callback, "cr")
  118.         end
  119.        
  120.         active = true
  121.     end
  122. end
  123.  
  124. function profiler.Stop()
  125.     if not profiler.enabled then return end
  126.    
  127.     if profiler.type == "statistical" then
  128.         profiler.jitpf.stop()
  129.     elseif profiler.type == "instrumental" then
  130.         debug.sethook()
  131.     end
  132.    
  133.     active = false
  134. end
  135.  
  136. function profiler.Restart()
  137.     profiler.data = {}
  138.     data = profiler.data
  139. end
  140.  
  141. function profiler.GetZone()
  142.     return zone
  143. end
  144.  
  145. function profiler.GetBenchmark()
  146.     local out = {}
  147.    
  148.     for zone, file_data in pairs(data) do
  149.         for path, lines in pairs(file_data) do
  150.             for line, data in pairs(lines) do
  151.                
  152.                 line =  tonumber(line)
  153.                
  154.                 local path = fix_path(path:gsub("%[.-%]", ""):gsub("@", ""))
  155.                 local name
  156.                 local debug_info
  157.                
  158.                 if data.func then                  
  159.                     debug_info = debug.getinfo(data.func)
  160.                    
  161.                     -- remove some useless fields
  162.                     debug_info.source = nil
  163.                     debug_info.short_src = nil
  164.                     debug_info.currentline = nil
  165.                     debug_info.func = nil
  166.                 end
  167.            
  168.                 if read_file then
  169.                     local content = read_file(path)
  170.                    
  171.                     if content then
  172.                         name = content:explode("\n")[line]
  173.                         if name then
  174.                             name = name:gsub("function ", "")
  175.                             name = name:trim()         
  176.                         else
  177.                             name = "unknown(line not found)"
  178.                         end
  179.                     else
  180.                         name = "unknown(file not found)"
  181.                     end
  182.                 elseif data.func then      
  183.                     name = ("%s(%s)"):format(data.func_name, table.concat(getparams(data.func), ", "))
  184.                 end
  185.                
  186.                 local temp = {
  187.                     zone = zone ~= "no zone" and zone or nil,
  188.                     path = path,
  189.                    
  190.                     line = line,
  191.                     name = name,
  192.                     debug_info = debug_info,
  193.                 }
  194.                
  195.                 if data.total_time then
  196.                     temp.average_time = data.total_time / data.samples
  197.                     temp.total_time = data.total_time
  198.                 end
  199.                
  200.                 if data.total_garbage and data.total_garbage > 0 then
  201.                     temp.average_garbage = math.floor(data.total_garbage / data.samples)
  202.                     temp.total_garbage = data.total_garbage
  203.                 end
  204.                                
  205.                 temp.sample_duration = clock() - data.start_time
  206.                 temp.times_called = data.samples
  207.                
  208.                 table.insert(out, temp)
  209.             end
  210.         end
  211.     end
  212.  
  213.     return out
  214. end
  215.  
  216. return profiler
Advertisement
Add Comment
Please, Sign In to add comment