R
RoSsIaCrIiLoIA
d_0=32.000000
d_1=38.000000
Test success
d_0=34.000000
d_1=42.000000
Test success
d_0=1.000000
d_1=0.000000
Test success
d_0=32.000000
d_1=38.000000
Test success
d_0=7.000000
d_1=10.000000
Test success
d_0=0.000000
d_1=0.000000
Test success
C:a>ab
d_0=27.000000
d_1=33.000000
Test success
d_0=17.000000
d_1=21.000000
Test success
d_0=0.000000
d_1=0.000000
Test success
(33-27=6) 6/33=x/100 => x=+18%
(21-17=4) 4/21=x/100 => x=+19%
Someone says that only a good assembly programmer can surpass a C
compiler. I'm a novice in the programming world so
Why my C version of strlcpy is slower than assembly version?
Why the C version of strlcpy of a senior C programmer is slower than
the assembly version of a novice as I am? (It does't seem suitable)
--------------------
; nasmw -f obj this_file.asm
section _DATA public align=4 class=DATA use32
section _TEXT public align=1 class=CODE use32
global _asm_strlcpy_m
extern _strlen
;size_t
;strlcpy_m(char* dst, const char* src, size_t sz)
;{size_t z=sz;
; char a;
;----------------------------*/
; if( sz )
; {if( src )
; {--z;
; l1: --sz;
; if(sz==0) goto l2;
; a=*src; ++src;
; *dst=a; ++dst;
; if(a) goto l1;
; return z-sz;
; l2: *dst=0;
; l0: z+=strlen(src);
; }
; else if(dst) *dst=0;
; }
; else if(src) goto l0;
; return z-sz;
;} /* strlcpy */
_asm_strlcpy_m:
push ebx
push esi
push edi
%define @dst [esp+16]
%define @src [esp+20]
%define @sz [esp+24]
mov ebx, @sz ; z=@sz b=sz
mov edi, @dst
mov esi, @src
cmp ebx, 0
je .l5
cmp esi, 0
je .l3
dec dword @sz
..l0:
dec ebx
jz .l1
mov al, [esi]
inc esi
mov [edi], al
inc edi
cmp al, 0
jne .l0
..le:
mov eax, @sz
sub eax, ebx
pop edi
pop esi
pop ebx
ret
..l1:
mov byte[edi], 0
..l2:
push esi
call _strlen
add esp, 4
add @sz, eax
jmp short .le
..l3:
cmp edi, 0
je .le
mov byte[edi], 0
jmp short .le
..l5:
cmp esi, 0
jne .l2
jmp short .le
%undef @dst
%undef @src
%undef @sz
; end file g.asm
--------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>
/* Yes, I know strlcat and strlcpy are in the implementors
namespace. Change them if you must.
See <http://cbfalconer.home.att.net/download/strlcpy.zip>
for documentation and rationale.
The objective is to detect whether a given string terminates
another string. This is a fairly tortuous way of doing
"endswith", but is fairly clear.
By C.B.Falconer. Released to public domain
*/
/* ---------------------- */
static int endswith_m(const char* , const char* );
static size_t revstring_m(char* string);
void rand_phrase(char* a, size_t le);
size_t strlcpy_m(char* dst, const char* src, size_t sz);
size_t asm_strlcpy_m(char* dst, const char* src, size_t sz);
size_t strlcat_m(char* dst, const char* src, size_t sz);
int test3(unsigned cicli,unsigned len_s0,unsigned len_s1,
size_t (*f0)(char*, const char*, size_t),
size_t (*f1)(char*, const char*, size_t) );
int test1(unsigned cicli, unsigned len_s0,
size_t (*f0)(char*), size_t (*f1)(char*) );
/* reverse string in place. Return length */
static size_t revstring(char *string)
{
char *last, temp;
size_t lgh;
if ((lgh = strlen(string)) > 1) {
last = string + lgh; /* points to '\0' */
while (last-- > string) {
temp = *string; *string++ = *last; *last = temp;
}
}
return lgh;
} /* revstring */
/* ---------------------- */
static size_t strlcpy(char *dst, const char *src, size_t sz)
{
const char *start = src;
if (src && sz--) {
while ((*dst++ = *src))
if (sz--) src++;
else {
*(--dst) = '\0';
break;
}
}
if (src) {
while (*src++) continue;
return src - start - 1;
}
else if (sz) *dst = '\0';
return 0;
} /* strlcpy */
/* ---------------------- */
static size_t strlcat(char *dst, const char *src, size_t sz)
{
char *start = dst;
while (*dst++) /* assumes sz >= strlen(dst) */
if (sz) sz--; /* i.e. well formed string */
dst--;
return dst - start + strlcpy(dst, src, sz);
} /* strlcat */
/* ---------------------- */
/* does searchme end with the phrase phrase? */
/* illustrates the power of reversing things */
/* (if not the efficacy) */
static int endswith(char *phrase, char *searchme)
{
int result, lgh, i;
lgh = revstring(phrase); revstring(searchme);
result = 1;
for (i = 0; i < lgh; i++) /* strncmp if we had it */
if (phrase != searchme) {
result = 0; break;
}
revstring_m(phrase); revstring_m(searchme);
return result;
} /* endswith */
/*End of By C.B.Falconer. */
#define G goto
#define U unsigned
#define R return
#define W while
#define F for
#define P printf
#define B break
int main(void)
{srand((U)time(0));
test3(50000000, 200, 200, asm_strlcpy_m, strlcpy);
test3(50000000, 200, 200, asm_strlcpy_m, strlcpy_m);
test1(300000, 100, revstring, revstring_m );
return 0;
} /* main, endswith */
/* 25 + 25 + 10 = 60 0..59 */
char lettere(U j)
{char *u="abcdefghijklmnopqrstuvwyz"
"ABCDEFGHIJKLMNOPQRSTUVWYZ"
"0123456789";
R u[j%60];
}
void rand_phrase(char* a, size_t le)
{U i=0;
/*------------------------------*/
assert(a!=0);
if(le==0) G l0;
la: a=lettere((U)rand()); if(++i<le)G la;
l0:
a=0;
}
/* does searchme end with the phrase phrase? */
/* By RoSsIaCrIiLoIA */
int endswith_m(const char* phrase, const char* searchme)
{const char *p1, *p2;
int r=0;
/*------------------------------*/
assert(phrase!=0 && searchme!=0);
p1= phrase +strlen(phrase ); /**p1=*p2=0 */
p2= searchme+strlen(searchme); /*ok caso *p1=0 o *p2=0 */
G l1;
l0: --p1; --p2;
l1: if(*p1!=*p2) G le;
if(p2==searchme)G l2;
if(p1!=phrase) G l0;
G le;
l2: r=1;
le:
R r;
}
/* reverse string in place. Return length */
size_t revstring_m(char *string)
{char *last, temp;
size_t lgh;
/*-------------------------------------*/
if( (lgh=strlen(string))>1 )
{
last= string+lgh-1;
l0:
temp=*string, *string=*last, *last=temp;
--last; ++string;
if(last>string) G l0;
}
return lgh;
} /* revstring */
size_t
strlcpy_m(char* dst, const char* src, size_t sz)
{size_t z=sz;
char a;
/*----------------------------*/
if( sz )
{if( src )
{--z;
l1: --sz;
if(sz==0) G l2;
a=*src; ++src;
*dst=a; ++dst;
if(a) G l1;
R z-sz;
l2: *dst=0;
l0: z+=strlen(src);
}
else if(dst) *dst=0;
}
else if(src) G l0;
R z-sz;
} /* strlcpy */
size_t
strlcat_m(char* dst, const char* src, size_t sz)
{size_t z;
/*--------------------*/
if( (z=strlen(dst)) + 1 <= sz )
R z + strlcpy_m(dst+z, src, sz-z);
else {if(sz) dst[sz-1]=0; /* se dest=NULL could write it */
R z + (src ? strlen(src): 0);
}
} /* strlcat */
int test3(cicli, len_s0, len_s1, f0, f1)
U cicli, len_s0, len_s1;
size_t (*f0)(char*, const char*, size_t),
(*f1)(char*, const char*, size_t);
{char *s2, *s0, *s1, *s3;
size_t i, k0, k1, h0, h1, h3;
time_t t0, t1;
/*-------------------------------------{}*/
if(cicli==0||len_s0==0||len_s1==0||f0==0||f1==0)
R 0;
if(len_s0>100000||len_s1>100000)
R 0;
s0=malloc(len_s0);
if(s0==0) R 0;
if((s1=malloc(len_s1))==0)
{free(s0); R 0;}
if((s2=malloc(len_s0))==0)
{free(s0);free(s1); R 0;}
if((s3=malloc(len_s0))==0)
{free(s0);free(s1); free(s2); R 0;}
i=0;
l0:
h0=rand()%len_s0; h1=rand()%len_s1;
h3=h0+1+rand()%(len_s0-h0);
rand_phrase(s0, h0); rand_phrase(s1, h1);
strcpy(s3, s0); strcpy(s2, s0);
if( (k0=f0(s0, s1, h3 )) !=
(k1=f1(s2, s1, h3 )) )
{l1:
P("test failure:"
"s3=%s# s1=%s# s0=%s# s2=%s# k0=%u# k1=%u# len(s0)=%u h0=%u h1=%u
giri=%u\n",
s3, s1, s0, s2, (U)k0, (U)k1,(U)strlen(s0),(U)h0,(U)h1,
(U)i);
free(s0); free(s1); free(s2); free(s3);
R 0;
}
if(strcmp(s0, s2)!=0)G l1;
if(++i<cicli/500)G l0;
i=0;
l34:
h1=rand()%len_s1; rand_phrase(s1, h1);
if(h1==0) G l34;
t0=time(0);
l2:
// h0=rand()%len_s0; rand_phrase(s0, h3);
// h1=rand()%len_s1; rand_phrase(s1, h1);
// h3=(h0+h1+1)%(len_s0);
++*s1;
if(f0(s0, s1, h1+1)==1234567) ++i;
if(++i<cicli)G l2;
t1=time(0);
P("d_0=%f\n", difftime(t1,t0));
i=0;
t0=time(0);
l3:
// h0=rand()%len_s0; rand_phrase(s0, h0);
// h1=rand()%len_s1; rand_phrase(s1, h1);
// h3=(h0+h1+1)%(len_s0);
++*s1;
if(f1(s0, s1, h1+1)==1234567) ++i;
if(++i<cicli)G l3;
t1=time(0);
P("d_1=%f\n", difftime(t1,t0));
free(s0); free(s1); free(s2); free(s3);
P("Test success\n");
R 1;
}
int test1(cicli, len_s0, f0, f1)
U cicli, len_s0;
size_t (*f0)(char*), (*f1)(char*);
{char *s0, *s1, *s2;
size_t i, k0, k1, h0, h1, h3, len_s1=len_s0;
time_t t0, t1;
/*-------------------------------------{}*/
if(cicli==0||len_s0==0||f0==0||f1==0)
R 0;
if(len_s0>100000)
R 0;
s0=malloc(len_s0);
if(s0==0) R 0;
if((s1=malloc(len_s1))==0)
{free(s0); R 0;}
if((s2=malloc(len_s0))==0)
{free(s0);free(s1); R 0;}
i=0;
l0:
h0=rand()%len_s0;
rand_phrase(s0, h0);
strcpy(s1, s0);
if( (k0=f0(s0))!=(k1=f1(s1)) )
{l1:
P("test failure:"
"s1=%s# s0=%s# s2=%s# k0=%u# k1=%u# len(s0)=%u h0=%u h1=%u
giri=%u\n",
s1, s0, s2, (U)k0, (U)k1,(U)strlen(s0),(U)h0,(U)h1, (U)i);
free(s0); free(s1); free(s2);
R 0;
}
if(strcmp(s0, s1)!=0)G l1;
if(++i<cicli/50)G l0;
i=0;
l34:
h1=rand()%len_s1; rand_phrase(s1, h1);
if(h1==0) G l34;
t0=time(0);
l2:
++*s1;
if(f0(s1)==1234567) ++i;
if(++i<cicli)G l2;
t1=time(0);
P("d_0=%f\n", difftime(t1,t0));
i=0;
t0=time(0);
l3:
++*s1;
if(f1(s1)==1234567) ++i;
if(++i<cicli)G l3;
t1=time(0);
P("d_1=%f\n", difftime(t1,t0));
free(s0); free(s1); free(s2);
P("Test success\n");
R 1;
}
d_1=38.000000
Test success
d_0=34.000000
d_1=42.000000
Test success
d_0=1.000000
d_1=0.000000
Test success
d_0=32.000000
d_1=38.000000
Test success
d_0=7.000000
d_1=10.000000
Test success
d_0=0.000000
d_1=0.000000
Test success
C:a>ab
d_0=27.000000
d_1=33.000000
Test success
d_0=17.000000
d_1=21.000000
Test success
d_0=0.000000
d_1=0.000000
Test success
(33-27=6) 6/33=x/100 => x=+18%
(21-17=4) 4/21=x/100 => x=+19%
Someone says that only a good assembly programmer can surpass a C
compiler. I'm a novice in the programming world so
Why my C version of strlcpy is slower than assembly version?
Why the C version of strlcpy of a senior C programmer is slower than
the assembly version of a novice as I am? (It does't seem suitable)
--------------------
; nasmw -f obj this_file.asm
section _DATA public align=4 class=DATA use32
section _TEXT public align=1 class=CODE use32
global _asm_strlcpy_m
extern _strlen
;size_t
;strlcpy_m(char* dst, const char* src, size_t sz)
;{size_t z=sz;
; char a;
;----------------------------*/
; if( sz )
; {if( src )
; {--z;
; l1: --sz;
; if(sz==0) goto l2;
; a=*src; ++src;
; *dst=a; ++dst;
; if(a) goto l1;
; return z-sz;
; l2: *dst=0;
; l0: z+=strlen(src);
; }
; else if(dst) *dst=0;
; }
; else if(src) goto l0;
; return z-sz;
;} /* strlcpy */
_asm_strlcpy_m:
push ebx
push esi
push edi
%define @dst [esp+16]
%define @src [esp+20]
%define @sz [esp+24]
mov ebx, @sz ; z=@sz b=sz
mov edi, @dst
mov esi, @src
cmp ebx, 0
je .l5
cmp esi, 0
je .l3
dec dword @sz
..l0:
dec ebx
jz .l1
mov al, [esi]
inc esi
mov [edi], al
inc edi
cmp al, 0
jne .l0
..le:
mov eax, @sz
sub eax, ebx
pop edi
pop esi
pop ebx
ret
..l1:
mov byte[edi], 0
..l2:
push esi
call _strlen
add esp, 4
add @sz, eax
jmp short .le
..l3:
cmp edi, 0
je .le
mov byte[edi], 0
jmp short .le
..l5:
cmp esi, 0
jne .l2
jmp short .le
%undef @dst
%undef @src
%undef @sz
; end file g.asm
--------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>
/* Yes, I know strlcat and strlcpy are in the implementors
namespace. Change them if you must.
See <http://cbfalconer.home.att.net/download/strlcpy.zip>
for documentation and rationale.
The objective is to detect whether a given string terminates
another string. This is a fairly tortuous way of doing
"endswith", but is fairly clear.
By C.B.Falconer. Released to public domain
*/
/* ---------------------- */
static int endswith_m(const char* , const char* );
static size_t revstring_m(char* string);
void rand_phrase(char* a, size_t le);
size_t strlcpy_m(char* dst, const char* src, size_t sz);
size_t asm_strlcpy_m(char* dst, const char* src, size_t sz);
size_t strlcat_m(char* dst, const char* src, size_t sz);
int test3(unsigned cicli,unsigned len_s0,unsigned len_s1,
size_t (*f0)(char*, const char*, size_t),
size_t (*f1)(char*, const char*, size_t) );
int test1(unsigned cicli, unsigned len_s0,
size_t (*f0)(char*), size_t (*f1)(char*) );
/* reverse string in place. Return length */
static size_t revstring(char *string)
{
char *last, temp;
size_t lgh;
if ((lgh = strlen(string)) > 1) {
last = string + lgh; /* points to '\0' */
while (last-- > string) {
temp = *string; *string++ = *last; *last = temp;
}
}
return lgh;
} /* revstring */
/* ---------------------- */
static size_t strlcpy(char *dst, const char *src, size_t sz)
{
const char *start = src;
if (src && sz--) {
while ((*dst++ = *src))
if (sz--) src++;
else {
*(--dst) = '\0';
break;
}
}
if (src) {
while (*src++) continue;
return src - start - 1;
}
else if (sz) *dst = '\0';
return 0;
} /* strlcpy */
/* ---------------------- */
static size_t strlcat(char *dst, const char *src, size_t sz)
{
char *start = dst;
while (*dst++) /* assumes sz >= strlen(dst) */
if (sz) sz--; /* i.e. well formed string */
dst--;
return dst - start + strlcpy(dst, src, sz);
} /* strlcat */
/* ---------------------- */
/* does searchme end with the phrase phrase? */
/* illustrates the power of reversing things */
/* (if not the efficacy) */
static int endswith(char *phrase, char *searchme)
{
int result, lgh, i;
lgh = revstring(phrase); revstring(searchme);
result = 1;
for (i = 0; i < lgh; i++) /* strncmp if we had it */
if (phrase != searchme) {
result = 0; break;
}
revstring_m(phrase); revstring_m(searchme);
return result;
} /* endswith */
/*End of By C.B.Falconer. */
#define G goto
#define U unsigned
#define R return
#define W while
#define F for
#define P printf
#define B break
int main(void)
{srand((U)time(0));
test3(50000000, 200, 200, asm_strlcpy_m, strlcpy);
test3(50000000, 200, 200, asm_strlcpy_m, strlcpy_m);
test1(300000, 100, revstring, revstring_m );
return 0;
} /* main, endswith */
/* 25 + 25 + 10 = 60 0..59 */
char lettere(U j)
{char *u="abcdefghijklmnopqrstuvwyz"
"ABCDEFGHIJKLMNOPQRSTUVWYZ"
"0123456789";
R u[j%60];
}
void rand_phrase(char* a, size_t le)
{U i=0;
/*------------------------------*/
assert(a!=0);
if(le==0) G l0;
la: a=lettere((U)rand()); if(++i<le)G la;
l0:
a=0;
}
/* does searchme end with the phrase phrase? */
/* By RoSsIaCrIiLoIA */
int endswith_m(const char* phrase, const char* searchme)
{const char *p1, *p2;
int r=0;
/*------------------------------*/
assert(phrase!=0 && searchme!=0);
p1= phrase +strlen(phrase ); /**p1=*p2=0 */
p2= searchme+strlen(searchme); /*ok caso *p1=0 o *p2=0 */
G l1;
l0: --p1; --p2;
l1: if(*p1!=*p2) G le;
if(p2==searchme)G l2;
if(p1!=phrase) G l0;
G le;
l2: r=1;
le:
R r;
}
/* reverse string in place. Return length */
size_t revstring_m(char *string)
{char *last, temp;
size_t lgh;
/*-------------------------------------*/
if( (lgh=strlen(string))>1 )
{
last= string+lgh-1;
l0:
temp=*string, *string=*last, *last=temp;
--last; ++string;
if(last>string) G l0;
}
return lgh;
} /* revstring */
size_t
strlcpy_m(char* dst, const char* src, size_t sz)
{size_t z=sz;
char a;
/*----------------------------*/
if( sz )
{if( src )
{--z;
l1: --sz;
if(sz==0) G l2;
a=*src; ++src;
*dst=a; ++dst;
if(a) G l1;
R z-sz;
l2: *dst=0;
l0: z+=strlen(src);
}
else if(dst) *dst=0;
}
else if(src) G l0;
R z-sz;
} /* strlcpy */
size_t
strlcat_m(char* dst, const char* src, size_t sz)
{size_t z;
/*--------------------*/
if( (z=strlen(dst)) + 1 <= sz )
R z + strlcpy_m(dst+z, src, sz-z);
else {if(sz) dst[sz-1]=0; /* se dest=NULL could write it */
R z + (src ? strlen(src): 0);
}
} /* strlcat */
int test3(cicli, len_s0, len_s1, f0, f1)
U cicli, len_s0, len_s1;
size_t (*f0)(char*, const char*, size_t),
(*f1)(char*, const char*, size_t);
{char *s2, *s0, *s1, *s3;
size_t i, k0, k1, h0, h1, h3;
time_t t0, t1;
/*-------------------------------------{}*/
if(cicli==0||len_s0==0||len_s1==0||f0==0||f1==0)
R 0;
if(len_s0>100000||len_s1>100000)
R 0;
s0=malloc(len_s0);
if(s0==0) R 0;
if((s1=malloc(len_s1))==0)
{free(s0); R 0;}
if((s2=malloc(len_s0))==0)
{free(s0);free(s1); R 0;}
if((s3=malloc(len_s0))==0)
{free(s0);free(s1); free(s2); R 0;}
i=0;
l0:
h0=rand()%len_s0; h1=rand()%len_s1;
h3=h0+1+rand()%(len_s0-h0);
rand_phrase(s0, h0); rand_phrase(s1, h1);
strcpy(s3, s0); strcpy(s2, s0);
if( (k0=f0(s0, s1, h3 )) !=
(k1=f1(s2, s1, h3 )) )
{l1:
P("test failure:"
"s3=%s# s1=%s# s0=%s# s2=%s# k0=%u# k1=%u# len(s0)=%u h0=%u h1=%u
giri=%u\n",
s3, s1, s0, s2, (U)k0, (U)k1,(U)strlen(s0),(U)h0,(U)h1,
(U)i);
free(s0); free(s1); free(s2); free(s3);
R 0;
}
if(strcmp(s0, s2)!=0)G l1;
if(++i<cicli/500)G l0;
i=0;
l34:
h1=rand()%len_s1; rand_phrase(s1, h1);
if(h1==0) G l34;
t0=time(0);
l2:
// h0=rand()%len_s0; rand_phrase(s0, h3);
// h1=rand()%len_s1; rand_phrase(s1, h1);
// h3=(h0+h1+1)%(len_s0);
++*s1;
if(f0(s0, s1, h1+1)==1234567) ++i;
if(++i<cicli)G l2;
t1=time(0);
P("d_0=%f\n", difftime(t1,t0));
i=0;
t0=time(0);
l3:
// h0=rand()%len_s0; rand_phrase(s0, h0);
// h1=rand()%len_s1; rand_phrase(s1, h1);
// h3=(h0+h1+1)%(len_s0);
++*s1;
if(f1(s0, s1, h1+1)==1234567) ++i;
if(++i<cicli)G l3;
t1=time(0);
P("d_1=%f\n", difftime(t1,t0));
free(s0); free(s1); free(s2); free(s3);
P("Test success\n");
R 1;
}
int test1(cicli, len_s0, f0, f1)
U cicli, len_s0;
size_t (*f0)(char*), (*f1)(char*);
{char *s0, *s1, *s2;
size_t i, k0, k1, h0, h1, h3, len_s1=len_s0;
time_t t0, t1;
/*-------------------------------------{}*/
if(cicli==0||len_s0==0||f0==0||f1==0)
R 0;
if(len_s0>100000)
R 0;
s0=malloc(len_s0);
if(s0==0) R 0;
if((s1=malloc(len_s1))==0)
{free(s0); R 0;}
if((s2=malloc(len_s0))==0)
{free(s0);free(s1); R 0;}
i=0;
l0:
h0=rand()%len_s0;
rand_phrase(s0, h0);
strcpy(s1, s0);
if( (k0=f0(s0))!=(k1=f1(s1)) )
{l1:
P("test failure:"
"s1=%s# s0=%s# s2=%s# k0=%u# k1=%u# len(s0)=%u h0=%u h1=%u
giri=%u\n",
s1, s0, s2, (U)k0, (U)k1,(U)strlen(s0),(U)h0,(U)h1, (U)i);
free(s0); free(s1); free(s2);
R 0;
}
if(strcmp(s0, s1)!=0)G l1;
if(++i<cicli/50)G l0;
i=0;
l34:
h1=rand()%len_s1; rand_phrase(s1, h1);
if(h1==0) G l34;
t0=time(0);
l2:
++*s1;
if(f0(s1)==1234567) ++i;
if(++i<cicli)G l2;
t1=time(0);
P("d_0=%f\n", difftime(t1,t0));
i=0;
t0=time(0);
l3:
++*s1;
if(f1(s1)==1234567) ++i;
if(++i<cicli)G l3;
t1=time(0);
P("d_1=%f\n", difftime(t1,t0));
free(s0); free(s1); free(s2);
P("Test success\n");
R 1;
}