From: Kyrylo Tkachov <[email protected]>
The stage 2 and stage 3 object comparison runs one command per object in a
serial shell loop. Everything after it waits while an otherwise idle machine
compares thousands of objects.
Generate one make target per object and run the comparisons through $(MAKE),
so they share the original jobserver. Keep the generated makefile and result
shards invocation-specific, clean them on normal and signal exits, and sort
the shards before creating the traditional .bad_compare diagnostic. Files in
the exclusion list still only warn. Comparator statuses other than zero or
one now report an operational error instead of being treated as equal.
The tail-based fallback for cmp implementations without byte skipping used
fixed temporary names. Give those files process-specific names, clean them
with a trap, and preserve the same status contract for tail failures and
signals.
On highly parallel AArch64 and x86_64 systems this reduces comparison wall
time by about 95%.
ChangeLog:
* Makefile.tpl ([+compare-target+]): Run object comparisons through an
invocation-specific parallel sub-make. Collect sorted failure shards
and clean temporary state on exit.
* Makefile.in: Regenerate.
* configure: Regenerate.
config/ChangeLog:
* acx.m4 (ACX_PROG_CMP_IGNORE_INITIAL): Use process-specific temporary
files and clean them on exit. Diagnose tail failures as errors.
Signed-off-by: Kyrylo Tkachov <[email protected]>
---
Makefile.in | 116 ++++++++++++++++++++++++++++++++++++--------------
Makefile.tpl | 58 ++++++++++++++++++-------
config/acx.m4 | 11 ++++-
configure | 11 ++++-
4 files changed, 146 insertions(+), 50 deletions(-)
diff --git a/Makefile.in b/Makefile.in
index f34142cc077..5cca69c3f52 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -66022,6 +66022,9 @@ do-clean: clean-stage3
# only possibility, but now it conflicts with no-bootstrap rules
@if gcc-bootstrap
+# Run the comparisons in parallel through a generated sub-makefile under
+# the jobserver. Each failing recipe writes a separate result shard that
+# is collected after the sub-make finishes.
compare:
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
@@ -66030,29 +66033,52 @@ compare:
exit 0; \
fi; \
: $(MAKE); $(stage); \
- rm -f .bad_compare; \
+ compare_id=$$$$; \
+ bad_compare=.bad_compare.$$compare_id; export bad_compare; \
+ compare_makefile=compare.$$compare_id.mk; \
+ trap 'st=$$?; rm -f "$$compare_makefile" "$$bad_compare" \
+ "$$bad_compare".*; trap - 0; exit $$st' 0; \
+ trap 'exit 1' 1 2 3 15; \
echo Comparing stages 2 and 3; \
sed=`echo stage3 | sed 's,^stage,,;s,.,.,g'`; \
files=`find stage3-* -name "*$(objext)" -print | \
sed -n s,^stage$$sed-,,p`; \
- for file in $${files} ${extra-compare}; do \
- f1=$$r/stage2-$$file; f2=$$r/stage3-$$file; \
- if test ! -f $$f1; then continue; fi; \
- $(do-compare) > /dev/null 2>&1; \
- if test $$? -eq 1; then \
- case $$file in \
- @compare_exclusions@) \
- echo warning: $$file differs ;; \
- *) \
- echo $$file differs >> .bad_compare ;; \
- esac; \
- fi; \
- done; \
- if [ -f .bad_compare ]; then \
+ cmp_raw='$(do-compare)'; \
+ { \
+ echo 'all:'; \
+ echo '.PHONY: all FORCE'; \
+ echo 'FORCE:'; \
+ printf 'compare/%%: FORCE ; @'; \
+ printf 'f1=$$$$r/stage2-$$*; '; \
+ printf 'f2=$$$$r/stage3-$$*; '; \
+ printf '%s' "$$cmp_raw" | sed 's,\$$,$$$$,g'; \
+ printf ' > /dev/null 2>&1; st=$$$$?; '; \
+ printf 'if test $$$$st -eq 1; then '; \
+ printf 'case $$* in '; \
+ printf '@compare_exclusions@) echo warning: $$* differs ;; '; \
+ printf '*) echo $$* differs >> "$$$$bad_compare.$$$$$$$$" ;; '; \
+ printf 'esac; '; \
+ printf 'elif test $$$$st -ne 0; then '; \
+ printf 'echo "$$* compare: error status $$$$st" '; \
+ printf '>> "$$$$bad_compare.$$$$$$$$"; fi\n'; \
+ for file in $${files} ${extra-compare}; do \
+ if test ! -f $$r/stage2-$$file; then continue; fi; \
+ echo "all: compare/$$file"; \
+ done; \
+ } > "$$compare_makefile"; \
+ $(MAKE) -s -f "$$compare_makefile" all; compare_status=$$?; \
+ if test $$compare_status -ne 0; then \
+ exit $$compare_status; \
+ fi; \
+ set -- "$$bad_compare".*; \
+ if test -f "$$1"; then \
echo "Bootstrap comparison failure!"; \
- cat .bad_compare; \
+ LC_ALL=C sort "$$bad_compare".* > "$$bad_compare" || exit 1; \
+ cat "$$bad_compare"; \
+ mv -f "$$bad_compare" .bad_compare; \
exit 1; \
else \
+ rm -f .bad_compare; \
echo Comparison successful.; \
fi; \
$(STAMP) compare
@@ -66456,6 +66482,9 @@ do-clean: clean-stage4
# only possibility, but now it conflicts with no-bootstrap rules
@if gcc-bootstrap
+# Run the comparisons in parallel through a generated sub-makefile under
+# the jobserver. Each failing recipe writes a separate result shard that
+# is collected after the sub-make finishes.
compare3:
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
@@ -66464,29 +66493,52 @@ compare3:
exit 0; \
fi; \
: $(MAKE); $(stage); \
- rm -f .bad_compare; \
+ compare_id=$$$$; \
+ bad_compare=.bad_compare.$$compare_id; export bad_compare; \
+ compare_makefile=compare3.$$compare_id.mk; \
+ trap 'st=$$?; rm -f "$$compare_makefile" "$$bad_compare" \
+ "$$bad_compare".*; trap - 0; exit $$st' 0; \
+ trap 'exit 1' 1 2 3 15; \
echo Comparing stages 3 and 4; \
sed=`echo stage4 | sed 's,^stage,,;s,.,.,g'`; \
files=`find stage4-* -name "*$(objext)" -print | \
sed -n s,^stage$$sed-,,p`; \
- for file in $${files} ${extra-compare}; do \
- f1=$$r/stage3-$$file; f2=$$r/stage4-$$file; \
- if test ! -f $$f1; then continue; fi; \
- $(do-compare3) > /dev/null 2>&1; \
- if test $$? -eq 1; then \
- case $$file in \
- @compare_exclusions@) \
- echo warning: $$file differs ;; \
- *) \
- echo $$file differs >> .bad_compare ;; \
- esac; \
- fi; \
- done; \
- if [ -f .bad_compare ]; then \
+ cmp_raw='$(do-compare3)'; \
+ { \
+ echo 'all:'; \
+ echo '.PHONY: all FORCE'; \
+ echo 'FORCE:'; \
+ printf 'compare3/%%: FORCE ; @'; \
+ printf 'f1=$$$$r/stage3-$$*; '; \
+ printf 'f2=$$$$r/stage4-$$*; '; \
+ printf '%s' "$$cmp_raw" | sed 's,\$$,$$$$,g'; \
+ printf ' > /dev/null 2>&1; st=$$$$?; '; \
+ printf 'if test $$$$st -eq 1; then '; \
+ printf 'case $$* in '; \
+ printf '@compare_exclusions@) echo warning: $$* differs ;; '; \
+ printf '*) echo $$* differs >> "$$$$bad_compare.$$$$$$$$" ;; '; \
+ printf 'esac; '; \
+ printf 'elif test $$$$st -ne 0; then '; \
+ printf 'echo "$$* compare: error status $$$$st" '; \
+ printf '>> "$$$$bad_compare.$$$$$$$$"; fi\n'; \
+ for file in $${files} ${extra-compare}; do \
+ if test ! -f $$r/stage3-$$file; then continue; fi; \
+ echo "all: compare3/$$file"; \
+ done; \
+ } > "$$compare_makefile"; \
+ $(MAKE) -s -f "$$compare_makefile" all; compare_status=$$?; \
+ if test $$compare_status -ne 0; then \
+ exit $$compare_status; \
+ fi; \
+ set -- "$$bad_compare".*; \
+ if test -f "$$1"; then \
echo "Bootstrap comparison failure!"; \
- cat .bad_compare; \
+ LC_ALL=C sort "$$bad_compare".* > "$$bad_compare" || exit 1; \
+ cat "$$bad_compare"; \
+ mv -f "$$bad_compare" .bad_compare; \
exit 1; \
else \
+ rm -f .bad_compare; \
echo Comparison successful.; \
fi; \
$(STAMP) compare3
diff --git a/Makefile.tpl b/Makefile.tpl
index 5891b67b697..98bd03e9a33 100644
--- a/Makefile.tpl
+++ b/Makefile.tpl
@@ -1821,6 +1821,9 @@ do-clean: clean-stage[+id+]
# only possibility, but now it conflicts with no-bootstrap rules
@if gcc-bootstrap
[+ IF compare-target +]
+# Run the comparisons in parallel through a generated sub-makefile under
+# the jobserver. Each failing recipe writes a separate result shard that
+# is collected after the sub-make finishes.
[+compare-target+]:
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
@@ -1829,29 +1832,52 @@ do-clean: clean-stage[+id+]
exit 0; \
fi; \
: $(MAKE); $(stage); \
- rm -f .bad_compare; \
+ compare_id=$$$$; \
+ bad_compare=.bad_compare.$$compare_id; export bad_compare; \
+ compare_makefile=[+compare-target+].$$compare_id.mk; \
+ trap 'st=$$?; rm -f "$$compare_makefile" "$$bad_compare" \
+ "$$bad_compare".*; trap - 0; exit $$st' 0; \
+ trap 'exit 1' 1 2 3 15; \
echo Comparing stages [+prev+] and [+id+]; \
sed=`echo stage[+id+] | sed 's,^stage,,;s,.,.,g'`; \
files=`find stage[+id+]-* -name "*$(objext)" -print | \
sed -n s,^stage$$sed-,,p`; \
- for file in $${files} ${extra-compare}; do \
- f1=$$r/stage[+prev+]-$$file; f2=$$r/stage[+id+]-$$file; \
- if test ! -f $$f1; then continue; fi; \
- $(do-[+compare-target+]) > /dev/null 2>&1; \
- if test $$? -eq 1; then \
- case $$file in \
- @compare_exclusions@) \
- echo warning: $$file differs ;; \
- *) \
- echo $$file differs >> .bad_compare ;; \
- esac; \
- fi; \
- done; \
- if [ -f .bad_compare ]; then \
+ cmp_raw='$(do-[+compare-target+])'; \
+ { \
+ echo 'all:'; \
+ echo '.PHONY: all FORCE'; \
+ echo 'FORCE:'; \
+ printf '[+compare-target+]/%%: FORCE ; @'; \
+ printf 'f1=$$$$r/stage[+prev+]-$$*; '; \
+ printf 'f2=$$$$r/stage[+id+]-$$*; '; \
+ printf '%s' "$$cmp_raw" | sed 's,\$$,$$$$,g'; \
+ printf ' > /dev/null 2>&1; st=$$$$?; '; \
+ printf 'if test $$$$st -eq 1; then '; \
+ printf 'case $$* in '; \
+ printf '@compare_exclusions@) echo warning: $$* differs ;; '; \
+ printf '*) echo $$* differs >> "$$$$bad_compare.$$$$$$$$" ;; '; \
+ printf 'esac; '; \
+ printf 'elif test $$$$st -ne 0; then '; \
+ printf 'echo "$$* compare: error status $$$$st" '; \
+ printf '>> "$$$$bad_compare.$$$$$$$$"; fi\n'; \
+ for file in $${files} ${extra-compare}; do \
+ if test ! -f $$r/stage[+prev+]-$$file; then continue; fi; \
+ echo "all: [+compare-target+]/$$file"; \
+ done; \
+ } > "$$compare_makefile"; \
+ $(MAKE) -s -f "$$compare_makefile" all; compare_status=$$?; \
+ if test $$compare_status -ne 0; then \
+ exit $$compare_status; \
+ fi; \
+ set -- "$$bad_compare".*; \
+ if test -f "$$1"; then \
echo "Bootstrap comparison failure!"; \
- cat .bad_compare; \
+ LC_ALL=C sort "$$bad_compare".* > "$$bad_compare" || exit 1; \
+ cat "$$bad_compare"; \
+ mv -f "$$bad_compare" .bad_compare; \
exit 1; \
else \
+ rm -f .bad_compare; \
echo Comparison successful.; \
fi; \
$(STAMP) [+compare-target+][+ IF prev +]
diff --git a/config/acx.m4 b/config/acx.m4
index ef5468bdd35..5547cbeb9b8 100644
--- a/config/acx.m4
+++ b/config/acx.m4
@@ -477,7 +477,16 @@ AC_DEFUN([ACX_PROG_CMP_IGNORE_INITIAL],
[AC_CACHE_CHECK([how to compare bootstrapped objects], gcc_cv_prog_cmp_skip,
[ echo abfoo >t1
echo cdfoo >t2
- gcc_cv_prog_cmp_skip='tail -c +17 $$f1 > tmp-foo1; tail -c +17 $$f2 >
tmp-foo2; cmp tmp-foo1 tmp-foo2'
+ gcc_cv_prog_cmp_skip='(trap "st=\$$?; rm -f tmp-foo1.$$$$ '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tmp-foo2.$$$$; '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'trap - 0; exit \$$st" 0; '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'trap "exit 2" 1 2 3 15; '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tail -c +17 $$f1 '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'> tmp-foo1.$$$$ || exit 2; '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tail -c +17 $$f2 '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'> tmp-foo2.$$$$ || exit 2; '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'cmp tmp-foo1.$$$$ '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tmp-foo2.$$$$)'
if cmp t1 t2 2 2 > /dev/null 2>&1; then
if cmp t1 t2 1 1 > /dev/null 2>&1; then
:
diff --git a/configure b/configure
index ad490083741..4db0edbdccd 100755
--- a/configure
+++ b/configure
@@ -6123,7 +6123,16 @@ if ${gcc_cv_prog_cmp_skip+:} false; then :
else
echo abfoo >t1
echo cdfoo >t2
- gcc_cv_prog_cmp_skip='tail -c +17 $$f1 > tmp-foo1; tail -c +17 $$f2 >
tmp-foo2; cmp tmp-foo1 tmp-foo2'
+ gcc_cv_prog_cmp_skip='(trap "st=\$$?; rm -f tmp-foo1.$$$$ '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tmp-foo2.$$$$; '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'trap - 0; exit \$$st" 0; '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'trap "exit 2" 1 2 3 15; '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tail -c +17 $$f1 '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'> tmp-foo1.$$$$ || exit 2; '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tail -c +17 $$f2 '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'> tmp-foo2.$$$$ || exit 2; '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'cmp tmp-foo1.$$$$ '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tmp-foo2.$$$$)'
if cmp t1 t2 2 2 > /dev/null 2>&1; then
if cmp t1 t2 1 1 > /dev/null 2>&1; then
:
--
2.50.1 (Apple Git-155)