Повышение скорости собственного визуализатора отладки для Delphi 2010 - PullRequest
8 голосов
/ 01 апреля 2010

Я написал визуализатор отладки Delphi для TDataSet для отображения значений текущей строки, источника + снимок экрана: 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;

Теперь я понятия не имею, как улучшить производительность.

Ответы [ 3 ]

9 голосов
/ 01 апреля 2010

Для оценки необходимо выполнить удивительный объем работы. Компилятор должен скомпилировать его, разрешив символы по адресам памяти, в то время как оценка свойств может вызвать вызов функций, что требует отладчика для копирования аргументов в отладчик, установки стекового фрейма, вызова вызываемой функции, сбора результаты - и это включает в себя приостановку и возобновление работы беженца.

Я могу только предложить попробовать упаковать больше работы в вызов Evaluate. Я не уверен на 100%, как взаимодействие между отладчиком и оценщиком (который является частью компилятора) работает для этих визуализаторов, но может помочь объединение как можно большего количества работы. Попробуйте создать более сложное выражение перед вызовом Evaluate после цикла. Возможно, вам понадобится использовать соглашение об экранировании или разделении, чтобы распаковать результаты. Например, представьте, как будет выглядеть выражение, которое строит список значений полей и возвращает их в виде строки, разделенной запятыми, - но вам нужно будет экранировать запятые в самих значениях.

4 голосов
/ 17 августа 2010

Поскольку Delphi - это процесс, отличный от отлаженного exe-файла, вы не можете напрямую использовать указатели памяти вашего exe-файла, поэтому вам нужно использовать «.Evaluate» для всего.

Вы можете использовать 2 разных подхода:

  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)

0 голосов
/ 02 апреля 2010

У меня еще не было возможности поиграть с визуализаторами отладки, поэтому я не знаю, работает ли это, но пытались ли вы использовать 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; 
...