mlua icon indicating copy to clipboard operation
mlua copied to clipboard

Enhancement: HookTrigger for resuming after yield

Open johalun opened this issue 5 months ago • 2 comments

Unless there's another of achieving the same thing, I propose adding a hook triggers for resuming and yielding a coroutine/thread.

I want to measure the CPU time spent running Lua code. I use mLua with Tokio and all the async bells and whistles.

I can get almost all the way there by measuring wall time for executing a Lua function, then subtracting the time spend suspended during function calls to Rust that will cause the async task to yield.

Example async Rust function called from Lua

pub async fn sleep(_lua: mlua::Lua, seconds: usize) -> mlua::Result<()> {
    start_timer();    
    tokio::time::sleep(std::time::Duration::from_secs(seconds as u64)).await;
    stop_timer();
    Ok(())
}

But it's not very ergonomic. It would be nicer if this could all be handled in a hook trigger callback. What's missing is when I yield the Lua function due to hitting the limit on max instruction count (HookTriggers::every_nth_instruction) run and yield for other async tasks to run on the same thread (by returning mlua::VmState::Yield) there's is no way for me to know when the Lua thread resumes and I can't measure the time spent yielding when yielding due to this hook trigger.

Hook trigger for when the thread resumes/yields would allow me to correctly measure CPU time spent running Lua.

johalun avatar Aug 02 '25 16:08 johalun

You can try the following hook:

lua.set_global_hook(HookTriggers::ON_CALLS, |_lua, debug| {
    let name = debug.names().name;
    if name.as_deref() == Some("poll") {
        println!("calling poll()");
    }
    if name.as_deref() == Some("yield") {
        println!("calling yield()");
    }
    Ok(VmState::Continue)
})
.unwrap();

poll() is called to resume Rust future, yield is called when future return Poll::Pending. If Rust future return Poll::Ready then yield will not be called.

But it's not very ergonomic.

Usually it can be solved by adding tracing support to app, for example tokio/tracing

khvzak avatar Aug 09 '25 22:08 khvzak

This is a high performance environment so I can't run hooks on every function call.

johalun avatar Aug 09 '25 23:08 johalun