[开源项目发布]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开始到结束的时间。递归亦是如此统计,不会叠加。