Skip to content

Build system: use ocaml{c,opt}.opt instead of ocaml{c,opt} when available#8840

Merged
gasche merged 9 commits intoocaml:trunkfrom
gasche:tools-ocamlc.opt
Oct 12, 2019
Merged

Build system: use ocaml{c,opt}.opt instead of ocaml{c,opt} when available#8840
gasche merged 9 commits intoocaml:trunkfrom
gasche:tools-ocamlc.opt

Conversation

@gasche
Copy link
Copy Markdown
Member

@gasche gasche commented Jul 28, 2019

This PR supersedes #8839, it tweaks the build system to use native-compiled compilers (and lexer) in most of the tools that can be compiled after the .opt compilers are built in the opt.opt (world.opt) build scenarios: otherlibs, ocamltest, ocamldoc and the debugger.

On my machine the total world.opt build time with -j5 decreases from 3m30s to 2m50s, and it seems to save around a minute of CPU time.

@pmetzger
Copy link
Copy Markdown
Member

Very nice fix!

@gasche gasche force-pushed the tools-ocamlc.opt branch 2 times, most recently from 9f021c4 to d79c325 Compare July 29, 2019 06:26
@gasche
Copy link
Copy Markdown
Member Author

gasche commented Jul 29, 2019

If ocamlc.opt is older than ocamlc then it should not be used silently, because it may be stale (make world.opt, then hack on the compiler, then just make core, then make ocamldoc, the changes to the compiler should be taken into account. In that case I plan to emit a warning and revert to the most-recently-built tool (the bytecode one).

The warning cannot be observed in a cold-build scenario, and it should not be observable when running make world.opt several times, but it could be observed if rebuilding from an existing build (so mostly during development). It will mention the two ways to silence the warning, either to remove the stale native tools, or to touch them to use them.

@gasche
Copy link
Copy Markdown
Member Author

gasche commented Jul 30, 2019

I have implemented the newer-than check (it's a Make function rather than a shell script to easily make use of Make's $(info ...) printing function, but Make functions are not very pleasant to write or read). A warning such as the following is displayed if, for example, ocamlc is newer than ocamlc.opt:

Warning: we are not using the native binary ocamlc.opt because it is older than the bytecode binary ocamlc; you should silence this warning by either removing ocamlc.opt or rebuilding it (or touch-ing it) if you want it used.

@gasche gasche force-pushed the tools-ocamlc.opt branch from cbbcdc0 to d5a4ca6 Compare July 30, 2019 20:29
@xavierleroy
Copy link
Copy Markdown
Contributor

I have implemented the newer-than check (it's a Make function rather than a shell script to easily make use of Make's $(info ...) printing function, but Make functions are not very pleasant to write or read).

I applaud the effort (of using make functions) but dislike the smells of scripting (using eval, passing variables by reference, escaping $). Here is a more functional version that almost looks like Lisp code:

check_not_stale = \
  $(if $(shell test $(ROOTDIR)/$1 -nt $(ROOTDIR)/$2 && echo stale), \
    $(info Warning: we are not using the native binary $2 \
because it is older than the bytecode binary $1; \
you should silence this warning by either removing $2 \
or rebuilding it (or `touch`-ing it) if you want it used.), \
    ok)

choose_best = \
  $(if $(and $(wildcard $(ROOTDIR)/$2), $(strip $(call check_not_stale,$1,$2))), \
    $(ROOTDIR)/$2, \
    $(ROOTDIR)/$1)

BEST_OCAMLC := $(call choose_best,ocamlc,ocamlc.opt)
BEST_OCAMLOPT := $(call choose_best,ocamlopt,ocamlopt.opt)
BEST_OCAMLLEX := $(call choose_best,lex/ocamllex,lex/ocamllex.opt)

@gasche
Copy link
Copy Markdown
Member Author

gasche commented Aug 2, 2019

Very nice! I pushed a patch with your version. (In the bytecode case we need to prefix with $(CAMLRUN).)

I had thought of doing something like that (without the assignment) but I couldn't find a way that would (1) statically make the choice at Makefile-invocation time (I'm worried of the performance cost of checking at each compiler invocation) and (2) keep using the = assignment that allows other Makefiles to redefine CAMLRUN and get away with it. This is one reason why I used eval, which allows to statically compute the code to run dynamically -- staged programming!

In fact I checked, and CAMLRUN is not redefined anywhere in this style (some other variables use redefinitions and lazy expansions, in particular the CAML{C,OPT} and CAML{C,OPT}_CMD pairing) -- it is sometimes redefined on recursive invocation of Make (to promote, for example) but that should be fine. So we don't need to keep (2) and can use eager assignment with your version.

@gasche gasche force-pushed the tools-ocamlc.opt branch from c2ecd5f to c70f998 Compare August 2, 2019 20:31
@gasche
Copy link
Copy Markdown
Member Author

gasche commented Aug 30, 2019

(cc @shindere this is the other Makefile-oriented PR that I mentioned.)

@shindere
Copy link
Copy Markdown
Contributor

shindere commented Aug 30, 2019 via email

@gasche
Copy link
Copy Markdown
Member Author

gasche commented Sep 23, 2019

I addressed the review comments of @shindere -- I have a one-argument instead of two-argument function now. ocamldoc is not using this mechanism because it is not generic enough -- the invocation command for ocamldoc is fairly complex due to dynamic linking.

@shindere
Copy link
Copy Markdown
Contributor

shindere commented Sep 27, 2019 via email

@dra27
Copy link
Copy Markdown
Member

dra27 commented Sep 27, 2019

I think it's good to have a mechanism where these definitions must be explicitly opted into. The alternative would be to have them in Makefile.common but have a variable which can be defined before Makefile.common is included to enable them.

Personally I think having the Makefile.best_binaries as it is better

ok)

choose_best = $(strip $(if \
$(and $(wildcard $(ROOTDIR)/$1.opt),$(strip $(call check_not_stale,$1,$1.opt))), \
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alas, this line is failing check-typo (I can't remember if you're a fan of the githook or not - worrying that if you are, that it's not working??)

Copy link
Copy Markdown
Contributor

@dbuenzli dbuenzli Sep 27, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dra27 could we have instructions in HACKING.adoc on how to enable them (instructions were given in a discussion not long time ago) ? It's quite annoying to make PRs have the slow CI fail only on this.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They've been in CONTRIBUTING.md since the hook was added (L71-L72)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah thanks ! Maybe there are too much of these documents...

@shindere
Copy link
Copy Markdown
Contributor

shindere commented Sep 27, 2019 via email

@shindere
Copy link
Copy Markdown
Contributor

shindere commented Sep 27, 2019 via email

@shindere
Copy link
Copy Markdown
Contributor

shindere commented Sep 27, 2019 via email

@gasche
Copy link
Copy Markdown
Member Author

gasche commented Sep 27, 2019

Personally I think having the Makefile.best_binaries as it is better

It does not really scale...

I'm not sure what sort of scalability you have in mind here, is it the scalability of ls at the root? When we write programs, we tend to consider that it is good style to split distinct part of the codebase in different files, instead of having everything in a single source file.

We could think of moving the sub-Makefiles into tools/ for example, or a new makefiles/ directory (as we used to have in the testsuite).

@shindere
Copy link
Copy Markdown
Contributor

shindere commented Sep 27, 2019 via email

@gasche
Copy link
Copy Markdown
Member Author

gasche commented Sep 27, 2019

I don't see the problem. If you forget to include a makefile that provides definitions/variables, then your makefile code fails and you quickly notice the problem. On the other hand, having a monster Makefile that defines everything at once makes it harder to reason about, for example, which definitions are or are not in scope at a given point. (For example, everytime you add a definition there, you have to check all Makefiles including it, which is all makefiles, for naming conflicts.)

@shindere
Copy link
Copy Markdown
Contributor

shindere commented Sep 27, 2019 via email

@gasche
Copy link
Copy Markdown
Member Author

gasche commented Oct 12, 2019

Could we try to make faster progress on this PR? Saving 40s to a minute of compiler full-build time seems like an important quality-of-life improvement for developers (and could also help CI response times), it's disappointing to wait for two months to make a decision.

(make -C ocamltest) will run the first rule of the ocamltest Makefile,
which happens to be the 'all' rule. This is not robust to the addition
of new rules in some of the included Makefile, and indeed a previous
version of the previous commit broke it inadvertently.
On my machine, a sequential build of (make all allopt) goes from 31s
to 11s, and a parallel build (-j5) goes from 16s to 6s.
On my machine the sequential build time goes from 7.5s to 3.5s.
On my machine the sequential build time goes from 3.7s to 1.3s
On my machine, the sequential build time goes from 30s to 10s.
Copy link
Copy Markdown
Member

@dra27 dra27 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think from the conversation @shindere was happy for the Makefile layout to stay as-is - but that can of course be addressed in a subsequent PR

@gasche
Copy link
Copy Markdown
Member Author

gasche commented Oct 12, 2019

Thanks! (I'm sorry for my sprout of grumpiness now.)

I had just rebased the PR to fix the check-typo issue, so we should wait for CI.

@dra27
Copy link
Copy Markdown
Member

dra27 commented Oct 12, 2019

I took no grumpiness 🙂 - feel free to merge when AppVeyor comes back

@dra27
Copy link
Copy Markdown
Member

dra27 commented Oct 12, 2019

I presume as you rebased you'd like to keep the commit history?

@gasche gasche merged commit e48615c into ocaml:trunk Oct 12, 2019
@gasche
Copy link
Copy Markdown
Member Author

gasche commented Oct 12, 2019

I just merged, thanks everyone for the feedback.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants