In che misura il generico e la meta-programmazione utilizzando modelli C ++ sono utili nella scienza computazionale?


17

Il linguaggio C ++ fornisce una programmazione e una metaprogrammazione generiche attraverso modelli. Queste tecniche hanno trovato la loro strada in molti pacchetti di calcolo scientifico su larga scala (ad esempio, MPQC , LAMMPS , CGAL , Trilinos ). Ma cosa hanno effettivamente contribuito al calcolo scientifico in un valore che va oltre i linguaggi non generici e non meta come C o Fortran in termini di tempo di sviluppo complessivo e usabilità per un'efficienza uguale o adeguata?

Dato un compito di calcolo scientifico, i modelli generici e di meta-programmazione tramite modelli C ++ hanno dimostrato un miglioramento della produttività, espressività o usabilità misurati da qualsiasi benchmark ben compreso (righe di codice, sforzo personale, ecc ...)? Di conseguenza, quali rischi sono associati all'uso di modelli C ++ per la programmazione generica e la metadoprogrammazione?


Sono preoccupato che questa domanda possa essere troppo aperta alle opinioni, ma voglio vedere cosa dicono le persone nella comunità.
Geoff Oxberry,

1
Ho completamente cancellato il commento deragliare. Se desideri che venga ripubblicato in chat o meta, sono felice di farlo. Vedi il mio meta qui .
Aron Ahmadia,

3
Inoltre, vedere la domanda correlata qui sui consigli su quando utilizzare e quando evitare i modelli di espressione .
Aron Ahmadia,

Non credo sia corretto affermare che LAMMPS utilizza modelli o metaprogrammi. LAMMPS è un codice orientato agli oggetti che assomiglia molto a Fortran per la maggior parte del tempo. Non penso nemmeno che MPQC abbia molti modelli, ma è fortemente orientato agli oggetti e polimorfico.
Jeff,

1
OpenFOAM fa ampio uso di modelli e altre funzionalità di C ++.
Dohn Joe,

Risposte:


14

Penso che in generale la metaprogrammazione dei modelli sia risultata inutilizzabile in pratica: si compila troppo lentamente e i messaggi di errore che riceviamo sono semplicemente impossibili da decifrare. La barriera all'ingresso per i nuovi arrivati ​​è anche troppo elevata quando si utilizza la metaprogrammazione.

Naturalmente, la programmazione generica è un problema completamente diverso, come testimoniato da Trilinos, deal.II (la mia biblioteca), DUNE e molte altre biblioteche - esprimere lo stesso concetto operando su tipi di dati diversi è una specie di gioco da ragazzi, e la comunità lo ha ampiamente accettato fintanto che rimane entro limiti che evitano i problemi della metaprogrammazione. Penso che la programmazione generica si qualifichi come un evidente successo.

Naturalmente, nessuno di questi argomenti è immediatamente collegato a OOP. OOP, ancora una volta, direi, universalmente accettato dalla comunità scientifica informatica. Ancor meno della programmazione generica, non è un argomento di dibattito: ogni libreria di successo scritta negli ultimi 15 anni (sia essa scritta in C ++, C o Fortran) utilizza tecniche OOP.


4
tmp può essere difficile per gli utenti alle prime armi, ma spesso viene eseguito molto bene all'interno della libreria. È una di quelle tecniche che possono davvero ridurre la quantità di codice ma devi davvero sapere cosa stai facendo. Se non mi credi vai a leggere la fonte di Eigen o Elemental. Il suo bellissimo codice che senza modelli sarebbe praticamente impossibile.
Aterrel,

5
Certo, è una tecnica con valore. Ma è difficile da mantenere ed è spesso difficile da usare se esposto all'interfaccia esterna. Detto questo, penso che uno dei motivi per cui TMP non è stato del tutto il successo che la gente inizialmente si sarebbe aspettato è che i compilatori sono diventati molto buoni. TMP vive del fatto che molte cose sono note al momento della compilazione e possono quindi essere propagate come costanti nel codice reale. Ma i compilatori sono diventati abbastanza bravi nell'inline, nella clonazione di funzioni, ecc., E oggi una parte significativa del vantaggio può essere ottenuta usando una programmazione "normale".
Wolfgang Bangerth,

15

Vorrei fare un esempio basato sull'esperienza. La maggior parte delle biblioteche che utilizzo quotidianamente utilizzano OOP in qualche modo. OOP è in grado di nascondere la complessità richiesta per molti domini, non è un meccanismo che aiuta davvero con le prestazioni. Ciò che può accadere è che una libreria è in grado di utilizzare ottimizzazioni specifiche basate sulla gerarchia degli oggetti, ma per la maggior parte si tratta di nascondere la complessità all'utente. Cerca i modelli di progettazione, sono i meccanismi spesso impiegati per realizzare questo nascondiglio di complessità.

Prendi PETSc come esempio. PETSc utilizza un modello ispettore / esecutore di OOP in cui uno qualsiasi dei suoi algoritmi esamina le routine disponibili in un determinato oggetto e sceglie quale eseguire per eseguire la routine. Ciò consente all'utente di separare le preoccupazioni, ad esempio l'azione della matrice può includere qualsiasi tipo di routine bloccata o ottimizzata ed essere efficacemente utilizzata da numerosi solutori iterativi. Dando all'utente la possibilità di specificare i propri tipi di dati e valutazioni, ottengono alcune routine importanti accelerate e hanno anche l'intera funzionalità della libreria ancora disponibile.

Un altro esempio che darò è FEniCS e deal.II. Entrambe queste librerie usano OOP per generalizzare un gran numero di metodi agli elementi finiti. In entrambi gli elementi, il tipo di elemento, l'ordine degli elementi, la rappresentazione in quadratura e così via sono intercambiabili. Sebbene entrambe queste librerie siano "più lente" di alcuni codici FEM strutturati per scopi speciali, sono in grado di risolvere un'ampia varietà di problemi con gran parte della complessità della FEM sconosciuta all'utente.

Il mio ultimo esempio è Elementale. Elemental è una nuova densa libreria di algebra lineare che ha portato la difficoltà di gestire i comunicatori MPI e la posizione dei dati in un costrutto linguistico molto semplice. Il risultato è che se si dispone di un codice seriale FLAME, modificando i tipi di dati è possibile anche avere un codice parallelo tramite Elemental. Ancora più interessante puoi giocare con la distribuzione dei dati impostando una distribuzione uguale a un'altra.

OOP dovrebbe essere pensato come un modo per gestire la complessità, non un paradigma per competere con l'assemblaggio laminato a mano. Anche farlo in modo inadeguato comporterà un sacco di sovraccarico, quindi è necessario mantenere i tempi e aggiornare i meccanismi con cui lo usano.


3

Ciò che le funzioni linguistiche come OOPfanno per il calcolo scientifico è rendere le dichiarazioni di codice più compatte che aiutano a comprendere e usare meglio il codice. Ad esempio, le FFTroutine devono contenere un gran numero di argomenti per ogni chiamata di funzione rendendo il codice ingombrante.

Utilizzando moduleo le classistruzioni solo ciò che è necessario al momento della chiamata può essere passato, poiché il resto degli argomenti si riferisce alla configurazione del problema (cioè dimensione delle matrici e coefficienti).

Nella mia esperienza, ho ricevuto SUBROUTINEchiamate con 55 argomenti (in & out) e l'ho ridotto a 5 rendendo il codice migliore.

Questo è un valore.


3

Sono un forte sostenitore della programmazione generica e della meta-programmazione per il calcolo scientifico. In realtà sto sviluppando una libreria di software C ++ gratuita per i metodi Galerkin basati su queste tecniche denominate Feel ++ (http://www.feelpp.org), che sta prendendo costantemente slancio. È vero che ci sono ancora difficoltà come tempi di compilazione lenti e che la curva di apprendimento potrebbe essere ripida se si vuole capire cosa sta succedendo dietro la scena. Questo è comunque estremamente interessante e strabiliante. Se fatto a livello di libreria e nascondendo la complessità dietro un linguaggio specifico di dominio, otterrai uno strumento estremamente potente. Abbiamo a disposizione una gamma molto ampia di metodi da utilizzare e confrontare. Ai fini dell'insegnamento dell'informatica scientifica questo è fantastico, anche per la ricerca e nuovi metodi numerici, per applicazioni su larga scala, bene ci lavoriamo ma finora tutto bene, possiamo già fare delle cose carine. Abbiamo ingegneri, fisici e matematici che lo usano: la maggior parte di loro usa il linguaggio solo per la formulazione variazionale e ne è contento. Osservando alcune delle formulazioni manipolate dai nostri colleghi fisici, non vorrei vederle fatte "a mano" senza un linguaggio di alto livello per descrivere la formulazione variazionale. Personalmente ritengo che queste "tecniche" o "paradigmi" siano ora necessarie per affrontare la complessità del codice di calcolo scientifico con la necessità di moltiplicare le dimensioni del codice per un fattore enorme. Probabilmente è necessario migliorare il supporto della meta-programmazione in C ++, ma è già in buona forma, specialmente da C ++ 11.


2

Potresti trovare il documento http://arxiv.org/abs/1104.1729 pertinente alla tua domanda. Discute i modelli di espressione (una particolare applicazione della meta-programmazione di modelli utilizzata nel codice scientifico) dal punto di vista delle prestazioni.


Quel documento mi fa impazzire. Confronta il Fortran semplice più veloce che hai con MKL e perderà. L'assemblaggio accordato a mano non è qualcosa a cui aspiriamo, è ciò che fai quando ogni nanosecondo conta e può essere riutilizzato da un numero molto elevato di persone.
Aterrel,

@aterrel: questo è esattamente il contrasto che mi chiedo. Sapendo che dovrai fare l'ottimizzazione manuale come ultima fase di sviluppo, quale lingua sceglieresti come base da utilizzare prima dell'ultima fase? Disponiamo di dati concreti per suggerire quale lingua scegliere?
Deathbreath,

9
@Deathbreath: ripeterò una risposta che ho fatto anche su molti altri thread - che nel complesso, ottimizzare l'ultimo bit di velocità dal tuo codice è qualcosa che fai molto raramente. Ma programmi algoritmi di alto livello in ogni momento. Quindi scegli la lingua che ti consente di fare rapidamente le cose grandi. C'è sempre un modo per includere cose di basso livello in qualche modo, ma non dovrebbe essere la cosa che determina la tua scelta del linguaggio di programmazione.
Wolfgang Bangerth,

0

I modelli sono molto bravi a rimuovere i controlli di tipo / dominio in fase di esecuzione. Questi possono essere curati al momento della compilazione. In teoria, ciò può aumentare le prestazioni rispetto allo stesso tipo di implementazione in C o Fortran in cui il controllo del tipo può essere eseguito solo in fase di esecuzione - i controlli sono implementati nel codice sorgente. Tuttavia, puoi ottenere gli stessi risultati in C usando le opzioni del precompilatore, ma queste devono essere fatte a mano a differenza dei modelli.

Tuttavia, i modelli possono anche generare un notevole sovraccarico. Spesso possono creare un eccesso di codice che può influire sull'uso della cache delle istruzioni. Inoltre, gli approcci generici possono spesso incatenare il compilatore durante l'ottimizzazione: non è sempre semplice per l'analisi del codice quando si utilizzano approcci generici. È sempre un problema con l'automazione, inclusa l'ottimizzazione del compilatore, molto spesso il codice di output non è compatibile con la cache.

I vantaggi del controllo del tipo / dominio, sebbene certamente più sicuri, sono l'unico vero vantaggio che posso vedere in termini di prestazioni e questi sono generalmente impercettibili. Ma come ho detto, l'effetto complessivo può essere negativo a seconda di ciò che stai facendo. Ecco perché è spesso meglio ottimizzare manualmente il codice in presenza di colli di bottiglia significativi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.