Commit 9b6d2d92 authored by Petr Pudlak's avatar Petr Pudlak

Compile every Haskell object file separately

This allows parallel compilation of all targets, including the Haskell
object files. While re-starting GHC for every Haskell source almost
doubles the total CPU time, allowing it run in parallel at the end cuts
down the wall-clock time to half.

Haskell targets are split into two: main ones and testing ones.
The testing targets (starting with "test/") are build with coverage
automatically. Therefore the testing object and interface files have
different extensions (this also allows their parallel compilation).

GHC is now used to produce a separate Makefile.ghc with all
dependencies. This is then included and used for compiling each object
file separately.

Note that the inclusion + generation of Makefile.ghc is turned off when
calling clean/ganeti/distclean. For some reason, Makefile infinitely
recurses when calling "make ganeti", if it includes Makefile.ghc. But
since using ifneq/endif in Makefile.am conflicts with Automake, it was
necessary to put the snippet into an Automake variable and substitute it
into the resulting Makefile.
Signed-off-by: default avatarPetr Pudlak <pudlak@google.com>
Reviewed-by: default avatarKlaus Aehlig <aehlig@google.com>
parent 1551758e
......@@ -239,6 +239,10 @@ CLEANFILES = \
$(addsuffix /*.py[co],$(DIRS)) \
$(addsuffix /*.hi,$(HS_DIRS)) \
$(addsuffix /*.o,$(HS_DIRS)) \
$(addsuffix /*.$(HTEST_SUFFIX)_hi,$(HS_DIRS)) \
$(addsuffix /*.$(HTEST_SUFFIX)_o,$(HS_DIRS)) \
Makefile.ghc \
Makefile.ghc.bak \
$(PYTHON_BOOTSTRAP) \
$(gnt_python_sbin_SCRIPTS) \
epydoc.conf \
......@@ -614,6 +618,9 @@ HS_DEFAULT_PROGS = \
HS_ALL_PROGS = $(HS_DEFAULT_PROGS) $(HS_MYEXECLIB_PROGS)
HS_TEST_PROGS = $(filter test/%,$(HS_ALL_PROGS))
HS_SRC_PROGS = $(filter-out test/%,$(HS_ALL_PROGS))
HS_PROG_SRCS = $(patsubst %,%.hs,$(HS_DEFAULT_PROGS)) src/mon-collector.hs
HS_BUILT_TEST_HELPERS = $(HS_BIN_ROLES:%=test/hs/%) test/hs/hail
......@@ -623,6 +630,22 @@ HFLAGS = \
-fwarn-tabs \
$(GHC_BYVERSION_FLAGS)
if HPROFILE
HFLAGS += -prof -auto-all
endif
if HCOVERAGE
HFLAGS += -fhpc
endif
if HTEST
HFLAGS += -DTEST
endif
HTEST_SUFFIX = hpc
HTEST_FLAGS = $(HFLAGS) -fhpc -itest/hs \
-osuf .$(HTEST_SUFFIX)_o \
-hisuf .$(HTEST_SUFFIX)_hi
# extra flags that can be overriden on the command line (e.g. -Wwarn, etc.)
HEXTRA =
# internal extra flags (used for test/hs/htest mainly)
......@@ -989,60 +1012,46 @@ install-exec-hook:
$(LN_S) -f htools $(DESTDIR)$(bindir)/$$role ; \
done
HNORMAL_SUFFIX = .o
HPROFILE_SUFFIX = .prof.o
HCOVERAGE_SUFFIX = .hpc.o
HTEST_SUFFIX = .test.o
HS_SRCS = $(HS_LIBTESTBUILT_SRCS)
HSUFFIX = $(if $(HPROFILE),$(HPROFILE_SUFFIX), \
$(if $(HCOVERAGE),$(HCOVERAGE_SUFFIX), \
$(if $(HTEST),$(HTEST_SUFFIX), \
$(HNORMAL_SUFFIX))))
Makefile.ghc: $(HS_ALL_PROGS:%=%.hs) $(HS_SRCS) Makefile | $(built_base_sources)
$(GHC) -M -dep-makefile $@ -dep-suffix $(HTEST_SUFFIX) $(HFLAGS) \
$(HS_PARALLEL3) $(HS_REGEX_PCRE) $(HEXTRA) $(HS_ALL_PROGS:%=%.hs) $(HS_SRCS)
HFLAGS += $(if $(HPROFILE),-prof -auto-all,)
HFLAGS += $(if $(HCOVERAGE),-fhpc,)
HFLAGS += $(if $(HTEST),-DTEST,)
@include_makefile_ghc@
HS_SRCS = $(HS_LIBTESTBUILT_SRCS)
%.o:
$(GHC) -c $(HFLAGS) \
$(HS_PARALLEL3) $(HS_REGEX_PCRE) $(HEXTRA) $(@:%.o=%.hs)
%.$(HTEST_SUFFIX)_o:
$(GHC) -c $(HTEST_FLAGS) \
$(HS_PARALLEL3) $(HS_REGEX_PCRE) $(HEXTRA) $(@:%.$(HTEST_SUFFIX)_o=%.hs)
.NOTPARALLEL: $(HS_ALL_PROGS)
.PHONY: $(HS_ALL_PROGS)
$(HS_ALL_PROGS): %: %.hs $(HS_SRCS) Makefile
@if [ "$(notdir $@)" = "test" ] && [ "$(HS_NODEV)" ]; then \
%.hi: %.o ;
%.$(HTEST_SUFFIX)_hi: %.$(HTEST_SUFFIX)_o ;
$(HS_SRC_PROGS): %: %.o | stamp-directories
$(GHC) $(HFLAGS) \
$(HS_PARALLEL3) $(HS_REGEX_PCRE) $(HEXTRA) --make $(@:%=%.hs)
@rm -f $(notdir $@).tix
@touch "$@"
$(HS_TEST_PROGS): %: %.$(HTEST_SUFFIX)_o \
| stamp-directories $(BUILT_PYTHON_SOURCES)
@if [ "$(HS_NODEV)" ]; then \
echo "Error: cannot run unittests without the development" \
" libraries (see devnotes.rst)" 1>&2; \
exit 1; \
fi
$(GHC) $(HTEST_FLAGS) \
$(HS_PARALLEL3) $(HS_REGEX_PCRE) $(HEXTRA) --make $(@:%=%.hs)
@rm -f $(notdir $@).tix
$(GHC) --make $(HFLAGS) \
-osuf $(HSUFFIX) \
-hisuf $(patsubst %.o,%.hi,$(HSUFFIX)) \
$(HS_PARALLEL3) $(HS_REGEX_PCRE) $(HEXTRA) $@
@touch "$@"
# for the test/hs/htest binary, we need to enable profiling/coverage
test/hs/htest: HCOVERAGE = true
test/hs/htest: HFLAGS += -itest/hs
test/hs/htest: | $(BUILT_PYTHON_SOURCES)
# we compile the hpc-htools binary with the program coverage
test/hs/hpc-htools: HCOVERAGE = true
# we compile the hpc-mon-collector binary with the program coverage
test/hs/hpc-mon-collector: HCOVERAGE = true
# test dependency
test/hs/offline-test.sh: test/hs/hpc-htools test/hs/hpc-mon-collector
# rule for building profiling-enabled versions of the haskell programs
.PHONY: hs-prof
hs-prof:
@if [ -z "$(TARGET)" ]; then \
echo "You need to define TARGET when running this rule" 1>&2; \
exit 1; \
fi
$(MAKE) $(AM_MAKEFLAGS) HPROFILE=y $(TARGET)
dist_sbin_SCRIPTS = \
tools/ganeti-listrunner
......
......@@ -809,6 +809,18 @@ fi
AC_SUBST(PY_NODEV)
AM_CONDITIONAL([PY_UNIT], [test -n $PY_NODEV])
include_makefile_ghc='
ifneq ($(MAKECMDGOALS),ganeti)
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(MAKECMDGOALS),distclean)
include Makefile.ghc
endif
endif
endif
'
AC_SUBST([include_makefile_ghc])
AM_SUBST_NOTMAKE([include_makefile_ghc])
AC_CONFIG_FILES([ Makefile ])
AC_OUTPUT
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment