Skip to main content

luaur_repl_cli/functions/
profiler_loop.rs

1//! Faithful port of `static void profilerLoop()` (CLI/src/Profiler.cpp:75).
2
3use core::ffi::c_int;
4use core::sync::atomic::Ordering;
5use std::thread;
6
7use luaur_vm::functions::lua_clock::lua_clock;
8use luaur_vm::records::lua_state::lua_State;
9
10use crate::functions::profiler_trigger::{profiler_trigger, G_PROFILER};
11
12/// The VM safepoint interrupt callback. `extern "C-unwind"` to match
13/// `LuaCallbacks::interrupt`; mirrors C++ assigning
14/// `gProfiler.callbacks->interrupt = profilerTrigger`.
15unsafe extern "C-unwind" fn profiler_interrupt(l: *mut lua_State, gc: c_int) {
16    profiler_trigger(l, gc as i32);
17}
18
19pub fn profiler_loop() {
20    unsafe {
21        let p = core::ptr::addr_of_mut!(G_PROFILER);
22        // `frequency` and `callbacks` are set by `profiler_start` before this
23        // thread is spawned, so they are stable for the lifetime of the loop.
24        let frequency = (*p).frequency as f64;
25        let callbacks = (*p).callbacks;
26
27        let mut last = lua_clock();
28
29        while !(*p).exit.load(Ordering::Relaxed) {
30            let now = lua_clock();
31
32            if now - last >= 1.0 / frequency {
33                let ticks = ((now - last) * 1e6) as i64;
34
35                (*p).ticks.fetch_add(ticks as u64, Ordering::Relaxed);
36                (*p).samples.fetch_add(1, Ordering::Relaxed);
37                if !callbacks.is_null() {
38                    (*callbacks).interrupt = Some(profiler_interrupt);
39                }
40
41                last += ticks as f64 * 1e-6;
42            } else {
43                thread::yield_now();
44            }
45        }
46    }
47}