Profiler – narzędzie dewelopera cz. III

Coraz więcej programistów korzysta z narzędzia Developer Studio, pora więc pokazać jak korzystać w nim z Profilera (dostępnego od wersji OE 11.6), omawianego w dwóch poprzednich artykułach.
Środowisko tego narzędzia nadaje się o wiele bardziej do wyświetlania złożonych informacji w kilku okienkach niż tradycyjny edytor.
Spróbujmy najpierw otworzyć wygenerowany wcześniej w profilerze plik typu .out. Najwygodniej będzie zmienić to rozszerzenie na natywne dla profilera czyli .prof.
Importuję do nowego projektu OpenEdge plik .prof oraz dwa pliki procedur.

Dwukrotne kliknięcie na plik .prof otwiera widok Profilera.

Opis kolumn jest analogiczny jak opisany w poprzednim artykule, więc nie będę się powtarzać. Nas interesuje teraz jak generować plik .prof z poziomu Developer Studio po dokonaniu pewnych zmian w programie (np. chcę aby procedura orderval.p wykonała się dla wszystkich iteracji).
Pierwszym krokiem jest dodanie katalogu profiler do ścieżki PROPATH dla projektu.
Następnie, wybieramy z menu Run -> Run Configurations. Dodajemy nową konfigurację (np. o nazwie Profiler), wstawiamy nazwę procedury CustReport.p…

… a w zakładce Profiler zaznaczamy pole Enable profiling.

Klikamy przycisk Run i czekamy aż program zakończy działanie, po czym otwiera się okno Viewera z nowymi statystykami.

Na razie kończę omawaiać to narzędzie. Niektórzy z Was chcieliby dowiedzieć się więcej o możliwości instalacji i wykorzystania OECC i temu poświęcę następne artykuły.

Profiler – narzędzie dewelopera cz. II

Dziś kontynuujemy wykorzystanie narzędzia Profiler Control do przetestowania kodu naszej aplikacji. Weźmy np. prosty poniższy przykład CustReport.p który wyświetla w pętli podstawowe pola z tablicy Customer,

DEFINE VARIABLE dOrdervalue AS DECIMAL NO-UNDO.

FOR EACH customer WHERE custnum < 100:
   dOrdervalue = 0.
   IF custnum < 40 THEN 
      RUN ordervalue.p (custnum, OUTPUT dOrdervalue).
   
   DISP custnum name dOrdervalue.

END.

a dla części iteracji uruchamia dodatkową procedurę ordervalue.p zliczającą sumę zamówień klienta.

DEF INPUT PARAM icustnum AS INTEGER.
DEF OUTPUT PARAM dordval AS DECIMAL.

FIND customer WHERE customer.custnum = icustnum.

FOR EACH order OF customer, EACH orderline OF order:
   dordval += price * qty.
END.

Po uruchomieniu Profilera zostanie wygenerowany plik typu .out. Jeśli spróbujemy go otworzyć przy pomocy przycisku VIEW z panelu narzędzia, dostaniemy komunikat o błędzie: Cannot load data. Don’t know how to load data for version 3.
Otwórzmy plik zwykłym edytorem tekstowym, np. Notepad++. Na pierwszej pozycji znajduje się nr wersji a potem data. Zmieniamy wartość nr wersji 3 na 1.
Zobaczmy przy okazji, że plik ten zawiera informacje generowane podczas inicjalizacji sesji oraz dane niezbędne do analizy przy pomocy Viewera.

Po naciśnięciu VIEW zobaczymy poniższy ekran.

Profiler udostępnia statystyki dotyczące działania programu. Dane te są podzielone według bloków i poszczególnych linii kodu. Każdy blok reprezentuje aktualną procedurę, procedurę wewnętrzną lub funkcję. W górnym pasku, po lewej stronie możemy wybrać zarejestrowaną sesję. Obszar 1 zawiera następujące informacje:

Code Block: nazwa wewnętrznej procedury lub funkcji, tryger interfejsu użytkownika i nazwa programu
Calls To: liczba wykonań tego bloku kodu
Avg Time: średni czas w sekundach potrzebny do wykonania tego bloku kodu
Tot Time: całkowity czas w sekundach potrzebny do wykonania tego bloku kodu
%Session: procent całej sesji wykorzystany przez ten blok kodu w porównaniu z innymi blokami kodu
Cum Time: całkowity czas potrzebny do wykonania tego bloku kodu oprócz całkowitego czasu wszystkich bloków kodu wywołanych przez ten blok.

Obszar 3 zawiera informacje dot. linii kodu:

Line: numer linii w wybranym programie
Exec Count: liczba wykonań tej linii kodu
Avg Exec: średni czas wykonania tej linii kodu w sekundach
Tot Time: całkowity czas w sekundach potrzebny do wykonania tej linii kodu
Cum Time: całkowity czas w sekundach, jaki zajęło wykonanie tego wiersza kodu, a także wszelkich bloków kodu, wywołanych przez tę linię. UWAGA: ta liczba będzie się różnić od Tot Time tylko wtedy, gdy linia kodu jest instrukcją uruchomienia procedury lub wywołania funkcji.
Pozostałe pola nie są używane.

Wreszcie obszar 2.
Calling Code Block oraz Called Code Block umożliwiają nawigację między różnymi sekcjami kodu poprzez dwukrotne kliknięcie wybranego wiersza.
Widzimy, że procedura ordervalue.p była wywołana 38 razy, co zajęło niecałe 4% czasu sesji.

Jeszcze jedna sprawa – na ekranie wyjściowym Profilera (pierwszy obraz w poprzednim artykule) widzimy po prawej stronie trzy pola wyboru: Listing, Coverage, Tracking.
Pierwsze służy do wygenerowania listingu, który będzie widoczny w Viewerze. Coverage służy do generowania dodatkowych danych dla procedur zewnętrznych, a Tracking do określenia filtra dla generowania danych tylko dla określonych procedur. Jeśli zaznaczymy Listing i ponownie uruchomimy sesję, na ekranie pojawi się listing programu, a wybór linii kodu a w browserze podświetli tę linię na listingu. Bardzo użyteczna funkcja.


Teraz trzeba już tylko przetestować własne procedury aby zorientować się w przydatności Profilera.
To jeszcze nie koniec. W następnym odcinku zobaczymy jak używać tego narzędzia w Developer Studio.

Profiler – narzędzie dewelopera cz. I

Profiler czy Profiler Control to narzędzie znane już od wersji V9 Progressa. Było dostępne w postaci źródłowej z katalogu DLC\src\samples\profile, a w późniejszych wersjach dodane do pakietu samples, który można pobrać oddzielnie. Jest to deweloperskie narzędzie darmowe i niewspierane. Wielu klientów korzysta z niego na całym świecie. Zostałem niedawno poproszony o przypomnienie jak rozpocząć z nim pracę, co opiszę w niniejszym artykule.

Profiler jest powszechnym i użytecznym narzędziem programisty do oceny wydajności aplikacji. Krótko mówiąc, profiler dostarcza „profil” konkretnego wykonania programu czyli informacje o czasach wykonania poszczególnych modułów oraz kolejność ich wywołań; dzięki czemu można przeanalizować, gdzie program spędza większość czasu i jaka część aplikacji wywołuje inną część aplikacji. W szczególności możemy przeanalizować czas wykonań dla konkretnych zapytań lub znaleźć podejrzanie dużą liczbę iteracji dla instrukcji.

Narzędzie to składa się z dwóch modułów – modułu zbierającego dane oraz modułu graficznego (Windows), w którym można te dane analizować. Profiler śledzi opóźnienia w aplikacji spowodowane przez kod programu ignorując jednocześnie te wywołane interakcją użytkownika.

Pierwsza wersja tego narzędzia wymagała utworzenia pustej bazy prof.db i załadowania do niej definicji z pliku prof.df. Ja przedstawię tutaj nowszą wersję, w której baza nie jest potrzebna gdyż wszystkie dane są gromadzone w tablicach tymczasowych.
Wersja ta zawiera graficzny interfejs użytkownika, który upraszcza uruchamianie i zatrzymywanie procedur. Może wykrywać czy jest uruchomiony Progress Dynamics a także umożliwia uruchamianie dynamicznych kontenerów oraz statycznych smart obiektów i innych procedur. Zawiera wszystkie te same informacje, ale eliminuje znaczną część złożoności poprzedniego narzędzia, eliminując czasochłonne ładowanie danych profilu. Do statystyk wykonania, dodano więcej informacji. To narzędzie zawiera również dodatkową funkcjonalność, która daje użytkownikowi możliwość wykonywania porównań i eksportowania danych do zewnętrznych programów. Można go pobrać tutaj.

W niniejszym artykule oprócz wprowadzenia i informacji ogólnych znajdziecie metody jak rozpocząć z nim pracę. W styczniu natomiast napiszę jak interpretować dane.

W zasadzie są dwie metody generowania danych dla profilera: uruchamiając narzędzie z parametrem startowym -profile lub używając handle (uchwyt) PROFILER. Najprostszym sposobem jest uruchomienie pliku profiler.w, co widać powyżej. Program ten uruchamiany jest bezparametrowo ale wykorzystuje on wspomniany uchwyt.
Pojawi się komunikat czy uruchomić sesję profilera. Jeśli potwierdzicie, przełącznik radiowy ustawi się w pozycji Profile, jeśli nie, w pozycji Run.
Wybieramy Profile i w polu Procedure wpisujemy nazwę profilowanej procedury (nie ma niestety drzewa systemu z plikami do wyboru). Oprócz pola procedury widać także pole Container. Jest ono aktywne gdy mamy otwartą sesję z produktem Progress Dynamics. Domyślnie narzędzie jest ustawione tak aby śledzić dane dla sesji klient-serwer lecz jest też możliwe śledzenie sesji dla klient-appserver dla Dynamics.

Po wpisaniu nazwy programu i naciśnięciu Run, dane zostaną zapisane do pliku, którego nazwa jest generowana automatycznie (możemy ją oczywiście zmienić). W tym przypadku clntprof20221227.out. Po zakończeniu procesu wybierz przycisk Stop. Spowoduje to, że program profilujący zakończy działanie procedury (o ile nadal działa) a dane sesji zostaną wyeksportuje pliku wyjściowego (jeśli zaznaczone jest pole Write On Stop). Dane można także zapisać w dowolnym momencie naciskając przycisk Write Data.

Możemy sami skorzystać z uchwytu PROFILER. Ta metoda jest wygodna jeśli chcemy programowo profilować tylko wybrane fragmenty kodu. Wymaga ona więcej pracy ale daje dodatkowe możliwości i w przypadku złożonych programów jest nieoceniona. Przykładowy fragment kodu widzimy poniżej.

ASSIGN
   PROFILER:DESCRIPTION = "Profiler Start"
   PROFILER:DIRECTORY = "c:/WrkOpenEdge126/"
   PROFILER:FILE-NAME = "clntprof20221227.out"
   PROFILER:COVERAGE = TRUE
   PROFILER:LISTINGS = TRUE
   PROFILER:ENABLED = TRUE
   PROFILER:PROFILING = TRUE.

Jeśli chcemy profilować dane całej aplikacji, możemy skorzystać z parametru startowego -profile profiler.txt który wstawiamy do ikonki lub skryptu uruchamiającego procedurę.

W piku profiler.txt definiujemy parametry np:

   -description "Profiler Start"
   -listings = "c:/WrkOpenEdge126/"
   -filename = "clntprof20221227.out"

OK, to na razie tyle. Następnym razem zajmiemy się generowaniem i analizą danych.