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
|
||||
attempt on first call. Failures are sentineled (never retried). *)
|
||||
|
||||
let _jit_warned : (string, bool) Hashtbl.t = Hashtbl.create 16
|
||||
|
||||
let register_jit_hook env =
|
||||
Sx_ref.jit_call_hook := Some (fun f args ->
|
||||
match f with
|
||||
| Lambda l ->
|
||||
(match l.l_compiled with
|
||||
| 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)
|
||||
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 *)
|
||||
| None ->
|
||||
let fn_name = match l.l_name with Some n -> n | None -> "?" in
|
||||
@@ -715,7 +724,10 @@ let register_jit_hook env =
|
||||
| Some cl ->
|
||||
l.l_compiled <- Some cl;
|
||||
(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
|
||||
end)
|
||||
| _ -> None)
|
||||
|
||||
@@ -165,7 +165,8 @@ and vm_call vm f args =
|
||||
not the caller's globals. Closure vars were merged at compile time. *)
|
||||
(try push vm (call_closure cl args cl.vm_env_ref)
|
||||
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)))
|
||||
| Some _ ->
|
||||
(* Compile failed — CEK *)
|
||||
@@ -179,9 +180,7 @@ and vm_call vm f args =
|
||||
| Some cl ->
|
||||
l.l_compiled <- Some cl;
|
||||
(try push vm (call_closure cl args cl.vm_env_ref)
|
||||
with _e ->
|
||||
(* Don't mark failed — error may be data-dependent *)
|
||||
push vm (Sx_ref.cek_call f (List args)))
|
||||
with _e -> push vm (Sx_ref.cek_call f (List args)))
|
||||
| None ->
|
||||
push vm (Sx_ref.cek_call f (List args))
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user