2010-05-27 2 views
1
학교에서

, 우리에 대한 virtual C++ 함수, 그들은 를 해결 (또는 일치, 나는 용어가 무엇인지 모르는, 또는 발견 - 우리가 영어 공부를하지 않는) 방법을 컴파일 시간 대신 실행 시간. 교사는 또한 컴파일 시간 해상도가 실행 시간보다 훨씬 빠르다고 말했습니다. 그러나 빠른 실험은 다른 방법을 제안합니다. 이 작은 프로그램을 만들었습니다 :실행 시간 방식의 해상도가 컴파일 시간 해상도보다 빠른 이유는 무엇입니까?

#include <iostream> 
#include <limits.h> 

using namespace std; 

class A { 
    public: 
    void f() { 
     // do nothing 
    } 
}; 

class B: public A { 
    public: 
    void f() { 
     // do nothing 
    } 
}; 

int main() { 
    unsigned int i; 
    A *a = new B; 
    for (i=0; i < UINT_MAX; i++) a->f(); 
    return 0; 
} 

나는 위의 프로그램을 컴파일하고 이름을 normal으로 지정했습니다. 그럼, 다음과 같이 할 A 수정 :

class A { 
    public: 
    virtual void f() { 
     // do nothing 
    } 
}; 

를 집계하고이를 virtual 이름. 결과는 다음과 같습니다.

[[email protected] C]$ time ./normal 

real 0m25.834s 
user 0m25.742s 
sys 0m0.000s 
[[email protected] C]$ time ./virtual 

real 0m24.630s 
user 0m24.472s 
sys 0m0.003s 
[[email protected] C]$ time ./normal 

real 0m25.860s 
user 0m25.735s 
sys 0m0.007s 
[[email protected] C]$ time ./virtual 

real 0m24.514s 
user 0m24.475s 
sys 0m0.000s 
[[email protected] C]$ time ./normal 

real 0m26.022s 
user 0m25.795s 
sys 0m0.013s 
[[email protected] C]$ time ./virtual 

real 0m24.503s 
user 0m24.468s 
sys 0m0.000s 

가상 버전에 비해 1 초 정도의 차이가 지속되는 것 같습니다. 왜 이런거야?


관련 항목 : 듀얼 코어 펜티엄 @ 2.80Ghz, 두 가지 테스트 사이에서 실행되는 추가 응용 프로그램 없음. gcc 4.5.0을 사용하는 Archlinux. 처럼, 일반적으로 컴파일 :

$ g++ test.cpp -o normal 

는 또한, -Wall 중 하나, 경고를 뱉어하지 않습니다.


편집 : A.cpp, B.cppmain.cpp에 내 프로그램을 분리 한. 또한, 나는 f() (모두 A::f()B::f()) 함수는 실제로 이 (A::A() 1로 초기화 xApublicint 구성원 x = 0 - x) 일을했다.

[[email protected] poo]$ time ./normal-unoptimized 

real 0m31.172s 
user 0m30.621s 
sys 0m0.033s 
[[email protected] poo]$ time ./normal-O2 

real 0m2.417s 
user 0m2.363s 
sys 0m0.007s 
[[email protected] poo]$ time ./normal-O3 

real 0m2.495s 
user 0m2.447s 
sys 0m0.000s 
[[email protected] poo]$ time ./virtual-unoptimized 

real 0m32.386s 
user 0m32.111s 
sys 0m0.010s 
[[email protected] poo]$ time ./virtual-O2 

real 0m26.875s 
user 0m26.668s 
sys 0m0.003s 
[[email protected] poo]$ time ./virtual-O3 

real 0m26.905s 
user 0m26.645s 
sys 0m0.017s 

최적화되지 않은 1 초 빠른 때 가상 아직도, 나는 조금 특이한 찾을 : 여섯 개 버전이 점을 컴파일, 여기 내 최종 결과입니다. 그러나 이것은 좋은 실험이었으며 귀하의 답변에 대해 모두 감사드립니다.

+2

-O3 (레벨 3 최적화)을 사용해보실 수 있습니까? – CMircea

+0

내가 찾는 용어는 * vtable *이라고 생각합니다. –

+0

아, 또 다른 마이크로 벤치! Lovely, 나는 그들을 그리워하기 시작했다. – mdma

답변

6

최적화되지 않은 코드의 프로파일 링은 거의 의미가 없습니다. 의미있는 결과를 얻으려면 -O2을 사용하십시오. -O3을 사용하면 더 빠른 코드가 생성 될 수 있지만 A::fB::fmain (즉, 별도의 컴파일 단위)으로 따로 컴파일하지 않으면 현실적인 결과가 생성되지 않을 수 있습니다.

피드백을 기반으로, 심지어 -O2조차도 너무 공격적입니다. 2ms 결과는 컴파일러가 루프를 완전히 최적화했기 때문입니다.직접 전화는 이 아니며이 빠릅니다. 사실, 어떤 차이를 관찰하는 것은 매우 어렵습니다. f의 구현을 별도의 컴파일 단위로 이동하여 실수를 가져옵니다. 클래스를 .h로 정의하지만, 자신의 .cc 파일에 A::fB::f을 정의하십시오.

+0

이런 젠장! '-O2'와'-O3' 둘 다'normal' 버전을 .002 초로 줄 였고'virtual'은 ~ 27 초 정도였습니다. – Felix

+2

@Felix 옵티마이 저는 아마도 함수 호출 (및 아마도 루프)을 모두 제거했을 것입니다.이 문제를 방지하려면 전역 보조 효과가 있어야합니다. –

+0

@Felix : 이것은 또한 일반적인 가상 함수 호출의 오버 헤드를 나타내는 것이 아니라는 점에 유의하십시오. '보통'경우에는 아마도 모든 함수 호출과 전체 루프가 최적화되어 버렸을 것입니다. – sth

11

vtable을 캐시에 저장하면 실제로 수행하는 가상 함수와 가상이 아닌 함수 간의 성능 차이가 매우 작습니다. C++을 사용하여 소프트웨어를 개발할 때 반드시 염두해야 할 것은 아닙니다. 그리고 다른 사람들이 지적했듯이 C++에서 최적화되지 않은 코드를 벤치마킹하는 것은 무의미합니다.

+3

현실 세계에서 +1, @Felix, 이것에 대해 걱정하는 것은 * 마이크로 최적화 *, 그리고 프로그래머들이 시간을 낭비하는 것은 아닙니다. 대형 시스템을 프로그래밍하는 것만 큼 어렵습니다. 가상 통화 (및 기타 마이크로 최적화)의 속도에 대해 정말로 염려하는 유일한 경우는 수백만 초 동안 해당 기능을 호출 할 때입니다. –

2

CPU가 코드를 재구성하고 계산 및 메모리 액세스를 재구성하는 과정에서 얼마나 많은 일이 있었는지를 감안할 때 4 %의 차이를 너무 많이 읽지는 ​​않을 것입니다. 합리적인 판단을 할 수 없으므로 걱정할 필요가 없습니다. 이와 같은 마이크로 벤치 마크의 결론.

실제 메모리 액세스로 실제 계산을 시도하여 가상 메소드의 비용이 얼마나 들지 느껴보십시오. 가상 메소드 자체는 보통 문제가 아닙니다. 현대 CPU는 vtable에서 가져온 포인터를 다른 작업과 인터리브합니다. 성능을 저하시키는 인라이닝이 부족합니다.

1

프로그램의 단순성을 감안할 때 컴파일러가 특정 항목이나 그 라인을 따라 무언가를 최적화하는 적절한 기회가 있습니다. 복잡성 추가/컴파일러가 원하는 것을 정확히 컴파일하는 것은 이런 종류의 것을 목표로해야하는 무언가입니다 (런타임에서 차이점은 함수 호출의 나머지 부분보다 적은 2 개의 역 참조라고 생각합니다). 이렇게하는 한 가지 방법은 @Marcelo가 말했듯이 A와 B를 main에서 분리 된 파일로 컴파일하는 것입니다. 한 단계 더 나아가 각각의 파일을 컴파일합니다. 그러나 나는 위에서 언급 한 이유 때문에 컴파일러가 코드의 리터럴 변환을 생성하고 제거하지 않도록 최적화를 해제해야한다고 동의합니다.