2013-11-28 1 views
0

함수에 20 개의 매개 변수 (포인터) (예제에서 사용 된 4 개)가 있고 모두 NULL을 가리키는 기본값이 있으면이 함수를 호출 할 때마다 런타임 중에 NULL 값을 스택하기 위해 PUSH를 수행한다는 의미입니까?C++ 함수의 기본 매개 변수화가 기본값을 스택으로 푸시합니까?

function test(val1=NULL, val2=NULL, .... val20=NULL) 

내가 속도를 최대화하기 위해이 요청하고 함수 호출시 # 사이클을 줄여 오전 :

샘플 등의 기능처럼 보일 수 있습니다.

테스트 케이스 (LOGICAL 이해 그다지)

// ArgsListTest.cpp 
// @author Mathew Kurian 

#include "stdafx.h" 
#include <iostream> 
#include <time.h> 

using namespace std; 

// Look at the difference in psuedo-assembly code 
// My knowledge in compiler is little, but I can see that 
// that there are unncessary cycles being wasted for this part. 

// **** With array (this example) ***** 
// LOAD   Reg, memAddressOfArray 
// WRITETOMEM Reg, ptrToVar1 
// INCREMENT sp 
// WRITETOMEM Reg, ptrToVar2 
// DECREMENT sp 
// PUSH   ptrToArray 
// JUMP   test 

// ***** IDEALLY SUPPOSED TO LIKE THIS ***** 
// PUSH  ptrToVar2 
// PUSH  ptrToVar1 
// JUMP  test 

class Base 
{ 
public: 
    virtual int test(void* arguments[]) 
    { 
     cout << "Base function being called. VTable lookup ignored since there is no virtual." << endl; 
     cout << *static_cast<int*>(arguments[0]) << endl; // Parameter 1 (Thinks there is only 1 parameter!) 

     int x = 5;  x += 1; // Random math to prevent optimizations. (I hope) 
     return x; 
    } 
}; 

class Derived : public Base 
{ 
public: 
    virtual int test(void* arguments[]) 
    { 
     // cout << "Derived function being called. VTable lookup during runtime. Slight overhead here!" << endl; 

     // cout << *static_cast<string*>(arguments[0]) << endl; // Parameter 1 
     // cout << *static_cast<int*>(arguments[1]) << endl; // Parameter 2 

     int x = 5;  x += 1; 
     return x; 
    } 
}; 

class Base2 
{ 
public: 
    virtual int test(void* arg1 = NULL, void* arg2 = NULL, void* arg3 = NULL, void* arg4 = NULL) 
    { 
     // cout << "Base2 function being called. VTable lookup ignored since there is no virtual." << endl; 

     // cout << *static_cast<string*>(arg1) << endl; // Parameter 1 
     // cout << *static_cast<int*>(arg2) << endl; // Parameter 2 
     int x = 5;  x += 1; 
     return x; 
    } 

    virtual int test2() 
    { 
     int x = 5;  x += 1; 
     return x; 
    } 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    Base * base = new Derived; 
    Base2 * base2 = new Base2; 

    int r = 0; 
    string * str = new string("sunny"); 
    int * vale = new int(20); 
    int iterations = 1000000000; 

    //================================================================================ 

    printf("Using No-Parameters [%d iterations]\n", iterations); 

    clock_t tStart = clock(); 

    for (int x = 0; x < iterations; x++) 
    { 
     r = base2->test2(); 
    } 

    printf("Time taken: %.9fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC); 

    //================================================================================ 

    printf("Using Array [%d iterations]\n", iterations); 

    tStart = clock(); 

    for (int x = 0; x < iterations; x++) 
    { 
     void * arguments[] = { str, vale }; 
     r = base->test(arguments); 
    } 

    printf("Time taken: %.9fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC); 

    //================================================================================ 

    printf("Using Default-Parameters [%d iterations]\n", iterations); 

    tStart = clock(); 

    for (int x = 0; x < iterations; x++) 
    { 
     r = base2->test(str, vale); 
    } 

    printf("Time taken: %.9fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC); 

    //================================================================================ 

    // cout << "NOTE: Derived class has no extra methods although the parameter counts are different.\n  Parent class doesn't even realize parameter 1 exists!" << endl; 

    std::getchar(); 

    return 0; 
} 

OUTPUT

enter image description here

왜 제보다 먼저 검사 느리다 (HERE AS WELL 일부 EXTRA 일이있다) ? 그리고 실제로 배열을 만드는 것이 단지 PUSH NULL보다 빠릅니까?

+4

표준은 그것을 말하지 않으며 구현 세부 사항입니다. 그러나 대부분의 시간은 그렇습니다. 컴파일 중에 함수가 라이닝되지 않은 경우 호출 규칙을 준수해야합니다. – WiSaGaN

+1

실제로 20 개의 인수가있는 경우, 더 좁은 인터페이스를 고려하거나 "struct"에 대한 참조를 전달할 수 있습니다. –

+3

조기 최적화는 모든 악의 뿌리입니다 –

답변

2

아마 가상 메서드가 결과에 영향을 미치고 있습니다. 나는 여러분의 메서드를 다른 성능 순서를 보여준 전역 범위에 복사했습니다.

Using No-Parameters [1000000000 iterations] 
Time taken: 24.831000000s 
Using Array [1000000000 iterations] 
Time taken: 24.730000000s 
Using Default-Parameters [1000000000 iterations] 
Time taken: 25.241000000s 
Using No-Parameters [1000000000 iterations] on int testA() 
Time taken: 21.664000000s 
Using Array [1000000000 iterations] on int testB(void* arguments[]) 
Time taken: 22.384000000s 
Using Default-Parameters [1000000000 iterations] int testC(void* arg1 = NULL, ...) 
Time taken: 22.329000000s 

EDIT : 어레이를 TestB의 할당을

동일한 테스트는 for 루프의 범위를 벗어난 이동 :

Using No-Parameters [1000000000 iterations] 
Time taken: 24.713000000s 
Using Array [1000000000 iterations] 
Time taken: 24.686000000s 
Using Default-Parameters [1000000000 iterations] 
Time taken: 25.225000000s 
Using No-Parameters [1000000000 iterations] on int testA() 
Time taken: 21.653000000s 
Using Array [1000000000 iterations] on int testB(void* arguments[]) 
Time taken: 21.896000000s 
Using Default-Parameters [1000000000 iterations] int testC(void* arg1 = NULL, ...) 
Time taken: 22.353000000s 
+0

testB에서 for 루프 외부의 배열 할당을 제거하면 가장 빠른 testA 인 testA, testB, testC 순서로 다음 순서가 생성됩니다. 더 이상의 조사가 없으면 인수 계수가 일관된 방식으로 실적에 영향을 미치는 것으로 보입니다. – bvj

+0

BTW, testA, testB 및 testC는 op 메서드의 출력에 테스트되고 표시되는 원래 메서드의 복사본입니다. 따라서 여섯 가지 테스트. – bvj

+0

글로벌 범위 란 무엇입니까? 코드를 보여줄 수 있습니까? – bluejamesbond

0

을 아마도. 다른 간단한 해결책은 여러 진입 점을 가지고있다 :

# Pseudocode 
    PUSH nullptr # Default argument 20 
    PUSH nullptr # Default argument 19 
    PUSH nullptr # Default argument 18 
    ... 
    ENTRYPOINT(test) 

당신이 N 기본 인자가있는 경우, 당신은 정규 엔트리 포인트의 앞에 주소 N 지침으로 이동. 이점 : 이제이 기본 인수를 푸시하는 코드를 호출자간에 공유 할 수 있습니다. 그래도 약간의 링커가 필요합니다.

+0

확대 해 주시겠습니까? 이 같은 것을 C++ 코드 자체에 포함 시키시겠습니까? – bluejamesbond

+0

@ mk1 : 이것은 의사 어셈블리 코드입니다. 컴파일러가 기본 인수를 사용하여 C++ 함수의 대체 구현을 생성하는 방법을 보여줍니다. 각 호출자가 기본 인수를 푸시할지 궁금해하고있었습니다. 이 예제는 호출 된 함수에 대한 선택적인 프롤로그를 사용하여 푸싱을 수행 할 수 있음을 보여줍니다. – MSalters

관련 문제