examples/luastate.lua

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