🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: pl.comp.lang.delphi
13 messages
13 total messages Started by apl Fri, 26 Jun 2020 05:03
callChain
#294610
Author: apl
Date: Fri, 26 Jun 2020 05:03
71 lines
2973 bytes
Drodzy koledzy,
każdy z was wie, jakim koszmarem jest debugowanie programu, zwłaszcza takiego, do którego sięgamy po wielu latach celem przebudowy nie mówiąc już o cudzych kodach źródłowych.
Bardzo pomocna w tym przypadku jest znajomość całego łańcucha wołań prowadzących do danego podprogramu.
W tym poście chciałbym podzielić się bardzo prostym wynalazkiem i poddać go waszej krytycznej ocenie. 
Przypuśćmy, że śledzonym podprogramem jest procedure sub2.
Mój "chwyt" polega na dodaniu parametru formalnego callChain:string przekazywanego przez wartość oraz na zamieszczeniu na początku treści wykonawczej instrukcji callChain:=callChain+'>sub2'; Zabieg ten należy powtórzyć w każdym podprogramie wołającym wybrany śledzony (tu: sub2) z tym, że zamiast sub2 wpisujemy nazwę podprogramu wołającego z dodatkiem znaku '>' rozdzielającego nazwy w tworzonym łańcuchu. Krytyczne fragmenty treści sub2 obejmujemy instrukcją try except end, gdzie zamieszczamy showMessage informujący o błędzie. W przypadku iteracji, czy rekurencji przydatne będzie proliferowanie wartości zmiennych sterujących - dodajemy wtedy wymagane parametry formalne przekazywane przez wartość. Poniżej zamieszczam maksymalnie uproszczony przykład ilustrujący tę ideę zawierający iterację i rekurencję, stąd parametry i,n:word.
Tak wzbogacony program daje nieoceniony wgląd w bieżący stan wykonania programu odczytując aktualną wartość callChain. Program niejako buduje się sam, żądając brakujących parametrów formalnych podczas kompilacji.
Tym postem chciałbym zapoczątkować wakacyjną akcję dzielenia się na tym forum swoimi chwytami warsztatowymi. Gorąco zachęcam!!!
Pozdrawiam, apl

P.S. Błagam, powiedzcie PADowi NIE!!!


 procedure sub2(callChain:string;i,n:word);
  var   r:real;
 begin
  callChain:=callChain+'>sub2';
  r:=0;
  try      //enclosure of a critical fragment
   r:=r/r;
  except
    showMessage('Error occured in a call chain "'+callChain+'". Iteration step='+intToStr(i)+'. Recursion step='+intToStr(n))
  end;
 end;{sub2}

 procedure sub1(callChain:string;i,n:word);
 begin
  callChain:=callChain+'>sub1';
  sub2(callChain,i,n);
 end;{sub1}

procedure sub0(callChain:string;n:word);
 var   i:shortInt;
 begin
  callChain:=callChain+'>sub0';
  for i:=0 to 5 do sub1(callChain,i,n);
  if n<3 then sub0(callChain,n+1);  //recursion
 end;{sub0}
end.

Wołanie z poziomu formatki, to np.:


procedure TForm1.Button1Click(Sender: TObject);
begin
 sub0('>TForm1.Button1Click',0);
end;
Re: callChain
#294613
Author: apl
Date: Fri, 26 Jun 2020 06:20
10 lines
598 bytes
Wyobraź sobie kolego, że postać exe liczy ci cóś przez 10 godzin i pada. Gdzie twój call stack???
Albo pada u klienta - gdzie twój call stack? Tu możesz dowolnie opisać potencjalnie zaistniałą sytuację i dostać perfekcyjny komunikat.
Poza tym call stack, jak się można łatwo przekonać daje, delikatnie mówiąc, zagmatwany obraz (D2005). Po co się z tym męczyć, skoro tak łatwo można wprowadzić własne, adekwatne śledzenie i komunikaty?

Pozdrawiam, apl
Re: callChain
#294614
Author: apl
Date: Fri, 26 Jun 2020 06:22
8 lines
366 bytes
W dniu piątek, 26 czerwca 2020 14:11:41 UTC+2 użytkownik Jan Drawski napisał:
> > P.S. Błagam, powiedzcie PADowi NIE!!!
> 
> Miałem na niego nie głosować ale że tu wrzucasz politykę to zagłosuję na 
> niego. Ten twój wpis o tym ostatecznie zadecydował.

Życzę powodzenia, pozdrawiam.
Re: callChain
#294617
Author: apl
Date: Fri, 26 Jun 2020 12:18
98 lines
2639 bytes
> 
> Program, który wkleiłeś nie zadziała jak opisałeś, sprawdź.
> 
> -- 
> pozdrawiam
> Roman Tyczka

Dziekuję za zainteresowanie moim pomysłem.
Być może Twoje oczekiwania są inne, a być może patrzę i czegoś nie widzę (tę wersję upraszczałem korzystając z Notatnika)

Na wszelki wypadek wklejam jednak wersję skopiowaną wprost z edytora Delphi. Jest ona minimalnie bogatsza, a mianowicie w proc. sub0 jest instrukcja
 if n=0 then callChain:=callChain+'>sub0';
zamiast poprzedniej
 callChain:=callChain+'>sub0';
Warunek if n=0 zapobiega powtarzaniu się nazwy '>sub0' w wołaniach rekurencyjnych aby skrócić łańcuch odnotowujący te wołania w sytuacji, gdy mamy licznik takich wołań. Zamieszczam tu pełne treści obu modułów składających się na program testowy.
W efekcie np. wykonania 1. kroku otrzymasz komunikat:

Error occured in call chain ">TForm1.Button1Click>sub0>sub1>sub2". Iteration step=0. Recursion step=0

czyli informację, że błąd powstał w procedurze sub2 wołanej z procedury sub1, która była wołana z procedury sub0, a ta z kolei ze zdarzenia OnClick  przycisku button1. 

Pozdrawiam,
apl

unit Unit1;

interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
uses unit2;
procedure TForm1.Button1Click(Sender: TObject);
begin
 sub0('>TForm1.Button1Click',0);
end;

end.


unit Unit2;

interface
 procedure sub0(callChain:string;n:word);
implementation
 uses dialogs,SysUtils;

 procedure sub2(callChain:string;i,n:word);
  var   r:real;
 begin
  callChain:=callChain+'>sub2';
  r:=0;
   try      //enclosure of a critical fragment
   r:=r/r;
   except
    showMessage('Error occured in call chain "'+callChain+'". Iteration step='+intToStr(i)+'. Recursion step='+intToStr(n))
   end;
 end;{sub2}

 procedure sub1(callChain:string;i,n:word);
 begin
  callChain:=callChain+'>sub1';
  sub2(callChain,i,n);
 end;{sub1}

procedure sub0(callChain:string;n:word);
 var   i:shortInt;
 begin
  if n=0 then callChain:=callChain+'>sub0';
  for i:=0 to 5 do sub1(callChain,i,n);
  if n<3 then sub0(callChain,n+1);  //recursion
 end;{sub0}
end.
Re: callChain
#294618
Author: apl
Date: Fri, 26 Jun 2020 12:20
74 lines
3172 bytes
W dniu piątek, 26 czerwca 2020 14:03:13 UTC+2 użytkownik apl napisał:
> Drodzy koledzy,
> każdy z was wie, jakim koszmarem jest debugowanie programu, zwłaszcza takiego, do którego sięgamy po wielu latach celem przebudowy nie mówiąc już o cudzych kodach źródłowych.
> Bardzo pomocna w tym przypadku jest znajomość całego łańcucha wołań prowadzących do danego podprogramu.
> W tym poście chciałbym podzielić się bardzo prostym wynalazkiem i poddać go waszej krytycznej ocenie. 
> Przypuśćmy, że śledzonym podprogramem jest procedure sub2.
> Mój "chwyt" polega na dodaniu parametru formalnego callChain:string przekazywanego przez wartość oraz na zamieszczeniu na początku treści wykonawczej instrukcji callChain:=callChain+'>sub2'; Zabieg ten należy powtórzyć w każdym podprogramie wołającym wybrany śledzony (tu: sub2) z tym, że zamiast sub2 wpisujemy nazwę podprogramu wołającego z dodatkiem znaku '>' rozdzielającego nazwy w tworzonym łańcuchu. Krytyczne fragmenty treści sub2 obejmujemy instrukcją try except end, gdzie zamieszczamy showMessage informujący o błędzie. W przypadku iteracji, czy rekurencji przydatne będzie proliferowanie wartości zmiennych sterujących - dodajemy wtedy wymagane parametry formalne przekazywane przez wartość. Poniżej zamieszczam maksymalnie uproszczony przykład ilustrujący tę ideę zawierający iterację i rekurencję, stąd parametry i,n:word.
> Tak wzbogacony program daje nieoceniony wgląd w bieżący stan wykonania programu odczytując aktualną wartość callChain. Program niejako buduje się sam, żądając brakujących parametrów formalnych podczas kompilacji.
> Tym postem chciałbym zapoczątkować wakacyjną akcję dzielenia się na tym forum swoimi chwytami warsztatowymi. Gorąco zachęcam!!!
> Pozdrawiam, apl
> 
> P.S. Błagam, powiedzcie PADowi NIE!!!
> 
> 
>  procedure sub2(callChain:string;i,n:word);
>   var   r:real;
>  begin
>   callChain:=callChain+'>sub2';
>   r:=0;
>   try      //enclosure of a critical fragment
>    r:=r/r;
>   except
>     showMessage('Error occured in a call chain "'+callChain+'". Iteration step='+intToStr(i)+'. Recursion step='+intToStr(n))
>   end;
>  end;{sub2}
> 
>  procedure sub1(callChain:string;i,n:word);
>  begin
>   callChain:=callChain+'>sub1';
>   sub2(callChain,i,n);
>  end;{sub1}
> 
> procedure sub0(callChain:string;n:word);
>  var   i:shortInt;
>  begin
>   callChain:=callChain+'>sub0';
>   for i:=0 to 5 do sub1(callChain,i,n);
>   if n<3 then sub0(callChain,n+1);  //recursion
>  end;{sub0}
> end.
> 
> Wołanie z poziomu formatki, to np.:
> 
> 
> procedure TForm1.Button1Click(Sender: TObject);
> begin
>  sub0('>TForm1.Button1Click',0);
> end;
Re: callChain
#294611
Author: Jan Drawski
Date: Fri, 26 Jun 2020 14:11
3 lines
166 bytes
> P.S. B³agam, powiedzcie PADowi NIE!!!

Mia³em na niego nie g³osowaæ ale ¿e tu wrzucasz politykê to zag³osujê na
niego. Ten twój wpis o tym ostatecznie zadecydowa³.
Re: callChain
#294612
Author: Tomek D
Date: Fri, 26 Jun 2020 14:18
17 lines
1989 bytes
W dniu 26.06.2020 o 14:03, apl pisze:
>
> Drodzy koledzy,
> każdy z was wie, jakim koszmarem jest debugowanie programu, zwłaszcza takiego, do którego sięgamy po wielu latach celem przebudowy nie mówiąc już o cudzych kodach źródłowych.
> Bardzo pomocna w tym przypadku jest znajomość całego łańcucha wołań prowadzących do danego podprogramu.
> W tym poście chciałbym podzielić się bardzo prostym wynalazkiem i poddać go waszej krytycznej ocenie.
> Przypuśćmy, że śledzonym podprogramem jest procedure sub2.
> Mój "chwyt" polega na dodaniu parametru formalnego callChain:string przekazywanego przez wartość oraz na zamieszczeniu na początku treści wykonawczej instrukcji callChain:ÊllChain+'>sub2'; Zabieg ten należy powtórzyć w każdym podprogramie wołającym wybrany śledzony (tu: sub2) z tym, że zamiast sub2 wpisujemy nazwę podprogramu wołającego z dodatkiem znaku '>' rozdzielającego nazwy w tworzonym łańcuchu. Krytyczne fragmenty treści sub2 obejmujemy instrukcją try except end, gdzie zamieszczamy showMessage informujący o błędzie. W przypadku iteracji, czy rekurencji przydatne będzie proliferowanie wartości zmiennych sterujących - dodajemy wtedy wymagane parametry formalne przekazywane przez wartość. Poniżej zamieszczam maksymalnie uproszczony przykład ilustrujący tę ideę zawierający iterację i rekurencję, stąd parametry i,n:word.
> Tak wzbogacony program daje nieoceniony wgląd w bieżący stan wykonania programu odczytując aktualną wartość callChain. Program niejako buduje się sam, żądając brakujących parametrów formalnych podczas kompilacji.

Może nie rozumiem problemu autora wątku, ale w środowisku Delphi podczas
debugowania jest dostępne okno "Call stack", które pokazuje ścieżkę
wywołań. I nie wymaga modyfikacji kodu źródłowego.

Ponadto mamy zewnętrzne narzędzia takie jak madExcept, EurekaLog,
CodeSite, które wydatnie ułatwiają lokalizację błędów.

Tomek D.
Re: callChain
#294615
Author: Tomek D
Date: Fri, 26 Jun 2020 15:49
11 lines
679 bytes
W dniu 26.06.2020 o 15:20, apl pisze:
> Wyobraź sobie kolego, że postać exe liczy ci cóś przez 10 godzin i pada. Gdzie twój call stack???
> Albo pada u klienta - gdzie twój call stack? Tu możesz dowolnie opisać potencjalnie zaistniałą sytuację i dostać perfekcyjny komunikat.
> Poza tym call stack, jak się można łatwo przekonać daje, delikatnie mówiąc, zagmatwany obraz (D2005). Po co się z tym męczyć, skoro tak łatwo można wprowadzić własne, adekwatne śledzenie i komunikaty?
>
> Pozdrawiam, apl
>
Proszę zapoznaj się z madExcept, EurekaLog - one dają Ci Call Stack dla
działającej aplikacji i wiele więcej. Po co się męczyć.

Tomek D.
Re: callChain
#294616
Author: Roman Tyczka
Date: Fri, 26 Jun 2020 17:27
54 lines
2797 bytes
On Fri, 26 Jun 2020 05:03:12 -0700 (PDT), apl wrote:

> Drodzy koledzy,
> każdy z was wie, jakim koszmarem jest debugowanie programu, zwłaszcza takiego, do którego sięgamy po wielu latach celem przebudowy nie mówiąc już o cudzych kodach źródłowych.
> Bardzo pomocna w tym przypadku jest znajomość całego łańcucha wołań prowadzących do danego podprogramu.
> W tym poście chciałbym podzielić się bardzo prostym wynalazkiem i poddać go waszej krytycznej ocenie.
> Przypuśćmy, że śledzonym podprogramem jest procedure sub2.
> Mój "chwyt" polega na dodaniu parametru formalnego callChain:string przekazywanego przez wartość oraz na zamieszczeniu na początku treści wykonawczej instrukcji callChain:ÊllChain+'>sub2'; Zabieg ten należy powtórzyć w każdym podprogramie wołającym wybrany śledzony (tu: sub2) z tym, że zamiast sub2 wpisujemy nazwę podprogramu wołającego z dodatkiem znaku '>' rozdzielającego nazwy w tworzonym łańcuchu. Krytyczne fragmenty treści sub2 obejmujemy instrukcją try except end, gdzie zamieszczamy showMessage informujący o błędzie. W przypadku iteracji, czy rekurencji przydatne będzie proliferowanie wartości zmiennych sterujących - dodajemy wtedy wymagane parametry formalne przekazywane przez wartość. Poniżej zamieszczam maksymalnie uproszczony przykład ilustrujący tę ideę zawierający iterację i rekurencję, stąd parametry i,n:word.
> Tak wzbogacony program daje nieoceniony wgląd w bieżący stan wykonania programu odczytując aktualną wartość callChain. Program niejako buduje się sam, żądając brakujących parametrów formalnych podczas kompilacji.
> Tym postem chciałbym zapoczątkować wakacyjną akcję dzielenia się na tym forum swoimi chwytami warsztatowymi. Gorąco zachęcam!!!
> Pozdrawiam, apl
>
> P.S. Błagam, powiedzcie PADowi NIE!!!
>
>
>  procedure sub2(callChain:string;i,n:word);
>   var   r:real;
>  begin
>   callChain:ÊllChain+'>sub2';
>   r:=0;
>   try      //enclosure of a critical fragment
>    r:=r/r;
>   except
>     showMessage('Error occured in a call chain "'+callChain+'". Iteration step='+intToStr(i)+'. Recursion step='+intToStr(n))
>   end;
>  end;{sub2}
>
>  procedure sub1(callChain:string;i,n:word);
>  begin
>   callChain:ÊllChain+'>sub1';
>   sub2(callChain,i,n);
>  end;{sub1}
>
> procedure sub0(callChain:string;n:word);
>  var   i:shortInt;
>  begin
>   callChain:ÊllChain+'>sub0';
>   for i:=0 to 5 do sub1(callChain,i,n);
>   if n<3 then sub0(callChain,n+1);  //recursion
>  end;{sub0}
> end.
>
> Wołanie z poziomu formatki, to np.:
>
>
> procedure TForm1.Button1Click(Sender: TObject);
> begin
>  sub0('>TForm1.Button1Click',0);
> end;

Program, który wkleiłeś nie zadziała jak opisałeś, sprawdź.

--
pozdrawiam
Roman Tyczka
Re: callChain
#294619
Author: zpksoft
Date: Sat, 27 Jun 2020 00:33
13 lines
578 bytes
W dniu piątek, 26 czerwca 2020 21:18:31 UTC+2 użytkownik apl napisał:
>...
> czyli informację, że błąd powstał w procedurze sub2 wołanej z procedury sub1, która była wołana z procedury sub0, a ta z kolei ze zdarzenia OnClick  przycisku button1. 
>...

Błąd (logiczny) mógł powstać dużo wcześniej tylko (maszynowy) objawił się dopiero tutaj. Nie wskazuje Ci to więc miejsca wystąpienia błędu tylko miejsce wykrzaczenia programu.

Paweł
Re: callChain
#294620
Author: apl
Date: Sat, 27 Jun 2020 02:29
19 lines
978 bytes
> 
> Błąd (logiczny) mógł powstać dużo wcześniej tylko (maszynowy) objawił się dopiero tutaj. Nie wskazuje Ci to więc miejsca wystąpienia błędu tylko miejsce wykrzaczenia programu.
> 
> Paweł

Tak, to powszechnie znana prawda, ale od czegoś konkretnego trzeba zacząć. Pewnym mankamentem metody jest to, że trzeba wpisywać nazwę podprogramu zamiast odwoływać się do pewnej zmiennej, której wartość taką nazwę zawiera (W VB np., zmienne są jakoś tam numerowane, ale nie zgłębiałem tego tematu). Niestety, popularna dokumentacja nie zawiera takiej informacji, ale być może ktoś z kolegów posiada taką informację i podzieli się nią na forum. Wiedza taka może znaleźć rozliczne zastosowania w konstrukcji programów.
Pozdrawiam,
apl
Re: callChain
#294621
Author: zpksoft
Date: Sat, 27 Jun 2020 02:45
26 lines
1280 bytes
W dniu sobota, 27 czerwca 2020 11:29:52 UTC+2 użytkownik apl napisał:
> > 
> > Błąd (logiczny) mógł powstać dużo wcześniej tylko (maszynowy) objawił się dopiero tutaj. Nie wskazuje Ci to więc miejsca wystąpienia błędu tylko miejsce wykrzaczenia programu.
> > 
> > Paweł
> 
> Tak, to powszechnie znana prawda, ale od czegoś konkretnego trzeba zacząć. Pewnym mankamentem metody jest to, że trzeba wpisywać nazwę podprogramu zamiast odwoływać się do pewnej zmiennej, której wartość taką nazwę zawiera (W VB np., zmienne są jakoś tam numerowane, ale nie zgłębiałem tego tematu). Niestety, popularna dokumentacja nie zawiera takiej informacji, ale być może ktoś z kolegów posiada taką informację i podzieli się nią na forum. Wiedza taka może znaleźć rozliczne zastosowania w konstrukcji programów.
> Pozdrawiam,
> apl

Jak dla mnie to mankamentem jest ingerencja w kod, szpikowanie procedur tymi informacjami. Ale jak kto lubi :)
Ja wolę postawić breakpoint i przeanalizować wartości zmiennych.
Re: callChain
#294622
Author: apl
Date: Sun, 28 Jun 2020 02:24
11 lines
279 bytes
Dzięki kolego za ten tip, zapoznam się z tymi programami

apl

>  
> Proszę zapoznaj się z madExcept, EurekaLog - one dają Ci Call Stack dla 
> działającej aplikacji i wiele więcej. Po co się męczyć.
> 
> Tomek D.
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads