Article View: gnu.gcc.help
Article #42626performance measurements across 8 platforms: atoi()/sprintf("%d")
From: forman
Date: Thu, 16 Nov 1995 00:00
Date: Thu, 16 Nov 1995 00:00
311 lines
7975 bytes
7975 bytes
I timed the attached program on a number of platforms to compare the
relative performance of their system library versions of atoi() and
sprintf(str,"%d",i) against a hand-coded C version. In most cases, it
was easy to beat the system library-- perhaps losing some generality,
but I'm surprised how much better the simple hand-coded C version does
on some platforms. This generality shouldn't cost you more than a
factor of 2, should it?
OS & MACHINE USER TIMES RATIO
====================== ============== =====
IRIX 5.3, SGI Indy 6.23 / 10.84 .574
FreeBSD 2.0.5, Pent.90 10.13 / 30.14 .336
OSF1 3.2, DEC-ALPHA300X 13.0 / 22.7 .572
LINUX 1.2.11, Pentium90 13.4 /180.3 .074
AIX 3.2.5, PowerPC-41T 17.4 / 19.7 .883
ULTRIX 4.2, DEC-MIPS 28.8 / 69.0 .417
SUNOS 4.1.2, SPARC-10 45.0 / 51.2 .878
SUNOS 4.1.2, SPARC-2 126.2 / 84.4 1.50
^^^^
^^^^ system library atoi()/sprintf()
^^^^
^^^^ hand-coded C versions gcc -O3
Someone (aorenste@sunspot.tiac.net) has since posted a version of
the program which beats socks off the system library implementations.
(I'll attach his routines too.) Which platform would you rather have?
OS & MACHINE USER TIMES RATIO
====================== ============== =====
IRIX 5.3, SGI Indy 3.68 / 10.84 .339
LINUX 1.2.11, Pentium90 4.6 /180.3 .025
OSF1 3.2, DEC-ALPHA300X 5.9 / 22.7 .259
SUNOS 4.1.2, SPARC-10 8.3 / 51.2 .162
AIX 3.2.5, PowerPC-41T 18.5 / 19.7 .939
ULTRIX 4.2, DEC-MIPS 20.0 / 69.0 .289
(Could someone please re-run the Linux / Pentium 90 timing?
Our library probably wasn't configured right.)
-George
PS: Strange but true, Pentium90s makes a high pitched whine when I run
certain CPU-bound jobs, e.g. testing the library 'a.out -10000000'
Any idea why? It can be quite earritating.
----------------------------------------------------------------
graduate student, Computer Science & Engineering, Univ. of Washington
/****************************************************************
# begin Makefile
a.out:
gcc -O3 contest.c
test: a.out
time a.out 10000
time a.out -10000
your: a.out
time a.out 1000000
lib: a.out
time a.out -1000000
contest: a.out
echo "This may take around 5 minutes..."
time a.out 1000000
time a.out -1000000
echo "Divide the first user time by the second."
# end Makefile
#
# Here's a csh alias for extracting & using Makefiles stored inside .c files:
# Usage: inmake contest.c [make options]
#
# alias inmake awk "'/begin Makefile/,/end Makefile/{print}' \!:1 \
# >/tmp/InMakefile.$$; make -f /tmp/InMakefile.$$ \!:2*"
****************************************************************/
#include <stdio.h>
#include <stdlib.h>
extern int fast_atoi(char *string); /* fast atoi() */
extern int fast_itoa(char *buf, int i); /* fast sprintf(buf,"%d",i); */
int main( int argc, char *argv[])
{
char buf[80];
int i,j;
int N = 10000; /* # of iterations / 2 */
if (argc > 1) N = atoi(argv[1]);
/* test your code a bit */
if (fast_atoi("2147483647") != 2147483647) exit(1);
if (fast_atoi(" 0") != 0) exit(1);
if (fast_atoi("00123") != 123) exit(1);
if (fast_atoi("-2147483647")!= -2147483647) exit(1);
if (N < 0) { /* negative --> time library code */
N = -N;
for (i = -N; i < N; i++) {
sprintf( buf, "%d", i);
j = atoi(buf);
if (i != j) exit(1); /* error (unlikely in library code) */
}
}
else { /* positive --> time your code */
for (i = -N; i < N; i++) {
fast_itoa( buf, i);
j = fast_atoi(buf);
if (i != j) exit(1); /* error */
}
}
return 0;
}
int fast_atoi(char *string) /* fast version of atoi() */
{
int number=0;
char negative=0;
while (*string==32) string++; /* skip leading spaces */
if (*string=='-') /* negative ? */
{negative=1;string++;}
else
negative=0;
while (isdigit(*string))
{
number*=10;
number+=(*string)-48; /* make char to int and add to number */
string++;
}
if (negative) number=-number;
return number;
}
int fast_itoa(char *buf, int i) /* fast version of sprintf(buf,"%d",i); */
{
int nr_written=0;
char tmp[40];
char *pointer;
pointer=tmp;
*pointer++=0;
if (i<0)
{
i=-i;
*buf++='-';
nr_written++;
}
while (i)
{
nr_written++;
*pointer++=(i%10)+48;
i/=10;
}
pointer--;
while (*buf++=*pointer--); /* copy number (reversed) from tmp to buf */
return nr_written;
}
And Aaron's faster code:
/* fast_itoa & fast_atoi by Aaron Orenstein (aorenste@sunspot.tiac.net) */
/* Given to the public domain */
#include <ctype.h>
/* WARNING: Assuming 32-bit ints */
/* ------------------------------------------------------------------------ */
int fast_atoi(register char *string) /* fast version of atoi() */
{
register int total=0;
int neg=0;
while(isspace(*string)) string++;
if(*string=='-')
{
neg=1;
string++;
}
while(isdigit(*string))
total=(total*10)+*string++-'0';
if(neg)
return -total;
else
return total;
}
/* ------------------------------------------------------------------------ */
#define DECODE_N(n) \
decode1##n: \
if(i<5##n) \
if(i<3##n) \
if(i<2##n) \
if(i<1##n) \
*ptr++='0'; \
else \
{ *ptr++='1'; i-=1##n; } \
else /* 2##n <= i < 3##n */ \
{ *ptr++='2'; i-=2##n; } \
else /* 3##n <= i < 5##n */ \
if(i<4##n) \
{ *ptr++='3'; i-=3##n; } \
else /* 4##n <= i < 5##n */ \
{ *ptr++='4'; i-=4##n; } \
else /* i>=5##n */ \
if(i<7##n) \
if(i<6##n) \
{ *ptr++='5'; i-=5##n; } \
else /* 6##n <= i < 7##n */ \
{ *ptr++='6'; i-=6##n; } \
else /* 7##n <= i < 10##n */ \
if(i<9##n) \
if(i<8##n) \
{ *ptr++='7'; i-=7##n; } \
else /* 8##n <= i < 9##n */ \
{ *ptr++='8'; i-=8##n; } \
else /* 9##n <= i < 10##n */ \
{ *ptr++='9'; i-=9##n; }
/* fast version of sprintf(buf,"%d",i); */
int fast_itoa(char *buf, register int i)
{
register char *ptr=buf;
register int place=9;
if(i==0)
{
*ptr++='0';
*ptr=0;
return 1;
}
if(i<0)
{
*ptr++='-';
i=-i;
}
if(i<10) goto decode1;
if(i<100) goto decode10;
if(i<1000) goto decode100;
if(i<10000) goto decode1000;
if(i<100000) goto decode10000;
if(i<1000000) goto decode100000;
if(i<10000000) goto decode1000000;
if(i<100000000) goto decode10000000;
if(i<1000000000) goto decode100000000;
if(i<2000000000)
{ *ptr++='1'; i-=1000000000; }
else /* 2000000000 <= i < 2147483648 */
{ *ptr++='2'; i-=2000000000; }
DECODE_N(00000000)
DECODE_N(0000000)
DECODE_N(000000)
DECODE_N(00000)
DECODE_N(0000)
DECODE_N(000)
DECODE_N(00)
DECODE_N(0)
decode1:
*ptr++=i+'0';
done:
*ptr=0;
return ptr-buf;
}
Technical Details
Message-ID:
<gnusenetDI229s.AA7@beaver.cs.washington.edu>Path:
arc1-ca.pugleaf.net!unknown!not-for-mailShow Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: 11318c,f08e09659acad946,start
X-Google-Attributes: gid11318c,public
From: forman@cs.washington.EDU.university.of.washington
Subject: performance measurements across 8 platforms: atoi()/sprintf("%d")
Date: 1995/11/16
Message-ID: <gnusenetDI229s.AA7@beaver.cs.washington.edu>
X-Deja-AN: 119586903
distribution: gnu
sender: daemon@cis.ohio-state.edu
organization: Computer Science & Engineering, U of Washington, Seattle
keywords: comp.programming.contests
newsgroups: gnu.gcc.help