GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Linux-Anwendungsprofilerstellung

Idealerweise benötige ich eine Anwendung, die an einen Prozess angehängt wird und regelmäßige Snapshots protokolliert von:

  • Speichernutzung
  • Anzahl der Threads
  • CPU-Auslastung

Nun, um diese Art von Informationen über Ihren Prozess zu sammeln, brauchen Sie unter Linux eigentlich keinen Profiler.

  1. Sie können top verwenden im Batch-Modus. Es läuft im Batch-Modus entweder bis es beendet wird oder bis N Iterationen durchgeführt werden:

    top -b -p `pidof a.out`
    

    oder

    top -b -p `pidof a.out` -n 100
    

    und Sie erhalten Folgendes:

    $ top -b -p `pidof a.out`
    
    top - 10:31:50 up 12 days, 19:08,  5 users,  load average: 0.02, 0.01, 0.02
    Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
    Cpu(s):  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Mem:  16330584k total,  2335024k used, 13995560k free,   241348k buffers
    Swap:  4194296k total,        0k used,  4194296k free,  1631880k cached
    
      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
    24402 SK        20   0 98.7m 1056  860 S 43.9  0.0   0:11.87 a.out
    
    
    top - 10:31:53 up 12 days, 19:08,  5 users,  load average: 0.02, 0.01, 0.02
    Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
    Cpu(s):  0.9%us,  3.7%sy,  0.0%ni, 95.5%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Mem:  16330584k total,  2335148k used, 13995436k free,   241348k buffers
    Swap:  4194296k total,        0k used,  4194296k free,  1631880k cached
    
    PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
    24402 SK      20   0 98.7m 1072  860 S 19.0  0.0   0:12.44 a.out
    
  2. Sie können ps verwenden (zum Beispiel in einem Shell-Skript)

    ps --format pid,pcpu,cputime,etime,size,vsz,cmd -p `pidof a.out`
    

    Ich brauche eine Möglichkeit, die Leistung einer Anwendung auf einem Linux-Rechner aufzuzeichnen

    Dazu müssen Sie perf verwenden wenn Ihr Linux-Kernel größer als 2.6.32 ist oder OProfile, wenn es älter ist. Beide Programme erfordern nicht, dass Sie Ihr Programm instrumentieren (wie es Gprof erfordert). Um jedoch den Anrufgraphen korrekt in perf zu bekommen Sie müssen Ihr Programm mit -fno-omit-frame-pointer erstellen. Beispiel:g++ -fno-omit-frame-pointer -O2 main.cpp .

Wie für Linux perf :

  1. So zeichnen Sie Leistungsdaten auf:

    perf record -p `pidof a.out`
    

    oder um 10 Sekunden lang aufzunehmen:

    perf record -p `pidof a.out` sleep 10
    

    oder mit einem Callgraph aufzuzeichnen ()

    perf record -g -p `pidof a.out`
    
  2. Zur Analyse der aufgezeichneten Daten

    perf report --stdio
    perf report --stdio --sort=dso -g none
    perf report --stdio -g none
    perf report --stdio -g
    

    Unter RHEL 6.3 darf /boot/System.map-2.6.32-279.el6.x86_64 gelesen werden, daher füge ich normalerweise --kallsyms=/boot/System.map-2.6.32-279.el6.x86_64 hinzu, wenn Erstellen eines Leistungsberichts:

    perf report --stdio -g --kallsyms=/boot/System.map-2.6.32-279.el6.x86_64
    
    Hier habe ich weitere Informationen zur Verwendung von Linux `perf` geschrieben:

    Zunächst einmal - dies ist ein Tutorial über Linux-Profiling mit perf

    Sie können perf verwenden wenn Ihr Linux-Kernel größer als 2.6.32 ist oder OProfile, wenn es älter ist. Beide Programme erfordern nicht, dass Sie Ihr Programm instrumentieren (wie es Gprof erfordert). Um jedoch den Anrufgraphen korrekt in perf zu erhalten Sie müssen Ihr Programm mit -fno-omit-frame-pointer erstellen . Beispiel:g++ -fno-omit-frame-pointer -O2 main.cpp .

    Mit perf top sehen Sie eine „Live“-Analyse Ihrer Bewerbung :

     sudo perf top -p `pidof a.out` -K
    

Oder Sie können Leistungsdaten einer laufenden Anwendung aufzeichnen und anschließend analysieren:

  1. So zeichnen Sie Leistungsdaten auf:

    perf record -p `pidof a.out`
    

    oder um 10 Sekunden lang aufzunehmen:

    perf record -p `pidof a.out` sleep 10
    

    oder mit einem Callgraph aufzuzeichnen ()

    perf record -g -p `pidof a.out`
    
  2. Zur Analyse der aufgezeichneten Daten

perf report --stdio
perf report --stdio --sort=dso -g none
perf report --stdio -g none
perf report --stdio -g

Oder Sie können Leistungsdaten einer Anwendung aufzeichnen und anschließend analysieren, indem Sie die Anwendung einfach auf diese Weise starten und darauf warten, dass sie beendet wird:

perf record ./a.out

Dies ist ein Beispiel für die Profilerstellung eines Testprogramms.

Das Testprogramm befindet sich in der Datei main.cpp (main.cpp steht am Ende der Antwort):

Ich kompiliere es auf diese Weise:

g++ -m64 -fno-omit-frame-pointer -g main.cpp -L.  -ltcmalloc_minimal -o my_test

Ich verwende libmalloc_minimial.so, da es mit -fno-omit-frame-pointer kompiliert wird, während libc malloc scheinbar ohne diese Option kompiliert wird. Dann führe ich mein Testprogramm aus:

./my_test 100000000

Dann zeichne ich Leistungsdaten eines laufenden Prozesses auf:

perf record -g  -p `pidof my_test` -o ./my_test.perf.data sleep 30

Dann analysiere ich die Belastung pro Modul:

perf report --stdio -g none --sort comm,dso -i ./my_test.perf.data

# Overhead  Command                 Shared Object
# ........  .......  ............................
#
    70.06%  my_test  my_test
    28.33%  my_test  libtcmalloc_minimal.so.0.1.0
     1.61%  my_test  [kernel.kallsyms]

Dann wird die Belastung pro Funktion analysiert:

perf report --stdio -g none -i ./my_test.perf.data | c++filt

# Overhead  Command                 Shared Object                       Symbol
# ........  .......  ............................  ...........................
#
    29.30%  my_test  my_test                       [.] f2(long)
    29.14%  my_test  my_test                       [.] f1(long)
    15.17%  my_test  libtcmalloc_minimal.so.0.1.0  [.] operator new(unsigned long)
    13.16%  my_test  libtcmalloc_minimal.so.0.1.0  [.] operator delete(void*)
     9.44%  my_test  my_test                       [.] process_request(long)
     1.01%  my_test  my_test                       [.] operator delete(void*)@plt
     0.97%  my_test  my_test                       [.] operator new(unsigned long)@plt
     0.20%  my_test  my_test                       [.] main
     0.19%  my_test  [kernel.kallsyms]             [k] apic_timer_interrupt
     0.16%  my_test  [kernel.kallsyms]             [k] _spin_lock
     0.13%  my_test  [kernel.kallsyms]             [k] native_write_msr_safe

     and so on ...

Dann werden Anrufketten analysiert:

perf report --stdio -g graph -i ./my_test.perf.data | c++filt

# Overhead  Command                 Shared Object                       Symbol
# ........  .......  ............................  ...........................
#
    29.30%  my_test  my_test                       [.] f2(long)
            |
            --- f2(long)
               |
                --29.01%-- process_request(long)
                          main
                          __libc_start_main

    29.14%  my_test  my_test                       [.] f1(long)
            |
            --- f1(long)
               |
               |--15.05%-- process_request(long)
               |          main
               |          __libc_start_main
               |
                --13.79%-- f2(long)
                          process_request(long)
                          main
                          __libc_start_main

    15.17%  my_test  libtcmalloc_minimal.so.0.1.0  [.] operator new(unsigned long)
            |
            --- operator new(unsigned long)
               |
               |--11.44%-- f1(long)
               |          |
               |          |--5.75%-- process_request(long)
               |          |          main
               |          |          __libc_start_main
               |          |
               |           --5.69%-- f2(long)
               |                     process_request(long)
               |                     main
               |                     __libc_start_main
               |
                --3.01%-- process_request(long)
                          main
                          __libc_start_main

    13.16%  my_test  libtcmalloc_minimal.so.0.1.0  [.] operator delete(void*)
            |
            --- operator delete(void*)
               |
               |--9.13%-- f1(long)
               |          |
               |          |--4.63%-- f2(long)
               |          |          process_request(long)
               |          |          main
               |          |          __libc_start_main
               |          |
               |           --4.51%-- process_request(long)
               |                     main
               |                     __libc_start_main
               |
               |--3.05%-- process_request(long)
               |          main
               |          __libc_start_main
               |
                --0.80%-- f2(long)
                          process_request(long)
                          main
                          __libc_start_main

     9.44%  my_test  my_test                       [.] process_request(long)
            |
            --- process_request(long)
               |
                --9.39%-- main
                          __libc_start_main

     1.01%  my_test  my_test                       [.] operator delete(void*)@plt
            |
            --- operator delete(void*)@plt

     0.97%  my_test  my_test                       [.] operator new(unsigned long)@plt
            |
            --- operator new(unsigned long)@plt

     0.20%  my_test  my_test                       [.] main
     0.19%  my_test  [kernel.kallsyms]             [k] apic_timer_interrupt
     0.16%  my_test  [kernel.kallsyms]             [k] _spin_lock
     and so on ...

An diesem Punkt wissen Sie also, wo Ihr Programm Zeit verbringt.

Und das ist die main.cpp Datei für den Test:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

time_t f1(time_t time_value)
{
  for (int j = 0; j < 10; ++j) {
    ++time_value;
    if (j%5 == 0) {
      double *p = new double;
      delete p;
    }
  }
  return time_value;
}

time_t f2(time_t time_value)
{
  for (int j = 0; j < 40; ++j) {
    ++time_value;
  }
  time_value = f1(time_value);
  return time_value;
}

time_t process_request(time_t time_value)
{
  for (int j = 0; j < 10; ++j) {
    int *p = new int;
    delete p;
    for (int m = 0; m < 10; ++m) {
      ++time_value;
    }
  }
  for (int i = 0; i < 10; ++i) {
    time_value = f1(time_value);
    time_value = f2(time_value);
  }
  return time_value;
}

int main(int argc, char* argv2[])
{
  int number_loops = argc > 1 ? atoi(argv2[1]) : 1;
  time_t time_value = time(0);
  printf("number loops %d\n", number_loops);
  printf("time_value: %d\n", time_value);

  for (int i = 0; i < number_loops; ++i) {
    time_value = process_request(time_value);
  }
  printf("time_value: %ld\n", time_value);
  return 0;
}

Linus Torvalds selbst zitieren:

Verwenden Sie nicht gprof. Du bist viel besser dran, das neuere Linux-Tool 'perf' zu verwenden.

Und später ...

Ich kann so ziemlich garantieren, dass Sie gprof oder oprofile nie wieder verwenden werden, sobald Sie damit angefangen haben.

Siehe Re:[PATCH] grep:kein externes grep für Skip-Worktree-Einträge ausführen (2010-01-04)


Linux
  1. Linux – Befehl zum Messen von Tlb-Fehlschlägen unter Linux?

  2. Linux – Welche Anwendung für einen Kalender verwenden?

  3. Linux – Installation von Perf auf Slackware 13.1 fehlgeschlagen?

  4. Einschränken des Syscall-Zugriffs für eine Linux-Anwendung

  5. Wie signiere ich eine Mac OS X-Anwendung unter Linux?

So senden Sie Linux-Anwendungsprotokolle an AWS CloudWatch

Terminal Velocity – Eine CLI-Notizanwendung für Linux

So aktivieren Sie die Option „Bearbeiten“ in der Shutter-Anwendung unter Linux

Genießen Sie Twitch unter Linux mit der GNOME Twitch-Anwendung

Linux Perf-Befehl

So installieren und konfigurieren Sie Perf in Linux-Distributionen