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

Proposed by Lawrence Mitchell
Status: Superseded
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
Fluidity Core Team Pending
Review via email: mp+60897@code.launchpad.net

This proposal has been superseded by a proposal from 2011-06-27.

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

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 :

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.

lp:~wence/fluidity/make-fixes updated
3476. By Lawrence Mitchell

Makefile.in: Remove unnecessary --check-clean from VERSION

Should have gone with previous change, but was missed.

Revision history for this message
Lawrence Mitchell (wence) wrote :

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.

lp:~wence/fluidity/make-fixes updated
3477. By Lawrence Mitchell

Makefile.in: Use bzr revision-info not version-info

The latter takes a looong time, especially with a custom format, and
the former produces equally usable results.

3478. By Lawrence Mitchell

Merge from trunk

3479. By Lawrence Mitchell

Merge from trunk.

3480. By Lawrence Mitchell

scripts: Don't use with in make_check_options and make_register_diagnostics

The with statement only appeared in python 2.5 (in __future__) which
is not the minimum supported version. So just use try/finally to open
the output file instead.

3481. By Lawrence Mitchell

Merge from trunk

Revision history for this message
Lawrence Mitchell (wence) wrote :

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?

lp:~wence/fluidity/make-fixes updated
3482. By Lawrence Mitchell

Merge from trunk

3483. By Lawrence Mitchell

Add libwm to clean-light target

Now that the libwm target is no longer .PHONY, we need to clean it
when cleaning lib/libfluidity.a (for example via clean-light). This
ensures that make; make clean-light; make works as a build sequence.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Makefile.in'
2--- Makefile.in 2011-06-02 11:01:17 +0000
3+++ Makefile.in 2011-06-27 14:02:36 +0000
4@@ -63,7 +63,7 @@
5
6 EVAL = scripts/silenteval
7
8-VERSION = $(shell svnversion .)
9+VERSION = $(shell bzr revision-info)
10
11 ifeq (@MBA2D@,yes)
12 LIBMBA2D = lib/libmba2d.a
13@@ -143,7 +143,7 @@
14 @cd @FLFEMDEM_PATH@;$(MAKE)
15 endif
16
17-bin/@FLUIDITY@: main.o fluidity_library
18+bin/@FLUIDITY@: main.o lib/lib@FLUIDITY@.a
19 @echo "BUILD fluidity"
20 @echo " MKDIR bin"
21 @mkdir -p bin
22@@ -262,8 +262,7 @@
23 fluidity_library: lib/lib@FLUIDITY@.a
24 lib/lib@FLUIDITY@.a: $(OBJS) python_build sub_system
25 @echo "DEFINE __FLUIDITY_VERSION__"
26- @echo "#undef __FLUIDITY_VERSION__" >> include/confdefs.h
27- @echo "#define __FLUIDITY_VERSION__ \"$(VERSION)\"" >> include/confdefs.h
28+ @grep "$(VERSION)" include/confdefs.h >/dev/null 2>&1 || (echo "#undef __FLUIDITY_VERSION__" >> include/confdefs.h && echo "#define __FLUIDITY_VERSION__ \"$(VERSION)\"" >> include/confdefs.h)
29 @echo "BUILD libfluidity"
30 @echo " MKDIR lib"
31 @mkdir -p lib
32@@ -309,10 +308,10 @@
33 @cd main; $(MAKE)
34 @echo " MAKE options_check"
35 @./scripts/make_check_options
36- @cd preprocessor; $(MAKE) check_options
37+ @cd preprocessor; $(MAKE) check_options.o
38 @echo " MAKE register_diagnostics"
39 @./scripts/make_register_diagnostics
40- @cd preprocessor; $(MAKE) register_diagnostics
41+ @cd preprocessor; $(MAKE) register_diagnostics.o
42
43 fldecomp: fluidity_library
44 @echo "BUILD fldecomp"
45@@ -334,6 +333,8 @@
46 clean-light:
47 @echo " CLEAN debug"
48 @cd debug; $(MAKE) clean
49+ @echo " CLEAN libwm"
50+ @cd libwm; $(MAKE) clean
51 @echo " CLEAN femtools"
52 @cd femtools; $(MAKE) clean
53 @echo " CLEAN femtools/tests"
54
55=== modified file 'libwm/Makefile.in'
56--- libwm/Makefile.in 2011-05-27 13:44:17 +0000
57+++ libwm/Makefile.in 2011-06-27 14:02:36 +0000
58@@ -63,9 +63,10 @@
59 @echo " CXX $<"
60 $(CXX) $(CXXFLAGS) -I. -I../include -c $<
61
62-default: $(OBJS)
63+$(LIB): $(OBJS)
64 $(AR) $(ARFLAGS) $(LIB) $(OBJS)
65 cp *.h ../include/
66+default: $(LIB)
67
68 clean:
69 rm -f *.o *.mod
70
71=== modified file 'preprocessor/Makefile.in'
72--- preprocessor/Makefile.in 2011-05-19 14:29:56 +0000
73+++ preprocessor/Makefile.in 2011-06-27 14:02:36 +0000
74@@ -74,17 +74,17 @@
75 @$(AR) $(ARFLAGS) $(LIB) $(OBJS)
76 default: $(LIB)
77
78-.PHONY:check_options
79-
80 # This gets run last by the fluidity build process.
81-check_options: check_options.o
82+check_options.o: check_options.F90
83+ @echo " FC $<"
84+ $(FC) $(FCFLAGS) -c $<
85 mkdir -p ../lib
86 $(AR) $(ARFLAGS) $(LIB) check_options.o &> check.log
87
88-.PHONY:register_diagnostics
89-
90 # This gets run last by the fluidity build process.
91-register_diagnostics: register_diagnostics.o
92+register_diagnostics.o: register_diagnostics.F90
93+ @echo " FC $<"
94+ $(FC) $(FCFLAGS) -c $<
95 mkdir -p ../lib
96 $(AR) $(ARFLAGS) $(LIB) register_diagnostics.o &> register_diagnostics.log
97
98
99=== modified file 'scripts/make_check_options'
100--- scripts/make_check_options 2010-11-16 23:08:06 +0000
101+++ scripts/make_check_options 2011-06-27 14:02:36 +0000
102@@ -1,6 +1,9 @@
103 #!/usr/bin/env python
104 import re
105 import glob
106+import hashlib
107+import StringIO
108+
109
110 # File header
111 header="""
112@@ -11,9 +14,23 @@
113 end subroutine check_options
114 """
115
116-outfile=file("preprocessor/check_options.F90", "w")
117-
118-outfile.write(header)
119+outfile='preprocessor/check_options.F90'
120+
121+# get sha1 digest of existing generated file. Can't use 'rw' here
122+# because it updates the modtime of the file, which we're trying to
123+# avoid doing.
124+orig=hashlib.sha1()
125+try:
126+ f=open(outfile, 'r')
127+ orig.update(f.read())
128+except IOError:
129+ pass
130+else:
131+ f.close()
132+
133+# Now read module files to generate potential new data
134+output=StringIO.StringIO()
135+output.write(header)
136
137 # List of fortran source files.
138 fortran_files=glob.glob("*/*.F")+glob.glob("*/*.F90")
139@@ -23,7 +40,7 @@
140 module_list=[]
141
142 for filename in fortran_files:
143-
144+
145 fortran=file(filename,"r").read()
146
147 modules=module_re.findall(fortran)
148@@ -31,21 +48,37 @@
149 for module in modules:
150
151 if re.search(r"^\s*subroutine\s+"+module+"_check_options\s*$",\
152- fortran,\
153- re.IGNORECASE|re.MULTILINE):
154+ fortran,\
155+ re.IGNORECASE|re.MULTILINE):
156 module_list.append(module)
157
158 for module in module_list:
159
160- outfile.write(" use "+module+", only: "+module+"_check_options\n")
161+ output.write(" use "+module+", only: "+module+"_check_options\n")
162
163 # Ensure that the subroutine is legal in the trivial case.
164-outfile.write("""
165+output.write("""
166 continue
167 """)
168
169 for module in module_list:
170
171- outfile.write(" call "+module+"_check_options\n")
172-
173-outfile.write(footer)
174+ output.write(" call "+module+"_check_options\n")
175+
176+output.write(footer)
177+
178+new=hashlib.sha1()
179+new.update(output.getvalue())
180+
181+# Only write file if sha1sums differ
182+if new.digest() != orig.digest():
183+ try:
184+ f=open(outfile, 'w')
185+ f.write(output.getvalue())
186+ except IOError:
187+ # Fixme, this should fail better
188+ pass
189+ else:
190+ f.close()
191+
192+output.close()
193
194=== modified file 'scripts/make_register_diagnostics'
195--- scripts/make_register_diagnostics 2011-02-05 16:05:31 +0000
196+++ scripts/make_register_diagnostics 2011-06-27 14:02:36 +0000
197@@ -1,6 +1,9 @@
198 #!/usr/bin/env python
199 import re
200 import glob
201+import hashlib
202+import StringIO
203+
204
205 # File header
206 header="""
207@@ -11,9 +14,23 @@
208 end subroutine register_diagnostics
209 """
210
211-outfile=file("preprocessor/register_diagnostics.F90", "w")
212-
213-outfile.write(header)
214+outfile = 'preprocessor/register_diagnostics.F90'
215+
216+# get sha1 digest of existing generated file. Can't use 'rw' here
217+# because it updates the modtime of the file, which we're trying to
218+# avoid doing.
219+orig=hashlib.sha1()
220+try:
221+ f=open(outfile, 'r')
222+ orig.update(f.read())
223+except IOError:
224+ pass
225+else:
226+ f.close()
227+
228+# Now read module files to generate potential new data
229+output=StringIO.StringIO()
230+output.write(header)
231
232 # List of fortran source files.
233 fortran_files=glob.glob("*/*.F")+glob.glob("*/*.F90")
234@@ -23,7 +40,7 @@
235 module_list=[]
236
237 for filename in fortran_files:
238-
239+
240 fortran=file(filename,"r").read()
241
242 modules=module_re.findall(fortran)
243@@ -31,21 +48,36 @@
244 for module in modules:
245
246 if re.search(r"^\s*subroutine\s+"+module+"_register_diagnostic\s*$",\
247- fortran,\
248- re.IGNORECASE|re.MULTILINE):
249+ fortran,\
250+ re.IGNORECASE|re.MULTILINE):
251 module_list.append(module)
252
253 for module in module_list:
254
255- outfile.write(" use "+module+", only: "+module+"_register_diagnostic\n")
256+ output.write(" use "+module+", only: "+module+"_register_diagnostic\n")
257
258 # Ensure that the subroutine is legal in the trivial case.
259-outfile.write("""
260+output.write("""
261 continue
262 """)
263
264 for module in module_list:
265
266- outfile.write(" call "+module+"_register_diagnostic\n")
267-
268-outfile.write(footer)
269+ output.write(" call "+module+"_register_diagnostic\n")
270+
271+output.write(footer)
272+
273+new=hashlib.sha1()
274+new.update(output.getvalue())
275+
276+# Only write file if sha1sums differ
277+if new.digest() != orig.digest():
278+ try:
279+ f=open(outfile, 'w')
280+ f.write(output.getvalue())
281+ except IOError:
282+ # Fixme, this should fail better
283+ pass
284+ else:
285+ f.close()
286+output.close()