C ++ utilizzando Intrinsics in un modo multipiattaforma

3

Ho una libreria matematica multipiattaforma su cui sto lavorando e voglio assicurarmi che alcune operazioni comuni vengano eseguite in modo ottimizzato, quindi desidero utilizzare alcune funzioni intrinseche racchiuse in funzioni inline per calcolare cose come sqrt (float / double). Devo dire che a questo punto ho intenzione di indirizzare solo alcune piattaforme selezionate che sono menzionate nella fonte qui sotto.

Ho avviato un singolo prototipo della funzione sqrt () ma prima di procedere ulteriormente desidero sapere se sto facendo qualcosa di assolutamente sbagliato.

Sto seguendo la documentazione a: link
link

Inoltre, noterai che ho una riga vuota sotto la libbra definita per macintosh. So che le versioni più recenti stanno usando clang / llvm. Come si ottiene l'accesso alle funzioni intrinseche nelle versioni più recenti di mac os e dei relativi compilatori?

#ifndef INTRINSICS_H_INCLUDED
#define INTRINSICS_H_INCLUDED

#if defined(_WIN32)
#elif defined(__gnu_linux__) || defined(__linux__)
#elif defined(__ANDROID__)
#elif defined(__CYGWIN__)
#elif defined(macintosh)
#else
#include <cmath>
#endif

#if defined(_WIN32)
#pragma function( sqrt )
#endif
template<typename T>
inline float sqrt(T &val)
{
#if defined(_WIN32)
  return sqrt(val);
#elif defined(__gnu_linux__) || defined(__linux__)
  return __builtin_sqrt(val);
#elif defined(__ANDROID__)
  return __builtin_sqrt(val);
#elif defined(__CYGWIN__)
  return __builtin_sqrt(val);
#elif defined(macintosh)
  // How do I do this
#else
  return std::sqrt(val);
#endif
}
#if defined(_WIN32)
#pragma function( sqrt )
#endif
#endif
    
posta Matthew Hoggan 30.05.2013 - 07:01
fonte

2 risposte

3

Vorrei iniziare con una retorica.

Se esiste un'implementazione superiore che non ha alcun compromesso negativo, perché le librerie standard non sono già in uso?

Non è una questione di ottimizzazione prematura, se la funzione viene utilizzata in una libreria di elaborazione matematica o di grandi dati in cui i guadagni in termini di prestazioni saranno moltiplicati per milioni o miliardi. Un primo esempio è la libreria OpenCV, in cui i guadagni in termini di prestazioni, anche se solo poche percentuali qua e là, si traducono in un reciproco aumento del numero di frame video elaborati al secondo. Diamo un'occhiata all'implementazione della radice quadrata in OpenCV.

link

Sommario:

  • Se il chiamante è interessato al reciproco della radice quadrata, vai dritto per quello.
  • Se il chiamante è interessato a confrontare le grandezze di due valori dopo aver preso radice quadrata su ognuno, prova ad eliminare quel passo radice quadrata (con qualche logica aggiuntiva).
  • Se il chiamante è interessato a calcolare le radici quadrate (oi loro reciproci) per un array di valori, usa gli equivalenti SIMD.
  • Altrimenti, torna a std::sqrt .

  • (Edited)

    • Se il chiamante ha bisogno solo della approssimativa approssimativa della radice quadrata, consulta l'argomento Wikipedia su questo argomento. (Questo argomento è così vasto che non è possibile riassumere qui.)

Modifica

Resto corretto (per la risposta di dan04) da alcune omissioni importanti della mia risposta originale.

  • Il compilatore deve essere detto all'architettura della CPU di destinazione.
  • Il compilatore deve essere detto per favorire la velocità rispetto alla precisione
  • Il compilatore deve essere autorizzato ad omettere i controlli dell'intervallo di input
    • Esempio: sqrt viene compilato in una libreria chiamare
      • In questo esempio, la funzione di libreria convalida che il valore di input non è negativo. Se lo è, chiama un gestore di errori, che quindi genera un'eccezione C ++. Questi comportamenti aggiuntivi rendono impossibile omettere la chiamata alla libreria.
  • La CPU ha bisogno di essere informata su flush-to-zero e di trattare denormals-as-zero
    • Questo è fatto in fase di runtime.

(Sto dando esempi in MSVC, ma anche altri compilatori dovrebbero essere esplicitamente informati per generare codice veloce.)

Poiché queste sono opzioni del compilatore, devono essere specificate nel makefile, non nel codice sorgente.

Suggerimento:

Potrebbe essere necessario utilizzare un'utility di configurazione makefile come CMake per verificare il supporto del compilatore e l'ottimalità dei vari componenti intrinseci (e per utilizzare la versione più veloce disponibile su quella piattaforma).

Dettagli matematici:

C'è un lungo articolo su Wikipedia sui metodi di calcolo delle radici quadrate e le sue approssimazioni approssimative, incluso il "trucco di Carmack" inventato da Walsh e Tarolli.

Alcune di queste tecniche sono adatte all'implementazione VLSI. Se è così, è tipico che siano già impiegati in moderne CPU generiche. Alcune di queste funzioni accelerate richiedono che il chiamante effettui uno o più metodi di Newton o l'iterazione di Goldschmidt per convergere da una stima iniziale.

    
risposta data 31.05.2013 - 03:27
fonte
1

Invece di ingombrare il codice sorgente con tutte queste macro, potresti utilizzare i flag di ottimizzazione, come /Oi in MSVC ++, per fare in modo che i compilatori eseguano questa ottimizzazione per te.

    
risposta data 31.05.2013 - 05:06
fonte

Leggi altre domande sui tag