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

时间:2010-03-31 20:14:25

标签: 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;

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

3 个答案:

答案 0 :(得分:9)

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

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

答案 1 :(得分:4)

因为Delphi与调试的exe不同,所以不能直接使用exe的内存指针,因此需要对所有内容使用“.Evaluate”。

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

  1. 将特殊的调试转储功能添加到可执行文件中,该功能可以在一次调用中进行所有值检索
  2. 将特殊的dll注入到exe中,与1相同(更多黑客等)
  3. 我有选项1工作,2也应该是可能的但是因为黑客战术而有点复杂和“丑陋”... 使用下面的代码(只需添加到dpr),您可以使用:

    Result := 'Dump=' + Evaluate('TObjectDumper.SpecialDump(' + FExpression + ')');
    

    选项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.
    

    编辑:万一有人感兴趣:我也有选项2工作(bpl注射)

答案 2 :(得分:0)

我还没有机会使用调试可视化工具,所以我不知道这是否有效,但您是否尝试过使用Evaluate()将FExpression转换为实际的内存地址?如果可以这样做,那么将该内存地址类型转换为TDataSet指针并正常使用其属性,而无需通过其他Evaluate()调用。例如:

procedure TDataSetViewerFrame.mFillData; 
var 
  DS: TDataSet;
  I: Integer; 
  //  sw: TStopwatch; 
begin 
  //  sw := TStopwatch.StartNew; 
  DS := TDataSet(StrToInt(Evaluate(FExpression)); // this line may need tweaking
  for I := 0 to DS.Fields.Count - 1 do 
  begin 
    with DS.Fields[I] do begin
      FFields.Add(FieldName);
      FValues.Add(VarToStr(Value));
    end;
  end; 
  {
  sw.Stop; 
  s := sw.Elapsed; 
  Application.MessageBox(Pchar(s), '');
  } 
end;