lexifi / landmarks Goto Github PK
View Code? Open in Web Editor NEWA Simple Profiling Library for OCaml
License: MIT License
A Simple Profiling Library for OCaml
License: MIT License
I have been trying to use the new compatibility with js_of_ocaml added in #36.
I have my code organized into a library with the final part of my code being
let () =
Js.export "somefun" some_function
This is then called in javascript with
var lib = require('./mylib.bc.js');
lib.some_function()
and I run the whole thing with OCAML_LANDMARKS="format=textual" node test.js
Landmarks does produce output, but it seems that it only profiles the setup code being run, not the eventual use of some_function. If I put a print statement in some_function, it is printed after the output of Landmarks, which is full of timings for loading different modules in my code.
the we viewer requires me to re-choose a changed profile file with unchanged name. it would be more convenient if i could just click the load button again.
We're using Landmarks on Frama-C (when landmarks is installed, it is optionally enabled when building Frama-C), but a recent addition of a let+
operator in our code results in an error:
Fatal error: exception (...): let operators are not supported before OCaml 4.08
Error: Error while running external preprocessor
Command line: /home/user/.opam/4.08.1/lib/landmarks/ppx/./ppx.exe --as-ppx '/tmp/camlppx2353e9' '/tmp/camlppxf2433e'
I tried using OCaml 4.08, but also 4.12, and I get the same error message mentioning OCaml < 4.08, so I'm assuming it's an issue with the error message and not my OCaml version.
I believe that fixing #26 would fix this as well, but in case there's a simpler workaround for this issue in particular, it would be helpful. For now, we have to disable landmarks to be able to compile Frama-C.
Hello,
The online viewer is a 404 and the package landmarks-viewer
mentioned in the README doesn't exist.
I just tried landmarks on an experimental program of mine, and it is really nice: the web interface is convenient and it's really easy to set up, so thanks!
A small change that might be nice, when using [@@@landmarks auto]
, would be to have function names qualified by their path from the name of the current module. For instance, in:
(* file A.ml *)
let x = …
module B = struct
let y = …
end
we would have, in the trace, "A.x" and "A.B.y" instead of "x" and "y".
For instance:
let () =
let[@landmark] rec f () = ()
and g () = f () in
g ()
will produce unused variable "f".
This is a bug in the ppx "translation".
On the other hand, the warning will disappear with:
let f = ()
let () =
let[@landmark] rec f () = ()
and g () = f () in
g ()
this seems to be a bug in the ocaml compiler.
This is a simplified example of an issue that happened with Frama-C's visitors:
(* a.ml *)
type visitAction = Go | Skip
class visitor = object
method visit () = Go
end
(* b.ml *)
class skip_visitor = object
inherit A.visitor
method! visit () = Skip (* Could be A.Skip, but due to inheritance, the module name is unnecessary *)
end
OCAML_LANDMARKS=auto ocamlfind ocamlopt -package landmarks -package landmarks-ppx a.ml b.ml
This fails with:
File "b.ml", line 4, characters 21-25:
4 | method! visit () = Skip
^^^^
Error: Unbound constructor Skip
Without Landmarks instrumentation, the above compiles, since the Skip
constructor is found in module A
.
If I explicitly write A.Skip
in b.ml
, it works fine.
If this is hard to fix, I believe a small addition to the Known issues section with the workaround should suffice to help people find it. Classes and inheritance are rarely used anyway in OCaml.
i can invoke the local installed version of the web viewer, but that fails to load json files. only the online version works for me. ocaml 4.04.0+flambda. mac os x. firefox newest.
this will make the instrumentation example in the dune docs work. see
I'd like to suggest a clarification about recursive function calls to the Github README page (which I find very useful as reference for new users): I think it could be useful to add something related to the call counters, e.g. that they may not correspond to the "intuitive" notion when using PPX-generated landmarks inside recursive call nests.
For instance, in the following program:
let[@landmark] rec f n =
if n <= 1 then 1 else g (n-1)
and[@landmark] g n =
f (n-1)
let[@landmark] rec h n =
if n <= 1 then 1 else h (n-1)
let () =
Format.printf "g = %d@." (g 10);
Format.printf "h = %d@." (h 10);
The report says that functions g
and h
were both called once (1 calls
), and f
seems to not have been called.
This is not very intuitive (I'd have expected all functions to have several calls each) and can lead to some confusion. For instance, in my real-world case, I had a mutually recursive function which was not directly called, so it was not being reported, even though the function was indirectly called by another one. A small clarification about that could help beginners.
I am considering using Landmarks for a project, but opam install landmarks
wants to downgrade and recompile ppxlib
, which is a red flag as most of the OCaml ppx ecosystem depends on ppxlib
nowadays (I don't want to recompile all those dependencies, and I should not have to downgrade).
I think that there are two related problems here:
Landmarks has a strict dependency on ocaml-migrate-parsetree < 2.0.0
; could this requirement be lifted in a new version of landmarks, that would make it compatible with the rest of the still-alive ppx ecosystem?
I don't actually plan to use landmarks ppx support, so I would prefer being able to install landmarks without dealing with all of that. Could the ppx support be proposed in a separate package landmarks-ppx
, so that non-ppx users can easily install the software without having to pay for ppx maintainability woes?
I would be willing to help along the way, but not to do (2), which sounds easier but is also very boring packaging stuff. @mlasson, if you were motivated to implement (2), I could have a try at a PR to fix (1) in reciprocity -- unless this has already been done somewhere and I missed it, of course.
Since the main branch has already been ported to ppxlib
it would be great if you could cut a release, so that landmarks
can be used together with other PPXs in their latest version.
Thank you for the incredibly useful landmarks
library! It works flawlessly for us on x86, but we seem to be out of luck for now on our Apple M1s. Is there a nontrivial technical obstruction for supporting arm64
? If there is anything we could do to help, we would be happy to try.
I tried to build the following example:
open Landmark
let loop = register "loop"
let sleep = register "sleep"
let main = register "main"
let zzz () =
enter sleep;
Unix.sleep 1;
exit sleep
let () =
begin
start_profiling ();
enter main;
enter loop;
for _ = 1 to 9 do
zzz ()
done;
exit loop;
zzz ();
exit main;
end
With a dune file like:
(executable
(name main)
(libraries landmarks unix)
(modes native)
(preprocess (pps landmarks.ppx --auto))
)
Unfortunately when I run dune build
from the project's root directory the generated program (main.exe) returns the following output:
Warning: landmark failure when closing 'load(bin/main)' (bin/main.ml:1), expecting 'ROOT' (src/landmark.ml).
Call graph './main.exe':
------------------------
Note: Nodes accounting for less than 1.00% of their parent have been ignored.
Aggregated table:
----------------
Name; Filename; Calls; Time; Allocated bytes
ROOT; src/landmark.ml; 0; 69.01K; 59888
Fatal error: exception Landmark.LandmarkFailure("unable to recover from landmark failure when closing 'load(bin/main)' (bin/main.ml:1), expecting 'ROOT' (src/landmark.ml).")
Having said that, building the same program with ocamlfind ocamlc -o prog -package landmarks -package unix -linkpkg main.ml
results with perfectly fine working program that produces the following output:
Call graph './prog':
--------------------
[ 22.61G cycles in 1 calls ] - 100.00% : main
[ 20.35G cycles in 1 calls ] | - 90.00% : loop
[ 20.35G cycles in 9 calls ] | | - 100.00% : �[1;31msleep�[0m
[ 2.26G cycles in 1 calls ] | - 10.00% : �[0;31msleep�[0m
Note: Nodes accounting for less than 1.00% of their parent have been ignored.
Aggregated table:
----------------
Name; Filename; Calls; Time; Allocated bytes
ROOT; src/landmark.ml; 0; 22.61G; 113304
main; unknown; 1; 22.61G; 7456
sleep; unknown; 10; 22.61G; 2720
loop; unknown; 1; 20.35G; 5472
We have problem with polymorphism constraints:
let[@landmark] f : type t. t -> t = fun x -> x`
will trigger a clean but disapointing error message:
ppx_landmark: this landmark annotation requires a name argument
whereas exlicititly providing the name
let[@landmark "f"] f : type t. t -> t = fun x -> x
generates an unlocated type error after the ppx:
File "none", line 1:
Error: This definition has type 't -> 't which is less general than
't0. 't0 -> 't0
Landmarks expects landmarks to be correctly nested, making it impossible to bench interleaved asynchronous code, for instance when using Lwt
or Async
.
(* This will not measure the request, only the creation of the monad which takes 0ms *)
let[@landmark] test () =
let* response = http_request () in
process_response response
(* This will probably crash in non toy examples as other threads will probably interleave incompatible enter/leaves *)
let[@landmark] test () =
Landmarks.enter mark;
let* response = http_request () in
let res = process_response response in
Landmarks.leave mark;
res
Is it something we'd want to support in landmarks ? Has it already been looked into ?
I'm keen to try implementing it, but at the same time it seems to me it would require some convoluted way to register threads with landmarks and a bunch of lookup maps that may impact the program performances, which is never great for a bench tool.
It seems that the online viewer cannot read the generated JSON files anymore. Is this expected? Thanks for the nice tool :-)
The provided sample typecore.json
shows:
load(bytecomp/opcodes.ml) 30 396 151 744 080
i.e. 30396 calls and 151744080 CPU cycles. I've been told (personal communication) that this landmark wraps the initialization for that compilation unit, so it should really be called at most once in a given process (as other load(...)
landmark).
4.03, 4.04 are released this year, it would be nice to support some not too old compiler like 4.02.3
Run the ppx in automatic mode on :
module M = struct
type t = A | B
end
class a =
object
method f = M.A
end
class b =
object
inherit a
method! f = B
end
Class b get translated into:
class b =
object
inherit a
method! f =
Landmark.enter __generated_landmark;
let r = try B with e -> (Landmark.exit __generated_landmark; Landmark.raise e) in
Landmark.exit __generated_landmark;
r
end
which triggers "Error: Unbound constructor B" because the typechecker does not know at this point that the B has the same type as the method's returned type.
We could add type annotations ("'a") to guide the inference (we have to make sure that 'a is fresh of course).
class b =
object
inherit a
method! f : 'a =
Landmark.enter __generated_landmark;
let r = try (B : 'a) with e -> (Landmark.exit __generated_landmark; Landmark.raise e) in
Landmark.exit __generated_landmark;
r
end
If there's an annotation on the returned type we probably should copy it around the body in a similar fashion.
Speaking of viewers, web browsers come with their own profile viewers. Maybe you could simply piggyback on these.
For Chrome this happens at the chrome://tracing
address and the JSON file format it can read is described here.
For Firefox it's in the browser's webdeveloper performance tools or here. The format seems to be a little bit less well documented but some type defintions can be found here.
I tried compiling landmarks on the freshly-released OCaml 4.04.1, but I got the following error when trying opam install landmarks
(I made a local opam repository using the extracted contents of the OCaml release archive):
[ERROR] The compilation of landmarks failed at "make".
Processing 1/1: [landmarks: ocamlfind remove]
#=== ERROR while installing landmarks.1.1 =====================================#
# opam-version 1.2.2
# os linux
# command make
# path /home/andr/.opam/4.04.1+local-git-/build/landmarks.1.1
# compiler 4.04.1+local-git-
# exit-code 2
# env-file /home/andr/.opam/4.04.1+local-git-/build/landmarks.1.1/landmarks-21719-5f1023.env
# stdout-file /home/andr/.opam/4.04.1+local-git-/build/landmarks.1.1/landmarks-21719-5f1023.out
# stderr-file /home/andr/.opam/4.04.1+local-git-/build/landmarks.1.1/landmarks-21719-5f1023.err
### stdout ###
# ocamldep -I . *.mli *.ml > .depend
# ocamlopt -c clock.c
# ocamlc -w +A-30-42-41-48-40-4 -safe-string -strict-sequence -bin-annot -g -c landmark_misc.ml
# ocamlc -w +A-30-42-41-48-40-4 -safe-string -strict-sequence -bin-annot -g -c landmark_graph.mli
# ocamlc -w +A-30-42-41-48-40-4 -safe-string -strict-sequence -bin-annot -g -c landmark_graph.ml
# ocamlc -w +A-30-42-41-48-40-4 -safe-string -strict-sequence -bin-annot -g -c landmark.mli
# ocamlc -w +A-30-42-41-48-40-4 -safe-string -strict-sequence -bin-annot -g -c landmark.ml
# ocamlmklib -o landmarks clock.o landmark_misc.cmo landmark_graph.cmo landmark.cmo
### stderr ###
# /usr/bin/ld: clock.o: relocation R_X86_64_PC32 against undefined symbol `caml_copy_int64' can not be used when making a shared object; recompile with -fPIC
# /usr/bin/ld: final link failed: Bad value
# collect2: error: ld returned 1 exit status
# make[1]: *** [Makefile:38: landmarks.cma] Error 2
# make: *** [Makefile:15: landmarks] Error 2
I don't have the time right now to try adding the suggested flag, but I'll do later. In any case, I wanted to notify about it.
I am using a Fedora 26-alpha with GCC 7, so it is not impossible that it is an issue due to this somewhat bleeding-edge configuration. However, I am able to compile landmarks on OCaml 4.04.0 without issues.
Instrumenting
let in_box ~x1 c =
x1 <= c.x1
produces
let in_box ~x1 x1 =
Landmark.enter __generated_landmark_a80eafc94c19d07eaf47a4752adba800_1;
(let r =
try (in_box ~x1) x1
with
....
(clash between the generated argument x1 and the label)
output=temporary:profile
would create files under profile/ in the current directory).Sys.argv
.I tried both the OPAM 1.0 version and git-pinning as indicated, and got the same result in both cases.
After compiling the example program, I tried several options, but got some errors:
$ OCAML_LANDMARKS=debug ./prog
[LANDMARKS] Unknown option 'debug'.
$ OCAML_LANDMARKS=on ./prog
[LANDMARKS] Unknown option 'on'.
$ OCAML_LANDMARKS=output=/tmp/file.txt ./prog
[LANDMARKS] The argument '/tmp/file.txt' in not valid for the option 'output'.
$ OCAML_LANDMARKS=output=temporary:/tmp/ ./prog
[LANDMARKS] The argument 'temporary:/tmp/' in not valid for the option 'output'.
This also happens when adding simple and double quotes to the names of the file or directory in the latter cases.
The other options I tried (off, format=json, auto, etc.) all seem to work, so I don't know if I'm doing something wrong.
I have a new OCaml user that wants to track a sequence of function calls (just to better understand the code), and the easiest way seems to be to just add calls to printf at each function entry and exit (or even just entry). But manually doing so is a bit annoying.
I wonder if Landmark's PPX could somehow enable this behavior: with a simple annotation [@landmark "something"]
in each function to be tracked, instead of incrementing the counters, just print a message such as "entering function f" or something... is there something like this?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.