Anuncios

Bienvenidos sean a este post, mas alla de su nombre esta libreria es tambien util para otras tareas que la depuracion.

Anuncios

Una tarea comun es la perfilacion, para usar un perfil con tiempo es mejor emplear una interfaz de C porque la sobrecarga de una llamada de Lua para cada gancho es demasiado alto y podria invalidar cualquier medicion, sin embargo para el conteo de perfiles Lua hace un trabajo decente, en este post haremos un perfilador rudimentario que lista el numero de veces que una funcion es llamado en un programa durante una ejecucion, las estructuras de datos principales de nuestro programa son dos tablas, una que asocia las funciones a sus contadores de llamada, otro que asocia funciones a sus nombres, los indices de cada tabla son las funciones mismas:

local Contadores = {}
local Nombres = {}
Anuncios

Podemos recuperar el dato del nombre despues de la perfilacion pero recuerda que tenemos mejores resultados si conseguimos el nombre de la funcion mientras esta activa porque despues Lua puede mirar en el codigo que esta llamando la funcion para encontrar su nombre, nuestro siguiente paso es definir la funcion de gancho, su trabajo es conseguir la funcion siendo llamada e incrementar el correspondiente contador y de paso guarda el nombre de la funcion:

local function gancho()
	local f = debug.getinfo(2, "f").func
	if Contadores[f] == nil then
		Contadores[f] = 1
		Nombres[f] = debug.getinfo(2, "Sn")
	else
		Contadores[f] = Contadores[f] + 1
	end
end
Anuncios

El proximo paso es ejecutar el programa con este gancho, vamos a asumir que el chunk principal del programa esta en un archivo que el usuario da este nombre como un argumento para este perfilador:

$ lua5.3 perfilador prog-princ
Anuncios

Con este esquema el perfilador puede conseguir el nombre del archivo en arg[1], encender el gancho y correr el programa:

local f = assert(loadfile(arg[1]))
debug.sethook(gancho, "c")
f()
debug.sethook()
Anuncios

La segunda linea se encarga de iniciar el gancho, corre el programa principal y luego libera el gancho, nuestro ultimo paso sera mostrar los resultados, la siguiente funcion produce un nombre por una funcion porque los nombres de las funciones en Lua son tan inciertos, asi que agregamos a cada funcion su ubicacion dado por un par archivo:linea, si una funcion no tiene nombre usamos solamente su ubicacion, si una funcion es de C solo usamos su nombre (como si no tuviera ubicacion):

function getnombre(func)
	local n = Nombres[func]
	if n.what == "C" then
		return n.name
	end
	local lc = string.format("[%s]:%s", n.short_src, n.linedefined)
	if n.namewhat ~= "" then
		return string.format("%s (%s)", lc, n.name)
	else
		return lc
	end
end
Anuncios

Para finalmente imprimir cada funcion con su contador:

for func, contar in pairs(Contadores) do
	print(getnombre(func), contar)
end
Anuncios

Antes de probarlo veamos como queda nuestro codigo fuente final:

perfilador.lua

local Contadores = {}
local Nombres = {}

local function gancho()
	local f = debug.getinfo(2, "f").func
	if Contadores[f] == nil then
		Contadores[f] = 1
		Nombres[f] = debug.getinfo(2, "Sn")
	else
		Contadores[f] = Contadores[f] + 1
	end
end

local f = assert(loadstring(arg[1]))
debug.sethook(gancho, "c")
f()
debug.sethook()

function getnombre(func)
	local n = Nombres[func]
	if n.what == "C" then
		return n.name
	end
	local lc = string.format("[%s]:%s", n.short_src, n.linedefined)
	if n.namewhat ~= "" then
		return string.format("[%s]:%s", lc, n.name)
	else
		return lc
	end
end

for func, contar in pairs(Contadores) do
	print(getnombre(func), contar)
end
Anuncios

Con nuestro codigo detallado veamos como funciona en la vida real, para ello vamos a tomar un codigo que hemos hecho anteriormente y lo ejecutaremos como dijimos antes:

tinchicus@dbn001dsk:~/lenguaje/lua$ lua5.3 perfilador.lua prueba.lua
10
20
30
[prueba.lua]:0 (f)      1
[prueba.lua]:1 (valores)        1
print   3
sethook 1
nil     3
[prueba.lua]:3 (for iterator)   4
Anuncios

En este caso podemos ver como se ejecuta el programa, luego nos pasa el nombre del mismo, su nivel, la cantidad de veces que se llama, cuantas veces se llama a valores, asi como a las otras funciones, con esto tenemos el perfilador basico listo, se pueden agregar mejoras pero asi como esta es una buena base para herramientas mas avanzadas.

Anuncios

En resumen, hoy hemos visto perfiles, que son, para que se pueden usar, como se configuran, como se puede implementar y como nos devuelven la informacion, espero les haya sido util sigueme en Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Tengo un Patreon donde podes acceder de manera exclusiva a material para este blog antes de ser publicado, sigue los pasos del link para saber como.

Tambien podes donar

Es para mantenimiento del sitio, gracias!

$1.00