Re: CORBA::string_dup

Serguei Kolos <[email protected]> Mon, 06 Oct 2003 18:32:08 +0200
Newsgroups gmane.comp.corba.omniorb.devel
Message-ID <[email protected]>

Duncan Grisby wrote:

>On Friday 26 September, Serguei Kolos wrote:
>
>  
>
>>I have noticed that the CORBA::string_dup function uses strcpy to copy 
>>strings.
>>Unfortunately on many systems strcpy is much slower then for example 
>>memcpy.
>>For example on Linux (RedHat 7.3) the strcpy is 5 (sic!) times slower. 
>>    
>>
>
>Really?  Wow!  I wonder what it's doing.
>
>  
>
>>What do you think about the idea of using the memcpy in the
>>CORBA::string_dup instead of the strcpy? Are there any drawbacks
>>with the memcpy?
>>    
>>
>
>I suspect that on other platforms memcpy might be slower than strcpy.
>
I have tested on Solaris 5.7 with SunPro 5.2. The memcpy is still faster 
then strcpy (bu not so dramatic
as on Linux).

>
>Something to try is to replace the call with the obvious for loop.
>Between omniORB 3 and 4 I did some profiling and found that strcmp was
>stupidly slow, and by far the fastest thing was an inline function
>with a for loop. It will probably be the same with strcpy.
>  
>
I have tested this also and found that the for loop solution is not 
always faster in
case of strcpy and strlen (on Solaris for example). It depends on 
OS/compiler.
I attached simple program that makes timing for various strdup 
implementations.
You can see that the fastest one is always system strdup, but as far as 
I know
the strdup is not available on all the platforms. But note also a 
difference between strcpy
and memcpy.

In my PIII 800 (RedHat 7.3 with g++ 2.95.2) box the output is:
(built with g++ -O3)

system strdup 2.41994
my_strdup (for loop for copy and length) 6.97561
my_strdup1 (strlen + strcpy) 10.8472
my_strdup2 (for loop for length + memcpy) 6.3582
my_strdup3 (strlen + memcpy)7.16166
strcpy only 3.12776
memcpy only 0.565542

Note the last two lines - times differ in 6 times.

On Solaris with SunPro 5.2 situation with strcpy is not so dramatic:
(built with CC -xO4)

system strdup 7.86524
my_strdup (for loop for copy and length) 15.1074
my_strdup1 (strlen + strcpy) 8.08667
my_strdup2 (for loop for length + memcpy) 12.9627
my_strdup3 (strlen + memcpy)7.29567
strcpy only 3.63349
memcpy only 2.71386

But again the fastest one is "strlen + memcpy".

And finally here are the results from dual PIII 1Ghz (RedHat 9 with g++ 
3.3.1)
(built with g++ -O3)
The memcpy is 6 !!! times faster.
The fastest one is again system strdup.

system strdup 1.70942
my_strdup (for loop for copy and length) 5.44478
my_strdup1 (strlen + strcpy) 6.53631
my_strdup2 (for loop for length + memcpy) 4.92023
my_strdup3 (strlen + memcpy)4.81977
strcpy only 2.08511
memcpy only 0.36471

I don't know what the strcpy is doing here.

Finally I believe it would be wise to change strcpy to something else in 
string_dup.

Cheers,
Sergei

_______________________________________________
omniORB-dev mailing list
[email protected]
http://www.omniorb-support.com/mailman/listinfo/omniorb-dev
test_copy.cc (text/plain, 3 KB)
#include <iostream.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>

using namespace std;

#define SIZE 1024

char * my_strdup( const char * s )
{
	register const char *p = s;
	for ( ;*p++; );
	
	char * d = new char[p-s+1];
	
	p = s;
	register char * r = d;
	for ( ;*p++; ) 
		*r++ = *p++;
	*r = 0;
	return d;
}

char * my_strdup1( const char * s )
{
	int i = strlen( s );
	
	char * d = new char[i+1];
	
	strcpy( d, s );
	
	return d;
}

char * my_strdup2( const char * s )
{
	const char *p = s;
	for ( ;*p++; );
	
	char * d = new char[p-s+1];
	
	memcpy( d, s, p-s+1 );
	return d;
}

char * my_strdup3( const char * s )
{
	int i = strlen( s );
	
	char * d = new char[i+1];
	
	memcpy( d, s, i+1 );
	return d;
}

void my_strdup4( char * d, const char * s )
{
	strcpy( d, s );
}

void my_strdup5( char * d, const char * s )
{
	memcpy( d, s, SIZE );
}


int main()
{
	struct timeval start, stop;
	int i;
	float time;
	
	char buff[SIZE];
	memset( buff, '1', SIZE-1 );
	buff[SIZE-1] = 0;
		
	gettimeofday( &start, 0 );
	for ( i = 0; i < 1000000; i++ )
	{
		char * d = strdup( buff );
		free( d );
		buff[24] = '2';
	}
	gettimeofday( &stop, 0 );
	
	time = ( stop.tv_sec - start.tv_sec ) * 1000000 + ( stop.tv_usec - start.tv_usec );
	cout << "system strdup " << time/1000000. << endl;
	
	gettimeofday( &start, 0 );
	for ( i = 0; i < 1000000; i++ )
	{
		char * d = my_strdup( buff );
		free( d );
	}
	gettimeofday( &stop, 0 );
	
	time = ( stop.tv_sec - start.tv_sec ) * 1000000 + ( stop.tv_usec - start.tv_usec );
	cout << "my_strdup (for loop for copy and length) " << time/1000000. << endl;
	
	gettimeofday( &start, 0 );
	for ( i = 0; i < 1000000; i++ )
	{
		char * d = my_strdup1( buff );
		delete[] d;
	}
	gettimeofday( &stop, 0 );
	
	time = ( stop.tv_sec - start.tv_sec ) * 1000000 + ( stop.tv_usec - start.tv_usec );
	cout << "my_strdup1 (strlen + strcpy) " << time/1000000. << endl;
	
	gettimeofday( &start, 0 );
	for ( i = 0; i < 1000000; i++ )
	{
		char * d = my_strdup2( buff );
		delete[] d;
	}
	gettimeofday( &stop, 0 );
	
	time = ( stop.tv_sec - start.tv_sec ) * 1000000 + ( stop.tv_usec - start.tv_usec );
	cout << "my_strdup2 (for loop for length + memcpy) " << time/1000000. << endl;
	
	gettimeofday( &start, 0 );
	for ( i = 0; i < 1000000; i++ )
	{
		char * d = my_strdup3( buff );
		delete[] d;
	}
	gettimeofday( &stop, 0 );
	
	time = ( stop.tv_sec - start.tv_sec ) * 1000000 + ( stop.tv_usec - start.tv_usec );
	cout << "my_strdup3 (strlen + memcpy) " << time/1000000. << endl;
	
	gettimeofday( &start, 0 );
	char * d = new char[strlen(buff)+1];
	for ( i = 0; i < 1000000; i++ )
	{
		my_strdup4( d, buff );
	}
	gettimeofday( &stop, 0 );
	
	time = ( stop.tv_sec - start.tv_sec ) * 1000000 + ( stop.tv_usec - start.tv_usec );
	cout << "strcpy only " << time/1000000. << endl;
	
	gettimeofday( &start, 0 );
	for ( i = 0; i < 1000000; i++ )
	{
		my_strdup5( d, buff );
	}
	gettimeofday( &stop, 0 );
	
	time = ( stop.tv_sec - start.tv_sec ) * 1000000 + ( stop.tv_usec - start.tv_usec );
	cout << "memcpy only " << time/1000000. << endl;
	
}