This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Standalone cpp: reduce output overhead


This patch makes a few changes to the output end of standalone cpp
which should improve its performance.  We were spending around 25% of
runtime in stdio routines; it's now down to about 12% for the same
test case.

The patch makes two conceptual changes: avoid the use of fputs, and
use more unlocked stdio routines.  fputs has a great deal of overhead,
and cpplib used it to output millions of short (1-10 chars) strings.
In one place we do not have the length of the string precalculated but
we know it's less than five characters, so I used a loop calling
putc.  In another place, the string can be arbitrarily long but we
have the length as an integer, so I used fwrite, which has much less
overhead.

Since we are now making many more calls to fwrite, we get bit by GNU
libc's incomprehensible decision to protect stdio streams from
concurrent access even if the program is single-threaded.  The only
cure is to use fwrite_unlocked, which is not a standard routine, so
requires another block of #ifdefs in system.h to get it selected and
prototyped.  As long as I was adding gunk to system.h anyway I set us
up to use fprintf_unlocked too; that doesn't affect cpplib much but
may speed up RTL dumps and assembly output a bit.

An additional improvement may be possible by giving numbers their own
SPELL_* category; right now they are classified as strings, which
penalizes both numbers and strings with a bunch of conditional putcs
handling quote marks.  That change will touch a lot more code and
therefore I will test and submit it separately.

I would like to know what difference, if any, this makes on a system
with a different stdio implementation.

Bootstrapping i686-linux, will apply if successful.

zw

	* cpplex.c (cpp_output_token): Use a putc loop for
	SPELL_OPERATOR, and fwrite for SPELL_IDENT.

	* configure.in: Detect fwrite_unlocked and fprintf_unlocked.
	* system.h: Replace fwrite and fprintf with their unlocked
	variants if available.

===================================================================
Index: cpplex.c
--- cpplex.c	2001/09/27 12:59:37	1.168
+++ cpplex.c	2001/09/27 21:37:59
@@ -1514,6 +1514,7 @@ cpp_output_token (token, fp)
     case SPELL_OPERATOR:
       {
 	const unsigned char *spelling;
+	int c;
 
 	if (token->flags & DIGRAPH)
 	  spelling
@@ -1523,13 +1524,16 @@ cpp_output_token (token, fp)
 	else
 	  spelling = TOKEN_NAME (token);
 
-	ufputs (spelling, fp);
+	c = *spelling;
+	do
+	  putc (c, fp);
+	while ((c = *++spelling) != '\0');
       }
       break;
 
     spell_ident:
     case SPELL_IDENT:
-      ufputs (NODE_NAME (token->val.node), fp);
+      fwrite (NODE_NAME (token->val.node), 1, NODE_LEN (token->val.node), fp);
     break;
 
     case SPELL_STRING:
===================================================================
Index: configure.in
--- configure.in	2001/09/12 16:15:55	1.540
+++ configure.in	2001/09/27 21:37:57
@@ -578,7 +578,8 @@ dnl gcc_AC_C_ENUM_BF_UNSIGNED
 AC_CHECK_FUNCS(strtoul bsearch popen times clock \
 	strchr strrchr kill getrlimit setrlimit atoll atoq \
 	sysconf isascii gettimeofday strsignal putc_unlocked fputc_unlocked \
-	fputs_unlocked getrusage nl_langinfo lstat)
+	fputs_unlocked fwrite_unlocked fprintf_unlocked getrusage nl_langinfo \
+	lstat)
 
 AC_CHECK_TYPE(ssize_t, int)
 
@@ -623,7 +624,8 @@ AM_ICONV
 saved_CFLAGS="$CFLAGS"
 CFLAGS="$CFLAGS -I${srcdir} -I${srcdir}/../include"
 gcc_AC_CHECK_DECLS(getenv atol sbrk abort atof getcwd getwd \
-	strsignal putc_unlocked fputs_unlocked strstr environ errno \
+	strsignal putc_unlocked fputs_unlocked fwrite_unlocked \
+        fprintf_unlocked strstr environ errno \
 	malloc realloc calloc free basename getopt clock, , ,[
 #include "ansidecl.h"
 #include "system.h"])
===================================================================
Index: system.h
--- system.h	2001/09/10 22:34:03	1.102
+++ system.h	2001/09/27 21:37:59
@@ -55,28 +55,53 @@ Software Foundation, 59 Temple Place - S
 #endif
 
 /* The compiler is not a multi-threaded application and therefore we
-   do not have to use the locking functions.
+   do not have to use the locking functions.  In fact, using the locking
+   functions can cause the compiler to be significantly slower under
+   I/O bound conditions (such as -g -O0 on very large source files).
 
-   HAVE_DECL_PUTC_UNLOCKED actually indicates whether or not the IO
+   HAVE_DECL_PUTC_UNLOCKED actually indicates whether or not the stdio
    code is multi-thread safe by default.  If it is set to 0, then do
    not worry about using the _unlocked functions.
    
-   fputs_unlocked is an extension and needs to be prototyped specially.  */
+   fputs_unlocked, fwrite_unlocked, and fprintf_unlocked are
+   extensions and need to be prototyped by hand (since we do not
+   define _GNU_SOURCE).  */
 
-#if defined HAVE_PUTC_UNLOCKED && (defined (HAVE_DECL_PUTC_UNLOCKED) && HAVE_DECL_PUTC_UNLOCKED)
-# undef putc
-# define putc(C, Stream) putc_unlocked (C, Stream)
-#endif
-#if defined HAVE_FPUTC_UNLOCKED && (defined (HAVE_DECL_PUTC_UNLOCKED) && HAVE_DECL_PUTC_UNLOCKED)
-# undef fputc
-# define fputc(C, Stream) fputc_unlocked (C, Stream)
-#endif
-#if defined HAVE_FPUTS_UNLOCKED && (defined (HAVE_DECL_PUTC_UNLOCKED) && HAVE_DECL_PUTC_UNLOCKED)
-# undef fputs
-# define fputs(String, Stream) fputs_unlocked (String, Stream)
-# if defined (HAVE_DECL_FPUTS_UNLOCKED) && !HAVE_DECL_FPUTS_UNLOCKED
+#if defined HAVE_DECL_PUTC_UNLOCKED && HAVE_DECL_PUTC_UNLOCKED
+
+# ifdef HAVE_PUTC_UNLOCKED
+#  undef putc
+#  define putc(C, Stream) putc_unlocked (C, Stream)
+# endif
+# ifdef HAVE_FPUTC_UNLOCKED
+#  undef fputc
+#  define fputc(C, Stream) fputc_unlocked (C, Stream)
+# endif
+
+# ifdef HAVE_FPUTS_UNLOCKED
+#  undef fputs
+#  define fputs(String, Stream) fputs_unlocked (String, Stream)
+#  if defined (HAVE_DECL_FPUTS_UNLOCKED) && !HAVE_DECL_FPUTS_UNLOCKED
 extern int fputs_unlocked PARAMS ((const char *, FILE *));
+#  endif
 # endif
+# ifdef HAVE_FWRITE_UNLOCKED
+#  undef fwrite
+#  define fwrite(Ptr, Size, N, Stream) fwrite_unlocked (Ptr, Size, N, Stream)
+#  if


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]