Programmazione parallela - C

bucanieri,

scrivo spesso simulazioni scientifiche che impiegano qualche giorno di calcoli a cacare fuori un numerello sul mio portatile, su cui c'è la ubuntu col gcc 4.3.3. Dal sistem monitor vedo che il processo a regime impiega il 50% delle risorse CPU, ovvero usa solo un core. Poichè ne ho due volevo splittare i calcolelli su entrambi, da dove parto e chi sa come fare?

Ll.
compra 2 pc da 1 core e falli lavorare su 2 conti diversi! In media, otterrai il risultato voluto!

Boh mi spiace, va ben oltre l'accendere/spegnere computer quindi non so che dirti
Non sono espertissimo ma quando mi ero interessato alla questione ero giunto alle seguenti conclusioni.

Dal punto di vista delle tecniche, quella più semplice, sia dal punto di vista della programmazione all'atto pratico, sia per velocità di apprendimento, è sicuramente OpenMP (http://en.wikipedia.org/wiki/OpenMP). Penso che anche in meno di una giornata dovresti essere in grado di paralellizzare i cicli all'interno del tuo programma. Ovviamente questa semplicità d'uso viene ottenuta a scapito della duttilità del sistema.
I linguaggi supportati sono C/C++ e Fortran (e quindi non dovrebbero esserci problemi visto che suppongo, anche per esperienza personale, che le tue simulazioni siano in uno di questi tre linguaggi) e mi sembra che la tua versione di gcc sia sufficientemente recente da supportarlo senza problemi. Per quanto riguarda la documentazione ci sono dei tutorial sul sito ufficiale e in rete, oltre che un libro famoso che però non ho mai avuto occasione di leggere.
Più complesso è invece l'uso diretto dei POSIX threads (il sistema di base che utilizza OpenMP su piattaforme UNIX - oltre che la stragrande maggioranza del software multi-thread), anche se ovviamente hanno una maggiore versatilità. Se programmi in C dovresti poter utilizzare direttamente la loro interfaccia, mentre, se non ricordo male, per C++ dovrebbe essere disponibile un sistema di gestione all'interno di Boost. Non ho idea invece relativamente al loro utilizzo in programmi Fortran.
Per quanto riguarda la documentazione, quella in rete è estremamente vasta ed approfondita.

Ovviamente ti ricordo anche che non tutti i problemi sono ben paralizzazibili e che è necessario studiare bene la questione prima di gettarsi a scrivere il codice. Anche qui vi sono libri e corsi dedicati a questi problemi. Sicuramente scrivere degli algoritmi paralleli efficienti, e dal punto di vista tecnico e dal punto di vista teorico, non è banale.

Ah, un ultima soluzione, che potremmo definire il "calcolo in parallelo dei poveri" ma che è ancora più immediata, consiste nello strutturare la simulazione in modo che sia possibile lanciare due processi in parallelo (e.g. lancio "simulazione 1-50" e "simulazione 50-100" in due cartelle diverse). Il kernel farà il resto, associando un processo ad ogni processore.

Detto questo (e sperando di non aver scritto idiozie ) lascio la parola a qualcuno sicuramente più dotto di me in materia.
Scusa, non vorrei passare per idiota, ma dici al compilatore che hai dure core? Insomma dai make -J3?
Attento, lui non vuole compilare in parallelo (quello che ottieni con make -j3), vuole fare calcolo parallelo.
grazie ottima risp,

la cosa + naive che mi era venuta in mente infatti era fare una fork e lasciar fare al OS il lavoro sporco (scrivo in C), poi mi è caduto l'occhio su OpenMP. La parallelizzazione che ho in mente è banalissima: poichè devo calcolare delle medie statistiche ripeto un calcolone 500 volte, allora glielo fo fare in parallelo 250 volte su uno e 250 volte su un altro. Mi chiedevo appunto quale fosse la procedura "standard" per usare i nostri dual core, anche xchè mi fa troppo incazzare che roba stralenta tipo mathematica o matlab parallelizzi in automatico arrivando a prestazioni accettabili.

Ll.
Se hai una GPU Nvidia e riesci a sfruttare il CUDA, sei a posto (c'è da parallelizzare con una certa cura ma ottieni dei risultati veramente notevoli)

http://developer.download.nvidia.com/compute/cuda/sdk/website/projects/nbody/doc/nbody_gems3_ch31.pdf

(c'è in giro anche il toolset per matlab )
devi per forza sviluppare in C? perche altrimenti ti consiglio Octave e le sue librerie parallele. Sono una stronzata da far girare, tu in pratica installi octave sulle macchine della tua rete, lanci il processo master sfruttando i metodi delle librerie (il for ad esempio si chiama parfor) e imposti una serie di nodi (==indirizzi ip delle altre macchine nella rete su cui octave + librerie stanno girando) e lui suddivide il carico di lavoro automaticamente (o in alternativa puoi assegnare pezzi di codice ad una macchina piuttosto che un altra). sono molto semplici da usare, le usavo per i project euler che richiedevano brute forcing (usate in maniera spartana riducevo quasi a meta' il tempo di calcolo) e devo dire che sono davvero intrippose! ah tra l'altro, se apri 2-3 (non di piu) istanze di octave sul tuo pc, e usi le librerie parallele chiamandole su localhost, c'e' il modo di fargli abusare dei processori contemporaneamente (googla la guida, e' tosta ma fattibile)

in alternativa ti consiglio le pycuda (pyton + cuda) che pero' sono piu ostiche da settare, nonostante la nVidia dica che siano una passeggiata... usate per un hasher md5 con un mio amico, sembravano rapide, ma dopo un po segfaultavano, quindi non so darti un vero e proprio giudizio...

altra cosa: se hai pc in una lan, perche non usare i socket di C per spedire processi di qua e di la? ci sarebbe anche RMI di java (con la concorrenza dei thread) ma e' un bel casino da impararselo anche quello
Parallelizzo il codice xchè ho bisogno di prestazioni elevate, in questo senso usare matlab (o suoi derivati) o python mi rallenterebbe moltissimo, anche se la parallelizzazione è senz'altro + semplice.

Ll.


avevo sentito che è una scheggia, ma è vera la storia che "sbaglia a fare i conti" ?

Ll.


Non ne so molto, il CUDA l'ho scoperto pochi giorni fa, pietà

Nelle SDK ci sono gli esempi in cui mostrano che le soluzioni numeriche ottenute con CUDA convergono alle soluzioni numeriche tradizionali, però non saprei dire esattamente se è una proprietà generica o no
Se non sbaglio ci sono un po' di problemi di round off nel rappresentare i dati nel formato interno a CUDA... Può darsi che metodi instabili portino a soluzioni errate
fare multithreading in C/C++ è una scemata cmq, e se lo scheduler di Ubuntu non si droga ci pensa lui a suddividere i processi.
Per me fare multithreading e' difficilissimo, impazzirai

Se hai la possibilita' di fare cio' che ha consigliato insy, spezza i dati in due e fai partire due simulazioni alla volta e ci pensa il kernel a metterle una su un core e una sull'altro.

Altrimenti, a meno che la tua situazione sia facilmente parallelizzabile, preparati a riscrivere TUTTO

Asdo perche' non devo farlo io, ma c'e' poco da asdare <--- again! <--- lul!
Ecco come ho detto, ho da calcolare una media su 500 simulazione, dunque pensavo di mandarne 250 su un core e 250 sull'altro. Mi sembra una parallelizzazione così naive che pensavo di sfogliarmi la openMP e studiare come fare, secondo te è una capperata?

Ll.
Una simulazione come la esegui?

Se ogni esecuzione e' tipo questa:14:09 [email protected]:~$ esegui-simulazione
risultato: 42
15:09 [email protected]:~$
ovvero ogni simulazione e' un'esecuzione di un programma che parte e termina dicendoti il risultato, allora fai abbastanza facilmente con solo bash senza cambiare una riga di codice C.

Su 2 terminali scrivifor i in $(seq 1 250); do esegui-simulazione; done
In questo modo partono 250 simulazioni (una dopo l'altra, non tutte insieme ) su un terminale e 250 sull'altro (se vuoi interrompere chiudi il terminale).

Questo dovrebbe funzionare bene se l'esecuzione di ogni simulazione impiega sempre lo stesso tempo (minuto piu', minuto meno)

Se invece un'esecuzione puo' durare un giorno oppure due, allora puoi avere problemi: se le 250 sul terminale A sono molto brevi e quelle del terminale B sono molto lunghe, ti trovi che la prima infornata finisce mentre l'altra ancora e' in esecuzione. A quel punto ti trovi sempre con un solo core che macina a finire l'infornata B.

In questo caso potresti scriverti un programmino (in qualsiasi linguaggio di programmazione) che mantiene un pool di processi child (uno per ogni core) in cui ogni child non fa altro che lanciare l'eseguibile del simulatore con execve. Quando un child muore, il padre ne rifa' un altro, tenendo il conto e fermandosi a 500.
Sinceramente lanciare da bash 500 simulazioni mi sembra una capperata, come ho scritto sopra (e nel post ancora prima) le due alternative sono lanciare una fork o parallelizzare i cicli con la openMP. Appena mi passa questa influenza (non suina) mi metto a provare e vedo che ne cavo fuori.

Ll.
Occhio che se due istanze del simulatore usano le stesse risorse (aprono la stessa porta di rete, scrivono lo stesso file di log, etc.) sono guai
Boh, a casa mia si sceglie sempre la via piu' semplice perche' se sembra facile e' dura, se sembra dura e' fottutamente impossibile, poi vedi tu


Quando il problema è semplice nel senso che no c'è condivisione di informazioni tra i thread non ha molto senso pasticciare con librerie c tipo pthread o peggio ancora quelle di sistema per i processi.

Io userei openMP o pthread solo nel caso in cui serva fare dei join o nel caso in cui ci sia accesso concorrente a risorse (variabili in memoria o file).

Altrimenti è un complicarsi la vita. Certo che siccome sei un fisico(giusto?) e dovrai probabilmente scrivere spesso roba numerica, magari su larga scala potresti farlo per imparare;

In generale ricordati che creare un thread o peggio un processo prende risorse, quindi se hai troppi processi che girano concorrentemente rischi di perdere prestazioni.
Nel tuo esempio lanciare 500 thread ad esempio su un 2 core sarebbe una minchiata
Magari è meglio lanciare 3 processi con 200 200 e 100 toh, visto che alle volte alcuni finiscono prima non ti trovi la coda di roba che gira su un processore solo.
Io di solito divido il lavoro usando N + N/2 processi dove N sono le cpu. Tipo sul mio 8-core ci schiaffo di solito una dozzina di thread paralleli.
OpenMP è carina anche perché ha delle funzioncine per sapere quante cpu hai sulla macchina e ti rende il codice portabile.

Il consiglio di CUDA lo lascerei perdere, nel senso che CUDA è una figata, ma legarsi ad una tecnologia addirittura nei propri calcoli numerici mi pare rischioso.

Domani cambi scheda e puf ciao codice, domani ti danno 2 serveroni con 12 core l'uno e senza scheda video e puf riscrivi tutto
IMO usare i pthread è una scemata, ma è anche vero che chi è digiuno di C/C++ può andarsene a male.

la strada di .Z. è la più dispendiosa come memoria e overhead (per lo switch di contesto) ma è la più semplice per rendere sicura la parallelizzazione dei processi.

tu sei proprio sicuro che il problema sia parallelizzabile? i dati sono locali o globali? l'esito di una simulazione è indipendente dalle altre o no?

e soprattutto

non è che il tuo algorimo ci mette giorni perché, banalmente, non è ottimizzato? ogni volta che vedo il codice dei miei amici Fisici, mi viene il magone