[开源项目发布]Observer:根据map文件测试程序在运行中各个函数的运行时间

寒假断断续续写这个大概有小半个月了,过个年耽误了几天。

这两天清理了一些bug,整理了代码,打算发出来。

Observer是基于微软的detour3.0写的。

适用对象,c/c++编写成的exe文件(需要生成map文件)

下载Observer地址:http://pan.baidu.com/share/link?shareid=281171&uk=2133448544

下载源码地址(vs2008工程):https://github.com/youzhonghui/Observer

BUG可以发到http://1.obser.sinaapp.com/

如果要编译此源码,需要将detour3.0的include和lib.X86中的文件分别复制到 vs2008的安装目录 Microsoft Visual Studio 9.0\VC 下面的 include 和 lib 文件夹下。

下面有使用指南。

原理简介:

在程序link的阶段,可以选择让连接器生成map文件。map文件有函数名和函数期望载入地址等信息。而程序在载入的时候基本是不会发生重定位的(exe部分),所以根据这个信息,就可以利用detour注入dll改变函数的流程。

如果要看代码,注意下面几点便于代码理解:

1.只有自己编写的函数是Observer的测试对象,计时规则等可以看看下面的《Observer使用指南》。

2.测试对象的个数是不确定的,所以需要在运行的时候动态生成执行代码来对应每一个函数。(曾想过用一个函数套住所有的函数,但是这样做会比较复杂而且效率较低)

3.生成执行代码的方法是先写一个函数为"模板",然后每次拷贝这个模板的代码,再在需要改动的地方修改(在模板中做标记)

4.”模板"即为myFunc函数。会调用QueryPerformanceCounter作为计时器。调用函数用ret而不是call ( - -|| call要计算相对距离,ret可以用绝对地址)

5.要小心维护栈平衡,并且要先保存下会被修改寄存器,因为测试的函数是什么参数,是fastcall还是stdcall,返回值有没有用到栈等等都是不知道的,我要做的就是小心翼翼地把原来的状态都保存下来,之后再改回去。

《Observer使用指南》:

作者:南树
博客:http://www.cnblogs.com/nanshu/
Observer论坛:http://1.obser.sinaapp.com/
 
 
本软件绿色,无需安装。
 
运行时需要
    Observer_shell_v2.0.exe
    Observer-kernel_v1.0.dll
    withdll.exe
三个文件在同一个目录下。
 
使用方法:
    运行Observer_shell_v2.0.exe
    可以看到等待输入。
    将需要测试的目标exe文件拖入黑框,回车即可。
    保证map文件和目标exe文件在同一个目录下
    运行结束以后会在目标文件目录下生成 name_result.txt文件,即为测试结果。
    在sample文件夹中有供尝试的test。运行Observer_shell_v2.0.exe后将test拉入黑框回车,运行结束后会生成相应的结果文件。
    
生成map文件的方法:
    map是在link阶段生成的,如果用IDE的话,一般可以在工程属性的link页找到。
    如:vc6是 项目 -> 设置 -> 连接 -> 产生map文件
        vs2008是 properties -> linker -> Debugging -> Generate Map File
    其他IDE或者用makefile的可以上网查查。
 
注意:
    不要在路径中出现空格
    在name_result.txt的第一行有Minimum interval
        例如:Minimum interval:0.000411 ms
    表示如果一个函数一次执行期间所用时间小于0.000411 ms,所有时间将不会被记录,在结果中对于函数的调用时间为 0
    Frequency 表示函数被调用的次数
    Time      表示函数运行的时间。注意,请认真看下面的计时规则
    有可能您的平台不支持高精度计时器(在name_result.txt第一行显示Do not support timer),那么就无法使用本程序。
    如果你写的函数比较简短,有可能会被编译器当做内联函数优化掉,不会出现在map文件中。可以在编译器的优化选项中选择去掉此项。
    vc可以用#pragma optimize("",off)来取消优化
 
计时规则:
    测试的对象是自己写的函数,对于调用的API或者c标准库中的函数不作为测试对象。
    如果A,B函数都是测试对象,A中调用了B,那么A最后的时间是A开始到结束的时间 - B开始到结束的时间。递归亦是如此统计,不会叠加。
原文地址:https://www.cnblogs.com/nanshu/p/2915696.html