Merge lp:~wence/fluidity/make-fixes into lp:fluidity

Proposed by Lawrence Mitchell
Status: Merged
Merged at revision: 3509
Proposed branch: lp:~wence/fluidity/make-fixes
Merge into: lp:fluidity
Diff against target: 286 lines (+102/-35)
5 files modified
Makefile.in (+7/-6)
libwm/Makefile.in (+2/-1)
preprocessor/Makefile.in (+6/-6)
scripts/make_check_options (+44/-11)
scripts/make_register_diagnostics (+43/-11)
To merge this branch: bzr merge lp:~wence/fluidity/make-fixes
Reviewer Review Type Date Requested Status
Tim Bond (community) Approve
Review via email: mp+65996@code.launchpad.net

This proposal supersedes a proposal from 2011-05-13.

Commit message

Reduce spurious recompilations in clean or mostly-clean trees

Avoid touching lib/libfluidity.a unless actually necessary. This comes in a few parts:

o Use bzr revision-info to set up Fluidity's version number (and only update confdefs.h if the version changed)
o Calculate hashes of the check_options and register_diagnostics files and only update them if the hash changes
o Avoid depending on .PHONY targets that just point directly at actual targets

Description of the change

I think I've addressed all of the comments (mostly mine) below, and copyright assignments are in, so I think this is good to go. Here's the original description:

Various small fixes to decrease build times in mostly built trees.

The main effect of the change is to avoid touching lib/libfluidity.a as much as possible. Timing example, in a just-built tree:

before:
$ time make all
real 0m40.936s
user 0m19.053s
sys 0m21.117s

after:
$ time make all
real 0m11.736s
user 0m7.471s
sys 0m4.223s

As a bonus, the version-number fluidity reports is now meaningful again.

To post a comment you must log in.
Revision history for this message
Patrick Farrell (pefarrell) wrote : Posted in a previous version of this proposal

Hi Lawrence,

Looks like great work. I've always found this business of the build being slow quite annoying.

I tried it out, and it changed the time from 9s to 7s on my workstation. Quick question: there is a noticeable delay at the start of the build now, as it calls bzr version-info; it appears like it isn't doing anything for a second or two. Is there any way to speed up the bzr version-info, or is that just how long it takes, and there's nothing we can do? With your change, but without the bzr version-info, it takes just 3s to compile on my workstation.

Revision history for this message
Lawrence Mitchell (wence) wrote : Posted in a previous version of this proposal

It seems like the custom version-info format increases the time spent significantly:

fluidity-trunk $ time bzr version-info >/dev/null

real 0m0.293s
user 0m0.138s
sys 0m0.150s

fluidity-trunk $ time bzr version-info --custom --template="{revno} ({revision_id})" >/dev/null

real 0m0.865s
user 0m0.522s
sys 0m0.338s

If I try this:
$ cat > gen-version<<\EOF
#!/bin/bash

while read f; do
    if [[ $f == revision-id:\ * ]]; then
        revid=${f#revision-id: }
    elif [[ $f == revno:\ * ]]; then
        revno=${f#revno: }
    fi
done < <(bzr version-info) && echo "$revno (revid $revid)"
EOF

fluidity-trunk $ time ./gen-version >/dev/null

real 0m0.297s
user 0m0.123s
sys 0m0.170s

But is not portable over changes in the output format.

The clean solution is to use the format-spec, the fast solution appears to be to munge the textual output by hand.

The really fast solution is to do:

VERSION=$(shell cat .bzr/branch/last-revision)

but that is /really/ ugly, so I don't want to be the one doing it.

Revision history for this message
Lawrence Mitchell (wence) wrote : Posted in a previous version of this proposal

I'm not quite happy with this entire series as is. Specifically, it breaks the sequence:

make
make clean-light
make

Since libwm is not cleaned by clean-light, the object files are left lying around. The default rule in libwm/Makefile with this patch series is:

default: $(LIB)

$(LIB): $(OBJS)
     $(AR) $(ARFLAGS) $(LIB) $(OBJS)
 cp *.h ../include/

But the make sequence is:

make debug
make libwm

debug touches $(LIB) and so the modtime for $(LIB) is newer than $(OBJS), so they're not linked in to the library. This causes an undefined symbol link error when we try to build bin/fluidity.

I see two ways of fixing this:

revert to the previous (.PHONY) rule:

default: $(OBJS)
        ...

So that the object files are always stuffed in $(LIB)

Or add libwm to the list of clean-light targets.

I prefer the latter, thoughts?

Revision history for this message
Tim Bond (timothy-bond) wrote :

Looks good, approved.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Makefile.in'
--- Makefile.in 2011-06-02 11:01:17 +0000
+++ Makefile.in 2011-06-27 14:15:53 +0000
@@ -63,7 +63,7 @@
6363
64EVAL = scripts/silenteval64EVAL = scripts/silenteval
6565
66VERSION = $(shell svnversion .)66VERSION = $(shell bzr revision-info)
6767
68ifeq (@MBA2D@,yes)68ifeq (@MBA2D@,yes)
69LIBMBA2D = lib/libmba2d.a69LIBMBA2D = lib/libmba2d.a
@@ -143,7 +143,7 @@
143 @cd @FLFEMDEM_PATH@;$(MAKE)143 @cd @FLFEMDEM_PATH@;$(MAKE)
144endif144endif
145145
146bin/@FLUIDITY@: main.o fluidity_library146bin/@FLUIDITY@: main.o lib/lib@FLUIDITY@.a
147 @echo "BUILD fluidity"147 @echo "BUILD fluidity"
148 @echo " MKDIR bin"148 @echo " MKDIR bin"
149 @mkdir -p bin149 @mkdir -p bin
@@ -262,8 +262,7 @@
262fluidity_library: lib/lib@FLUIDITY@.a262fluidity_library: lib/lib@FLUIDITY@.a
263lib/lib@FLUIDITY@.a: $(OBJS) python_build sub_system 263lib/lib@FLUIDITY@.a: $(OBJS) python_build sub_system
264 @echo "DEFINE __FLUIDITY_VERSION__"264 @echo "DEFINE __FLUIDITY_VERSION__"
265 @echo "#undef __FLUIDITY_VERSION__" >> include/confdefs.h265 @grep "$(VERSION)" include/confdefs.h >/dev/null 2>&1 || (echo "#undef __FLUIDITY_VERSION__" >> include/confdefs.h && echo "#define __FLUIDITY_VERSION__ \"$(VERSION)\"" >> include/confdefs.h)
266 @echo "#define __FLUIDITY_VERSION__ \"$(VERSION)\"" >> include/confdefs.h
267 @echo "BUILD libfluidity"266 @echo "BUILD libfluidity"
268 @echo " MKDIR lib"267 @echo " MKDIR lib"
269 @mkdir -p lib268 @mkdir -p lib
@@ -309,10 +308,10 @@
309 @cd main; $(MAKE)308 @cd main; $(MAKE)
310 @echo " MAKE options_check"309 @echo " MAKE options_check"
311 @./scripts/make_check_options310 @./scripts/make_check_options
312 @cd preprocessor; $(MAKE) check_options311 @cd preprocessor; $(MAKE) check_options.o
313 @echo " MAKE register_diagnostics"312 @echo " MAKE register_diagnostics"
314 @./scripts/make_register_diagnostics313 @./scripts/make_register_diagnostics
315 @cd preprocessor; $(MAKE) register_diagnostics314 @cd preprocessor; $(MAKE) register_diagnostics.o
316315
317fldecomp: fluidity_library 316fldecomp: fluidity_library
318 @echo "BUILD fldecomp"317 @echo "BUILD fldecomp"
@@ -334,6 +333,8 @@
334clean-light:333clean-light:
335 @echo " CLEAN debug"334 @echo " CLEAN debug"
336 @cd debug; $(MAKE) clean335 @cd debug; $(MAKE) clean
336 @echo " CLEAN libwm"
337 @cd libwm; $(MAKE) clean
337 @echo " CLEAN femtools"338 @echo " CLEAN femtools"
338 @cd femtools; $(MAKE) clean339 @cd femtools; $(MAKE) clean
339 @echo " CLEAN femtools/tests"340 @echo " CLEAN femtools/tests"
340341
=== modified file 'libwm/Makefile.in'
--- libwm/Makefile.in 2011-05-27 13:44:17 +0000
+++ libwm/Makefile.in 2011-06-27 14:15:53 +0000
@@ -63,9 +63,10 @@
63 @echo " CXX $<"63 @echo " CXX $<"
64 $(CXX) $(CXXFLAGS) -I. -I../include -c $<64 $(CXX) $(CXXFLAGS) -I. -I../include -c $<
6565
66default: $(OBJS)66$(LIB): $(OBJS)
67 $(AR) $(ARFLAGS) $(LIB) $(OBJS)67 $(AR) $(ARFLAGS) $(LIB) $(OBJS)
68 cp *.h ../include/68 cp *.h ../include/
69default: $(LIB)
6970
70clean:71clean:
71 rm -f *.o *.mod72 rm -f *.o *.mod
7273
=== modified file 'preprocessor/Makefile.in'
--- preprocessor/Makefile.in 2011-05-19 14:29:56 +0000
+++ preprocessor/Makefile.in 2011-06-27 14:15:53 +0000
@@ -74,17 +74,17 @@
74 @$(AR) $(ARFLAGS) $(LIB) $(OBJS)74 @$(AR) $(ARFLAGS) $(LIB) $(OBJS)
75default: $(LIB)75default: $(LIB)
7676
77.PHONY:check_options
78
79# This gets run last by the fluidity build process.77# This gets run last by the fluidity build process.
80check_options: check_options.o78check_options.o: check_options.F90
79 @echo " FC $<"
80 $(FC) $(FCFLAGS) -c $<
81 mkdir -p ../lib81 mkdir -p ../lib
82 $(AR) $(ARFLAGS) $(LIB) check_options.o &> check.log82 $(AR) $(ARFLAGS) $(LIB) check_options.o &> check.log
8383
84.PHONY:register_diagnostics
85
86# This gets run last by the fluidity build process.84# This gets run last by the fluidity build process.
87register_diagnostics: register_diagnostics.o85register_diagnostics.o: register_diagnostics.F90
86 @echo " FC $<"
87 $(FC) $(FCFLAGS) -c $<
88 mkdir -p ../lib88 mkdir -p ../lib
89 $(AR) $(ARFLAGS) $(LIB) register_diagnostics.o &> register_diagnostics.log89 $(AR) $(ARFLAGS) $(LIB) register_diagnostics.o &> register_diagnostics.log
9090
9191
=== modified file 'scripts/make_check_options'
--- scripts/make_check_options 2010-11-16 23:08:06 +0000
+++ scripts/make_check_options 2011-06-27 14:15:53 +0000
@@ -1,6 +1,9 @@
1#!/usr/bin/env python1#!/usr/bin/env python
2import re2import re
3import glob3import glob
4import hashlib
5import StringIO
6
47
5# File header8# File header
6header="""9header="""
@@ -11,9 +14,23 @@
11end subroutine check_options14end subroutine check_options
12"""15"""
1316
14outfile=file("preprocessor/check_options.F90", "w")17outfile='preprocessor/check_options.F90'
1518
16outfile.write(header)19# get sha1 digest of existing generated file. Can't use 'rw' here
20# because it updates the modtime of the file, which we're trying to
21# avoid doing.
22orig=hashlib.sha1()
23try:
24 f=open(outfile, 'r')
25 orig.update(f.read())
26except IOError:
27 pass
28else:
29 f.close()
30
31# Now read module files to generate potential new data
32output=StringIO.StringIO()
33output.write(header)
1734
18# List of fortran source files.35# List of fortran source files.
19fortran_files=glob.glob("*/*.F")+glob.glob("*/*.F90")36fortran_files=glob.glob("*/*.F")+glob.glob("*/*.F90")
@@ -23,7 +40,7 @@
23module_list=[]40module_list=[]
2441
25for filename in fortran_files:42for filename in fortran_files:
26 43
27 fortran=file(filename,"r").read()44 fortran=file(filename,"r").read()
2845
29 modules=module_re.findall(fortran)46 modules=module_re.findall(fortran)
@@ -31,21 +48,37 @@
31 for module in modules:48 for module in modules:
3249
33 if re.search(r"^\s*subroutine\s+"+module+"_check_options\s*$",\50 if re.search(r"^\s*subroutine\s+"+module+"_check_options\s*$",\
34 fortran,\51 fortran,\
35 re.IGNORECASE|re.MULTILINE):52 re.IGNORECASE|re.MULTILINE):
36 module_list.append(module)53 module_list.append(module)
3754
38for module in module_list:55for module in module_list:
3956
40 outfile.write(" use "+module+", only: "+module+"_check_options\n")57 output.write(" use "+module+", only: "+module+"_check_options\n")
4158
42# Ensure that the subroutine is legal in the trivial case.59# Ensure that the subroutine is legal in the trivial case.
43outfile.write("""60output.write("""
44 continue61 continue
45 """)62 """)
4663
47for module in module_list:64for module in module_list:
4865
49 outfile.write(" call "+module+"_check_options\n")66 output.write(" call "+module+"_check_options\n")
5067
51outfile.write(footer)68output.write(footer)
69
70new=hashlib.sha1()
71new.update(output.getvalue())
72
73# Only write file if sha1sums differ
74if new.digest() != orig.digest():
75 try:
76 f=open(outfile, 'w')
77 f.write(output.getvalue())
78 except IOError:
79 # Fixme, this should fail better
80 pass
81 else:
82 f.close()
83
84output.close()
5285
=== modified file 'scripts/make_register_diagnostics'
--- scripts/make_register_diagnostics 2011-02-05 16:05:31 +0000
+++ scripts/make_register_diagnostics 2011-06-27 14:15:53 +0000
@@ -1,6 +1,9 @@
1#!/usr/bin/env python1#!/usr/bin/env python
2import re2import re
3import glob3import glob
4import hashlib
5import StringIO
6
47
5# File header8# File header
6header="""9header="""
@@ -11,9 +14,23 @@
11end subroutine register_diagnostics14end subroutine register_diagnostics
12"""15"""
1316
14outfile=file("preprocessor/register_diagnostics.F90", "w")17outfile = 'preprocessor/register_diagnostics.F90'
1518
16outfile.write(header)19# get sha1 digest of existing generated file. Can't use 'rw' here
20# because it updates the modtime of the file, which we're trying to
21# avoid doing.
22orig=hashlib.sha1()
23try:
24 f=open(outfile, 'r')
25 orig.update(f.read())
26except IOError:
27 pass
28else:
29 f.close()
30
31# Now read module files to generate potential new data
32output=StringIO.StringIO()
33output.write(header)
1734
18# List of fortran source files.35# List of fortran source files.
19fortran_files=glob.glob("*/*.F")+glob.glob("*/*.F90")36fortran_files=glob.glob("*/*.F")+glob.glob("*/*.F90")
@@ -23,7 +40,7 @@
23module_list=[]40module_list=[]
2441
25for filename in fortran_files:42for filename in fortran_files:
26 43
27 fortran=file(filename,"r").read()44 fortran=file(filename,"r").read()
2845
29 modules=module_re.findall(fortran)46 modules=module_re.findall(fortran)
@@ -31,21 +48,36 @@
31 for module in modules:48 for module in modules:
3249
33 if re.search(r"^\s*subroutine\s+"+module+"_register_diagnostic\s*$",\50 if re.search(r"^\s*subroutine\s+"+module+"_register_diagnostic\s*$",\
34 fortran,\51 fortran,\
35 re.IGNORECASE|re.MULTILINE):52 re.IGNORECASE|re.MULTILINE):
36 module_list.append(module)53 module_list.append(module)
3754
38for module in module_list:55for module in module_list:
3956
40 outfile.write(" use "+module+", only: "+module+"_register_diagnostic\n")57 output.write(" use "+module+", only: "+module+"_register_diagnostic\n")
4158
42# Ensure that the subroutine is legal in the trivial case.59# Ensure that the subroutine is legal in the trivial case.
43outfile.write("""60output.write("""
44 continue61 continue
45 """)62 """)
4663
47for module in module_list:64for module in module_list:
4865
49 outfile.write(" call "+module+"_register_diagnostic\n")66 output.write(" call "+module+"_register_diagnostic\n")
5067
51outfile.write(footer)68output.write(footer)
69
70new=hashlib.sha1()
71new.update(output.getvalue())
72
73# Only write file if sha1sums differ
74if new.digest() != orig.digest():
75 try:
76 f=open(outfile, 'w')
77 f.write(output.getvalue())
78 except IOError:
79 # Fixme, this should fail better
80 pass
81 else:
82 f.close()
83output.close()