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.
-
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
-
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 inperf
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
:
-
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`
-
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:
Hier habe ich weitere Informationen zur Verwendung von Linux `perf` geschrieben:perf report --stdio -g --kallsyms=/boot/System.map-2.6.32-279.el6.x86_64
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:
-
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`
-
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)