2010-10-29 7 views
35

Prima di leggere la domanda:
Questa domanda non riguarda quanto sia utile usare dynamic_cast. È solo per le sue prestazioni.Prestazioni di dynamic_cast?

Ho recentemente sviluppato un progetto in cui viene utilizzato molto il dynamic_cast.
Quando si parla con i colleghi, quasi tutti dicono che lo dynamic_cast non deve essere utilizzato a causa delle sue cattive prestazioni (si tratta di colleghi con background diversi e in alcuni casi non si conoscono. società enorme)

Ho deciso di testare le prestazioni di questo metodo invece di crederci.

Il seguente codice è stato utilizzato:

ptime firstValue(microsec_clock::local_time()); 

ChildObject* castedObject = dynamic_cast<ChildObject*>(parentObject); 

ptime secondValue(microsec_clock::local_time()); 
time_duration diff = secondValue - firstValue; 
std::cout << "Cast1 lasts:\t" << diff.fractional_seconds() << " microsec" << std::endl; 

Il codice sopra usa metodi da boost::date_time su Linux per ottenere i valori utilizzabili.
Ho eseguito 3 dynamic_cast in un'unica esecuzione, il codice per misurarli è lo stesso.

I risultati di 1 esecuzione sono stati i seguenti:
Cast1 dura: 74 microsec
Cast2 dura: 2 microsec
Cast3 dura: 1 microsec

Il primo getto sempre prese 74-111 microsec, il seguente i calchi nella stessa esecuzione richiedevano 1-3 microsec.

Quindi finalmente le mie domande:
dynamic_cast si comporta davvero male?
Secondo il test, non lo è. Il mio codice test è corretto?
Perché così tanti sviluppatori pensano che sia lento se non lo è?

+13

Mi manca qualcosa? Non riesco a vedere alcun codice per cast2 o cast3. – Flexo

+4

Chi può dire cosa c'è di male? Il tuo programma funziona abbastanza bene? Se è così, allora le prestazioni non sono male. Il tempo totale in versioni dinamiche è una grande percentuale del tempo di esecuzione? In caso contrario, preoccupati prima di altre cose. Più in generale, 74 microsecondi sono terribilmente lenti per alcune applicazioni: nel mio ultimo lavoro, avrei ricevuto e analizzato un intero record di aggiornamento dalla borsa, aggiornato il database e detto alle app client in tempo reale. Se sei interessato, confrontalo con altri modi per ottenere lo stesso comportamento. –

+3

Avere molti dynamic_cast nel codice è un indicatore sicuro dei problemi di progettazione. –

risposta

42

In primo luogo, è necessario misurare le prestazioni molto più di poche iterazioni, poiché i risultati saranno dominati dalla risoluzione del timer. Prova ad es. 1 milione +, al fine di costruire un'immagine rappresentativa. Inoltre, questo risultato non ha senso se non lo paragoni a qualcosa, cioè facendo l'equivalente ma senza il lancio dinamico.

In secondo luogo, è necessario assicurarsi che il compilatore non fornisca risultati falsi, ottimizzando lo spostamento di più stringhe dinamiche sullo stesso puntatore (quindi utilizzare un ciclo, ma utilizzare un puntatore di input diverso ogni volta).

Il lancio dinamico sarà più lento, poiché è necessario accedere alla tabella RTTI (informazioni sul tipo di esecuzione) per l'oggetto e verificare che il cast sia valido. Quindi, per usarlo correttamente, dovrai aggiungere un codice di gestione degli errori che controlli se il puntatore restituito è NULL. Tutto ciò richiede cicli.

So che non volevi parlare di questo, ma "un disegno dove dynamic_cast è molto utilizzato" è probabilmente un indicatore che si sta facendo qualcosa di sbagliato ...

+5

+1, ma le iterazioni di 10K probabilmente non sono sufficienti. Qualcosa come 100 milioni è meglio. – sharptooth

+0

@sharptooth: punto giusto! –

+0

@Oliver Charlesworth "... per poterlo utilizzare correttamente, è necessario aggiungere un codice di gestione degli errori che controlli se il puntatore restituito è NULL" Una versione analoga del controllo che si menziona è presente in ogni metodo di ricerca del tipo di runtime di un oggetto quindi questo non è un argomento. – spectre

24

prestazioni non ha senso senza confrontando funzionalità equivalente. Molte persone dicono che dynamic_cast è lento senza paragonarsi a un comportamento equivalente. Chiamali su questo. Detto in altro modo:

Se "funziona" non è un requisito, posso scrivere codice che non riesce più veloce del tuo.

Esistono vari modi per implementare dynamic_cast e alcuni sono più veloci di altri. Stroustrup ha pubblicato un articolo sull'utilizzo di primes to improve dynamic_cast, ad esempio. Sfortunatamente è inusuale controllare il modo in cui il compilatore implementa il cast, ma se le prestazioni sono davvero importanti per te, allora hai il controllo su quale compilatore usi.

Tuttavia, che non utilizzano dynamic_cast sarà sempre essere più veloce di usarlo - ma se non lo fai effettivamente bisogno dynamic_cast, quindi non lo uso! Se hai bisogno di una ricerca dinamica, allora ci sarà un sovraccarico e potrai quindi confrontare varie strategie.

+4

+1. Sì, ogni persona vivente alla fine muore. Ciò non significa che sia una cattiva idea essere vivi. – sharptooth

4

Mi dispiace dirlo, ma il test è praticamente inutile per determinare se il cast è lento o no. La risoluzione del microsecondo non è mai abbastanza buona. Stiamo parlando di un'operazione che, anche nel peggiore dei casi, non dovrebbe richiedere più di 100 tick dell'orologio o meno di 50 nanosecondi su un PC tipico.

Non c'è dubbio che il cast dinamico sarà più lento di un cast statico o di un cast reinterpretato, perché, a livello di assembly, gli ultimi due ammonteranno a un compito (molto veloce, l'ordine di 1 tick dell'orologio), e il cast dinamico richiede il codice per andare e ispezionare l'oggetto per determinare il suo tipo reale.

Non posso dire fuori mano quanto sia lento, che probabilmente varierebbe dal compilatore al compilatore, avrei bisogno di vedere il codice assembly generato per quella riga di codice. Ma, come ho detto, 50 nanosecondi per chiamata è il limite massimo di ciò che si aspetta essere ragionevole.

+0

dynamic_cast deve accedere a RTTI, questo richiederà dei cicli. – doron

16

Ecco alcuni punti di riferimento:
http://tinodidriksen.com/2010/04/14/cpp-dynamic-cast-performance/
http://www.nerdblog.com/2006/12/how-slow-is-dynamiccast.html

Secondo loro, dynamic_cast è 5-30 volte più lento di reinterpret_cast, e la migliore alternativa esegue quasi la stessa di reinterpret_cast.

citerò la conclusione dal primo articolo:

  • dynamic_cast è lento per tutto tranne la fusione per il tipo di base; che particolare fusione è ottimizzata su
  • livello ereditarietà ha un grande impatto sulla dynamic_cast
  • variabile membro + reinterpret_cast è il modo più affidabile per
    determinare tipo; tuttavia, che ha molto maggiore manutenzione aerea
    quando si codifica

numeri assoluti sono dell'ordine di 100 ns per un singolo getto. Valori come 74 msec non sembrano vicini alla realtà.

+1

Il valore che stava ottenendo era 74 usec (microsecondi), non 74 msec (millisecondi). Anche così, non sembra realistico. – Ponkadoodle