Bienvenidos sean a este post, mas alla de su nombre esta libreria es tambien util para otras tareas que la depuracion.
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 = {}
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
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
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()
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
Para finalmente imprimir cada funcion con su contador:
for func, contar in pairs(Contadores) do
print(getnombre(func), contar)
end
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
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
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.
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