转帖一篇关于DELPHI调试的文章-AQTime
AQTime教程
1 简介
AQTime和MemProof都是AutomatedQA旗下的产品,AQTime比MemProof提供了更丰富强大的功能。该产品含有完整的性能和调试工具集,能够收集程序运行时关键的性能信息和内存/资源分配信息,并提交概要报告和详细报告,还提供所有的程序优化处理工具,囊括了自定义过滤器、图形化的调用层次结构一直到源代码浏览等内容。AQTime的特色在于它不仅是一款调试工具,还是一款性能优化工具。另外,还支持与基于SCC API的版本控制软件集成使用。
2 使用方法
本文只针对DELPHI,其他开发语言可以参照。
2.1 下载
AQTime是一个商业软件,你可以在官方网站上下载试用版本:
本文使用的是AQTime 4.92 版本
2.2 安装
直接运行安装即可
2.3 准备
和MemProof一样,要求目标程序带有完整的调试信息。打开工程选项(Project-Options)
1、 Compiler面板
l 去掉Optimization(代码优化)选项
l 选择Stack Frames(为所有过程函数强制生成调用堆栈)选项
l 选择Debug information (在DCU文件中生成调试信息)选项
2、Linker面板
l 选择Detailed(生成完整的MAP文件,包含模块、单元、过程等地址信息)选项
l 选择Include TD32 debug info(将调试信息生成到可执行文件)选项
该选项会导致可执行文件体积增大,但不会影响运行效率以及内存占用,建议在正式发布时不要带上该选项。
3、Packages面板
如果希望使用Allocation profiler (资源分配测试方案)
去掉 Build with runtime packages
也可以不去掉该选项,但是必须使用Add Moudle把下列BPL添加进来:
VCL50.BPL - Delphi 5.
RTL60.BPL - Delphi 6.
RTL70.BPL - Delphi 7.
RTL90.BPL - Delphi 2005 for Win32.
2.4 面板简介
Event View -事件浏览,查看运行过程中的事件
Moniter -监视面板,监视运行期间各个模块的内存使用情况
Disassembler -汇编代码面板,查看汇编代码
Editor -代码浏览窗口,如果无法浏览代码,会出现路径配置,选择好代码的路径即可浏览
Details -详细信息窗口,查看比报告中更详细的内容
Call Graphic -图表方式显示方法调用情况
Call Tree -树方式显示方法调用情况
PE Reader - PE文件浏览窗口
2.5 开始
选择File-New Project From Moudle 打开待测试的程序,选择一种测试方案开始测试。AQTime共有五个大类共八种不同的测试方案,下面一一介绍:
2.5.1 Allocation(资源测试)
测试资源分配释放情况,检查内存泄漏。共有两个测试方案:Allocation Profiler(内存使用剖析)和 Resource profiler(系统资源使用监测)
2.5.1.1 Allocation Profiler(内存使用剖析)
2.5.1.1.1 说明
跟踪程序执行过程中对内存资源的使用情况,按类、对象检测并显示程序中对内存资源使用情况,确定明显或潜在的内存泄露来源, 避免由此造成的程序崩溃。AQTime会跟踪TObject继承下来的对象的创建和删除,以及通过内存管理函数
· GetMem, ReallocMem, FreeMem
· GetMemory, ReallocMemory, FreeMemory
· SysGetMem, SysReallocMem, SysFreeMem
分配和释放的内存。
注意:这个方案不会跟踪使用WINAPI创建和释放的内存
2.5.1.1.2 测试结果报告
测试结果报告中有类和对象两种统计报告:
类统计报告:
Class Name |
Total Created |
Live Count |
Live Size |
Total Size |
TFont |
8 |
1 |
36 |
288 |
Class Name -类名称,如果是通过内存管理函数分配的内存类名为:VCL native memory,如果选择了Check Memory Bounds(内存边界检查),类名也有可能为:Memory Overwrite Error
Total Created -程序运行期间创建的内存总数目
Live Count -当前还有多少数目内存未释放
Live Size -当前还有多大内存未释放
Total Size -程序运行期间创建的内存总大小
对象统计报告:
Object Name |
Size |
Root |
References To |
Address |
Get# |
TFont.503 |
60 |
False |
0 |
0x02CA1D9C |
1 |
Object Name -对象名称,对象名称的命名规则为:Class Name + period + number,如:TFont.503 代表:第503个被创建的TFont对象。
Size -内存泄漏的大小
Root -为True代表对象可能属于一个全局变量、本地变量或者函数的参数;为False代表对象是另一个对象的属性
References To -当前对象共关联了多少个其他对象
Address -对象地址
Get# -当运行过程中使用了Run-Get Results手工获取报告时,Get#代表当前报告属于第几次Get Results所获得的报告。(笔者多次使用Get Results后,所有结果依然为1,奇怪~~)
2.5.1.2 Resource profiler(系统资源使用监测)
2.5.1.2.1 说明
跟踪程序运行期间,对操作系统资源(如fonts, brushes, bitmaps, and other graphic components, registry, COM objects, print spooler, etc.)的使用情况(如某时间片内,程序本身开销的系统资源、因这些资源带来的内存和CPU开销、来自于这些资源使用中出现的错误)使检测者很容易获知在程序运行期间与之相关系统资源的分配和使用情况。
2.5.1.2.2 测试结果报告
测试结果报告中有类、对象和错误三种统计报告:
类统计报告:
Module Name |
Class Name |
Live Count |
Total Created |
Live Size |
Total Size |
Image |
PROJECT1.EXE |
TLS |
3 |
13 |
0 |
0 |
|
Module Name -分配这块资源的模块
Image -资源类型的图标
注:其他类型在上面已经介绍过了,不再重复。后面也遵照这条说明
对象统计报告:
Module Name |
Class Name |
Object Name |
Get# |
Image |
PROJECT1.EXE |
TLS |
TLS.13 |
1 |
|
2.5.2 Coverage(覆盖率测试)
覆盖率测试,共有一个测试方案:Coverage profiler(代码覆盖率分析)
2.5.2.1 Coverage profiler(代码覆盖率分析)
2.5.2.1.1 说明
代码覆盖率分析,测试出代码在运行过程中的执行情况。它提供routine 和 line两种级别,可以帮助查找出程序中的无用代码。
2.5.2.1.2 测试级别
AQTime共有3种测试级别:routine, line 和 class。不同的测试方案中支持的级别不同,routine, line 之在Performance 和 Coverage中支持;class只在Allocation中支持。其他测试方案则不支持测试级别的选择。选择测试方案可以在Areas面板中选择。
Routine -按方法,以方法或函数为单位
Line -按行,以代码行为单位
Class -按类,以类为单位
2.5.2.1.3 测试结果报告
测试报告中有三种类型:方法、模块和源码文件。每种类型按照线程划分报告,每个线程有一个报告结果。
方法统计报告:
Routine Name |
Hit Count |
Total Lines |
Lines Uncovered |
% Covered |
Mark |
TForm1::FormCreate |
1 |
5 |
0 |
100.00 % |
|
Routine Name -方法名称
Hit Count -方法执行时被记录的次数。这个属性不一定完全等于这个方法被运行的次数,如果测试过程中选择了Run-Disable Profiles停止记录的话,Hit Count将不会增加计数,而是增加Skip Count计数,所以,一个方法的完整运行次数应该等于:Hit Count + Skip Count
Total Lines -方法中总的代码行数,如果没有选择Line测试级别的话,将不会有统计结果。(注意代码的行数统计包括方法的Begin End,也就是说一个空的过程的代码行数也会有2行)
Lines Uncovered -方法中未被执行的代码行数
% Covered -代码覆盖率=(Total Lines-Lines Uncovered)/ Total Lines
Mark -该方法在运行期间是否被运行过
模块统计报告:
Module Name |
Hit Count |
% Covered |
Project1.exe |
25209 |
75.00 % |
源码文件统计报告:
File Name |
Hit Count |
% Covered |
Unit1.pas |
2 |
71.43 % |
2.5.3 Performance
性能测试,共有一个测试方案:Performance profiler(代码层或应用程序层的性能检测)
2.5.3.1 Performance profiler(代码层或应用程序层的性能检测)
2.5.3.1.1 说明
提供针对程序中任意范围[sourcefile、routine、class、unit]内的程序段或单行代码进行的性能检测。在程序执行期间,工具自动收集运行时的性能表征数据(如调用次数、执行时间、调用与被调用函数、函数调用层次图、执行期间发生的异常情况等等)。此外,工具提供与运行时间、CPU缓存使用等相关的多种计数器[如Elapsed Time、User Time、User+Kernel Time、CPU Cache Misses、Context Switches等],为了解应用代码级和应用程序级上的性能使用和确定可能存在的性能瓶颈提供详实的参考数据。
2.5.3.1.2 测试结果报告
测试报告中有三种类型:方法、模块和源码文件。每种类型按照线程划分报告,每个线程有一个报告结果。报告上方有四种时间精确度选择:Seconds, MilliSeconds, MicroSeconds, Machine Cycles
方法统计报告:
Routine Name |
Time |
Time with Children |
Shared Time |
Hie Count |
TForm1::FormCreate |
526 |
526 |
100.00 |
20.77 % |
Time -方法执行花费的总时间,不包括方法中调用的子方法所花费的时间。
Time with Children -方法执行花费的总时间,包括子方法所花费的时间
Shared Time - Shared Time = Time / Time with Children
模块统计报告:
Module Name |
Time |
% Time |
Hit Count |
Project1.exe |
2532 |
100.00 % |
3 |
% Time -当前模块在所有被测试的模块中所占用的时间比例
源码文件统计报告:
File Name |
Time |
% Time |
Hit Count |
Unit1.pas |
2022 |
79.86 % |
2 |
% Time -当前单元文件在所有被测试的单元文件中所占用的时间比例
以上三种测试报告中还有很多其他的项目,用户可以自己选择添加。如:Average Time(平均花费时间)、First Time(第一次被调用的时间)、Max Time and Min Time(最长/短一次调用所花费的时间)等等。
2.5.4 Static Analysis
静态分析并标识出待测程序的内部结构,共有三个测试方案:Platform ComplianceAPI(API平台支持测试)、Sequence Diagram Link(UML关系图)、Static Analysis(静态分析)
2.5.4.1 Platform ComplianceAPI(API平台支持测试)
程序中使用的API函数与特定平台的兼容性分析,识别出与操作系统不兼容的函数。
2.5.4.2 Sequence Diagram Link(UML时序图)
自动识别出待测程序中的函数调用关系,自动生成UML格式时序图,并通过word或visio格式显示。便于检测者及时检查程序的行为。
2.5.4.3 Static Analysis(静态分析)
静态分析并标识出待测程序的内部结构[如UML时序图、函数间调用关系、存在的循环语句、判断语句、异常处理]和程序规模[Bytes、lines]。
2.5.5 Tracing
异常跟踪,共有一种测试方案:Exception Tracer(异常跟踪)
2.5.5.1 Exception Tracer(异常跟踪)
监测程序运行期间出现的预知和未知异常,并将异常在源代码中进行定位。当程序出现异常时,Event Log窗口会记录下来,再Event View窗口选中异常查看,在Editor窗口中可以查看到当前异常所在的代码位置。
2.6 如何测试COM
COM组件的测试可分为以下几类:
in-process servers -进程中组件,如:ActiveX controls
out-of-process servers -进程外组件,如:独立进程中运行的OLE servers
DCOM -在独立进程中运行的OLE servers 且支持网络远程过程调用COM+ applications 和 MTS -作为服务程序运行在系统中
2.6.1 in-process servers
1、 根据2.3中介绍的方法为组件加上调试信息,重新编译并注册
2、 在Profiling Mode(工具栏第三个按钮)中选择Normal
3、 打开Run-Parameters,选择HOST APPLICATION(组件的宿主程序),如果有运行参数,在Parameters中加上运行参数
4、 开始测试
2.6.2 out-of-process servers
和普通应用程序一致
2.6.3 DCOM
1、根据2.3中介绍的方法为组件加上调试信息,重新编译并注册
2、在Profiling Mode(工具栏第三个按钮)中选择Com Server
3、打开Run-Parameters,选择HOST APPLICATION(组件的宿主程序),如果有运行参数,在Parameters中加上运行参数
4、开始测试
2.6.4 COM+ applications 和 MTS
1、 根据2.3中介绍的方法为组件加上调试信息,重新编译并注册
2、 在Profiling Mode(工具栏第三个按钮)中选择Normal
3、 打开Run-Parameters,选择C:\Windows\System32\dllhost.exe作为宿主程序,运行参数:/ProcessID:Application ID。如:/ProcessID:{52FC412B-819B-47BF-8E22-65426D5C11B7}
4、 开始测试
5、 点击Run-Get Results手工获取测试报告。这是个特殊的地方,因为使用Terminate结束运行时,AQTime获取不到任何通知,所以无法自动生成报告
2.7 如何测试服务程序
1、 根据2.3中介绍的方法为组件加上调试信息,重新编译并注册成系统服务
2、 在Profiling Mode(工具栏第三个按钮)中选择Services
3、 开始测试,AQTime会重新启动服务,挂接上去以获取测试信息
4、 点击Run-Get Results手工获取测试报告。这是个特殊的地方,因为使用Terminate结束运行时,AQTime获取不到任何通知,所以无法自动生成报告
2.8 如何测试IIS
1、 根据2.3中介绍的方法为组件加上调试信息,重新编译
2、 在Profiling Mode(工具栏第三个按钮)中选择IIS
3、 打开Run-Parameters,输入起始页面的URL
4、 开始测试,AQTime会重新启动IIS,挂接上去以获取测试信息
5、 点击Run-Get Results手工获取测试报告。这是个特殊的地方,因为使用Terminate结束运行时,AQTime获取不到任何通知,所以无法自动生成报告
2.9 其他功能
2.9.1 选择测试区域
在Ereas窗口中默认测试区域为Full Check(测试所有),你可以选择添加Ereas创建自己的测试区域,然后从左边的Moudles窗口中选择需要测试的模块拖过来即可。这样就可以测试指定的模块了。
3 总结
AQTime相对与MemProof来说要庞大复杂多了,需要开发人员有良好的基础,才可以应用自如。笔者平时只是拿AQTime来做效率测试,这个功能实在是太棒了。好了,就此打住~~