| 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"luatraverse" |
| 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(file, "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 |