2010-03-31 2 views
8

J'ai écrit visualiseur de débogage Delphi pour TDataSet pour afficher les valeurs de la ligne actuelle, source + capture d'écran: http://delphi.netcode.cz/text/tdataset-debug-visualizer.aspx. Bon travail, mais très lent. J'ai fait quelques optimisations (comment obtenir des noms de champs) mais toujours pour seulement 20 champs prend 10 secondes à montrer - très mauvais.Améliorer la vitesse de propre visualiseur de débogage pour Delphi 2010

Le problème principal semble être lent IOTAThread90.Evaluate utilisé par le code principal montré ci-dessous, cette procédure coûte la plupart du temps, ligne avec ** environ 80% de temps. FExpression est le nom de TDataset dans le code.

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; 

Maintenant, je ne sais pas comment améliorer les performances.

+0

Je ne suis pas familier avec ces composants de données, donc je ne sais pas comment améliorer de manière significative les performances.Cependant, votre copie pourrait être remplacée par une suppression, ce qui est probablement plus rapide. Et peut-être s <> '' pourrait être remplacé par longueur (s) = 0. S'il y a un gain de performance dans ce domaine, je ne sais pas. En général, cependant, je crois que la comparaison de chaînes utilisant = et <> est plus lente que les routines intelligentes SameText (s1, s2) et SameStr (s1, s2). –

+0

@Andreas - ces micro-optimisations ne pouvaient pas contribuer beaucoup à un retard de 10 ** seconde ** –

+0

@Barry Kelly: Je sais. C'est pourquoi j'ai écrit "Je ne sais pas comment améliorer significativement les performances". –

Répondre

9

Cette évaluation doit faire une quantité surprenante de travail. Le compilateur doit le compiler, en résolvant les symboles en adresses mémoire, tandis que l'évaluation des propriétés peut provoquer l'appel de fonctions, ce qui nécessite que le débogueur copie les arguments dans le débugee, mette en place une pile, appelle la fonction à appeler, collecte les résultats - et cela implique de faire une pause et de reprendre le debugee.

Je ne peux que suggérer d'essayer de faire plus de travail dans l'appel Evaluate. Je ne suis pas sûr à 100% de la façon dont l'interaction entre le débogueur et l'évaluateur (qui fait partie du compilateur) fonctionne pour ces visualiseurs, mais il peut être utile de grouper autant de tâches que possible. Essayez de créer une expression plus compliquée avant d'appeler Evaluate après la boucle. Vous devrez peut-être utiliser une convention d'échappement ou de délimitation pour décompresser les résultats. Par exemple, imaginez ce qu'une expression qui construit la liste des valeurs de champ et les renvoie comme une chaîne séparée par des virgules ressemblerait - mais vous auriez besoin d'échapper des virgules dans les valeurs elles-mêmes.

+0

Ok, comme test rapide j'ai construit la liste des valeurs de champs (sans échappement) et le temps total est maintenant d'environ 7s (sans échappement), mais remplacé "s.Fields [% d] .Value" à "% s.Fields [% d ] .AsString " Je sais que dans l'évaluateur peut être exécuté une seule procédure, mais puis-je déclarer une variable ou exécuter une instruction de séquence? quelque chose comme var l: TStringList; ds.GetFieldsNames (l); Résultat: = l.CommaText; l.free; – netcodecz

+0

Idée aléatoire - pourrait-on simplement définir une fonction "debugDump" spéciale pour n'importe quelle classe, et avoir juste * un * visualiseur de remplacement de texte qui essaie de l'invoquer sur n'importe quel objet? Cela supprimerait le besoin d'écrire des visualiseurs dans de nombreux cas (sinon la plupart). – Roddy

0

Je n'ai pas encore eu l'occasion de jouer avec les visualiseurs de débogage, donc je ne sais pas si cela fonctionne, mais avez-vous essayé d'utiliser Evaluate() pour convertir FExpression en adresse mémoire? Si vous pouvez le faire, transtypez cette adresse de mémoire en un pointeur TDataSet et utilisez ses propriétés normalement sans passer par des appels Evaluate() supplémentaires. Par exemple:

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

bonne idée, mais il y a un problème: Evaluer ('@' + FExpression) return 0, Evaluer (Format ('Addr (% s)', [FExpression])) retourner une adresse différente de Addr (dataset) ou @dataset dans liste de surveillance dans l'EDI -> AV – netcodecz

+0

Par exemple à partir de visualiseur retour $ 23F288 de l'IDE dans le même moment retour @ ds1 = $ AC46AC. Code: iAddr: = StrToInt (Evaluer (Format ('Addr (% s)', [FExpression]))); Application.MessageBox (Pchar (IntToStr (i)), ''); // débogage DS: = TDataSet (iAddr); – netcodecz

+1

L'adresse de l'objet TDataSet réel pointé est différente de l'adresse de prise de l'adresse du pointeur TDataSet lui-même. IOW: ds1 <> @ ds1. Quand j'ai l'occasion, je vais jouer avec les visualiseurs et voir ce que l'on peut faire avec eux. –

4

Parce que Delphi est un processus différent de votre débogué exe, vous ne pouvez pas utiliser directement les pointeurs de mémoire de votre exe, de sorte que vous devez utiliser pour tout « .Evaluate ».

Vous pouvez utiliser 2 approches différentes:

  1. Ajouter la fonction spéciale de vidage de débogage dans l'exécutable, qui fait tout récupération de valeur dans un appel
  2. Injecter dll spéciale en exe avec le même effet que 1 (plus hacking etc)

Je suis l'option 1 travail, 2 devrait également être possible, mais un peu plus compliqué et « laid » à cause de tactiques de piratage ... Avec le code ci-dessous (il suffit d'ajouter à DPR), vous pouvez utiliser:

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

Code de démonstration de l'option 1, changer pour votre TDataset (peut-être faire chaîne CSV de toutes les valeurs?):

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: au cas où quelqu'un est intéressé: Je suis l'option 2 travailler trop (bpl injection)

Questions connexes