Улучшите скорость собственной отладки visualizer для Delphi 2010

Я записал, что Delphi отлаживает visualizer для TDataSet для отображения значений текущей строки, источник + снимок экрана: http://delphi.netcode.cz/text/tdataset-debug-visualizer.aspx. Работа хорошего, но очень медленного. Я сделал некоторый optimalization (как получить имена полей), но все еще только для 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;

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

8
задан Barry Kelly 31 March 2010 в 20:32
поделиться

3 ответа

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

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

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

9
ответ дан 5 December 2019 в 12:57
поделиться

Поскольку 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.

Edit: in case someone interest: I got option 2 working too (bpl injection)

4
ответ дан 5 December 2019 в 12:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: