Misc.protect_refs: use Fun.protect to protect the backtrace#9060
Misc.protect_refs: use Fun.protect to protect the backtrace#9060gasche merged 1 commit intoocaml:trunkfrom
Conversation
8f7c8bf to
0d31f8f
Compare
|
Fun.protect has some overhead in contexts combining temporary mutations and exceptions raised for control flow (unless those are raised with Other than that, looks good to me. |
|
This is a good question, thanks. Most uses of
My gut feeling is that there will not be any noticeable performance regression, and that if we found any, the solution would be to use |
|
Thanks, the discussion is interesting, because it is a good occasion to confront the implementation of the new
let without_warnings f =
if !disabled then f ()
else Misc.protect_refs [Misc.R(disabled, true)] fbut here really it does not matter (see below).
So it is a priori unclear that this is the pathological case we are looking for, say with nested calls to Fun.protect in a success path which repeatedly end with an exception raised and caught.
I did diff --git a/utils/misc.ml b/utils/misc.ml
index f42b79350..7e900a5f2 100644
--- a/utils/misc.ml
+++ b/utils/misc.ml
@@ -51,6 +51,19 @@ let try_finally ?(always=(fun () -> ())) ?(exceptionally=(fun () -> ())) work =
type ref_and_value = R : 'a ref * 'a -> ref_and_value
+let count = ref 0
+
+let argv () =
+ let s = ref "" in
+ Array.iter (fun a -> s := !s ^ a ^ " ") Sys.argv;
+ !s
+
+let _ = at_exit (fun () ->
+ let f = open_out_gen [Open_append] 0 "/tmp/ocaml" in
+ Printf.fprintf f "%s\n backtraces copied %n times\n" (argv()) !count;
+ close_out f
+ )
+
let protect_refs =
let set_refs l = List.iter (fun (R (r, v)) -> r := v) l in
fun refs f ->
@@ -58,7 +71,7 @@ let protect_refs =
set_refs refs;
match f () with
| x -> set_refs backup; x
- | exception e -> set_refs backup; raise e
+ | exception e -> incr count; set_refs backup; raise e
(* List functions *)The result is the following: https://pad.inria.fr/p/np_XYK5b2EmjLyfbuNE My impression is: 1) good call about camlinternalFormat, 2) this is negligeable performance-wise, 3) looking further, one finds that all of the 113 copies are caused by the type-checking of one function, This is going to be food for thought when thinking about resource-management, but this patch is good to go (no need for additional benchmarks). |
|
Thanks for the analysis! This is nice work. |
Currently Fun.protect and Misc.try_finally can be used in code that tries carefully to preserve the first-failure backtrace, but Misc.protect_refs cannot. This PR fixes the discrepancy. See ocaml#9057 for a use-case. See the GPR ( ocaml#9060 ) for an in-depth discussion of the potential performance impact of this change.
0d31f8f to
956fcdc
Compare
956fcdc to
f5252e9
Compare
Currently Fun.protect and Misc.try_finally can be used in code that tries carefully to preserve the first-failure backtrace, but Misc.protect_refs cannot. This PR fixes the discrepancy. See ocaml#9057 for a use-case. See the GPR ( ocaml#9060 ) for an in-depth discussion of the potential performance impact of this change.
Currently Fun.protect and Misc.try_finally can be used in code that tries carefully to preserve the first-failure backtrace, but Misc.protect_refs cannot. This PR fixes the discrepancy. See ocaml#9057 for a use-case. See the GPR ( ocaml#9060 ) for an in-depth discussion of the potential performance impact of this change.
Currently Fun.protect and Misc.try_finally can be used in code that tries carefully to preserve the first-failure backtrace, but Misc.protect_refs cannot. This PR fixes the discrepancy. See #9057 for a use-case. See the GPR ( ocaml/ocaml#9060 ) for an in-depth discussion of the potential performance impact of this change.
Currently Fun.protect and Misc.try_finally can be used in code that
tries carefully to preserve the first-failure backtrace, but
Misc.protect_refs cannot. This PR fixes the discrepancy. See #9057 for
a use-case.