Skip to content
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

Creating toplevels is unbearably slow #818

Closed
dbuenzli opened this issue Jun 13, 2019 · 16 comments · Fixed by #902
Closed

Creating toplevels is unbearably slow #818

dbuenzli opened this issue Jun 13, 2019 · 16 comments · Fixed by #902

Comments

@dbuenzli
Copy link
Contributor

The simple eval example takes 34s on my machine.

Also when using --source-map-inline memory usage on small examples is so big that it leads to SIGSEGVs.

@dbuenzli dbuenzli changed the title Creating toplevels is unbarebly slow Creating toplevels is unbearebly slow Jun 13, 2019
@dbuenzli dbuenzli changed the title Creating toplevels is unbearebly slow Creating toplevels is unbearably slow Jun 13, 2019
@thangngoc89
Copy link
Contributor

Does this refer to compile time of toplevel? Because it has been this slow since I started workig with the toplevel. A usual build of sketch would take about 4 minutes on my machine

@dbuenzli
Copy link
Contributor Author

Yes.

@hhugo
Copy link
Member

hhugo commented Jul 24, 2019

I had a look few weeks ago, I think this has something to do with debug info.
I'll need more time to get to the bottom of this.

@hhugo
Copy link
Member

hhugo commented Nov 2, 2019

Here are some timing stat on my machine.
I believe the ~20 seconds spent in parsing is a regression.

Start parsing...
  parsing: 21.72
  tail calls: 0.08
    flow analysis 1: 0.76
    flow analysis 2: 1.30
    flow analysis 3: 0.23
    flow analysis 4: 0.38
    flow analysis 5: 1.86
  flow analysis: 4.53
  dead code elim.: 1.11
  inlining: 0.29
  dead code elim.: 0.86
  tail calls: 0.07
    phi-simpl. 1: 0.63
    phi-simpl. 2: 0.89
  phi-simpl.: 1.64
    flow analysis 1: 0.21
    flow analysis 2: 0.19
    flow analysis 3: 0.09
    flow analysis 4: 0.33
    flow analysis 5: 0.53
  flow analysis: 1.36
  dead code elim.: 0.64
  inlining: 0.22
  dead code elim.: 0.49
    flow analysis 1: 0.13
    flow analysis 2: 0.18
    flow analysis 3: 0.22
    flow analysis 4: 0.15
    flow analysis 5: 0.76
  flow analysis: 1.44
  dead code elim.: 0.48
  inlining: 0.23
  dead code elim.: 0.56
    phi-simpl. 1: 0.12
    phi-simpl. 2: 0.34
  phi-simpl.: 0.67
    flow analysis 1: 0.53
    flow analysis 2: 0.63
    flow analysis 3: 0.05
    flow analysis 4: 0.08
    flow analysis 5: 0.22
  flow analysis: 1.51
  free vars: 0.31
  dead code elim.: 0.76
Start Generation...
  code gen.: 2.94
Start Linking...
  linking: 0.40
Start Flagizing js...
    simpl: 0.14
    clean: 0.23
  optimizing: 0.37
Start Coloring...
  coloring: 3.37
Start Checks...
  checks: 0.85
Start Writing file...
  write: 1.46
compilation: 52.05

@hhugo
Copy link
Member

hhugo commented Nov 2, 2019

With #902 here is the new profile

Start parsing...
  parsing: 1.12
  tail calls: 0.06
    flow analysis 1: 0.40
    flow analysis 2: 0.43
    flow analysis 3: 0.12
    flow analysis 4: 0.23
    flow analysis 5: 0.40
  flow analysis: 1.60
  dead code elim.: 0.59
  inlining: 0.21
  dead code elim.: 0.57
  tail calls: 0.07
    phi-simpl. 1: 0.36
    phi-simpl. 2: 0.23
  phi-simpl.: 0.70
    flow analysis 1: 0.18
    flow analysis 2: 0.13
    flow analysis 3: 0.05
    flow analysis 4: 0.12
    flow analysis 5: 0.22
  flow analysis: 0.69
  dead code elim.: 0.45
  inlining: 0.24
  dead code elim.: 0.47
    flow analysis 1: 0.12
    flow analysis 2: 0.12
    flow analysis 3: 0.09
    flow analysis 4: 0.08
    flow analysis 5: 0.13
  flow analysis: 0.54
  dead code elim.: 0.41
  inlining: 0.17
  dead code elim.: 0.41
    phi-simpl. 1: 0.10
    phi-simpl. 2: 0.20
  phi-simpl.: 0.42
    flow analysis 1: 0.09
    flow analysis 2: 0.08
    flow analysis 3: 0.04
    flow analysis 4: 0.08
    flow analysis 5: 0.17
  flow analysis: 0.46
  free vars: 0.22
  dead code elim.: 0.39
Start Generation...
  code gen.: 1.30
Start Linking...
  linking: 0.45
Start Flagizing js...
    share constant: 0.51
    simpl: 0.17
    clean: 0.15
  optimizing: 0.84
Start Coloring...
  coloring: 1.72
Start Checks...
  checks: 0.81
Start Writing file...
  write: 1.26
compilation: 17.26

@hhugo hhugo added this to the 3.5 milestone Nov 2, 2019
@hhugo hhugo closed this as completed in #902 Nov 2, 2019
@dbuenzli
Copy link
Contributor Author

dbuenzli commented Nov 3, 2019

Thanks @hhugo !

I wanted to try your fix to get a feel of the change. But somehow just doing an opam pin js_of_ocaml --dev doesn't seem to show a difference and further pinning js_of_ocaml-toplevel fails with:

# File "toplevel/lib/jsooTop.ml", line 104, characters 12-68:
# 104 |             Js_of_ocaml_compiler.Ocaml_compiler.Symtable.reloc_ident name);
#                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Error: Unbound value Js_of_ocaml_compiler.Ocaml_compiler.Symtable.reloc_ident

@dbuenzli
Copy link
Contributor Author

dbuenzli commented Nov 3, 2019

Ah in fact it's js_of_ocaml-compiler and js_of_ocaml-toplevel that need a pin.
(I'm still a bit confused by the packaging structure of jsoo).

So for me it goes (for a bare toplevel) from 36s to 21s. Much better but still room for improvement ;-)

@hhugo
Copy link
Member

hhugo commented Nov 3, 2019

How do you build your toplevel ?

@dbuenzli
Copy link
Contributor Author

dbuenzli commented Nov 3, 2019

[040:spawn 1.02s top-build e:a0064a04e402c794] ['/Users/dbuenzli/.opam/4.08.0/bin/ocamlc' 
'-g' '-custom' '-o' '/private/tmp/bla/_b0/brzo/ocaml-top-html/a.out' 
'-I' '/Users/dbuenzli/.opam/4.08.0/lib/biniou/' 
'-I' '/Users/dbuenzli/.opam/4.08.0/lib/easy-format/' 
'-I' '/Users/dbuenzli/.opam/4.08.0/lib/js_of_ocaml-compiler/' 
'-I' '/Users/dbuenzli/.opam/4.08.0/lib/js_of_ocaml-toplevel/' 
'-I' '/Users/dbuenzli/.opam/4.08.0/lib/js_of_ocaml/' 
'-I' '/Users/dbuenzli/.opam/4.08.0/lib/ocaml/compiler-libs/' 
'-I' '/Users/dbuenzli/.opam/4.08.0/lib/yojson/' 
'-I' '/private/tmp/bla/_b0/brzo/ocaml-top-html/'
'/Users/dbuenzli/.opam/4.08.0/lib/easy-format/easy_format.cma'
'/Users/dbuenzli/.opam/4.08.0/lib/biniou/biniou.cma'
'/Users/dbuenzli/.opam/4.08.0/lib/yojson/yojson.cma'
'/Users/dbuenzli/.opam/4.08.0/lib/ocaml/compiler-libs/ocamlcommon.cma'
'/Users/dbuenzli/.opam/4.08.0/lib/js_of_ocaml-compiler/js_of_ocaml_compiler.cma' 
'/Users/dbuenzli/.opam/4.08.0/lib/ocaml/compiler-libs/ocamlbytecomp.cma'
'/Users/dbuenzli/.opam/4.08.0/lib/ocaml/compiler-libs/ocamltoplevel.cma'
'/Users/dbuenzli/.opam/4.08.0/lib/js_of_ocaml/js_of_ocaml.cma'
'/Users/dbuenzli/.opam/4.08.0/lib/js_of_ocaml-toplevel/js_of_ocaml_toplevel.cma'
'/private/tmp/bla/_b0/brzo/ocaml-top-html/brzo_jsoo_toplevel_ui.cmo'][0]

[041:spawn 18.9s top-build e:76ae7dfb8ec1daed] ['/Users/dbuenzli/.opam/4.08.0/bin/js_of_ocaml' 
'-o' '/private/tmp/bla/_b0/brzo/ocaml-top-html/a.js' '--extern-fs' '--toplevel' 
'--no-runtime' '--export' '/private/tmp/bla/_b0/brzo/ocaml-top-html/top_mod_names' 
'+runtime.js' '+toplevel.js' '+dynlink.js'  '/private/tmp/bla/_b0/brzo/ocaml-top-html/a.out'][0]
There are some missing primitives
Dummy implementations (raising 'Failure' exception) will be used if they are not available at runtime.
You can prevent the generation of dummy implementations with the commandline option '--disable genprim'
Missing primitives:
  caml_sys_time_include_children

With that top_mod_names files given to --export having all of the compilation units available in the linked .cmas from the previous step.

@hhugo
Copy link
Member

hhugo commented Nov 3, 2019

  • passing ---debug time to js_of_ocaml will give you the split between passes.
  • --disable shortvar should save ~4s

@dbuenzli
Copy link
Contributor Author

dbuenzli commented Nov 3, 2019

[041:spawn 15.7s top-build e:effe14f8cf7a85a9] ['/Users/dbuenzli/.opam/4.08.0/bin/js_of_ocaml' '-o' '/private/tmp/blo/_b0/brzo/ocaml-top-html/a.js' '--extern-fs' '--debug
' 'time' '--disable' 'shortvar' '--toplevel' '--no-runtime' '--export' '/private/tmp/blo/_b0/brzo/ocaml-top-html/top_mod_names' '+runtime.js' '+toplevel.js' '+dynlink.js'
 '/private/tmp/blo/_b0/brzo/ocaml-top-html/a.out'][0]
Start parsing...
  parsing: 0.88
  tail calls: 0.05
    flow analysis 1: 0.37
    flow analysis 2: 0.31
    flow analysis 3: 0.04
    flow analysis 4: 0.25
    flow analysis 5: 0.29
  flow analysis: 1.26
  dead code elim.: 0.58
  inlining: 0.22
  dead code elim.: 0.46
  tail calls: 0.04
    phi-simpl. 1: 0.33
    phi-simpl. 2: 0.21
  phi-simpl.: 0.64
    flow analysis 1: 0.20
    flow analysis 2: 0.13
    flow analysis 3: 0.04
    flow analysis 4: 0.27
    flow analysis 5: 0.23
  flow analysis: 0.87
  dead code elim.: 0.42
  inlining: 0.16
  dead code elim.: 0.52
    flow analysis 1: 0.13
    flow analysis 2: 0.08
    flow analysis 3: 0.03
    flow analysis 4: 0.05
    flow analysis 5: 0.17
  flow analysis: 0.46
  dead code elim.: 0.34
  inlining: 0.19
  dead code elim.: 0.39
    phi-simpl. 1: 0.08
    phi-simpl. 2: 0.10
  phi-simpl.: 0.27
    flow analysis 1: 0.08
    flow analysis 2: 0.08
    flow analysis 3: 0.03
    flow analysis 4: 0.10
    flow analysis 5: 0.15
  flow analysis: 0.44
  free vars: 0.24
  dead code elim.: 0.38
Start Generation...
  code gen.: 1.16
Start Linking...
There are some missing primitives
Dummy implementations (raising 'Failure' exception) will be used if they are not available at runtime.
You can prevent the generation of dummy implementations with the commandline option '--disable genprim'
Missing primitives:
  caml_sys_time_include_children
  linking: 0.42
Start Flagizing js...
    share constant: 0.53
    simpl: 0.16
    clean: 0.19
  optimizing: 0.88
Start Coloring...
  coloring: 1.63
Start Checks...
  checks: 0.67
Start Writing file...
  write: 0.96
compilation: 15.59

@hhugo
Copy link
Member

hhugo commented Nov 3, 2019

Thanks, this is consistent with what I see.

I don't think the rest of the slowness is specific to toplevels, but rather a property of compiling large executables.
One could try to spend more time speeding up the jsoo compiler or allow to create toplevels with separate compilation #901

Here is a profile without the --toplevel flag

Start parsing...
  parsing: 0.64
  tail calls: 0.06
    flow analysis 1: 0.40
    flow analysis 2: 0.51
    flow analysis 3: 0.09
    flow analysis 4: 0.30
    flow analysis 5: 0.49
  flow analysis: 1.79
  dead code elim.: 0.61
  inlining: 0.27
  dead code elim.: 0.60
  tail calls: 0.06
    phi-simpl. 1: 0.23
    phi-simpl. 2: 0.29
  phi-simpl.: 0.65
    flow analysis 1: 0.31
    flow analysis 2: 0.14
    flow analysis 3: 0.05
    flow analysis 4: 0.08
    flow analysis 5: 0.18
  flow analysis: 0.75
  dead code elim.: 0.32
  inlining: 0.17
  dead code elim.: 0.37
    flow analysis 1: 0.08
    flow analysis 2: 0.23
    flow analysis 3: 0.09
    flow analysis 4: 0.07
    flow analysis 5: 0.11
  flow analysis: 0.59
  dead code elim.: 0.36
  inlining: 0.15
  dead code elim.: 0.37
    phi-simpl. 1: 0.08
    phi-simpl. 2: 0.08
  phi-simpl.: 0.22
    flow analysis 1: 0.11
    flow analysis 2: 0.09
    flow analysis 3: 0.04
    flow analysis 4: 0.06
    flow analysis 5: 0.10
  flow analysis: 0.41
  free vars: 0.24
  dead code elim.: 0.35
Start Generation...
  code gen.: 0.96
Start Linking...
  linking: 0.39
Start Flagizing js...
    share constant: 0.39
    simpl: 0.22
    clean: 0.15
  optimizing: 0.75
Start Coloring...
  coloring: 1.44
Start Checks...
  checks: 0.69
Start Writing file...
  write: 0.22
compilation: 14.55

@hhugo
Copy link
Member

hhugo commented Nov 3, 2019

--disable inline can also save you a second or two

@dbuenzli
Copy link
Contributor Author

dbuenzli commented Nov 3, 2019

Ok thanks. So I guess maybe one should try to minimize the deps (also the resulting js file is 20Mo). One question with respect to this, when I create toplevels if I limit the --export not to include most compiler libs libraries, will it it influence dead code elimination and thus result in a smaller js file ? For example I'm not too keen on having yojson and its deps included by default in the toplevels.

@thangngoc89
Copy link
Contributor

@dbuenzli AFAIK, it won't help much. --export would simply write the cmi to js files. the actual source code is still there. You can look into expunge for doing what you said

@hhugo
Copy link
Member

hhugo commented Feb 14, 2023

I've added some support for separate compilation of toplevels in #1380. It's not documented yet. I'm waiting for the next release of dune to maybe use it by default in the jsoo repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants