sx-http: log JIT fallbacks once per function, not silently or flooding
JIT runtime errors now log once per function name via _jit_warned hashtable, then stay quiet for that function. No more silent swallowing (which hid real errors) or per-call flooding (which spammed thousands of lines and blocked the server). VM-level fallbacks (inside JIT-compiled code calling other JIT code) are silent — dedup happens at the hook level. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -690,15 +690,24 @@ let _jit_compiling = ref false (* re-entrancy guard *)
|
|||||||
(* JIT compilation is lazy-only: every named lambda gets one compile
|
(* JIT compilation is lazy-only: every named lambda gets one compile
|
||||||
attempt on first call. Failures are sentineled (never retried). *)
|
attempt on first call. Failures are sentineled (never retried). *)
|
||||||
|
|
||||||
|
let _jit_warned : (string, bool) Hashtbl.t = Hashtbl.create 16
|
||||||
|
|
||||||
let register_jit_hook env =
|
let register_jit_hook env =
|
||||||
Sx_ref.jit_call_hook := Some (fun f args ->
|
Sx_ref.jit_call_hook := Some (fun f args ->
|
||||||
match f with
|
match f with
|
||||||
| Lambda l ->
|
| Lambda l ->
|
||||||
(match l.l_compiled with
|
(match l.l_compiled with
|
||||||
| Some cl when not (Sx_vm.is_jit_failed cl) ->
|
| Some cl when not (Sx_vm.is_jit_failed cl) ->
|
||||||
(* Cached bytecode — run on VM, fall back to CEK on runtime error. *)
|
(* Cached bytecode — run on VM, fall back to CEK on runtime error.
|
||||||
|
Log once per function name, then stay quiet. Don't disable. *)
|
||||||
(try Some (Sx_vm.call_closure cl args cl.vm_env_ref)
|
(try Some (Sx_vm.call_closure cl args cl.vm_env_ref)
|
||||||
with _e -> None) (* silent fallback — no disable, no log *)
|
with e ->
|
||||||
|
let fn_name = match l.l_name with Some n -> n | None -> "?" in
|
||||||
|
if not (Hashtbl.mem _jit_warned fn_name) then begin
|
||||||
|
Hashtbl.replace _jit_warned fn_name true;
|
||||||
|
Printf.eprintf "[jit] %s runtime fallback to CEK: %s\n%!" fn_name (Printexc.to_string e)
|
||||||
|
end;
|
||||||
|
None)
|
||||||
| Some _ -> None (* compile failed or disabled — CEK handles *)
|
| Some _ -> None (* compile failed or disabled — CEK handles *)
|
||||||
| None ->
|
| None ->
|
||||||
let fn_name = match l.l_name with Some n -> n | None -> "?" in
|
let fn_name = match l.l_name with Some n -> n | None -> "?" in
|
||||||
@@ -715,7 +724,10 @@ let register_jit_hook env =
|
|||||||
| Some cl ->
|
| Some cl ->
|
||||||
l.l_compiled <- Some cl;
|
l.l_compiled <- Some cl;
|
||||||
(try Some (Sx_vm.call_closure cl args cl.vm_env_ref)
|
(try Some (Sx_vm.call_closure cl args cl.vm_env_ref)
|
||||||
with _e -> None) (* silent fallback, keep bytecode *)
|
with e ->
|
||||||
|
Printf.eprintf "[jit] %s first-call fallback to CEK: %s\n%!" fn_name (Printexc.to_string e);
|
||||||
|
Hashtbl.replace _jit_warned fn_name true;
|
||||||
|
None)
|
||||||
| None -> None
|
| None -> None
|
||||||
end)
|
end)
|
||||||
| _ -> None)
|
| _ -> None)
|
||||||
|
|||||||
@@ -165,7 +165,8 @@ and vm_call vm f args =
|
|||||||
not the caller's globals. Closure vars were merged at compile time. *)
|
not the caller's globals. Closure vars were merged at compile time. *)
|
||||||
(try push vm (call_closure cl args cl.vm_env_ref)
|
(try push vm (call_closure cl args cl.vm_env_ref)
|
||||||
with _e ->
|
with _e ->
|
||||||
(* Silent fallback to CEK — error is data-dependent, not a JIT bug *)
|
(* Fallback to CEK — data-dependent error, not a JIT bug.
|
||||||
|
Dedup logging happens in register_jit_hook. *)
|
||||||
push vm (Sx_ref.cek_call f (List args)))
|
push vm (Sx_ref.cek_call f (List args)))
|
||||||
| Some _ ->
|
| Some _ ->
|
||||||
(* Compile failed — CEK *)
|
(* Compile failed — CEK *)
|
||||||
@@ -179,9 +180,7 @@ and vm_call vm f args =
|
|||||||
| Some cl ->
|
| Some cl ->
|
||||||
l.l_compiled <- Some cl;
|
l.l_compiled <- Some cl;
|
||||||
(try push vm (call_closure cl args cl.vm_env_ref)
|
(try push vm (call_closure cl args cl.vm_env_ref)
|
||||||
with _e ->
|
with _e -> push vm (Sx_ref.cek_call f (List args)))
|
||||||
(* Don't mark failed — error may be data-dependent *)
|
|
||||||
push vm (Sx_ref.cek_call f (List args)))
|
|
||||||
| None ->
|
| None ->
|
||||||
push vm (Sx_ref.cek_call f (List args))
|
push vm (Sx_ref.cek_call f (List args))
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user