GNU/Linux >> Znalost Linux >  >> Linux

GPROF Tutorial – Jak používat Linux GNU GCC Profiling Tool

Profilování je důležitým aspektem programování softwaru. Pomocí profilování lze určit části v programovém kódu, které jsou časově náročné a je třeba je přepsat. To pomáhá zrychlit provádění vašeho programu, což je vždy žádoucí.

U velmi velkých projektů vám profilování může ušetřit den tím, že nejen určí části v programu, které jsou pomalejší, než se očekávalo, ale také může pomoci najdete mnoho dalších statistik, pomocí kterých lze odhalit a vyřešit mnoho potenciálních chyb.

V tomto článku prozkoumáme profilovací nástroj GNU „gprof“.

Jak používat gprof

Použití nástroje gprof není vůbec složité. Na vysoké úrovni stačí udělat následující:

  • Při kompilaci kódu povolte profilování
  • Spusťte programový kód k vytvoření profilovacích dat
  • Spusťte nástroj gprof na datovém souboru profilování (vygenerovaném v kroku výše).

Poslední výše uvedený krok vytvoří soubor analýzy, který je ve formě čitelné pro člověka. Tento soubor obsahuje několik tabulek (plochý profil a graf volání) a některé další informace. Zatímco plochý profil poskytuje přehled informací o načasování funkcí, jako je spotřeba času na provedení konkrétní funkce, kolikrát byla volána atd. Na druhou stranu se graf volání zaměřuje na každou funkci, jako jsou funkce, kterými funkce byla volána, jaké všechny funkce byly volány z této konkrétní funkce atd. Takže tímto způsobem lze získat představu o době provádění strávené v podprogramech.

Pokusme se pochopit tři výše uvedené kroky na praktickém příkladu. V celém článku bude použit následující testovací kód:

//test_gprof.c
#include<stdio.h>

void new_func1(void);

void func1(void)
{
    printf("\n Inside func1 \n");
    int i = 0;

    for(;i<0xffffffff;i++);
    new_func1();

    return;
}

static void func2(void)
{
    printf("\n Inside func2 \n");
    int i = 0;

    for(;i<0xffffffaa;i++);
    return;
}

int main(void)
{
    printf("\n Inside main()\n");
    int i = 0;

    for(;i<0xffffff;i++);
    func1();
    func2();

    return 0;
}
//test_gprof_new.c
#include<stdio.h>

void new_func1(void)
{
    printf("\n Inside new_func1()\n");
    int i = 0;

    for(;i<0xffffffee;i++);

    return;
}

Všimněte si, že smyčky „for“ uvnitř funkcí jsou k tomu, aby spotřebovaly určitou dobu provádění.

Krok 1:Profilování povoleno během kompilace

V tomto prvním kroku se musíme ujistit, že je po kompilaci kódu povoleno profilování. To je umožněno přidáním volby „-pg“ v kroku kompilace.

Z manuálové stránky gcc :

-pg :Vygeneruje extra kód pro zápis informací o profilu vhodných pro analytický program gprof. Tuto možnost musíte použít při kompilaci zdrojových souborů, o kterých chcete data, a musíte ji použít také při propojování.

Pojďme tedy zkompilovat náš kód s volbou „-pg“:

$ gcc -Wall -pg test_gprof.c test_gprof_new.c -o test_gprof
$

Poznámka:Volba '-pg' může být použita s příkazem gcc, který kompiluje (volba -c), příkazem gcc, který odkazuje (volba -o na objektových souborech) as příkazem gcc, který provádí obojí (jako v příkladu výše) .

Krok-2:Spusťte kód

Ve druhém kroku se provede binární soubor vytvořený jako výsledek kroku 1 (výše), aby bylo možné vygenerovat informace o profilování.

$ ls
test_gprof  test_gprof.c  test_gprof_new.c

$ ./test_gprof 

 Inside main()

 Inside func1 

 Inside new_func1()

 Inside func2 

$ ls
gmon.out  test_gprof  test_gprof.c  test_gprof_new.c

$

Vidíme tedy, že po spuštění binárního souboru se v aktuálním pracovním adresáři vygeneruje nový soubor ‚gmon.out‘.

Všimněte si, že pokud program během provádění změní aktuální pracovní adresář (pomocí chdir), pak se gmon.out vytvoří v novém aktuálním pracovním adresáři. Váš program také musí mít dostatečná oprávnění pro vytvoření gmon.out v aktuálním pracovním adresáři.

Krok-3:Spusťte nástroj gprof

V tomto kroku se spustí nástroj gprof s názvem spustitelného souboru a výše vygenerovaným argumentem ‚gmon.out‘. Tím se vytvoří soubor analýzy, který obsahuje všechny požadované profilovací informace.

$  gprof test_gprof gmon.out > analysis.txt

Všimněte si, že lze explicitně specifikovat výstupní soubor (jako ve výše uvedeném příkladu) nebo se informace vytvoří na stdout.

$ ls
analysis.txt  gmon.out  test_gprof  test_gprof.c  test_gprof_new.c

Vidíme tedy, že byl vygenerován soubor s názvem ‚analysis.txt‘.

V související poznámce byste také měli rozumět tomu, jak ladit váš program C pomocí gdb.

Porozumění informacím o profilování

Jak bylo uvedeno výše, všechny informace o profilování jsou nyní přítomny v „analysis.txt“. Pojďme se podívat na tento textový soubor:

Flat profile:

Each sample counts as 0.01 seconds.
%    cumulative self          self   total
time seconds    seconds calls s/call s/call name
33.86 15.52     15.52    1    15.52  15.52  func2
33.82 31.02     15.50    1    15.50  15.50  new_func1
33.29 46.27     15.26    1    15.26  30.75  func1
0.07  46.30     0.03                        main

% the percentage of the total running time of the
time program used by this function.

cumulative a running sum of the number of seconds accounted
seconds for by this function and those listed above it.

self the number of seconds accounted for by this
seconds function alone. This is the major sort for this
listing.

calls the number of times this function was invoked, if
this function is profiled, else blank.

self the average number of milliseconds spent in this
ms/call function per call, if this function is profiled,
else blank.

total the average number of milliseconds spent in this
ms/call function and its descendents per call, if this
function is profiled, else blank.

name the name of the function. This is the minor sort
for this listing. The index shows the location of
the function in the gprof listing. If the index is
in parenthesis it shows where it would appear in
the gprof listing if it were to be printed.

Call graph (explanation follows)

granularity: each sample hit covers 2 byte(s) for 0.02% of 46.30 seconds

index % time self children called name

[1]   100.0  0.03  46.27          main [1]
             15.26 15.50    1/1      func1 [2]
             15.52 0.00     1/1      func2 [3]
-----------------------------------------------
             15.26 15.50    1/1      main [1]
[2]   66.4   15.26 15.50    1     func1 [2]
             15.50 0.00     1/1      new_func1 [4]
-----------------------------------------------
             15.52 0.00     1/1      main [1]
[3]   33.5   15.52 0.00     1     func2 [3]
-----------------------------------------------
             15.50 0.00     1/1      func1 [2]
[4] 33.5     15.50 0.00     1     new_func1 [4]
-----------------------------------------------

This table describes the call tree of the program, and was sorted by
the total amount of time spent in each function and its children.

Each entry in this table consists of several lines. The line with the
index number at the left hand margin lists the current function.
The lines above it list the functions that called this function,
and the lines below it list the functions this one called.
This line lists:
index A unique number given to each element of the table.
Index numbers are sorted numerically.
The index number is printed next to every function name so
it is easier to look up where the function in the table.

% time This is the percentage of the `total' time that was spent
in this function and its children. Note that due to
different viewpoints, functions excluded by options, etc,
these numbers will NOT add up to 100%.

self This is the total amount of time spent in this function.

children This is the total amount of time propagated into this
function by its children.

called This is the number of times the function was called.
If the function called itself recursively, the number
only includes non-recursive calls, and is followed by
a `+' and the number of recursive calls.

name The name of the current function. The index number is
printed after it. If the function is a member of a
cycle, the cycle number is printed between the
function's name and the index number.

For the function's parents, the fields have the following meanings:

self This is the amount of time that was propagated directly
from the function into this parent.

children This is the amount of time that was propagated from
the function's children into this parent.

called This is the number of times this parent called the
function `/' the total number of times the function
was called. Recursive calls to the function are not
included in the number after the `/'.

name This is the name of the parent. The parent's index
number is printed after it. If the parent is a
member of a cycle, the cycle number is printed between
the name and the index number.

If the parents of the function cannot be determined, the word
`' is printed in the `name' field, and all the other
fields are blank.

For the function's children, the fields have the following meanings:

self This is the amount of time that was propagated directly
from the child into the function.

children This is the amount of time that was propagated from the
child's children to the function.

called This is the number of times the function called
this child `/' the total number of times the child
was called. Recursive calls by the child are not
listed in the number after the `/'.

name This is the name of the child. The child's index
number is printed after it. If the child is a
member of a cycle, the cycle number is printed
between the name and the index number.

If there are any cycles (circles) in the call graph, there is an
entry for the cycle-as-a-whole. This entry shows who called the
cycle (as parents) and the members of the cycle (as children.)
The `+' recursive calls entry shows the number of function calls that
were internal to the cycle, and the calls entry for each member shows,
for that member, how many times it was called from other members of
the cycle.

Index by function name

[2] func1 [1] main
[3] func2 [4] new_func1

Takže (jak již bylo řečeno) vidíme, že tento soubor je široce rozdělen na dvě části:

1. Plochý profil
2. Graf volání

Jednotlivé sloupce pro (plochý profil i graf volání) jsou velmi dobře vysvětleny v samotném výstupu.

Přizpůsobte výstup gprof pomocí příznaků

Pro přizpůsobení výstupu nástroje gprof jsou k dispozici různé příznaky. Některé z nich jsou popsány níže:

1. Potlačit tisk staticky (soukromých) deklarovaných funkcí pomocí -a

Pokud existují nějaké statické funkce, jejichž profilovací informace nepotřebujete, lze toho dosáhnout pomocí volby -a :

$ gprof -a test_gprof gmon.out > analysis.txt

Nyní, když vidíme soubor analýzy:

Flat profile:

Each sample counts as 0.01 seconds.
%        cumulative self           self    total
time  seconds       seconds calls  s/call  s/call  name
67.15 30.77         30.77     2    15.39  23.14    func1
33.82 46.27         15.50     1    15.50  15.50    new_func1
0.07   46.30         0.03                          main

...
...
...

Call graph (explanation follows)

granularity: each sample hit covers 2 byte(s) for 0.02% of 46.30 seconds

index   %time        self  children  called  name

[1]     100.0        0.03   46.27             main [1]
                     30.77  15.50     2/2      func1 [2]
-----------------------------------------------------
                     30.77  15.50     2/2      main [1]
[2]     99.9         30.77  15.50     2      func1 [2]
                     15.50   0.00     1/1      new_func1 [3]
----------------------------------------------------
                     15.50   0.00     1/1      func1 [2]
[3]        33.5      15.50 0.00       1      new_func1 [3]
-----------------------------------------------

...
...
...

Vidíme tedy, že neexistují žádné informace související s func2 (která je definována jako statická)

2. Potlačit upovídané reklamy pomocí -b

Jak jste již viděli, gprof vytváří výstup s mnoha podrobnými informacemi, takže v případě, že tyto informace nejsou vyžadovány, lze toho dosáhnout pomocí parametru -b.

$ gprof -b test_gprof gmon.out > analysis.txt

Nyní, když vidíme soubor analýzy:

Flat profile:

Each sample counts as 0.01 seconds.
%       cumulative    self            self    total
time    seconds       seconds  calls  s/call  s/call   name
33.86 15.52            15.52      1    15.52  15.52    func2
33.82 31.02            15.50      1    15.50  15.50    new_func1
33.29 46.27            15.26      1    15.26  30.75    func1
0.07   46.30            0.03                           main

Call graph

granularity: each sample hit covers 2 byte(s) for 0.02% of 46.30 seconds
index % time self children called name

[1]   100.0  0.03  46.27          main [1]
             15.26 15.50    1/1      func1 [2]
             15.52 0.00     1/1      func2 [3]
-----------------------------------------------
             15.26 15.50    1/1      main [1]
[2]   66.4   15.26 15.50    1     func1 [2]
             15.50 0.00     1/1      new_func1 [4]
-----------------------------------------------
             15.52 0.00     1/1      main [1]
[3]   33.5   15.52 0.00     1     func2 [3]
-----------------------------------------------
             15.50 0.00     1/1      func1 [2]
[4] 33.5     15.50 0.00     1     new_func1 [4]
-----------------------------------------------
Index by function name

[2] func1 [1] main
[3] func2 [4] new_func1

Vidíme tedy, že v souboru analýzy nejsou přítomny všechny podrobné informace.

3. Tiskněte pouze plochý profil pomocí -p

V případě, že je vyžadován pouze plochý profil, pak:

$ gprof -p -b test_gprof gmon.out > analysis.txt

Všimněte si, že jsem použil (a budu používat) volbu -b, abych se vyhnul dalším informacím ve výstupu analýzy.

Nyní, když vidíme výstup analýzy:

Flat profile:

Each sample counts as 0.01 seconds.
%       cumulative    self            self   total
time    seconds       seconds  calls  s/call  s/call  name
33.86   15.52          15.52      1   15.52   15.52    func2
33.82   31.02          15.50      1   15.50   15.50    new_func1
33.29   46.27          15.26      1   15.26   30.75    func1
0.07    46.30          0.03                            main

Vidíme tedy, že ve výstupu byl pouze plochý profil.

4. Tisk informací souvisejících s konkrétní funkcí v plochém profilu

Toho lze dosáhnout poskytnutím názvu funkce spolu s volbou -p:

$ gprof -pfunc1 -b test_gprof gmon.out > analysis.txt

Nyní, když vidíme výstup analýzy:

Flat profile:

Each sample counts as 0.01 seconds.
%          cumulative     self            self     total
time       seconds        seconds  calls  s/call   s/call  name
103.20     15.26          15.26     1     15.26   15.26    func1

Vidíme tedy, že je zobrazen plochý profil obsahující informace týkající se pouze funkce func1.

5. Potlačit plochý profil na výstupu pomocí -P

Pokud plochý profil není vyžadován, lze jej potlačit pomocí volby -P :

$ gprof -P -b test_gprof gmon.out > analysis.txt

Nyní, když vidíme výstup analýzy:

Call graph

granularity: each sample hit covers 2 byte(s) for 0.02% of 46.30 seconds
index % time self children called name

[1]   100.0  0.03  46.27          main [1]
             15.26 15.50    1/1      func1 [2]
             15.52 0.00     1/1      func2 [3]
-----------------------------------------------
             15.26 15.50    1/1      main [1]
[2]   66.4   15.26 15.50    1     func1 [2]
             15.50 0.00     1/1      new_func1 [4]
-----------------------------------------------
             15.52 0.00     1/1      main [1]
[3]   33.5   15.52 0.00     1     func2 [3]
-----------------------------------------------
             15.50 0.00     1/1      func1 [2]
[4] 33.5     15.50 0.00     1     new_func1 [4]
-----------------------------------------------
Index by function name

[2] func1 [1] main
[3] func2 [4] new_func1

Vidíme tedy, že plochý profil byl potlačen a ve výstupu byl zobrazen pouze graf volání.

Také, pokud existuje požadavek na tisk plochého profilu, ale s vyloučením konkrétní funkce, je to také možné pomocí parametru -P předáním názvu funkce (k vyloučení) spolu s ním.

$ gprof -Pfunc1 -b test_gprof gmon.out > analysis.txt

Ve výše uvedeném příkladu jsme se pokusili vyloučit „func1“ předáním spolu s volbou -P do gprof. Nyní se podívejme na výstup analýzy:

Flat profile:

Each sample counts as 0.01 seconds.
%         cumulative      self              self    total
time      seconds         seconds   calls   s/call  s/call  name
50.76     15.52            15.52      1     15.52   15.52   func2
50.69     31.02            15.50      1     15.50   15.50   new_func1
0.10      31.05            0.03                             main

Vidíme tedy, že plochý profil byl zobrazen, ale informace o func1 byly potlačeny.

6. Pomocí -q

vytiskněte pouze informace z grafu hovorů
gprof -q -b test_gprof gmon.out > analysis.txt

Ve výše uvedeném příkladu byla použita volba -q. Podívejme se, jaký vliv to má na výstup analýzy:

Call graph

granularity: each sample hit covers 2 byte(s) for 0.02% of 46.30 seconds
index % time self children called name

[1]   100.0  0.03  46.27          main [1]
             15.26 15.50    1/1      func1 [2]
             15.52 0.00     1/1      func2 [3]
-----------------------------------------------
             15.26 15.50    1/1      main [1]
[2]   66.4   15.26 15.50    1     func1 [2]
             15.50 0.00     1/1      new_func1 [4]
-----------------------------------------------
             15.52 0.00     1/1      main [1]
[3]   33.5   15.52 0.00     1     func2 [3]
-----------------------------------------------
             15.50 0.00     1/1      func1 [2]
[4] 33.5     15.50 0.00     1     new_func1 [4]
-----------------------------------------------
Index by function name

[2] func1 [1] main
[3] func2 [4] new_func1

Vidíme tedy, že ve výstupu byl vytištěn pouze graf volání.

7. Tisknout pouze informace o konkrétních funkcích v grafu volání.

To je možné předáním názvu funkce spolu s volbou -q.

$ gprof -qfunc1 -b test_gprof gmon.out > analysis.txt

Nyní, když vidíme výstup analýzy:

Call graph

granularity: each sample hit covers 2 byte(s) for 0.02% of 46.30 seconds
index % time self children called name

             15.26 15.50    1/1      main [1]
[2]   66.4   15.26 15.50    1     func1 [2]
             15.50 0.00     1/1      new_func1 [4]
-----------------------------------------------
             15.50 0.00     1/1      func1 [2]
[4]   33.5   15.50 0.00     1     new_func1 [4]
-----------------------------------------------
Index by function name

[2] func1 (1) main
(3) func2 [4] new_func1

Vidíme tedy, že informace týkající se pouze funkce func1 byly zobrazeny v grafu volání.

8. Potlačit graf volání pomocí -Q

Pokud nejsou ve výstupu analýzy vyžadovány informace z grafu volání, lze použít volbu -Q.

$ gprof -Q -b test_gprof gmon.out > analysis.txt

Nyní, když vidíme výstup analýzy:

Flat profile:

Each sample counts as 0.01 seconds.
%       cumulative    self            self    total
time    seconds       seconds  calls  s/call  s/call   name
33.86 15.52            15.52      1   15.52   15.52    func2
33.82 31.02            15.50      1   15.50   15.50    new_func1
33.29 46.27            15.26      1   15.26   30.75    func1
0.07   46.30            0.03                           main

Vidíme tedy, že ve výstupu je pouze plochý profil. Celý graf hovorů byl potlačen.

Také, pokud je žádoucí potlačit určitou funkci z grafu volání, lze toho dosáhnout předáním názvu požadované funkce spolu s volbou -Q do nástroje gprof.

$ gprof -Qfunc1 -b test_gprof gmon.out > analysis.txt

Ve výše uvedeném příkladu je název funkce func1 předán volbě -Q.

Nyní, když vidíme výstup analýzy:

Call graph

granularity: each sample hit covers 2 byte(s) for 0.02% of 46.30 seconds
index % time self children called name

[1]   100.0  0.03  46.27          main [1]
             15.26 15.50    1/1      func1 [2]
             15.52 0.00     1/1      func2 [3]
-----------------------------------------------
             15.52 0.00     1/1      main [1]
[3]   33.5   15.52 0.00     1     func2 [3]
-----------------------------------------------
             15.50 0.00     1/1      func1 [2]
[4]   33.5   15.50 0.00     1     new_func1 [4]
-----------------------------------------------
Index by function name

(2) func1 [1] main
[3] func2 [4] new_func1

Vidíme tedy, že informace grafu volání související s func1 byly potlačeny.


Linux
  1. Jak používat BusyBox na Linuxu

  2. Jak používám cron v Linuxu

  3. Jak používat FIND v Linuxu

  1. Jak používám nastavení usnadnění přístupu v systému Linux

  2. Jak používat Unzip v Linuxu

  3. Jak používat Su Command v Linuxu

  1. Jak používat pkgsrc na Linuxu

  2. Jak používat příkaz Disown v Linuxu

  3. Jak používat příkaz Linux SS