-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Sys.frame_pointers
#9842
Add Sys.frame_pointers
#9842
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good and I think would be a useful addition.
stdlib/sys.mlp
Outdated
@@ -35,6 +35,7 @@ external unix : unit -> bool = "%ostype_unix" | |||
external win32 : unit -> bool = "%ostype_win32" | |||
external cygwin : unit -> bool = "%ostype_cygwin" | |||
external get_backend_type : unit -> backend_type = "%backend_type" | |||
external frame_pointers : unit -> bool = "caml_sys_frame_pointers" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would make this noalloc
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addition of Sys.frame_pointers
I agree is fine, but we don't need a primitive to expose a static constant... patch for generating it in the same way as Config.with_frame_pointers
enclosed as review comments.
stdlib/sys.mlp
Outdated
@@ -45,6 +46,7 @@ let int_size = int_size () | |||
let unix = unix () | |||
let win32 = win32 () | |||
let cygwin = cygwin () | |||
let frame_pointers = frame_pointers () |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let frame_pointers = frame_pointers () | |
let frame_pointers = %%WITH_FRAME_POINTERS%% && backend_type = Native |
and delete the external
above (cf. utils/config.mlp
)
runtime/sys.c
Outdated
CAMLprim value caml_sys_frame_pointers(value unit) | ||
{ | ||
#if defined(NATIVE_CODE) && defined(WITH_FRAME_POINTERS) | ||
return Val_true; | ||
#else | ||
return Val_false; | ||
#endif | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no need for this primitive. Edit stdlib/Makefile
instead:
--- a/stdlib/Makefile
+++ b/stdlib/Makefile
@@ -180,8 +180,11 @@ stdlib.cma: $(OBJS)
stdlib.cmxa: $(OBJS:.cmo=.cmx)
$(CAMLOPT) -a -o $@ $^
-sys.ml: $(ROOTDIR)/VERSION sys.mlp
- sed -e "s|%%VERSION%%|`sed -e 1q $< | tr -d '\r'`|" sys.mlp > $@
+VERSION = $(shell sed -e 1q $(ROOTDIR)/VERSION | tr -d '\r')
+sys.ml: sys.mlp $(ROOTDIR)/VERSION
+ sed $(call SUBST_STRING,VERSION) \
+ $(call SUBST,WITH_FRAME_POINTERS) \
+ $< > $@
.PHONY: clean
clean::
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. Is adding complexity to the Makefile
better than adding code in C and OCaml? I'm unsure that it is. What about the dune build?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is how utils/config.ml
is generated - it adds no complexity at all... the functions are already there. Dune is irrelevant to the consideration (FWIW, it would require a switch for stdlib/sys.ml to be generated in the same way config.ml, which happens to be by calling make).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is adding complexity to the
Makefile
better than adding code in C and OCaml?
We are big fans of doing things statically rather than dynamically so yes, definitely. Especially when all the machinery is already available.
As an aside, is linking compiler-libs and using |
I don't think forcing programs to link compiler-libs to read this property is a good idea. This sort of property might be useful for programs to introspect themselves, and you wouldn't want to have to link all of those programs against compiler-libs. |
@dra27 I'm not keen on doing the |
|
I don't understand what you mean by the environment. This seems exactly the same as my frame pointers function:
|
a5d8a09
to
786886e
Compare
Or perhaps this one is a better example since the other one is only used in bytecode:
|
os_type, big-endian etc. are properties of the runtime, so you can't know them until you're linked with a runtime (for native code of course, most if not all these things are actually constant) - frame pointers is a property of both the runtime and the code you just built - i.e. it's statically known when you build the module rather than only when you run it. Sorry about this - I wasn't expecting putting |
To be fair you are proposing doing meta-programming in a Makefile -- I'll take C over that any day.
Ok, so you're saying that the reason that the rest of |
Sure, but as I said the file is already "meta-programmed" for
Endianness I don't know (that was all put in for #5774) - |
Ok, let's do it your way then. I might add a comment somewhere too to try and make it clearer why the current code is how it is. |
And different OS family, yes. Bytecode is that portable. That's why the corresponding constants in Sys must be determined at program start-up time. On the other hand, features of the runtime system that are not relevant to bytecode, like the |
There's a variant of Wadler's law that says that the most innocuous-looking OCaml pull requests are the most scrutinized. Let me continue this tradition.
|
Unfortunately the performance of "perf" using DWARF call-frame information is terrible. Since reading the DWARF live is too slow it basically
The specific use case where this came up was for a process to call perf on itself. In particular, it is useful to be able to send an RPC to a service in production and have it return data from perfing itself. Here you want to tell perf to use frame-pointers if they are available and fall back to DWARF otherwise.
We would like to enable this self-perfing functionality on the majority our executables. IIUC using |
|
@lpw25 wrote:
My understanding is that ORC is now pretty mainstream in Linux (since v4.14 or so) for kernel unwinding, but that The |
786886e
to
317db16
Compare
I've pushed @dra27's version of the patch and added a Changes entry.
My understanding is that using ORC in perf would increase the amount of trust being placed in the ORC unwinder from a security perspective, so I don't think all the remaining hurdles are technical. Even if perf supported ORC we would still need to implement code to output ORC for OCaml programs, either during compilation or afterwards based on the DWARF or frame tables. This is all a significant amount of work, so I'm not holding my breath for it.
That would be possible, but it is much more work for a result that is less reusable and harder to maintain. To be honest, if I'm going to make something that will only work at Jane Steet anyway, I'll probably just add this patch to the lengthening list of patches on our version of the compiler, since its maintenance is trivial. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems inappropriate for me to mark as "approved" an implementation I have proposed!
I asked about whether Config
was a solution to the original problem in case it had been forgotten completely - it sounds as though it wasn't and I agree it doesn't sound like a general solution (cf. linkall
, etc.)
There is another possibility: we already install config.cmx
and config.cmi
- it would be a very small and coherent alternative to install config.o
(and, for completeness, config.cmo
) which would mean you could specifically link config.cmx
, rather than the whole of ocamlcommon.cmxa
. Config
is - and always should be - a self-contained module.
This might be fine, although I think it would need to come with some kind of agreement that changes to its interface would be breaking changes. Maybe not full on stdlib level support, but some notion that this was a public interface and that it won't be changed in bugfix releases or rewritten from scratch on a whim. |
I don't think that guarantee would be problematic. I had a check through its history... since 4.00, there have only been 3 breaking changes to
I don't think we'd have suffered by having to mark |
Note that BPF also doesn't support ORC yet either. I suspect it's for the same reason, but ideally both perf and BPF would support it before frame pointer support is removed. |
@xavierleroy I think I've addressed the concerns you raised in my earlier comment. Are you satisfied that |
I'm neutral. It's not a big problem to add this to Sys, but the need still feels very specific to one use at Jane Street. |
I have the impression that making |
I'm not entirely sure what making config into a small library will entail. Any chance one of the proponents of this approach could make a PR? I'd quite like to have a solution to this. |
What about adding |
I worry about the bootstrap story. So, we will have two possibly different Config, one in boot/ and one in stdlib/. Which one is used for which purposes? |
There can be only one version of |
Just to confirm this statement: Yes, as stated above, the FP variant is the only way to be able to profile long running stuff with perf in a reasonable way (without massive overhead). We at AbsInt use this feature extensively for large analyses that runs for days, for the OCaml and the C++ parts, for both only the FP variant is viable. All other provided ways to reconstruct the call-stack either are too slow (DWARF) or don't work reliable for deep stacks (lbr). I think my only real contribution to this repository was one patch to fix some FP related issue that hindered our use of it ;=) |
FWIW I also think that adding |
I still don't understand the bootstrapping implications. There will be one copy of the Config unit in boot/ , used to build ocamlc, and one copy of Config in stdlib/ , used to build ocamlopt, and both copies will differ when entries are added or removed to Config, or change meaning. What will happen then? |
I've opened #9992 which shows one way it could be done. |
What is the status on this PR? My impression is that there is no consensus on whether we want it. |
I still want a solution to this, and remain of the opinion that |
At the risk of appearing to go back on my original comment about having |
(TL;DR instead of "Add |
This looks like a good idea and the most lightweight of all the proposals so far. It also goes well with the idea that this is an obscure feature that very few people will need. |
#10419's merged, so I think this can be closed. |
I recently had a user ask how to know whether the current OCaml program was compiled with frame pointers. I was slightly surprised that it wasn't available in
Sys
, so this PR makes that information available inSys
.