[教程]QProfile教程之一:基于 Delphi 的性能和函数路径分析引擎基础

【注】QProfile 为 QDAC 4.0 引入的独立单元,所以你可以在项目中直接引用该单元而不会引入其它问题。

QProfile 是一个基于 Delphi 的代码性能跟踪引擎,可以帮助您找到程序中那一部分代码的执行效率。同时,它还会记录您程序中函数调用顺序、调用及递归次数、依赖关系等信息,从而生成函数调用路径分析报告。

当然,做为实现上述功能,QProfile 并非毫无代价,但它的开销很小,您几乎可以放心的在正式运行的代码中启用本功能。

  • 占用内存极小,每个线程才会占用一个 IQProfileHelper 接口实现,TQProfile.Calc 会为每个序列重复访问共享第一次创建的实例。
  • 同一调用序列,仅在第一次访问时,才会分配内存,后续访问都是直接重用,而不会重新分配,省却重复分配内存时间。
  • 尽可能简化处理逻辑,降低函数跟踪分析需要的代码量。
  • 在需要完整性能时,程序中可以通过代码来随时禁用跟踪记录功能。

产品用途

  • 基于函数的调用次数、执行时间、调用序列等信息,分析代码性能瓶径,找到慢代码,从而进行针对性优化,从而提升产品运行效率。
  • 通过分析函数间调用关系,与业务流程进行比对,从而找出问题代码。
  • 通过执行函数路径分析,辅助开发人员对函数中无效的路径进行剔除,提升代码质量。
  • 并发冲突分析,辅助开发人员在多线程开发中,找到并发函数,以便进行必要的加锁处理,避免并发冲突。

已知问题

  • TQProfile 没有编写 IDE 插件来集成到 IDE,暂时不支持自动化为您的代码添加 TQProfile.Calc(函数名) 的代码,需要您自行在需要测试性能的地方调用 TQProfile.Calc 函数。
  • TQProfile 为每个线程维护跟踪信息,不同线程的跟踪信息并不会自动合并(当然,您可以对其进行后期处理)。
  • TQProfile 不会因为线程被释放,而自动释放该线程对应的跟踪记录,换句话说,如果您的程序在不断的创建/释放线程,而在对应的线程中存在跟踪代码,则会随着每次线程的创建和释放,生成一份除了线程ID不一样,其它内容重复的拷贝。
  • TQProfile 在启用状态下,会自动在程序退出时保存跟踪数据到 TQProfile.FileName 属性指定的 json 格式文件中。

基础用法

  1. 在您项目的搜索路径路径中加入 qdac.profile.pas 单元所在的目录。
  2. 在您的代码的 uses 指令中,加入 qdac.profile 。
  3. 为您需要跟踪的函数的开始计时位置,添加 TQProfile.Calc 调用代码。
  4. 确认 TQProfile.Enabled 为 true 以启用跟踪:
    • 调试模式,默认该值为 true
    • 命令行参数加入 /EnableProfile 可以强制设置该值为 true
    • 用户自己通过设置 TQProfile.Enabled := true 来启用跟踪。
  5. 编译运行程序,并执行必要的操作。
  6. 退出程序
  7. 查看性能和跟踪分析记录文件(默认为程序执行目录下的 profiles.json)

基础示例

...
implementation

uses qdac.profile;
//以上两行,后续示例省略

procedure test();
   procedure f1();
   begin
     TQProfile.Calc('test.f1');
     ...
   end;
begin
  TQProfile.Calc('f1');
  f1();
end;

输出结果

下面的结果是自带的示例程序的输出结果,具体格式解析,我们在后面进行详细说明。

[
  {
    "threadId":8740,
    "freq":10000000,
    "mainThread":true,
    "chains":[
      {
        "name":"TForm1.Button1Click",
        "maxNestLevel":0,
        "runs":1,
        "minTime":0,
        "maxTime":782,
        "totalTime":782,
        "avgTime":782,
        "children":[
          {
            "name":"TForm1.DoProfile",
            "maxNestLevel":32,
            "runs":1,
            "minTime":0,
            "maxTime":578,
            "totalTime":578,
            "avgTime":578
          }
        ]
      },
      {
        "name":"TForm1.Button1Click.ForceQueue#1",
        "maxNestLevel":0,
        "runs":1,
        "minTime":0,
        "maxTime":19876018,
        "totalTime":19876018,
        "avgTime":19876018,
        "refs":[
          "TForm1.Button1Click"
        ]
      },
      {
        "name":"TForm1.Button3Click",
        "maxNestLevel":0,
        "runs":1,
        "minTime":0,
        "maxTime":856,
        "totalTime":856,
        "avgTime":856
      }
    ]
  },
  {
    "threadId":7648,
    "chains":[
      {
        "name":"TForm1.DoProfile",
        "maxNestLevel":32,
        "runs":1,
        "minTime":0,
        "maxTime":590,
        "totalTime":590,
        "avgTime":590
      }
    ]
  }
]

滚动至顶部