如何分析一个EXE及其同时加载的DLL? [英] How to profile an EXE and the DLLs it loaded at the same time?

查看:311
本文介绍了如何分析一个EXE及其同时加载的DLL?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Windows上使用MinGW GCC编译器.如果将-pg开关添加到编译器,则可以使用配置文件数据生成EXE和DLL.

gmon.out生成.但是问题是,当我使用

gprof myprogram.exe gmon.out

我没有任何配置文件输出(表格标题和其他文本除外).

gprof mydll.dll gmon.out

我仅获得该特定DLL的输出,而没有获得主exe的输出.

也许exe和dll都希望生成相同的文件,并且dll胜出了.

目标是在一个输出中获得EXE和DLL中函数的统计信息.

gprof可以这样做吗?如果没有,是否有任何工具可以在Windows上执行此操作?

解决方案

似乎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(n³),被称为很多次,我必须重构……我完全忘记了该函数甚至存在……0x004390F9是WinMain. /p>

I'm using the MinGW GCC compiler on Windows. If I add -pg switch to the compiler I can generate both the EXE and the DLL with profile data.

The gmon.out is generated. But the problem is that when I use

gprof myprogram.exe gmon.out

I get no profile output (other than the table headings and other text).

gprof mydll.dll gmon.out

I get the output for that particular DLL only but not for the main exe.

Maybe both the exe and the dll wanted to generate the same file and the dll won.

The goal is getting stats for functions in both the EXE and DLL in one output.

Can gprof do that? If not, is there any tool that can do this on Windows?

解决方案

It seems gprof cannot do that. sprof is not available in MinGw. So rolled my own profiler.

I used -finstrument-functions So two functions __cyg_profile_func_enter and __cyg_profile_func_exit will be called before and after each functions respectively.

The actual profiling functions are exported into a DLL and called in these functions, and the DLL is linked to all EXE and DLL in question. So it can profile both of them

The code in the library is like this (removed clutter: asserts, error checking, simplified function calls for clarity).

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);
    }
}

And it produces logs like this:

 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
  ...

The function names can be found out from the MAP file. And the function at 0x691C83B9 in the DLL is indeed a suboptimal function with O(n³) complexity and is called lot of times, I must refactor that... I totally forgot that function even exist... The 0x004390F9 is the WinMain.

这篇关于如何分析一个EXE及其同时加载的DLL?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆