On 2013-01-10 10:55:20 +0100, Andres Freund wrote:
> On 2013-01-10 10:31:04 +0100, Andres Freund wrote:
> > On 2013-01-10 00:05:07 +0100, Andres Freund wrote:
> > > On 2013-01-09 17:28:35 -0500, Tom Lane wrote:
> > > > (We know this doesn't
> > > > matter, but gcc doesn't; this version of gcc apparently isn't doing much
> > > > with the knowledge that elog won't return.)
> > >
> > > Afaics one reason for that is that we don't have any such annotation for
> > > elog(), just for ereport. And I don't immediately see how it could be
> > > added to elog without relying on variadic macros. Bit of a shame, there
> > > probably a good number of callsites that could actually benefit from
> > > that knowledge.
> > > Is it worth making that annotation conditional on variadic macro
> > > support?
> >
> > A quick test confirms that. With:
> >
> > diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
> > index cbbda04..39cd809 100644
> > --- a/src/include/utils/elog.h
> > +++ b/src/include/utils/elog.h
> > @@ -212,7 +212,13 @@ extern int     getinternalerrposition(void);
> >   *         elog(ERROR, "portal \"%s\" not found", stmt->portalname);
> >   *----------
> >   */
> > +#ifdef __GNUC__
> > +#define elog(elevel, ...) elog_start(__FILE__, __LINE__, 
> > PG_FUNCNAME_MACRO), \
> > +           elog_finish(elevel, __VA_ARGS__),                               
> >                                 \
> > +           ((elevel) >= ERROR ? __builtin_unreachable() : (void) 0)
> > +#else
> >  #define elog       elog_start(__FILE__, __LINE__, PG_FUNCNAME_MACRO), 
> > elog_finish
> > +#endif
> >
> >  extern void elog_start(const char *filename, int lineno, const char 
> > *funcname);
> >  extern void
> >
> > nearly the same code is generated for both variants (this is no
> > additionally saved registers and such).
> >
> > Two unfinished things:
> > * the above only checks for gcc although all C99 compilers should
> >   support varargs macros
> > * It uses __builtin_unreachable() instead of abort() as that creates
> >   a smaller executable. That's gcc 4.5 only. Saves about 30kb in a
> >   both a stripped and unstripped binary.
> > * elog(ERROR) i.e. no args would require more macro ugliness, but that
> >   seems unneccesary
> >
> > Doing the __builtin_unreachable() for ereport as well saves about 50kb.
> >
> > Given that some of those elog/ereports are in performance critical code
> > paths it seems like a good idea to remove code from the
> > callsites. Adding configure check for __VA_ARGS__ and
> > __builtin_unreachable() should be simple enough?
> 
> For whatever its worth - I am not sure its much - after relying on
> variadic macros we can make elog into one function call instead of
> two. That saves another 100kb.
> 
> [tinker]
> 
> The builtin_unreachable and combined elog thing bring a measurable
> performance benefit of a rather surprising 7% when running Pavel's
> testcase ontop of yesterdays HEAD. So it seems worth investigating.
> About 3% of that is the __builtin_unreachable() and about 4% the
> combining of elog_start/finish.
> 
> Now that testcase sure isn't a very representative one for this, but I
> don't really see why it should benefit much more than other cases. Seems
> to be quite the benefit for relatively minor cost.
> Although I am pretty sure just copying the whole of
> elog_start/elog_finish into one elog_all() isn't the best way to go at
> this...

The attached patch:

* adds configure checks for __VA_ARGS__ and __builtin_unreachable
  support
* provides a pg_unreachable() macro that expands to
  __builtin_unreachable() or abort()
* changes #define elog ... into #define elog(elevel, ...) if varargs are
  available

It does *not* combine elog_start and elog_finish into one function if
varargs are available although that brings a rather measurable
size/performance benefit.

Greetings,

Andres Freund

-- 
 Andres Freund                     http://www.2ndQuadrant.com/
 PostgreSQL Development, 24x7 Support, Training & Services
>From 94a3f93f4c8a381358a4dc52a43ec60a8f3e33f6 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Fri, 11 Jan 2013 16:58:17 +0100
Subject: [PATCH] Mark elog() as not returning if the capabilities of the C
 compiler allow it

To do that:
* Add a configure check for __VA_ARGS__ support
* Provide pg_unreachable() macro which expands to__builtin_unreachable() if the
  compiler supports it, abort() otherwise

Marking it as such improves code generation and reduces executable size.
---
 config/c-compiler.m4     | 41 +++++++++++++++++++++++++++++++++++++++++
 configure.in             |  2 ++
 src/include/c.h          | 10 ++++++++++
 src/include/utils/elog.h | 18 +++++++++++++++---
 4 files changed, 68 insertions(+), 3 deletions(-)

diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 7cbb8ec..f3efe72 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -161,6 +161,47 @@ fi])# PGAC_C_TYPES_COMPATIBLE
 
 
 
+# PGAC_C_VA_ARGS
+# -----------------------
+# Check if the C compiler understands C99 style variadic macros and define
+# HAVE__VA_ARGS if so.
+AC_DEFUN([PGAC_C_VA_ARGS],
+[AC_CACHE_CHECK(for __VA_ARGS__, pgac_cv__va_args,
+[AC_TRY_COMPILE([#include <stdio.h>],
+[#define debug(...) fprintf(stderr, __VA_ARGS__)
+debug("%s", "blarg");
+],
+[pgac_cv__va_args=yes],
+[pgac_cv__va_args=no])])
+if test x"$pgac_cv__va_args" = xyes ; then
+AC_DEFINE(HAVE__VA_ARGS, 1,
+          [Define to 1 if your compiler understands C99 __VA_ARGS__ in macros.])
+fi])# PGAC_C_VA_ARGS
+
+
+
+# PGAC_C_UNREACHABLE
+# -----------------------
+
+# Check if the C compiler understands __builtin_unreachable() and define
+# HAVE__BUILTIN_UNREACHABLE if so.
+#
+# NB: Don't get the idea of putting a for(;;); or such before the
+# __builtin_unreachable() in that case some compilers remove it before linking
+# and only a warning instead of an error will be produced.
+AC_DEFUN([PGAC_C_UNREACHABLE],
+[AC_CACHE_CHECK(for __builtin_unreachable, pgac_cv__builtin_unreachable,
+[AC_TRY_LINK([],
+[__builtin_unreachable();],
+[pgac_cv__builtin_unreachable=yes],
+[pgac_cv__builtin_unreachable=no])])
+if test x"$pgac_cv__builtin_unreachable" = xyes ; then
+AC_DEFINE(HAVE__BUILTIN_UNREACHABLE, 1,
+          [Define to 1 if your compiler understands __builtin_unreachable.])
+fi])# PGAC_C_UNREACHABLE
+
+
+
 # PGAC_PROG_CC_CFLAGS_OPT
 # -----------------------
 # Given a string, check if the compiler supports the string as a
diff --git a/configure.in b/configure.in
index e2682f3..13ac2ab 100644
--- a/configure.in
+++ b/configure.in
@@ -1106,6 +1106,8 @@ AC_C_VOLATILE
 PGAC_C_FUNCNAME_SUPPORT
 PGAC_C_STATIC_ASSERT
 PGAC_C_TYPES_COMPATIBLE
+PGAC_C_VA_ARGS
+PGAC_C_UNREACHABLE
 PGAC_STRUCT_TIMEZONE
 PGAC_UNION_SEMUN
 PGAC_STRUCT_SOCKADDR_UN
diff --git a/src/include/c.h b/src/include/c.h
index c30df8b..77c3319 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -831,6 +831,16 @@ typedef NameData *Name;
 #define STATIC_IF_INLINE
 #endif	/* PG_USE_INLINE */
 
+/*
+ * Cross Platform support to mark locations as unreachable to avoid warnings
+ * and to aid code generation.
+ */
+#ifdef HAVE__BUILTIN_UNREACHABLE
+#define pg_unreachable() __builtin_unreachable()
+#else
+#define pg_unreachable() abort()
+#endif
+
 /* ----------------------------------------------------------------
  *				Section 7:	random stuff
  * ----------------------------------------------------------------
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index cbbda04..d6e1054 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -109,7 +109,7 @@
 #define ereport_domain(elevel, domain, rest)	\
 	(errstart(elevel, __FILE__, __LINE__, PG_FUNCNAME_MACRO, domain) ? \
 	 (errfinish rest) : (void) 0),									   \
-		((elevel) >= ERROR ? abort() : (void) 0)
+		((elevel) >= ERROR ? pg_unreachable() : (void) 0)
 
 #define ereport(elevel, rest)	\
 	ereport_domain(elevel, TEXTDOMAIN, rest)
@@ -210,10 +210,22 @@ extern int	getinternalerrposition(void);
 /*----------
  * Old-style error reporting API: to be used in this way:
  *		elog(ERROR, "portal \"%s\" not found", stmt->portalname);
+ *
+ * If we have support for variadic macros available we can signal that elog
+ * won't return with an elevel >= ERROR which can lead to better code being
+ * generated.
  *----------
  */
-#define elog	elog_start(__FILE__, __LINE__, PG_FUNCNAME_MACRO), elog_finish
-
+#ifdef HAVE__VA_ARGS
+#define elog(elevel, ...)												\
+	elog_start(__FILE__, __LINE__, PG_FUNCNAME_MACRO),					\
+		elog_finish(elevel, __VA_ARGS__),								\
+		((elevel) >= ERROR ? pg_unreachable() : (void) 0)
+#else
+#define elog															\
+	elog_start(__FILE__, __LINE__, PG_FUNCNAME_MACRO),					\
+		elog_finish
+#endif
 extern void elog_start(const char *filename, int lineno, const char *funcname);
 extern void
 elog_finish(int elevel, const char *fmt,...)
-- 
1.7.12.289.g0ce9864.dirty

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to