글수 69
strlen 같이 문자열 길이를 카운트 하는 함수는 연습삼아 누구나 한번쯤은 만들어 봤을겁니다.
간단하게 생각할 수 있는 방법으로는, 단순히 문자열 포인터의 값을 꺼내와서 NULL인지 보고, 아니면 계속 1씩 더해가며 루프를 도는 방법이겠죠.
[code]
int strlen8(const char *str)
{
const char *count = str;
while (*count)
count++;
return (count - str);
}
[/code]
아주 심플한 코드입니다.
그만큼 간단하기 때문에, 위 함수는 루프가 있음에도 인라인 처리가 됩니다.
32비트 환경에서는 32비트 단위로 처리하는게 가장 빠르다고 하니, int 단위로 처리할 수 있도록 함수를 만들어 봤습니다.
[code]
int strlen32(const char *str)
{
const int *count = (int *)str;
while (1) {
if ((*count & 0x000000ff) == 0) break;
if ((*count & 0x0000ff00) == 0) { str--; break; }
if ((*count & 0x00ff0000) == 0) { str-=2; break; }
if ((*count & 0xff000000) == 0) { str-=3; break; }
count++;
}
return ((char *)count - str);
}
[/code]
다소 복잡하고 부실하며, 또 노가다기가 다분히 보이는-_- 코드입니다.
언뜻 보이게는 별다른 처리가 없는 strlen8 함수가 더 빨라 보이지만, 테스트를 해보면 그렇지 않습니다.
(길이가 2760인 문자열로 테스트, QueryPerformanceCounter 함수로 시간 측정[단위: 초], 각각 10000번 반복)
strlen8 = 2760, time=0.078660
strlen32 = 2760, time=0.036939
strlen = 2760, time=0.009646
*strlen은 표준 함수에서 지원하는 함수입니다.
strlen32가 빠르게 나올 것임은 예상할 수 있었지만, 저 정도로 빠를 줄은 몰랐습니다.
strlen32 함수가 strlen8 보다 여러모로 허접(?)해보이지만, 거의 2배나 빠르다는 것을 알 수 있습니다.
물론 strlen은 어셈블리로 작성되어서 그런지 좀 더 빨랐지만 말입니다.
디버그 모드에서 테스트 했기 때문에 strlen8, strlen32 함수는 최적화가 이루어지지 않았기 때문입니다.
릴리즈 모드에서 테스트한 결과는 다음과 같습니다.
strlen8 = 2760, time=0.040689
strlen32 = 2760, time=0.015432
strlen = 2760, time=0.038248
이제 속도 차이가 확실히 보이는 것 같네요.
strlen32 함수는 표준 strlen 함수보다 약 2배 정도 빠릅니다.
strlen 함수도 코드를 살펴보면 VC++ 구현에서 strlen32 비슷하게 32비트씩 처리해서 비트 마스킹으로 구합니다만... (32비트 정렬도 해주고...)
릴리즈 모드에서 strlen32 함수는 인라인 처리 되면서 함수 호출이 일어나지 않아서 좀 더 빠르게 나온 것 같네요.
(릴리즈 모드에서 strlen8, strlen32 모두 인라인 처리되었습니다)
결론은, 32비트 환경에서 데이터 뭉텅이를 처리할 때는 바이트 단위보다 32비트씩 처리하는게 훨씬 빠르다는 것.
그리고, strlen 함수는 디버그 버전이 릴리즈 버전보다 훨씬 빠르네요 -_-;
간단하게 생각할 수 있는 방법으로는, 단순히 문자열 포인터의 값을 꺼내와서 NULL인지 보고, 아니면 계속 1씩 더해가며 루프를 도는 방법이겠죠.
[code]
int strlen8(const char *str)
{
const char *count = str;
while (*count)
count++;
return (count - str);
}
[/code]
아주 심플한 코드입니다.
그만큼 간단하기 때문에, 위 함수는 루프가 있음에도 인라인 처리가 됩니다.
32비트 환경에서는 32비트 단위로 처리하는게 가장 빠르다고 하니, int 단위로 처리할 수 있도록 함수를 만들어 봤습니다.
[code]
int strlen32(const char *str)
{
const int *count = (int *)str;
while (1) {
if ((*count & 0x000000ff) == 0) break;
if ((*count & 0x0000ff00) == 0) { str--; break; }
if ((*count & 0x00ff0000) == 0) { str-=2; break; }
if ((*count & 0xff000000) == 0) { str-=3; break; }
count++;
}
return ((char *)count - str);
}
[/code]
다소 복잡하고 부실하며, 또 노가다기가 다분히 보이는-_- 코드입니다.
언뜻 보이게는 별다른 처리가 없는 strlen8 함수가 더 빨라 보이지만, 테스트를 해보면 그렇지 않습니다.
(길이가 2760인 문자열로 테스트, QueryPerformanceCounter 함수로 시간 측정[단위: 초], 각각 10000번 반복)
strlen8 = 2760, time=0.078660
strlen32 = 2760, time=0.036939
strlen = 2760, time=0.009646
*strlen은 표준 함수에서 지원하는 함수입니다.
strlen32가 빠르게 나올 것임은 예상할 수 있었지만, 저 정도로 빠를 줄은 몰랐습니다.
strlen32 함수가 strlen8 보다 여러모로 허접(?)해보이지만, 거의 2배나 빠르다는 것을 알 수 있습니다.
물론 strlen은 어셈블리로 작성되어서 그런지 좀 더 빨랐지만 말입니다.
디버그 모드에서 테스트 했기 때문에 strlen8, strlen32 함수는 최적화가 이루어지지 않았기 때문입니다.
릴리즈 모드에서 테스트한 결과는 다음과 같습니다.
strlen8 = 2760, time=0.040689
strlen32 = 2760, time=0.015432
strlen = 2760, time=0.038248
이제 속도 차이가 확실히 보이는 것 같네요.
strlen32 함수는 표준 strlen 함수보다 약 2배 정도 빠릅니다.
strlen 함수도 코드를 살펴보면 VC++ 구현에서 strlen32 비슷하게 32비트씩 처리해서 비트 마스킹으로 구합니다만... (32비트 정렬도 해주고...)
릴리즈 모드에서 strlen32 함수는 인라인 처리 되면서 함수 호출이 일어나지 않아서 좀 더 빠르게 나온 것 같네요.
(릴리즈 모드에서 strlen8, strlen32 모두 인라인 처리되었습니다)
결론은, 32비트 환경에서 데이터 뭉텅이를 처리할 때는 바이트 단위보다 32비트씩 처리하는게 훨씬 빠르다는 것.
그리고, strlen 함수는 디버그 버전이 릴리즈 버전보다 훨씬 빠르네요 -_-;

vs2005 릴리즈 모드에서 길이 866의 문자열을 천만번 돌렸을 때 다음과 같이 나옵니다.
단위는 ms입니다.
unicode, dll
elpased time of strlen: 3763
elapsed time of strlen32: 3744
multibyte, dll
elpased time of strlen: 3776
elapsed time of strlen32: 3737
unicode, static
elpased time of strlen: 3765
elapsed time of strlen32: 3726
multibyte, static
elpased time of strlen: 3759
elapsed time of strlen32: 3725
릴리즈에서 최적화 하느라 코드를 무시해버리는 문제 때문에 result를 더했는데 그 부분에서 영향을 미쳤으려나요?