提高Delphi 2010自身调试可视化工具的速度

net*_*ecz 8 delphi debugging toolsapi

我为TDataSet编写了Delphi调试可视化工具,以显示当前行的值,源代码+截图:http://delphi.netcode.cz/text/tdataset-debug-visualizer.aspx.工作得很好,但很慢.我做了一些优化(如何获得字段名),但仍然只有20个字段需要10秒才能显示 - 非常糟糕.

主要问题似乎是缓慢IOTAThread90.Evaluate使用如下所示的主代码,这个程序花费大部分时间,与**约80%的时间一致.FExpression是代码中TDataset的名称.

procedure TDataSetViewerFrame.mFillData;
var
 iCount: Integer;
 I: Integer;
 //  sw: TStopwatch;
 s: string;
 begin
 //  sw := TStopwatch.StartNew;
   iCount := StrToIntDef(Evaluate(FExpression+'.Fields.Count'), 0);
   for I := 0 to iCount - 1 do
   begin
     s:= s + Format('%s.Fields[%d].FieldName+'',''+', [FExpression, I]);
  //  FFields.Add(Evaluate(Format('%s.Fields[%d].FieldName', [FExpression, I])));
     FValues.Add(Evaluate(Format('%s.Fields[%d].Value', [FExpression, I]))); //**
   end;
 if s<> '' then
   Delete(s, length(s)-4, 5);
 s := Evaluate(s);
 s:= Copy(s, 2, Length(s) -2);
 FFields.CommaText := s;
{  sw.Stop;
 s := sw.Elapsed;
 Application.MessageBox(Pchar(s), '');}
end;
Run Code Online (Sandbox Code Playgroud)

现在我不知道如何提高性能.

Bar*_*lly 9

评估需要做出惊人的工作量.编译器需要编译它,将符号解析为内存地址,而评估属性可能会导致函数被调用,这需要调试器将参数复制到debugee,设置堆栈帧,调用要调用的函数,收集结果 - 这涉及暂停和恢复debugee.

我只能建议尝试将更多工作打包到Evaluate电话中.我不是100%确定调试器和评估器(它是编译器的一部分)之间的交互如何适用于这些可视化工具,但是尽可能多地批量工作可能会有所帮助.尝试Evaluate在循环之后调用之前构建更复杂的表达式.您可能需要使用一些转义或分隔约定来解压缩结果.例如,想象一下构建字段值列表并将其作为逗号分隔字符串返回的表达式看起来像 - 但是您需要在值本身中转义逗号.


And*_*dré 5

由于 Delphi 与调试的 exe 是不同的进程,因此您无法直接使用 exe 的内存指针,因此您需要对所有内容使用“.Evaluate”。

您可以使用两种不同的方法:

  1. 将特殊的调试转储功能添加到可执行文件中,该功能可在一次调用中检索所有值
  2. 将特殊的 dll 注入到 exe 中,其作用与 1 相同(更多黑客攻击等)

我让选项 1 工作,2 也应该是可能的,但由于黑客策略而有点复杂和“丑陋”...使用下面的代码(只需添加到 dpr),您可以使用:

Result := 'Dump=' + Evaluate('TObjectDumper.SpecialDump(' + FExpression + ')');
Run Code Online (Sandbox Code Playgroud)

选项 1 的演示代码,将其更改为您的 TDataset(也许将所有值制作为 CSV 字符串?):

unit Unit1;

interface

type
  TObjectDumper = class
  public
    class function SpecialDump(aObj: TObject): string;
  end;

implementation

class function TObjectDumper.SpecialDump(aObj: TObject): string;
begin
  Result := ''; 
  if aObj <> nil then 
    Result := 'Special dump: ' + aObj.Classname;
end;

initialization
  //dummy call, just to ensure it is linked c.q. used by compiler
  TObjectDumper.SpecialDump(nil);

end.
Run Code Online (Sandbox Code Playgroud)

编辑:如果有人感兴趣:我也有选项 2(bpl 注入)