Idealmente, necesito una aplicación que se adjunte a un proceso y registre instantáneas periódicas de:
- uso de memoria
- número de subprocesos
- Uso de la CPU
Bueno, para recopilar este tipo de información sobre su proceso, en realidad no necesita un generador de perfiles en Linux.
-
Puedes usar
top
en modo por lotes. Se ejecuta en el modo por lotes hasta que se elimina o hasta que se realizan N iteraciones:top -b -p `pidof a.out`
o
top -b -p `pidof a.out` -n 100
y obtendrás esto:
$ 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
-
Puedes usar
ps
(por ejemplo, en un script de shell)
ps --format pid,pcpu,cputime,etime,size,vsz,cmd -p `pidof a.out`
Necesito algún medio para registrar el rendimiento de una aplicación en una máquina Linux
Para hacer esto necesitas usar
perf
si su kernel de Linux es mayor que 2.6.32 u OProfile si es anterior. Ambos programas no requieren que usted instrumente su programa (como lo requiere Gprof). Sin embargo, para obtener el gráfico de llamadas correctamente enperf
necesita construir su programa con -fno-omit-frame-pointer. Por ejemplo:g++ -fno-omit-frame-pointer -O2 main.cpp
.
En cuanto a Linux perf
:
-
Para registrar datos de rendimiento:
perf record -p `pidof a.out`
o para grabar durante 10 segundos:
perf record -p `pidof a.out` sleep 10
o para grabar con un gráfico de llamadas ()
perf record -g -p `pidof a.out`
-
Para analizar los datos registrados
perf report --stdio perf report --stdio --sort=dso -g none perf report --stdio -g none perf report --stdio -g
En RHEL 6.3, se permite leer /boot/System.map-2.6.32-279.el6.x86_64, por lo que generalmente agrego --kallsyms=/boot/System.map-2.6.32-279.el6.x86_64 cuando haciendo un informe de rendimiento:
Aquí escribí más información sobre el uso de Linux `perf`:perf report --stdio -g --kallsyms=/boot/System.map-2.6.32-279.el6.x86_64
En primer lugar, este es un tutorial sobre la creación de perfiles de Linux con perf
Puedes usar perf si su kernel de Linux es mayor que 2.6.32 u OProfile si es más antiguo. Ambos programas no requieren que usted instrumente su programa (como lo requiere Gprof). Sin embargo, para obtener el gráfico de llamadas correctamente en perf necesitas construir tu programa con
-fno-omit-frame-pointer
. Por ejemplo:g++ -fno-omit-frame-pointer -O2 main.cpp
.Puede ver un análisis "en vivo" de su aplicación con perf top :
sudo perf top -p `pidof a.out` -K
O puede registrar los datos de rendimiento de una aplicación en ejecución y analizarlos después:
-
Para registrar datos de rendimiento:
perf record -p `pidof a.out`
o para grabar durante 10 segundos:
perf record -p `pidof a.out` sleep 10
o para grabar con un gráfico de llamadas ()
perf record -g -p `pidof a.out`
-
Para analizar los datos registrados
perf report --stdio
perf report --stdio --sort=dso -g none
perf report --stdio -g none
perf report --stdio -g
O puede registrar los datos de rendimiento de una aplicación y analizarlos después simplemente iniciando la aplicación de esta manera y esperando a que se cierre:
perf record ./a.out
Este es un ejemplo de creación de perfiles de un programa de prueba.
El programa de prueba está en el archivo main.cpp (principal.cpp está al final de la respuesta):
Lo compilo de esta manera:
g++ -m64 -fno-omit-frame-pointer -g main.cpp -L. -ltcmalloc_minimal -o my_test
Yo uso libmalloc_minimial.so ya que está compilado con -fno-omit-frame-pointer mientras que libc malloc parece estar compilado sin esta opción. Luego ejecuto mi programa de prueba:
./my_test 100000000
Luego registro los datos de rendimiento de un proceso en ejecución:
perf record -g -p `pidof my_test` -o ./my_test.perf.data sleep 30
Luego analizo la carga por módulo:
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]
Luego se analiza la carga por función:
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 ...
Luego se analizan las cadenas de llamadas:
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 ...
Entonces, en este punto, ya sabe dónde pasa el tiempo su programa.
Y este es el main.cpp archivo para la prueba:
#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;
}
Citando al propio Linus Torvalds:
No use gprof. Eres mucho es mejor usar la nueva herramienta 'perf' de Linux.
Y luego...
Casi puedo garantizar que una vez que comience a usarlo, nunca volverá a usar gprof u oprofile.
Ver Re:[PATCH] grep:no hacer grep externo en entradas de skip-worktree (2010-01-04)