Multi core

Fastflow – Programmare i multicore

Il mondo dell’hardware ha da anni intrapreso la strada delle piattaforme parallele. Queste piattaforme sono diffuse principalmente sotto forma di
  • processori multicore
  • GPU General Purpose (GPGPU)
  • strutture lato server, eventualmente realizzate con tecnologie cloud

Le cpu multicore offrono una potenza notevole rispetto alle cpu single core e grazie al parallelismo sui task (più processi in esecuzione contemporaneamente) sono in grado di produrre un miglioramento prestazionale visibile anche a livello di utenza generica, per esempio nell’uso di sistemi operativi ed applicativi desktop.

Sfortunatamente per il programmatore però i singoli programmi non sono automaticamente in grado di sfruttare al meglio tali architetture e quindi il famoso “more core – do more” è solo in parte vero. Non è infatti detto che un generico programma (es. compressore di file tipo WinZip) sia capace di sfruttare i core di un processore. Per esempio il programma in questione potrebbe essere strutturato come un’insieme di thread tra loro cooperanti capaci di “sminuzzare” il calcolo in più parti tra loro eventualmente interdipendenti; poi sarebbe necessario allocare ogni thread su un core del processore (in modo statico o dinamico). Questo è indubbiamente il metodo usato per realizzare applicazioni moderne, ma  programmare esplicitamente un software del genere prevede di cimentarsi con una serie di problematiche che possono rendere il processo particolarmente lungo, esposto alla possibilità d’errore e in ultimo costoso.

Ovviamente esistono degli strumenti automatici capaci di fare parte del lavoro per noi, ma non sempre questi strumenti, pur introducendo molte ottimizzazioni, sono così furbi da riuscire a trasformare un algoritmo sequenziale in uno parallelo. Spesso è necessario quindi approcciare il problema da risolvere in modo alternativo per renderle capaci di sfruttare al meglio le potenti risorse oggi presenti in processori anche di fascia “a basso consumo”, come per esempio le architetture ARM multicore.
Fastflow
Grazie a FastFlow e alle tecniche di programmazione parallela strutturata possiamo scatenare la potenza dei nostri processori senza doverci preoccupare degli aspetti tecnici di più basso livello, permettendoci di concentrarci invece sugli aspetti centrali dell’applicazione. FastFlow permette quindi di realizzare applicazioni multicore usando un approccio strutturato, che favorisce il porting di applicazioni legacy, e capace inoltre di semplificare la stesura di codice manutenibile.

In particolare Fastflow si propone di

  1. Promuovere un modello di programmazione parallela strutturata che sia indipendente dalla piattaforma target
  2. Supportare lo sviluppo di applicazioni efficienti e portabili per piattaforme omogenee ed eterogenee, includendo multicore, many-core (es. GPGPU e FPGA) e cluster distribuiti costruiti su queste tecnologie

Questi obiettivi sono ottenuti astraendo i modelli di programmazioni basati sul concetto di memoria condivisa, a passaggio di messaggi e SIMT (Single Instruction Multiple Threads).

 

Struttura di Fastflow
Fastflow è concettualmente suddiviso in livelli. Tali livelli sono impilati l’uno sull’altro e hanno lo scopo di astrarre le funzionalità sottostanti fornendo quindi strumenti di alto livello per l’implementazione delle applicazioni.
L’architettura di Fastflow è organizzata in tre livelli principali
  1. High-level patterns
    Questi sono chiaramente caratterizzati dallo specifico contesto applicativo e sono indirizzati alla parallelizzazione di codice sequenziale legacy. Esempi d’uso di questi costrutti sono lo sfruttamento di cicli paralleli, parallelismo su flusso, algoritmi data-parallel, etc. Questi sono generalmente dotati della capacità di essere auto-ottimizzanti e soffrono di alcuni limiti sulle loro possibilità di composizione ed annidamento. Questi pattern sono costruiti usando le funzionalità del livello dei

    Fastflow architecture
    Struttura di Fastflow

    Core patterns

  2. Core patterns
    Questi pattern forniscono un modello generico e data-centrico di programmazione parallela. Il supporto a run-time del modello di programmazione è inoltre fornito ed è progettato per essere minimale e limitare al minimo l’overhead indotto dall’adozione di tecniche di programmazione parallela. A questo livello sono disponibili due paradigmi (farm e pipeline) la cui semantica può essere modificata usando il modificatore feedback. Questi due costrutti possono essere usati per realizzare processi ciclici organizzati in reti di esecutori paralleli (processi o threads). I task oppure elementi da processare fluiscono attraverso gli esecutori. Questi costrutti sono implementati sul livello Building blocks
  3. Building blocks
    Questo livello contiene i blocchi base usati per costruire (e generare, tramite templates C++ header-only) il supporto a tempo di esecuzione dei core patterns. Oggetti tipici a questo livello sono code, container di processi e threads, scheduler e gatherer. Il supporto a tempo di esecuzione per la memoria condivisa usa in modo esteso algoritmi lock e fence-free, il supporto in ambiente distribuito impiega scambio di messaggi zero-copy, il supporto GPGPU sfrutta invece l’asincronia e algoritmi ottimizzati per il paradigma SIMT.

I livelli descritti sono puramente concettuali, le funzionalità dei livelli sono compilate staticamente ed ottimizzate nel codice binario tramite tecniche di programmazione generativa (es. uso di template C++ inline)

 

 Riferimenti
  1. http://calvados.di.unipi.it/dokuwiki/doku.php/ffnamespace:architecture
  2. https://en.wikipedia.org/wiki/Algorithmic_skeleton#FastFlow