9

現在の行、ソース+スクリーンショットの値を表示するためにTDataSet用のDelphiデバッグビジュアライザーを作成しました:http://delphi.netcode.cz/text/tdataset-debug-visualizer.aspx。うまく機能していますが、非常に遅いです。私はいくつかの最適化(フィールド名を取得する方法)を行いましたが、それでも20フィールドだけが表示されるのに10秒かかります-非常に悪いです。

主な問題は遅いIOTAThread90のようです。以下に示すメインコードで使用される評価。この手順はほとんどの時間コストがかかり、**約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;

今、私はパフォーマンスを改善する方法がわかりません。

4

3 に答える 3

9

その評価は驚くべき量の仕事をする必要があります。コンパイラはそれをコンパイルし、シンボルをメモリアドレスに解決する必要がありますが、プロパティを評価すると関数が呼び出される可能性があります。これには、デバッガが引数をデバッグ対象にコピーし、スタックフレームを設定し、呼び出される関数を呼び出し、収集する必要があります。結果-これには、デバッガーの一時停止と再開が含まれます。

Evaluate私は、より多くの仕事を電話に詰め込もうとすることを提案することしかできません。デバッガーとエバリュエーター(コンパイラーの一部)の間の相互作用がこれらのビジュアライザーでどのように機能するかは100%わかりませんが、可能な限り多くの作業をバッチ処理すると役立つ場合があります。Evaluateループの後で呼び出す前に、より複雑な式を作成してみてください。結果を解凍するには、エスケープまたは区切りの規則を使用する必要がある場合があります。たとえば、フィールド値のリストを作成し、それらをコンマ区切りの文字列として返す式がどのようになるか想像してみてください。ただし、値自体でコンマをエスケープする必要があります。

于 2010-03-31T20:43:38.953 に答える
5

Delphi はデバッグされた exe とは異なるプロセスであるため、exe のメモリ ポインタを直接使用することはできません。そのため、すべてに「.Evaluate」を使用する必要があります。

2 つの異なるアプローチを使用できます。

  1. 1 回の呼び出しですべての値を取得する特別なデバッグ ダンプ関数を実行可能ファイルに追加します。
  2. 特別な dll を exe に挿入すると、1 と同じように実行されます (さらにハッキングなど)。

オプション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インジェクション)

于 2010-08-17T09:53:20.250 に答える
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; 
于 2010-04-01T20:10:10.643 に答える