Microsoft MVP성태의 닷넷 이야기
VC++: 87. 무시할 수 없는 Visual C++ 런타임 함수 성능 [링크 복사], [링크+제목 복사],
조회: 23017
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)

무시할 수 없는 Visual C++ 런타임 함수 성능

아래의 글에 달린 덧글 덕분에,

보이어-무어(Boyer-Moore) 알고리즘이 정말 빠를까?
; https://www.sysnet.pe.kr/2/0/1705

C 런타임 함수를 새롭게 보게 되었습니다. ^^

위의 글에서 strstr 함수가 boyer_moore 함수에 비해 굉장히 빠른 속도를 내는 것을 보았는데요. 덧글의 의견처럼 "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\crt\src\strstr.c"에 해당하는 소스코드는 Visual C++에서 실행되는 strstr 함수가 아니었습니다.

이를 확인하는 방법은 간단합니다.

Visual C++ 프로젝트에서 "Runtime Library" 옵션을 "Multi-threaded Debug"로 바꾸고,

crt_func_debug_0.png

Visual Studio에서 디버깅을 시작한 다음 strstr 함수로 F11(Step-into)키를 눌러 진입하면 다음과 같이 소스 코드를 찾는 창이 뜹니다.

crt_func_debug_1.png

"f:\dd\vctools\crt\crtw32\string\i386\strstr.asm" 경로는 마이크로소프트 측에서 빌드했을 때의 경로이고, 우리는 그냥 strstr.asm 파일을 찾아서 매핑시켜주면 됩니다. Visual Studio 2013을 설치한 경우 다음의 경로에 있으니,

C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\crt\src\intel\strstr.asm

이 파일을 맞춰주면 Visual Studio에서 assembly 코드에 대한 라인 단위 디버깅으로 진입합니다. 거기다, "Registers" 창을 띄워 놓으면 레지스터 값 확인까지 가능합니다. 이렇게!

crt_func_debug_2.png

참고로, strstr.asm의 소스 코드는 다음과 같습니다.

        page    ,132
        title   strstr - search for one string inside another
;***
;strstr.asm - search for one string inside another
;
;       Copyright (c) Microsoft Corporation. All rights reserved.
;
;Purpose:
;       defines strstr() - search for one string inside another
;
;*******************************************************************************

        .xlist
        include cruntime.inc
        .list

page
;***
;char *strstr(str1, str2) - search for str2 in str1
;
;Purpose:
;       finds the first occurrence of str2 in str1
;
;Entry:
;       char *str1 - string to search in
;       char *str2 - string to search for
;
;Exit:
;       returns a pointer to the first occurrence of string2 in
;       string1, or NULL if string2 does not occur in string1
;
;Uses:
;
;Exceptions:
;
;*******************************************************************************


__from_strstr_to_strchr proto

        CODESEG

        public  strstr

strstr  proc \
        str1:ptr byte, \
        str2:ptr byte

        OPTION PROLOGUE:NONE, EPILOGUE:NONE

        mov     ecx,[esp + 8]       ; str2 (the string to be searched for)
        mov     eax,[esp + 4]       ; str1 (the string to be searched)

        push    edi                 ; Preserve edi, ebx and esi
        push    ebx
        push    esi

;   .FPO (cdwLocals, cdwParams, cbProlog, cbRegs, fUseBP, cbFrame)
    .FPO      ( 0, 2, $-strstr, 3, 0, 0 )

; Include SSE2/SSE4.2 code paths for platforms that support them.
        include strstr_sse.inc

        mov     dl,[ecx]            ; dl contains first char from str2

        mov     edi,eax             ; str1 (the string to be searched)

        test    dl,dl               ; is str2 empty?
        jz      empty_str2

        mov     dh,[ecx + 1]        ; second char from str2
        test    dh,dh               ; is str2 a one-character string?
        jz      strchr_call         ; if so, go use strchr code

; length of str2 is now known to be > 1 (used later)
; dl contains first char from str2
; dh contains second char from str2
; edi holds str1

findnext:
        mov     esi,edi             ; esi = edi = pointers to somewhere in str1
        mov     ecx,[esp + 14h]     ; str2

;use edi instead of esi to eliminate AGI
        mov     al,[edi]            ; al is next char from str1

        add     esi,1               ; increment pointer into str1

        cmp     al,dl
        je      first_char_found

        test    al,al               ; end of str1?
        jz      not_found           ; yes, and no match has been found

loop_start:
        mov     al,[esi]            ; put next char from str1 into al
        add     esi,1               ; increment pointer in str1
in_loop:
        cmp     al,dl
        je      first_char_found

        test    al,al               ; end of str1?
        jnz     loop_start          ; no, go get another char from str1

not_found:
        pop     esi
        pop     ebx
        pop     edi
        xor     eax,eax
        ret

; recall that dh contains the second char from str2

first_char_found:
        mov     al,[esi]            ; put next char from str1 into al
        add     esi,1

        cmp     al,dh               ; compare second chars
        jnz     in_loop             ; no match, continue search

two_first_chars_equal:
        lea     edi,[esi - 1]       ; store position of last read char in str1

compare_loop:
        mov     ah,[ecx + 2]        ; put next char from str2 into ah
        test    ah,ah               ; end of str2?
        jz      match               ; if so, then a match has been found

        mov     al,[esi]            ; get next char from str1
        add     esi,2               ; bump pointer into str1 by 2

        cmp     al,ah               ; are chars from str1 and str2 equal?
        jne     findnext            ; no

; do one more iteration

        mov     al,[ecx + 3]        ; put the next char from str2 into al
        test    al,al               ; end of str2
        jz      match               ; if so, then a match has been found

        mov     ah,[esi - 1]        ; get next char from str1
        add     ecx,2               ; bump pointer in str1 by 2
        cmp     al,ah               ; are chars from str1 and str2 equal?
        je      compare_loop

; no match. test some more chars (to improve execution time for bad strings).

        jmp     findnext

; str2 string contains only one character so it's like the strchr functioin

strchr_call:
        xor     eax,eax
        pop     esi
        pop     ebx
        pop     edi
        mov     al,dl
        jmp     __from_strstr_to_strchr

;
;
; Match!  Return (ebx - 1)
;
match:
        lea     eax,[edi - 1]
        pop     esi
        pop     ebx
        pop     edi
        ret

empty_str2:           ; empty target string, return src (ANSI mandated)
        mov     eax,edi
        pop     esi
        pop     ebx
        pop     edi
        ret

strstr  endp
        end

어셈블리로 최적화된 strstr 함수 말고, C 언어로 된 strstr 함수로 테스트 하는 경우에는 Boyer-Moore 알고리즘이 대체로 빠릅니다.

52KB의 문자열을 준비하고 발견되지 않는 문자열로 10번씩 테스트 해보면,

// x86/Release 빌드
// (낮을 수록 빠릅니다.)
// boyer_moore 검색 시간
boyer_moore (861)
boyer_moore (881)
boyer_moore (979)
boyer_moore (849)
boyer_moore (847)
boyer_moore (865)
boyer_moore (870)
boyer_moore (912)
boyer_moore (853)
boyer_moore (850)

// strstr 검색 시간
strstr (1691)
strstr (1335)
strstr (1320)
strstr (1357)
strstr (1338)
strstr (1296)
strstr (1294)
strstr (1290)
strstr (1291)
strstr (1587)

boyer_moore가 빠릅니다. 1/3 지점 앞 부분에 나오는 약간 긴 텍스트로 검색해 보면,

// boyer_moore 검색 시간
boyer_moore (260)
boyer_moore (31)
boyer_moore (32)
boyer_moore (32)
boyer_moore (42)
boyer_moore (33)
boyer_moore (32)
boyer_moore (31)
boyer_moore (32)
boyer_moore (32)

// strstr 검색 시간
strstr (1345)
strstr (704)
strstr (1498)
strstr (1501)
strstr (403)
strstr (183)
strstr (184)
strstr (183)
strstr (182)
strstr (362)

역시 boyer_moore가 빠릅니다. 뒤에서 1/3 지점에 나오는 짧은 텍스트로 검색을 해보면,

boyer_moore (457)
boyer_moore (431)
boyer_moore (429)
boyer_moore (429)
boyer_moore (430)
boyer_moore (430)
boyer_moore (429)
boyer_moore (430)
boyer_moore (429)
boyer_moore (429)

strstr (213)
strstr (212)
strstr (212)
strstr (212)
strstr (211)
strstr (212)
strstr (340)
strstr (214)
strstr (213)
strstr (213)

이번만큼은 C 언어 함수인 strstr이 빠릅니다.

재미있군요. ^^ strstr C 함수가 사실 굉장히 간단한 편인데도 불구하고 assembly로 최적화했을 때의 속도 향상이 '월등'해지는 것이 꽤나 인상적입니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 2/6/2015]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 91  92  93  94  95  96  97  98  99  100  [101]  102  103  104  105  ...
NoWriterDateCnt.TitleFile(s)
11440정성태1/17/201820607.NET Framework: 727. ASP.NET의 HttpContext.Current 구현에 대응하는 ASP.NET Core의 IHttpContextAccessor/HttpContextAccessor 사용법파일 다운로드1
11439정성태1/17/201826286기타: 69. C# - CPU 100% 부하 주는 프로그램파일 다운로드1
11438정성태1/17/201820197오류 유형: 446. Error CS0234 The type or namespace name 'ITuple' does not exist in the namespace
11437정성태1/17/201819773VS.NET IDE: 124. Platform Toolset 설정에 따른 Visual C++의 헤더 파일 기본 디렉터리
11436정성태1/16/201822182개발 환경 구성: 352. ASP.NET Core (EXE) 프로세스가 IIS에서 호스팅되는 방법 - ASP.NET Core Module(AspNetCoreModule) [4]
11435정성태1/16/201823260개발 환경 구성: 351. OWIN 웹 서버(EXE)를 IIS에서 호스팅하는 방법 - HttpPlatformHandler (Reverse Proxy)파일 다운로드2
11434정성태1/15/201823908개발 환경 구성: 350. 사용자 정의 웹 서버(EXE)를 IIS에서 호스팅하는 방법 - HttpPlatformHandler (Reverse Proxy)파일 다운로드2
11433정성태1/15/201822070개발 환경 구성: 349. dotnet ef 명령어 사용을 위한 준비
11432정성태1/11/201828490.NET Framework: 726. WPF + Direct2D + SharpDX 출력 C# 예제파일 다운로드2
11431정성태1/11/201825644.NET Framework: 725. C# - 동기 방식이면서 비동기 메서드(awaitable)처럼 구현한 사례 [9]
11430정성태1/10/201829111.NET Framework: 724. WPF + Direct2D 출력 C# 예제 [2]파일 다운로드1
11429정성태1/9/201819663개발 환경 구성: 348. ASP.NET Core 2.1 Preview 버전 적용 방법
11428정성태1/6/201822876개발 환경 구성: 347. WinForm 프로젝트를 WPF 프로젝트 유형으로 변경하는 방법파일 다운로드1
11427정성태1/5/201820217오류 유형: 445. vcpkg 빌드 오류 - Starting the CLR failed with HRESULT 80040153
11426정성태1/5/201830431오류 유형: 444. curl로 호출할 때 발생하는 오류 정리
11425정성태1/4/201821072개발 환경 구성: 346. ASP.NET Core Web Application을 IIS에서 호스팅하는 방법 (2)
11424정성태1/4/201820514개발 환경 구성: 345. ASP.NET Core 프로젝트를 명령행에서 빌드하는 방법
11423정성태1/3/201838956VC++: 123. 내가 만든 코드보다 OpenCV의 속도가 월등히 빠른 이유 [8]파일 다운로드2
11422정성태1/2/201829063.NET Framework: 723. C# - OpenCvSharp 사용 시 C/C++을 이용한 속도 향상 (for 루프 연산) [4]파일 다운로드1
11421정성태1/2/201821294오류 유형: 443. Visual Studio - nuget configuration is invalid
11420정성태12/30/201725386.NET Framework: 722. C# - Windows 10 운영체제의 데스크톱 앱에서 음성인식(SpeechRecognizer) 사용하는 방법 [3]파일 다운로드1
11419정성태12/23/201727555.NET Framework: 721. WebClient 타입의 ...Async 메서드 호출은 왜 await + 동기 호출 시 hang 현상이 발생할까요? [2]파일 다운로드1
11418정성태12/23/201737273.NET Framework: 720. 비동기 메서드 내에서 await 시 ConfigureAwait 호출 의미 [2]파일 다운로드1
11417정성태12/22/201723190.NET Framework: 719. Task를 포함하는 async 메서드의 동작 방식 [2]
11416정성태12/21/201720305.NET Framework: 718. AsyncTaskMethodBuilder.Create() 메서드 동작 방식 [2]
11415정성태12/21/201722166.NET Framework: 717. Task를 포함하지 않는 async 메서드의 동작 방식 [6]
... 91  92  93  94  95  96  97  98  99  100  [101]  102  103  104  105  ...