profile-guided opt. w/ GCC
Profile-guided optimization is a relatively new GCC feature that
improves the quality of generated code by:
- compiling a copy of the source program with some profiling hooks
- running this copy of the program on some representative input data
- recompiling the program using the profiling data produced by the
previous stage; the profiling data lets GCC's optimizer generate more
efficient code
I think it would be cool to add support for PGO to PostgreSQL's build
system (for 8.1). There are a lot of situations where PostgreSQL is
compiled once, and then used for weeks or months (compilations for
inclusion in a distro being the extreme example). In that kind of
situation, trading some additional compile-time for even a small
improvement in run-time performance is worthwhile, IMHO.
I've attached a proof-of-concept patch that implements this. Caveats:
- you'll need to re-run autoconf
- the libgcov.a stuff is a temporary hack, you may need to adjust it for
where libgcov.a is on your system
- I've only bothered adding support for GCC 3.4 (IIRC profile-guided
optimization was introduced in GCC 3.3, but 3.4 adds a simpler interface
to using it). By the time 8.1 is out I think GCC 3.4+ will be pretty
prevalent anyway.
- the patch should remove the .gcda and .gcno files that are produced by
GCC; I haven't done that yet
The patch adds a new make target ("profile-opt") that does the PGO steps
outlined above -- the "representative input data" is the regression
tests running in serial mode. I haven't run any benchmarks yet (if
someone wants to try that, I'd be very curious to see the results).
Comments?
-Neil
Attachments:
pgo-support-8.patchtext/x-patch; charset=iso-8859-1; name=pgo-support-8.patchDownload
? autom4te.cache
Index: GNUmakefile.in
===================================================================
RCS file: /home/neilc/private-cvsroot/pgsql-server/GNUmakefile.in,v
retrieving revision 1.40
diff -c -r1.40 GNUmakefile.in
*** GNUmakefile.in 30 Jul 2004 12:26:39 -0000 1.40
--- GNUmakefile.in 30 Sep 2004 08:06:20 -0000
***************
*** 49,62 ****
# Garbage from autoconf:
@rm -rf autom4te.cache/
! check: all
! check installcheck:
$(MAKE) -C src/test $@
GNUmakefile: GNUmakefile.in $(top_builddir)/config.status
./config.status $@
##########################################################################
--- 49,79 ----
# Garbage from autoconf:
@rm -rf autom4te.cache/
! singlecheck check: all
! singlecheck check installcheck:
$(MAKE) -C src/test $@
GNUmakefile: GNUmakefile.in $(top_builddir)/config.status
./config.status $@
+ # XXX: do we need to run clean first?
+ profile-opt:
+ ifneq ($(profile_opt_support), yes)
+ @echo "Your C compiler does not contain support for profile-guided optimization."
+ @echo "PostgreSQL currently supports PGO when compiled with GCC 3.4 or later"
+ @false
+ else
+ @echo "Building PostgreSQL with support for profile generation"
+ $(MAKE) clean
+ $(MAKE) all CFLAGS="$(CFLAGS) -fprofile-generate"
+ @echo "Running regression tests to generate profile data"
+ $(MAKE) -C src/test/regress singlecheck
+ @echo "Rebuilding PostgreSQL to use profile data"
+ $(MAKE) clean
+ $(MAKE) all CFLAGS="$(CFLAGS) -fprofile-use"
+ @echo "Removing profile data"
+ endif
##########################################################################
Index: configure.in
===================================================================
RCS file: /home/neilc/private-cvsroot/pgsql-server/configure.in,v
retrieving revision 1.378
diff -c -r1.378 configure.in
*** configure.in 27 Sep 2004 02:17:14 -0000 1.378
--- configure.in 30 Sep 2004 08:06:20 -0000
***************
*** 253,258 ****
--- 253,261 ----
# Need to specify -fno-strict-aliasing too in case it's gcc 3.3 or later.
PGAC_PROG_CC_NO_STRICT_ALIASING
+ # Check whether the compiler supports profile-guided optimization
+ PGAC_PROG_CC_PROFILE_GUIDED_OPT
+
# supply -g if --enable-debug
if test "$enable_debug" = yes && test "$ac_cv_prog_cc_g" = yes; then
CFLAGS="$CFLAGS -g"
Index: config/c-compiler.m4
===================================================================
RCS file: /home/neilc/private-cvsroot/pgsql-server/config/c-compiler.m4,v
retrieving revision 1.12
diff -c -r1.12 c-compiler.m4
*** config/c-compiler.m4 2 Feb 2004 04:07:18 -0000 1.12
--- config/c-compiler.m4 30 Sep 2004 08:06:21 -0000
***************
*** 150,155 ****
--- 150,177 ----
CFLAGS="$CFLAGS $pgac_cv_prog_cc_no_strict_aliasing"
fi])# PGAC_PROG_CC_NO_STRICT_ALIASING
+ # PGAC_PROG_CC_PROFILE_GUIDED_OPT
+ # -------------------------------
+ # Find out if the C compiler supports profile-guided optimization. For
+ # the moment, we only support GCC (and GCC 3.4+ at that).
+ AC_DEFUN([PGAC_PROG_CC_PROFILE_GUIDED_OPT],
+ [AC_CACHE_CHECK([if $CC supports profile-guided optimization],
+ pgac_cv_prog_cc_pgo_support,
+ [pgac_save_CFLAGS=$CFLAGS
+ pgac_cv_prog_cc_pgo_support=no
+ if test "$GCC" = yes; then
+ CFLAGS="$pgac_save_CFLAGS -fprofile-use"
+ _AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
+ [pgac_cv_prog_cc_pgo_support=yes
+ break])
+ fi
+
+ CFLAGS=$pgac_save_CFLAGS
+ ])
+
+ gcc_pgo_support=$pgac_cv_prog_cc_pgo_support
+ AC_SUBST(gcc_pgo_support)
+ ]) # PGAC_PROG_CC_PROFILE_GUIDED_OPT
# The below backpatches the following Autoconf change:
#
Index: src/Makefile.global.in
===================================================================
RCS file: /home/neilc/private-cvsroot/pgsql-server/src/Makefile.global.in,v
retrieving revision 1.195
diff -c -r1.195 Makefile.global.in
*** src/Makefile.global.in 18 Sep 2004 13:28:54 -0000 1.195
--- src/Makefile.global.in 30 Sep 2004 08:06:21 -0000
***************
*** 185,190 ****
--- 185,193 ----
CFLAGS += -Wall -Wmissing-prototypes -Wmissing-declarations
endif
+ # profile-guided optimization
+ profile_opt_support = @gcc_pgo_support@
+
# Kind-of compilers
YACC = @YACC@
Index: src/backend/Makefile
===================================================================
RCS file: /home/neilc/private-cvsroot/pgsql-server/src/backend/Makefile,v
retrieving revision 1.104
diff -c -r1.104 Makefile
*** src/backend/Makefile 1 Aug 2004 18:07:42 -0000 1.104
--- src/backend/Makefile 30 Sep 2004 08:06:21 -0000
***************
*** 35,41 ****
ifneq ($(PORTNAME), win32)
postgres: $(OBJS)
! $(CC) $(CFLAGS) $(LDFLAGS) $(export_dynamic) $^ $(LIBS) -o $@
endif
endif
--- 35,41 ----
ifneq ($(PORTNAME), win32)
postgres: $(OBJS)
! $(CC) $(CFLAGS) $(LDFLAGS) $(export_dynamic) $^ /usr/lib/gcc/i486-linux/3.4.1/libgcov.a $(LIBS) -o $@
endif
endif
Index: src/bin/initdb/Makefile
===================================================================
RCS file: /home/neilc/private-cvsroot/pgsql-server/src/bin/initdb/Makefile,v
retrieving revision 1.44
diff -c -r1.44 Makefile
*** src/bin/initdb/Makefile 29 Aug 2004 04:13:01 -0000 1.44
--- src/bin/initdb/Makefile 30 Sep 2004 08:06:22 -0000
***************
*** 20,26 ****
all: submake-libpq submake-libpgport initdb
initdb: $(OBJS) $(libpq_builddir)/libpq.a
! $(CC) $(CFLAGS) $(OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@$(X)
dirmod.c: % : $(top_srcdir)/src/port/%
rm -f $@ && $(LN_S) $< .
--- 20,26 ----
all: submake-libpq submake-libpgport initdb
initdb: $(OBJS) $(libpq_builddir)/libpq.a
! $(CC) $(CFLAGS) $(OBJS) /usr/lib/gcc/i486-linux/3.4.1/libgcov.a $(libpq) $(LDFLAGS) $(LIBS) -o $@$(X)
dirmod.c: % : $(top_srcdir)/src/port/%
rm -f $@ && $(LN_S) $< .
Index: src/bin/pg_config/Makefile
===================================================================
RCS file: /home/neilc/private-cvsroot/pgsql-server/src/bin/pg_config/Makefile,v
retrieving revision 1.8
diff -c -r1.8 Makefile
*** src/bin/pg_config/Makefile 1 Aug 2004 06:56:38 -0000 1.8
--- src/bin/pg_config/Makefile 30 Sep 2004 08:06:22 -0000
***************
*** 14,20 ****
rm -f $@ && $(LN_S) $< .
pg_config: $(OBJS)
! $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LIBS) -o $@$(X)
install: all installdirs
$(INSTALL_SCRIPT) pg_config$(X) $(DESTDIR)$(bindir)/pg_config$(X)
--- 14,20 ----
rm -f $@ && $(LN_S) $< .
pg_config: $(OBJS)
! $(CC) $(CFLAGS) $(OBJS) /usr/lib/gcc/i486-linux/3.4.1/libgcov.a $(LDFLAGS) $(LIBS) -o $@$(X)
install: all installdirs
$(INSTALL_SCRIPT) pg_config$(X) $(DESTDIR)$(bindir)/pg_config$(X)
Index: src/bin/pg_ctl/Makefile
===================================================================
RCS file: /home/neilc/private-cvsroot/pgsql-server/src/bin/pg_ctl/Makefile,v
retrieving revision 1.15
diff -c -r1.15 Makefile
*** src/bin/pg_ctl/Makefile 29 Aug 2004 04:13:01 -0000 1.15
--- src/bin/pg_ctl/Makefile 30 Sep 2004 08:06:22 -0000
***************
*** 20,26 ****
all: submake-libpq submake-libpgport pg_ctl
pg_ctl: $(OBJS) $(libpq_builddir)/libpq.a
! $(CC) $(CFLAGS) $(OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@$(X)
exec.c: % : $(top_srcdir)/src/port/%
rm -f $@ && $(LN_S) $< .
--- 20,26 ----
all: submake-libpq submake-libpgport pg_ctl
pg_ctl: $(OBJS) $(libpq_builddir)/libpq.a
! $(CC) $(CFLAGS) $(OBJS) /usr/lib/gcc/i486-linux/3.4.1/libgcov.a $(libpq) $(LDFLAGS) $(LIBS) -o $@$(X)
exec.c: % : $(top_srcdir)/src/port/%
rm -f $@ && $(LN_S) $< .
Index: src/bin/psql/Makefile
===================================================================
RCS file: /home/neilc/private-cvsroot/pgsql-server/src/bin/psql/Makefile,v
retrieving revision 1.47
diff -c -r1.47 Makefile
*** src/bin/psql/Makefile 24 May 2004 01:01:37 -0000 1.47
--- src/bin/psql/Makefile 30 Sep 2004 08:06:22 -0000
***************
*** 27,33 ****
all: submake-libpq submake-libpgport psql
psql: $(OBJS) $(libpq_builddir)/libpq.a
! $(CC) $(CFLAGS) $(OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@$(X)
exec.c: % : $(top_srcdir)/src/port/%
rm -f $@ && $(LN_S) $< .
--- 27,33 ----
all: submake-libpq submake-libpgport psql
psql: $(OBJS) $(libpq_builddir)/libpq.a
! $(CC) $(CFLAGS) $(OBJS) /usr/lib/gcc/i486-linux/3.4.1/libgcov.a $(libpq) $(LDFLAGS) $(LIBS) -o $@$(X)
exec.c: % : $(top_srcdir)/src/port/%
rm -f $@ && $(LN_S) $< .
Index: src/bin/scripts/Makefile
===================================================================
RCS file: /home/neilc/private-cvsroot/pgsql-server/src/bin/scripts/Makefile,v
retrieving revision 1.28
diff -c -r1.28 Makefile
*** src/bin/scripts/Makefile 26 May 2004 17:24:05 -0000 1.28
--- src/bin/scripts/Makefile 30 Sep 2004 08:06:22 -0000
***************
*** 20,26 ****
all: submake-libpq submake-backend $(PROGRAMS)
%: %.o
! $(CC) $(CFLAGS) $^ $(libpq) $(LDFLAGS) $(LIBS) -o $@$(X)
createdb: createdb.o common.o exec.o dumputils.o $(top_builddir)/src/backend/parser/keywords.o
createlang: createlang.o common.o exec.o print.o mbprint.o
--- 20,26 ----
all: submake-libpq submake-backend $(PROGRAMS)
%: %.o
! $(CC) $(CFLAGS) $^ /usr/lib/gcc/i486-linux/3.4.1/libgcov.a $(libpq) $(LDFLAGS) $(LIBS) -o $@$(X)
createdb: createdb.o common.o exec.o dumputils.o $(top_builddir)/src/backend/parser/keywords.o
createlang: createlang.o common.o exec.o print.o mbprint.o
Index: src/test/regress/GNUmakefile
===================================================================
RCS file: /home/neilc/private-cvsroot/pgsql-server/src/test/regress/GNUmakefile,v
retrieving revision 1.47
diff -c -r1.47 GNUmakefile
*** src/test/regress/GNUmakefile 18 Jun 2004 06:14:25 -0000 1.47
--- src/test/regress/GNUmakefile 30 Sep 2004 08:06:22 -0000
***************
*** 127,142 ****
## Run tests
##
! check: all
-rm -rf ./testtablespace
mkdir ./testtablespace
$(SHELL) ./pg_regress --temp-install --top-builddir=$(top_builddir) --schedule=$(srcdir)/parallel_schedule --multibyte=$(MULTIBYTE) $(MAXCONNOPT)
! installcheck: all
! -rm -rf ./testtablespace
! mkdir ./testtablespace
$(SHELL) ./pg_regress --schedule=$(srcdir)/serial_schedule --multibyte=$(MULTIBYTE)
# old interfaces follow...
--- 127,144 ----
## Run tests
##
! setup-tablespace:
-rm -rf ./testtablespace
mkdir ./testtablespace
+
+ check: all setup-tablespace
$(SHELL) ./pg_regress --temp-install --top-builddir=$(top_builddir) --schedule=$(srcdir)/parallel_schedule --multibyte=$(MULTIBYTE) $(MAXCONNOPT)
! installcheck: all setup-tablespace
$(SHELL) ./pg_regress --schedule=$(srcdir)/serial_schedule --multibyte=$(MULTIBYTE)
+ singlecheck: all setup-tablespace
+ $(SHELL) ./pg_regress --temp-install --top-builddir=$(top_builddir) --schedule=$(srcdir)/serial_schedule --multibyte=$(MULTIBYTE)
# old interfaces follow...
Neil Conway wrote:
The patch adds a new make target ("profile-opt") that does the PGO
steps outlined above -- the "representative input data" is the
regression tests running in serial mode. I haven't run any benchmarks
yet (if someone wants to try that, I'd be very curious to see the
results).
I doubt that the regression tests are anywhere near representative input
data. They run a proportion of borderline and error cases that is much
higher than I would expect in normal use.
--
Peter Eisentraut
http://developer.postgresql.org/~petere/
On Thu, 2004-09-30 at 19:49, Peter Eisentraut wrote:
I doubt that the regression tests are anywhere near representative input
data. They run a proportion of borderline and error cases that is much
higher than I would expect in normal use.
That's definitely true. At first glance, the regression tests don't seem
to be *too* badly skewed:
[src/test/regress/expected]% grep ERROR *.out | wc -l
867
[src/test/regress/expected]% grep -i "^SELECT" *.out | wc -l
2924
[src/test/regress/expected]% grep -i "^INSERT" *.out | wc -l
2714
[src/test/regress/expected]% grep -i "^UPDATE" *.out | wc -l
122
[/src/test/regress/expected]% grep -i "^DELETE" *.out | wc -l
110
[src/test/regress/expected]% grep -i "^CREATE" *.out | wc -l
848
[src/test/regress/expected]% grep -i "^COPY" *.out | wc -l
46
I guess it depends on how closely the test data needs to match "normal"
input data for the gcc optimizer to be able to make valid decisions. My
intuition is that the regression tests are sufficiently close to normal
input that it won't be an issue, but I'm not sure.
-Neil
On Thu, Sep 30, 2004 at 07:07:27PM +1000, Neil Conway wrote:
I think it would be cool to add support for PGO to PostgreSQL's build
system (for 8.1). There are a lot of situations where PostgreSQL is
compiled once, and then used for weeks or months (compilations for
inclusion in a distro being the extreme example). In that kind of
situation, trading some additional compile-time for even a small
improvement in run-time performance is worthwhile, IMHO.
It's some time ago now, but a group at the Universitat Politecnica de
Catalunya (including my thesis advisor Alex Ramirez and our databases
specialist Josep Larriba-Pey) has done a case study on something similar,
using PostgreSQL as their case study.
What they researched was a code reordering algorithm that minimized both
taken branches and I-cache clashes. The scheme was quite aggressive, even
going so far as to coallocate code in some functions with code in their
most frequent callers. The study also includes a characterization of the
I-miss and execution intensities of the backend, in a neat matrix with
the major functions on one axis and the stage from which they're invoked
on the other.
The paper may be enlightening. Just a moment while I google for it...
...Got it. Here's the paper:
http://research.ac.upc.es/CAP/hpc/Papers/1999/aramirez1999aC.pdf
And here's the Citeseer entry:
http://citeseer.ist.psu.edu/context/163268/0
Jeroen
Peter Eisentraut <peter_e@gmx.net> writes:
Neil Conway wrote:
The patch adds a new make target ("profile-opt") that does the PGO
steps outlined above -- the "representative input data" is the
regression tests running in serial mode. I haven't run any benchmarks
yet (if someone wants to try that, I'd be very curious to see the
results).
I doubt that the regression tests are anywhere near representative input
data. They run a proportion of borderline and error cases that is much
higher than I would expect in normal use.
Also, the serial regression tests provide absolutely 0 exercise for any
of the code paths associated with concurrent behavior. At minimum I'd
suggest using the parallel tests instead.
It might be interesting to compare the results from PGO using the
regression tests to PGO using pgbench. pgbench probably goes overboard
in the other direction of not exercising enough stuff, but it would give
us some kind of data point about the consequences of different profiling
loads.
regards, tom lane