Interpretazione dei risultati del profilo

6

Sto praticando algoritmo e strutture dati. Pertanto, continuo a profilare i miei programmi. Ecco un esempio di output di gprof:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total           
 time   seconds   seconds    calls  ns/call  ns/call  name    
 29.76      2.58     2.58                             _IO_vfscanf_internal
 14.30      3.82     1.24                             ____strtof_l_internal
 11.71      4.84     1.02                             memcpy
  7.84      5.52     0.68  8400000    80.95    80.95  insertorupdate
  5.94      6.03     0.52                             _int_malloc
  5.77      6.53     0.50                             round_and_return
  3.81      6.86     0.33                             _IO_sputbackc
  3.23      7.14     0.28                             strlen
  2.88      7.39     0.25                             __strcmp_ia32
  2.13      7.58     0.19                             __isoc99_scanf
  2.13      7.76     0.19                             fgets
  2.02      7.94     0.18                             _IO_getline_info
  1.27      8.05     0.11                             __mpn_lshift
  1.21      8.15     0.11                             __memchr_sse2_bsf
  0.87      8.23     0.08                             malloc
  ... rest ...

Ma ho trovato difficile capire cosa significhi. Ad esempio, il mio programma impiega molto tempo in funzioni standard, immagino che dovrebbe essere buono, giusto? Perché, se una delle mie funzioni stesse consumando la maggior parte del tempo, ciò poteva significare che stavo facendo qualcosa di sbagliato. Ma come ho detto, non sono sicuro di interpretarlo correttamente, quindi qualsiasi suggerimento o suggerimento per leggerlo è il benvenuto.

    
posta yasar 02.05.2012 - 01:06
fonte

4 risposte

5

Non è buono né cattivo.

Immagina di dirti che trascorro 45 minuti per viaggiare dal punto A al punto B. È veloce? È lento? Significa che passo troppo tempo? O no? Finché non dico qual è il punto A, qual è il punto B, e quali sono le mie aspettative di velocità, non puoi dire nulla.

I risultati del profiler sono simili. Non ti dicono che qualcosa è assolutamente sbagliato o se il tuo codice è perfetto per le prestazioni. Ti mostrano solo risultati non elaborati, che ti consentono di interpretarli e studiarli.

Potresti avere un caso valido in cui uno dei tuoi metodi impiegherà molto tempo a fare qualcosa, perché, beh, ci si aspetta che passi una grande quantità di tempo, dal momento che ha molto lavoro da fare. O forse è un segno che devi ottimizzare questa parte del codice, perché ti aspettavi che questo metodo fosse almeno mille volte più veloce di quanto sia in realtà.

Il profilo aiuta a darti alcuni suggerimenti. I profiler SQL, in questo modo, sono forse facili da capire:

  • Se vedi che quando carichi una pagina web, la tua applicazione web invia la stessa identica query con gli stessi identici parametri dieci volte, probabilmente c'è qualcosa di sbagliato nel tuo codice, perché dovresti fare la query una sola volta.

  • Se vedi che durante il caricamento di una pagina web, una semplice query impiega 1,2 secondi, mentre ci si aspetta che impieghi qualche millisecondo, c'è un buon segno che tu o i tuoi colleghi avete dimenticato un indice su un tavolo o ha fatto qualcosa di sbagliato con la query.

Allo stesso modo, i profiler del codice:

  • Mostra che lo stesso metodo viene chiamato ancora e ancora: a volte, questo è quello che vuoi. A volte può indicare un bug.

  • Mostra il tempo trascorso da un metodo. A seconda del caso, è previsto o c'è un bug.

Questo significa che lo scopo di un profiler non è quello di dire che il tuo codice è buono o cattivo, - questo è ciò di cui sono requisiti i test di accettazione -, ma per identificare i colli di bottiglia quando fallisci soddisfare uno dei requisiti non funzionali relativi alle prestazioni.

    
risposta data 02.05.2012 - 02:31
fonte
4

In questo caso, quello che ti sta dicendo è che (come è attualmente scritto) il tuo programma sta passando la maggior parte del tempo a fare I / O. Le prime due funzioni sembrano essere coinvolte nella semplice lettura dei dati da un file.

La parte che sarebbe (o almeno potrebbe) disturbare un po 'è memcpy il terzo più alto, consumando quasi il 12% delle volte. Questa potrebbe essere anche (una parte più o meno inevitabile) della lettura dell'input, ma se la stai usando direttamente, potresti voler dare un'occhiata dove e quanto la stai usando per vedere se puoi lasciare i dati nello stesso posto di più, e (per esempio) ridisporre i puntatori ad esso piuttosto che spostare blocchi di dati in giro (ma tieni presente che anche nel migliore dei casi questo migliorerà solo la velocità di meno del 12%).

Per quanto riguarda le strutture dati e gli algoritmi, questo ti dice che sono (apparentemente) abbastanza veloci da contribuire poco al tempo di esecuzione complessivo. Il posto più importante da guardare è l'I / O. Dall'aspetto delle cose, la maggior parte del tempo viene speso in una chiamata a fscanf (o uno dei suoi cugini) facendo una conversione in virgola mobile. Se ti interessasse la velocità generale (non solo gli algoritmi che hai scritto), una ovvia possibilità sarebbe quella di archiviare quei dati in formato binario per evitare la conversione da stringa a binario.

    
risposta data 02.05.2012 - 13:19
fonte
1

Se stai lavorando con algoritmi e stai cercando di mostrare il comportamento di big-O, è meglio contare le operazioni di base, come i confronti o le allocazioni di memoria.

Quello che stai vedendo nel tuo output gprof è che il tuo programma spende la maggior parte del suo tempo per leggere gli input. E questo è solo il tempo di CPU sbloccato. Non conta il tempo I / O, anche se lo stai ancora aspettando. (E I / O è anche il tempo della CPU, solo con una CPU diversa.) Se contasse anche il tempo di I / O, vedresti una frazione ancora più grande in quel codice.

gprof stima per quanto tempo ogni routine ha tenuto il contatore del programma. Conta anche quante volte ogni routine è stata chiamata l'una dall'altra. Da ciò prova a capire quanto tempo sia stato responsabile di ogni routine, nel senso di passare il tempo o di dedicare del tempo. Il modo in cui calcola questo è pieno di problemi, come gli autori originali hanno ammesso liberamente, e sostanzialmente è rimasto così per 30 anni. È venerabile, ma non ti dirà molto di cui puoi contare.

    
risposta data 08.05.2012 - 03:43
fonte
0

In genere troverei inutile il profiling basato su sample della CPU se il profiler non includesse un modo per passare da un chiamato all'altro. In genere i tuoi hotspot migliori spesso non sono le funzioni che devono essere effettivamente ottimizzate. Sono le funzioni che li chiamano uno o due livelli in meno.

Come esempio recente, ho ottenuto una sessione in cui l'hotspot principale era una funzione di confronto tra un paio di numeri interi. Non c'è quasi alcun valore nel cercare di ottimizzarlo. Tuttavia, quando ho eseguito il drill down verso il chiamante, ho scoperto che era una chiamata qsort applicata a una parte del sistema che veniva invocata frequentemente. Ho sostituito qsort con std::sort di C ++, riducendo il tempo per l'operazione di fine utente totale da 4 secondi a 2, quindi un ordinamento digitale e le volte ridotte da circa 2 secondi a 1,2 secondi.

Un altro esempio che ho incontrato nelle codebase passate è stato vedere malloc come uno dei principali hotspot. Sarebbe estremamente controproducente pensare che sia necessario un allocatore di memoria generico più veloce. Invece la domanda dovrebbe essere il motivo per cui il codebase sta eseguendo così tante allocazioni dell'heap, e tipicamente saranno teeny se malloc è un enorme hotspot. Quindi, è possibile eseguire il drill down al chiamante che impiega più tempo ad allocare memoria attraverso malloc e vedere se è possibile, ad esempio, allocare grandi blocchi di memoria in anticipo e riunire la memoria pre-allocata. Altre volte potrebbe essere semplice come utilizzare lo stack per scenari di casi comuni quando i dati si adattano e si utilizza l'heap solo in quei rari casi in cui i dati non si adattano allo stack.

In ogni caso, per interpretare i risultati del profilo, è spesso necessario essere in grado di eseguire il drill down da chiamata a chiamata. Il vero colpevole di solito non è il "calle", ma uno o due livelli nello stack delle chiamate.

    
risposta data 17.12.2017 - 06:44
fonte

Leggi altre domande sui tag