2014-12-28 3 views
0

Windows에서 MinGW GCC 컴파일러를 사용하고 있습니다. 컴파일러에 -pg 스위치를 추가하면 프로필 데이터로 EXE와 DLL을 모두 생성 할 수 있습니다.EXE와 동시에로드 한 DLL을 프로파일하는 방법은 무엇입니까?

gmon.out이 생성됩니다. 그러나 문제는 내가 사용할 때이다.

gprof myprogram.exe gmon.out 

나는 (표 표제와 다른 텍스트를 제외하고) 프로필 출력을 얻지 못한다.

gprof mydll.dll gmon.out 

출력은 해당 특정 DLL에만 있지만 기본 exe는 아닙니다.

아마도 exe와 dll 모두 동일한 파일을 생성하려고했기 때문에 dll이 이겼습니다.

목표는 하나의 출력에서 ​​EXE와 DLL의 함수에 대한 통계를 얻는 것입니다.

gprof 할 수 있습니까? 그렇지 않은 경우 Windows에서이 작업을 수행 할 수있는 도구가 있습니까?

답변

0

gprof가 그렇게 할 수없는 것 같습니다. Sprof는 MinGw에서 사용할 수 없습니다. 그래서 내 프로필러 굴러.

내가 사용했습니다. -finstrument-functions 두 함수 __cyg_profile_func_enter__cyg_profile_func_exit은 각각 각 함수의 전후에 호출됩니다.

실제 프로파일 링 기능은 DLL로 내보내지고 이러한 함수에서 호출되며 DLL은 문제의 모든 EXE 및 DLL에 연결됩니다. 그래서 그것들 모두 프로파일 링 할 수 있습니다.

라이브러리의 코드는 다음과 같습니다 (명료성을 위해 제거 된 클러 터 : 어설 션, 오류 검사, 단순화 된 함수 호출).

static void proflib_init() 
{ 
    atexit(proflib_finalize); 

    empty(callstack); 
    empty(trackingData); 
    proflibIntialized = 1; 
} 

static void proflib_finalize() 
{ 
    /* Make a log. */ 
    FILE *f = fopen("proflib_log.txt", "wt"); 
    int i; 

    sortBySelftime(trackingData); 

    fprintf(f, "%10s%15s%15s%15s\n", "Func name", "Cumulative", "Self time", "Count"); 
    for (i = 0; i < getlength(trackingData); i++) 
    { 
     FunctionTimeInfo *fri = trackingData[i]; 

     fprintf(f, "%10p%15"PRIu64"%15"PRIu64"%20d\n", fri->addr, fri->cumulative, fri->selfTime, fri->count); 
    } 

    fclose(f); 
} 

void proflib_func_enter(void *func, void *caller) 
{ 
    FunctionTimeInfo elem; 
    long long pc; 

    pc = rdtsc(); /* Read timestamp counter from CPU. */ 

    if (!is_prolib_initialized()) 
    { 
     proflib_init(); 
    } 

    /* Register self time as control moves to the child function. */ 
    if (!isEmpty(callstack)) 
    { 
     FunctionTimeInfo *top = gettop(callstack); 

     top->selfTime += pc - top->selfSample; 
    } 

    elem.addr = func; /* Address of function. */ 
    elem.cumulative = pc; /* Time spent in function and functions called by this. (so far store the reference point only.)*/ 
    elem.selfSample = pc; /* Reference point for self time counting. */ 
    elem.count = 1; /* Number of this the function is counted. */ 
    elem.selfTime = 0; /* Time spent in the function not including called functions. */ 

    push(callstack, elem); 
} 

void proflib_func_exit(void *func, void *caller) 
{ 
    FunctionTimeInfo *fti; 
    FunctionTimeInfo *storedStat; 
    long long pc; 

    pc = rdtsc(); 

    fti = gettop(callstack); 

    fti->cumulative = pc - fti->cumulative; /* Finalize the time. */ 
    fti->selfTime += pc - fti->selfSample; 
    pop(callstack); 

    { 
     FunctionTimeInfo *top = gettop(callstack); 

     top->selfSample = pc; /* Set new self reference for the parent. */ 
    } 

    storedStat = find(trackingData, func); 

    if (storedStat) 
    { 
     /* Already have an entry. */ 
     storedStat->cumulative += fti->cumulative; 
     storedStat->selfTime += fti->selfTime; 
     storedStat->count++; 
    } 
    else 
    { 
     /* Add it as new entry. */ 
     add(trackingData, fti); 
    } 
} 

는 그리고는 다음과 같이 로그를 생성합니다

Func name  Cumulative  Self time   Count 
    691C83B9 1138235861408 1138235861408    1137730 
    00416396 539018507364 539018507364   16657216 
    0040A0DC 259288775768 199827541522    1914832 
    0041067D 876519599063 163253984165   92203200 
    691C9E0E 785372027387 150744125859    190020 
    004390F9 3608742795672 149177603708     1 
    0042E6A4 141485929006 116938396343    37753 
    00428CB8 456357355541 112610168088    193304 
    0041C2A4 340078363426 84539535634   114437798 
    691CB980 402228058455 82958191728    29675 
    00408A0A 79628811602 77769403982    512220 
    0040D8CD 93610151071 63396331438   87773597 
    0040D91A 60276409516 60276409516   175547194 
    00427C36 72489783460 58130405593     1 
    691C7C3D 56702394950 56702394950    3455819 
    691C949F 101350487028 47913486509    2977100 
    691CBBF3 241451044787 45153581905    29771 
    0043702E 920148247934 41990658926    25612 
    ... 

함수 이름은 MAP 파일에서 발견 할 수있다. 그리고 DLL에서 0x691C83B9의 함수는 실제로 O (n3) 복잡도를 가진 부 최적 함수이며 시간이 많이 필요하므로 리팩토링해야합니다 ... 함수가 존재한다는 것을 완전히 잊어 버렸습니다 ... 0x004390F9는 WinMain입니다.

+0

또한 Ctrl-C와'bt'를 10 번 사용하여'GDB'를 사용할 수도 있습니다. 스택에서 약 3 회 루틴을 보았을 때 약 33 %를 차지한다고 말했을 것입니다. 또한 인수가 무엇인지, 일상적인 계정의 코드 줄, 일반적으로 호출되는 곳 등을 확인할 수 있습니다. 이렇게하면 시간을 줄일 수있는 방법을 알 수 있습니다. 어쩌면 인수가 때로는 동일 할 수도 있습니다. 필요할 때보 다 더 자주 호출되는 것일 수 있습니다. 어쩌면 그 내부 코드가 펼쳐지거나 뭔가있을 수 있습니다. 작은 샘플의 자세한 샘플은 더 많은 정보를 제공합니다. –

+0

@MikeDunlavey 해당 기능으로 인해 산발적 인 마이크로 얼기가 발생했습니다. 이것은 GUI 응용 프로그램, 게임입니다. 전체 화면 게임에서 액션 중일 때 GDB에서 단순히 Ctrl-C 만 할 수는 없습니다. – Calmarius

+0

실제로 문제가있는 경우 게임을 일시 중지해도 문제가 없으십니까? 어쨌든,이 문제가 프레임 단위 그래픽에서 한 번만 발생하는 경우라면 서투른 방법이지만 효과적입니다. 프레임이 N ms보다 오래 걸리는 경우에만 인터럽트 할 수있는 감시 타이머를 준비하는 것입니다. 거기에 중단 점을 설정하면 스택이 왜 여분의 시간이 걸리는지 표시해야합니다. –

관련 문제