|
1 -- Copyright (c) 2011-2012 by Robert G. Jakabosky <bobby@neoawareness.com> |
|
2 -- |
|
3 -- Permission is hereby granted, free of charge, to any person obtaining a copy |
|
4 -- of this software and associated documentation files (the "Software"), to deal |
|
5 -- in the Software without restriction, including without limitation the rights |
|
6 -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
7 -- copies of the Software, and to permit persons to whom the Software is |
|
8 -- furnished to do so, subject to the following conditions: |
|
9 -- |
|
10 -- The above copyright notice and this permission notice shall be included in |
|
11 -- all copies or substantial portions of the Software. |
|
12 -- |
|
13 -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
14 -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
15 -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
16 -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
17 -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
18 -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
19 -- THE SOFTWARE. |
|
20 |
|
21 local ltraverse = require"traverse" |
|
22 local sformat = string.format |
|
23 local have_getsize = false |
|
24 local getsize = function() |
|
25 return 0 |
|
26 end |
|
27 if not jit then |
|
28 getsize = require"getsize" |
|
29 have_getsize = true |
|
30 end |
|
31 |
|
32 local _M = {} |
|
33 |
|
34 function _M.dump_stats(file) |
|
35 local type_cnts = {} |
|
36 local function type_inc(t) |
|
37 type_cnts[t] = (type_cnts[t] or 0) + 1 |
|
38 end |
|
39 local type_mem = {} |
|
40 local function type_mem_inc(v) |
|
41 if not have_getsize then return end |
|
42 local t = type(v) |
|
43 local s = getsize(v) |
|
44 type_mem[t] = (type_mem[t] or 0) + s |
|
45 end |
|
46 -- build metatable->type map for userdata type detection. |
|
47 local ud_types = {} |
|
48 local reg = debug.getregistry() |
|
49 for k,v in pairs(reg) do |
|
50 if type(k) == 'string' and type(v) == 'table' then |
|
51 ud_types[v] = k |
|
52 end |
|
53 end |
|
54 local function ud_type(ud) |
|
55 return ud_types[debug.getmetatable(ud)] or "<unknown>" |
|
56 end |
|
57 local str_data = 0 |
|
58 local funcs = { |
|
59 ["edge"] = function(from, to, how, name) |
|
60 type_inc"edges" |
|
61 end, |
|
62 ["table"] = function(v) |
|
63 type_inc"table" |
|
64 type_mem_inc(v) |
|
65 end, |
|
66 ["string"] = function(v) |
|
67 type_inc"string" |
|
68 str_data = str_data + #v |
|
69 type_mem_inc(v) |
|
70 end, |
|
71 ["userdata"] = function(v) |
|
72 type_inc"userdata" |
|
73 type_inc(ud_type(v)) |
|
74 type_mem_inc(v) |
|
75 end, |
|
76 ["cdata"] = function(v) |
|
77 type_inc"cdata" |
|
78 end, |
|
79 ["func"] = function(v) |
|
80 type_inc"function" |
|
81 type_mem_inc(v) |
|
82 end, |
|
83 ["thread"] = function(v) |
|
84 type_inc"thread" |
|
85 type_mem_inc(v) |
|
86 end, |
|
87 } |
|
88 local ignores = {} |
|
89 for k,v in pairs(funcs) do |
|
90 ignores[#ignores + 1] = k |
|
91 ignores[#ignores + 1] = v |
|
92 end |
|
93 ignores[#ignores + 1] = type_cnts |
|
94 ignores[#ignores + 1] = funcs |
|
95 ignores[#ignores + 1] = ignores |
|
96 |
|
97 ltraverse.traverse(funcs, ignores) |
|
98 |
|
99 local fd = file |
|
100 if type(file) == 'string' then |
|
101 fd = io.open(filename, "w") |
|
102 end |
|
103 fd:write(sformat("memory = %i bytes\n", collectgarbage"count" * 1024)) |
|
104 fd:write(sformat("str_data = %i\n", str_data)) |
|
105 fd:write(sformat("object type counts:\n")) |
|
106 for t,cnt in pairs(type_cnts) do |
|
107 fd:write(sformat(" %9s = %9i\n", t, cnt)) |
|
108 end |
|
109 fd:write("\n") |
|
110 if have_getsize then |
|
111 fd:write(sformat("per type memory usage:\n")) |
|
112 local total = 0 |
|
113 for t,mem in pairs(type_mem) do |
|
114 total = total + mem |
|
115 fd:write(sformat(" %9s = %9i bytes\n", t, mem)) |
|
116 end |
|
117 fd:write(sformat("total: %9i bytes\n", total)) |
|
118 fd:write("\n") |
|
119 end |
|
120 --[[ |
|
121 fd:write("LUA_REGISTRY dump:\n") |
|
122 for k,v in pairs(reg) do |
|
123 fd:write(tostring(k),'=', tostring(v),'\n') |
|
124 end |
|
125 --]] |
|
126 if type(file) == 'string' then |
|
127 fd:close() |
|
128 end |
|
129 end |
|
130 |
|
131 return _M |