Libiberty's snprintf for v3?

Kaveh R. Ghazi ghazi@caip.rutgers.edu
Tue Apr 22 23:13:00 GMT 2003


 > From: DJ Delorie <dj@redhat.com>
 > 
 > > Ok, but that's only a concern if these platforms are missing
 > > [v]snprintf and therefore would rely on the libiberty copy.
 > > E.g. I'd expect that cygwin has snprintf.  Don't know about the
 > > others.
 > > 
 > > Can you please clarify the other platforms' situations?
 > 
 > [v]snprintf will be in djgpp 2.04, but isn't in the current 2.03.

Ok I'd be interested in concrete measurements.  For the sake of this
discussion, I've written a new vsnprintf.c which uses the strategy I
outlined previously.  (It's mixed with a patch to remove system header
includes, but ignore that for the moment.)

I'd be interested to know how fast or slow this new vsnprintf.c is
vs. the current one in libiberty on djgpp 2.03.

I tested the speed by wrapping the -DTEST main program with a large
loop and defining CLEAR(X) and VERIFY(X) to be empty so that it
isolates the calls to checkit which simply wraps vsnprintf.

On unix (sparc-solaris2.7) it's either 10% or 20% faster depending on
whether it has to call alloca for extra space, as in when the
resulting string would be longer than `n'.

		--Kaveh

diff -rcp orig/egcc-CVS20030421/libiberty/vsnprintf.c egcc-CVS20030421/libiberty/vsnprintf.c
*** orig/egcc-CVS20030421/libiberty/vsnprintf.c	Tue Apr 22 12:11:27 2003
--- egcc-CVS20030421/libiberty/vsnprintf.c	Tue Apr 22 16:35:27 2003
*************** system version of this function is used.
*** 39,62 ****
  
  */
  
- #include "config.h"
  #include "ansidecl.h"
  
  #ifdef ANSI_PROTOTYPES
  #include <stdarg.h>
  #else
  #include <varargs.h>
  #endif
! #ifdef HAVE_STRING_H
! #include <string.h>
! #endif
! #ifdef HAVE_STDLIB_H
! #include <stdlib.h>
  #endif
  
! #include "libiberty.h"
  
- /* This implementation relies on a working vasprintf.  */
  int
  vsnprintf (s, n, format, ap)
       char * s;
--- 39,79 ----
  
  */
  
  #include "ansidecl.h"
  
  #ifdef ANSI_PROTOTYPES
  #include <stdarg.h>
+ #include <stddef.h>
  #else
  #include <varargs.h>
+ #define size_t unsigned long
  #endif
! 
! PTR memcpy PARAMS ((PTR, const PTR, size_t));
! int atexit PARAMS ((void (*)(void)));
! 
! #ifndef va_copy
! # ifdef __va_copy
! #   define va_copy(d,s)  __va_copy((d),(s))
! # else
! #   define va_copy(d,s)  ((d) = (s))
! # endif
  #endif
  
! #include <stdio.h>
! 
! static FILE *nullstream = 0;
! 
! #if defined(HAVE_ATEXIT) || defined (HAVE_ON_EXIT)
! static void close_nullstream PARAMS ((void));
! static void
! close_nullstream()
! {
!   if (nullstream)
!     fclose (nullstream);
! }
! #endif
  
  int
  vsnprintf (s, n, format, ap)
       char * s;
*************** vsnprintf (s, n, format, ap)
*** 64,93 ****
       const char *format;
       va_list ap;
  {
!   char *buf = 0;
!   int result = vasprintf (&buf, format, ap);
  
!   if (!buf)
!     return -1;
!   if (result < 0)
      {
!       free (buf);
!       return -1;
      }
  
!   result = strlen (buf);
    if (n > 0)
      {
!       if ((long) n > result)
! 	memcpy (s, buf, result+1);
        else
          {
  	  memcpy (s, buf, n-1);
  	  s[n - 1] = 0;
  	}
      }
!   free (buf);
!   return result;
  }
  
  #ifdef TEST
--- 81,133 ----
       const char *format;
       va_list ap;
  {
!   int size;
!   va_list ap2;
  
!   /* Open a stream on /dev/null and arrange to close it at exit.  */
!   if (!nullstream)
      {
!       if ((nullstream = fopen ("/dev/null", "a")))
!         {
! 	  /* We don't want to rely on libiberty's atexit.c so that
!              this file can be used outside libiberty.  */
! #ifdef HAVE_ATEXIT
! 	  atexit (close_nullstream);
! #else
! # ifdef HAVE_ON_EXIT
! 	  on_exit ((void *)close_nullstream, 0);
! # endif
! #endif	
! 	}
!       else
! 	return -1;
      }
+   
+   /* Copy `ap' before using it.  */
+   va_copy (ap2, ap);
  
!   size = vfprintf (nullstream, format, ap);
!   if (size < 0)
!     return -1;
!   
    if (n > 0)
      {
!       /* If `size' fits in `n' then just print to the user supplied
!          buffer, otherwise print to a temporary space and copy `n'
!          bytes.  */
!       if ((long) n > size)
! 	vsprintf (s, format, ap2);
        else
          {
+ 	  char *const buf = alloca (size + 1);
+ 
+ 	  vsprintf (buf, format, ap2);
  	  memcpy (s, buf, n-1);
  	  s[n - 1] = 0;
  	}
      }
! 
!   return size;
  }
  
  #ifdef TEST
*************** vsnprintf (s, n, format, ap)
*** 96,101 ****
--- 136,145 ----
  /* For assertions.  */
  #define VERIFY(P) do { if (!(P)) abort(); } while (0)
  
+ void abort PARAMS ((void));
+ int memcmp PARAMS ((const PTR, const PTR, size_t));
+ PTR memset PARAMS ((PTR, int, size_t));
+ 
  static int ATTRIBUTE_PRINTF_3
  checkit VPARAMS ((char *s, size_t n, const char *format, ...))
  {



More information about the Libstdc++ mailing list