LexiFi / landmarks

A Simple Profiling Library for OCaml
MIT License
129 stars 20 forks source link

Benchmarking js_of_ocaml library with `auto` only times constructor #38

Open WardBrian opened 1 year ago

WardBrian commented 1 year ago

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.

WardBrian commented 1 year ago

For anyone who is looking for a workaround to this, here is what I was able to do:

Inside the function I care about (some_function), I added a line before any work started:

  Landmark.start_profiling () ;

Then, before returning the result,

  Landmark.stop_profiling () ;
  let gc = Landmark.export_and_reset () in
  Landmark.Graph.output Out_channel.stderr gc ;

Then, running OCAML_LANDMARKS="format=textual" node test.js will output the normal Landmarks output twice, once with the timings of the loading, and once with the actual work of your function. Note that the environment variable doesn't really control very much if you use this method, you'd need to change the calls to start_profiling and output with the settings you need.

It would be great if --auto worked in such a way to cover this use case. Thanks again for a great library!

mlasson commented 1 year ago

Hello thanks for the report !

There's something I don't understand. Normally, the profiling start at loading time of the "Landmarks" module (when the environment variable is set). And the result should be dumped "at" exit. And everything should behave as manually starting the profiling like you did with the start/stop_profiling functions.

Would you have a small reproduction case I could look into ? Thanks !

hhugo commented 1 year ago

Here is what I think is happening just by reading this thread.

let () =
  Js.export "somefun" some_function

This will just export the function to js and continue executing the rest of the ocaml code. In particular, Std_exit will execute last and probability trigger dumping the results, too early, before you run your JavaScript function manually.

WardBrian commented 1 year ago

Here is an example: https://github.com/WardBrian/landmarks-js-example

I suspect @hhugo's explanation is correct. Dune considers all js_of_ocaml programs to be "executables", even in cases like this were the obvious purpose is to export a bunch of functions and use it as a library