TL; DR: foo
è veloce e piccolo per ottenere eventi di profilo, eseguirlo 100 volte in più. L'impostazione della frequenza era con errore di battitura e pprof
non campionerà più spesso di CONFIG_HZ (in genere 250). È preferibile passare al più moderno profiler Linux perf
(tutorial from its authors, wikipedia).
Versione lunga:
La funzione foo
è troppo breve e semplice - basta chiamare due funzioni. Compilato il test con g++ test.cc -lprofiler -o test.s -S -g
, con filtraggio di test.s
con c++filt
programma per rendere i nomi C++ leggibile:
foo():
.LFB972:
.loc 1 27 0
pushq %rbp
movq %rsp, %rbp
.loc 1 28 0
movl $.LC0, %esi
movl std::cout, %edi
call std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
movl std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&), %esi
movq %rax, %rdi
call std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))
.loc 1 29 0
popq %rbp
ret
.LFE972:
.size foo(), .-foo()
Così, per vederlo nella scheda è necessario eseguire foo
per più volte, cambiando int a = 1000;
in principale per qualcosa di molto più grande , come 10000 o meglio 100000 (come ho fatto io per il test).
Inoltre, è possibile correggere l'errore "CPUPROFILE_FREQUENC=10000
" per correggere CPUPROFILE_FREQUENCY
(notare lo Y
). Devo dire che 10000 è un'impostazione troppo alta per CPUPROFILE_FREQUENCY, perché di solito può generare solo 1000 o 250 eventi al secondo a seconda della configurazione del kernel CONFIG_HZ
(la maggior parte dei kernel 3.x ha 250, controllare grep CONFIG_HZ= /boot/config*
). E l'impostazione per CPUPROFILE_FREQUENCY in pprof di default è 100.
ho provato diversi valori di CPUPROFILE_FREQUENCY: 100000, 10000, 1000, 250 con script bash su Ubuntu 14.04
for a in 100000 100000 10000 10000 1000 1000 300 300 250 250; do
echo -n "$a ";
CPUPROFILE_FREQUENCY=$a CPUPROFILE=dump$a.txt ./test >/dev/null;
done
E i risultati sono stati gli stessi 120-140 eventi e tempo di esecuzione di ogni ./test intorno 0.5 secondi, in modo da cpuprofiler google-perftools non possono fare più eventi al secondo per singolo thread, che insieme CONFIG_HZ nel kernel (il mio ne ha 250).
100000 PROFILE: interrupts/evictions/bytes = 124/1/6584
100000 PROFILE: interrupts/evictions/bytes = 134/0/7864
10000 PROFILE: interrupts/evictions/bytes = 125/0/7488
10000 PROFILE: interrupts/evictions/bytes = 123/0/6960
1000 PROFILE: interrupts/evictions/bytes = 134/0/6264
1000 PROFILE: interrupts/evictions/bytes = 125/2/7272
300 PROFILE: interrupts/evictions/bytes = 137/2/7984
300 PROFILE: interrupts/evictions/bytes = 126/0/7216
250 PROFILE: interrupts/evictions/bytes = 123/3/6680
250 PROFILE: interrupts/evictions/bytes = 137/2/7352
con a = 1000 foo
e cout delle funzioni originali corre troppo veloce per ottenere ogni caso profilazione (anche su 250 eventi/s) su di essi in ogni corsa, in modo da avere nessun foo
, né le funzioni di Input/Output . In piccola quantità di piste, il __write_nocancel
può ottenuto evento di campionamento, quindi foo
e I/formare funzioni O libstdC++ saranno segnalati (da qualche parte non nella parte superiore, in modo da utilizzare --text
possibilità di pprof
o google-pprof
) con conteggio degli eventi pari a zero di sé, e conteggio degli eventi non-zero bambino:
....
1 0.9% 99.1% 1 0.9% __write_nocancel
....
0 0.0% 100.0% 1 0.9% _IO_new_file_overflow
0 0.0% 100.0% 1 0.9% _IO_new_file_write
0 0.0% 100.0% 1 0.9% __GI__IO_putc
0 0.0% 100.0% 1 0.9% foo
0 0.0% 100.0% 1 0.9% new_do_write
0 0.0% 100.0% 1 0.9% std::endl
0 0.0% 100.0% 1 0.9% std::ostream::put
Con a=100000
, foo è ancora troppo breve e veloce per ottenere propri eventi, ma funzioni di I/O ha ottenuto diversi. Questa è la lista che grepped dalla lunga --text
uscita:
34 24.6% 24.6% 34 24.6% __write_nocancel
1 0.7% 95.7% 35 25.4% __GI__IO_fflush
1 0.7% 96.4% 1 0.7% __GI__IO_putc
1 0.7% 97.8% 2 1.4% std::operator<<
1 0.7% 98.6% 36 26.1% std::ostream::flush
1 0.7% 99.3% 2 1.4% std::ostream::put
0 0.0% 100.0% 34 24.6% _IO_new_file_sync
0 0.0% 100.0% 34 24.6% _IO_new_file_write
0 0.0% 100.0% 40 29.0% foo
0 0.0% 100.0% 34 24.6% new_do_write
0 0.0% 100.0% 2 1.4% std::endl
funzioni con zero propri contatori visibili solo grazie alla pprof
capacità di catene leggere di chiamata (si sa che chiama le funzioni che ha ottenuto campione, se informazioni telaio non viene omesso) .
posso anche consigliare più capaci più moderne, (sia software che hardware eventi, fino a 5 kHz o più; sia in user-space e kernel profilazione) e profiler meglio supportato, il Linux perf
profiler (tutorial from its authors, wikipedia) .
Non ci sono risultati da perf
con a=10000
:
$ perf record ./test3 >/dev/null
... skip some perf's spam about inaccessibility of kernel symbols
... note the 3 kHz frequency here VVVV
Lowering default frequency rate to 3250.
Please consider tweaking /proc/sys/kernel/perf_event_max_sample_rate.
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.078 MB perf.data (~3386 samples) ]
Per vedere rapporto di testo da file di output perf.data
userò meno (perché perf report
da inizio di default del browser profilo interattivo):
$ perf report |less
... skip some extra info about the machine, kernel, and perf starting command
# Samples: 1K of event 'cycles'
# Event count (approx.): 1155264208
# Overhead Command Shared Object Symbol
41.94% test3 libm-2.19.so [.] __tan_sse2
16.95% test3 libm-2.19.so [.] __sin_sse2
13.40% test3 libm-2.19.so [.] __cos_sse2
4.93% test3 test3 [.] bar()
2.90% test3 libc-2.19.so [.] __GI___libc_write
....
0.20% test3 test3 [.] foo()
Oppure perf report -n | less
per visualizzare contatori evento (campione) non elaborati:
# Overhead Samples Command Shared Object
41.94% 663 test3 libm-2.19.so [.] __tan_sse2
16.95% 268 test3 libm-2.19.so [.] __sin_sse2
13.40% 212 test3 libm-2.19.so [.] __cos_sse2
4.93% 78 test3 test3 [.] bar()
2.90% 62 test3 libc-2.19.so [.] __GI___libc_write
....
0.20% 4 test3 test3 [.] foo()
Hai detto che hai provato "CPUPROFILE_FREQUENC = 10000" ma che manca una Y, quindi se reale (e ignorato) allora potresti non avere abbastanza campioni per far apparire il piccolo foo. – mgkrebbs
Stai guardando il tempo della CPU, non il tempo dell'orologio. La quantità di tempo CPU 'foo' usata è quasi nulla. Tutto ciò che fa è chiamare le funzioni di libreria che eseguono l'I/O e gli esempi di CPU non si verificano durante l'I/O. –