Hi! Thanks for the feedback! You're right, placing hooks automatically isn't the most intuitive thing in the world. I should write a tutorial and/or provide a sensible mass-hook default function.
But the gist of it is:
- create a new profiler
- surround code that you would like to profile with profiler:startCycle() and profiler:endCycle() (typically in love.draw() or love.update())
- create "events" for which you'd like to have detailed statistics
If you don't create custom events, everybody's runtime will be lumped together in a default event named "<ROOT>". Fortunately, it's easy to create events automatically by placing hooks onto functions that do important things, typically your draw() or update() functions. To create events from functions, you can either:
- hook each individual function by hand
- mass-hook a ton of functions that have the same name
A. is tedious for "real world" projects; it's only really useful to profile one-off functions that have a unique name. But it's done as such, assuming Missile, Enemy, Player are tables (e.g. classes):
Code: Select all
profiler:hook(Missile, 'draw', 'draw a missile')
profiler:hook(Enemy, 'draw', 'draw an enemy')
profiler:hook(Player, 'draw', 'draw myself')
Now for B., assuming Missile/Enemy/Player are global tables, you can do this instead:
Code: Select all
profiler:hookAll(_G, 'draw', {love})
This will look in all subtables of _G (in Lua, _G is the table of all globals) for functions named 'draw' and place a profiling hook on it. In other words, it'll match:
_G.Enemy.draw
_G.Missile.draw
_G.Player.draw
_G.love.draw
Oops! We don't want to place an automatic hook on love.draw(). That's why we give hookAll a list of tables to skip, in this case just {love}.
(Technical reason why you don't want to place a hook on love.draw(): hooks actually just wrap a function call in an event; events may only occur in a "profiling cycle"; but you start and end the cycles in love.draw(), so if an event is triggered before a cycle exists, the profiler will crash)
Similarly, in the little example posted on github, I've also told the profiler to ignore lg. I used "lg" as an alias for "love.graphics". Since I don't want the profiler to place a hook on love.graphics.draw (through lg.draw), I told it to ignore lg.
Note that while it is dangerous to profile love.draw, it's totally okay to profile love.graphics.draw (that's the one that draws images). You can even profile LÖVE itself, e.g. love.graphics.rectangle, love.graphics.print, etc.
So I've mainly talked about hooks on functions here, but you can also create little events in your code with pushEvent()/popEvent() (it's really simple). I recommend reading main.lua from the demo because it explores all possible use cases. Also, don't hesitate to read the comments in PROBE.lua, they also describe how you should call each function.
While writing this post, I've realized the API could be made more intuitive, and I'll think of ways to simplify interaction with the hook mechanism. I should also post tutorials/luadocs somewhere
Thankfully, you only need place hooks once (typically in love.load()) and then you don't have to touch them again, so if you'd like to use the profiler right away, you don't really *need* to understand the hook conundrum in-depth. But I'm really glad it's useful to you!