SIMD

De la Wikipedia, enciclopedia liberă
Salt la: Navigare, căutare
SIMD.svg

Single instruction, multiple data (abreviat SIMD; din engleză) reprezintă una dintre arhitecturile de calculatoare paralele menționate în Taxonomia lui Flynn. Acest tip de calculatoare dispune de elemente multiple de procesare (în imaginea din dreapta: PU) care toate efectuează în paralel aceeași operație sau instrucțiune, dar pe date diferite. Astfel, aceste mașini exploatează paralelismul datelor (pe măsura în care acesta e prezent).

Introducere[modificare | modificare sursă]

Majoritatea procesoarelor moderne conțin elemente hardware speciale care permit ca o singură instrucțiune să genereze operații multiple care să fie executate în paralel. Această tehnică se numește SIMD (o singură instrucțiune, date multiple). Spre exemplu, generațiile recente de procesoare Intel și AMD au instrucțiuni care realizează adunarea a patru perechi de numere reale în simplă precizie (tipul de date float din C) în paralel. Aceste instrucțiuni au fost create pentru a imbunătăți viteza aplicațiilor pentru procesare de imagine, sunet și video. Deși unele compilatoare incearcă să extragă automat acest tip de paralelism din programele scrise în C, o metodă mai fiabilă este scrierea programelor folosind tipuri speciale de date (vectorizate) în compilatoare precum GCC. Intel a introdus în 1999 instrucțiunile SSE – acronim pentru Streaming SIMD Extensions. SSE este o clasă de instrucțiuni pentru a manipula vectori de întregi sau de date în virgulă mobilă. Fiecare bloc de date poate avea dimensiuni de 1, 2 sau 4 octeți, împachetate în vectori de 128 de biți. Versiunile ulterioare ale acestui chip au depășit 24M de tranzistori, datorită înglobării memoriei cache de nivel 2 (L2). Ideea din spatele modelului SIMD este aceea că fiecare registru XMM de 16 octeți poate reține valori multiple. Instrucțiunile SSE pot apoi să efectueze operații pe acești regiștri precum adunarea sau înmulțirea a două sau patru seturi de valori în paralel. Compilatorul GCC suporta extensii ale limbajului C care permit programatorilor să scrie cod folosind operații vectorizate ce pot fi compilate în instrucțiunile SIMD ale SSE. Acest stil de programare este preferabil celui de a scrie cod direct în limbaj de asamblare fiindcă GCC poate genera cod pentru instrucțiunile SIMD de pe alte procesoare. Scrierea codului în C are de asemenea avantajul că GCC va genera cod scalar pentru sistemele care nu oferă suport pentru instrucțiuni vectorizate.[1]

Avantaje[modificare | modificare sursă]

O aplicație care poate beneficia de SIMD este una în care aceeași valoare se adaugă (sau se scade) la un număr mare de date, o operațiune comună în multiple aplicații multimedia. Un exemplu ar fi schimbarea luminozității unei imagini. Fiecare pixel al unei imagini este format din trei valori pentru luminozitate: roșu (R), verde (G) și albastru (B). Pentru a modifica luminozitatea, valorile R, G și B sunt citite din memorie, valoarea se adaugă (sau se scade) acestora și rezultatele valorilor sunt scrise înapoi în memorie.

Cu un procesor SIMD există două îmbunătățiri pentru acest proces. Pentru unul dintre ele, datele trebuie să fie în blocuri, și un număr de valori poate fi încărcat dintr-o dată. În loc de o serie de instrucțiuni ce spun „obtine acest pixel, acum obține următorul pixel”, un procesor de SIMD va avea o singură instrucțiune care va spune într-un mod eficient „obtine loturi de pixeli” („loturi” reprezintă un număr care variază de la design la design). Din diverse motive, acest lucru poate dura mult mai puțin decât „obtinerea” fiecărui pixel individualizat, așa cum se întâmplă la un design CPU tradițional.

Un alt avantaj îl reprezintă acela că sistemele SIMD includ de obicei doar acele instrucțiuni care pot fi aplicate la toate datele într-o singură operațiune. Cu alte cuvinte, în cazul în care sistemul SIMD lucrează până la opt puncte de date o dată, se adaugă operația ce va lucra cu toate cele opt valori în același timp. Deși același lucru este valabil pentru orice model de procesor super-scalar, nivelul de paralelism într-un sistem SIMD este de obicei mult mai mare.

Dezavantaje[modificare | modificare sursă]

  • Nu toți algoritmii pot fi vectorizați. De exemplu, o sarcină cu prioritate de control al fluxului, cum ar fi analiza codului, nu ar beneficia de SIMD;
  • Acesta are, de asemenea, registre cu fișiere de mari dimensiuni care conduc la creșterea consumului de energie și zona chip;
  • În prezent, punerea în aplicare a unui algoritm de instructiuni SIMD, implică de obicei forță de muncă umană, deoarece cele mai multe compilatoare nu generează instrucțiuni SIMD dintr-un program C. Vectorizarea în compilatoare este un domeniu activ de cercetare în informatică. (Compararea prelucrarii vectorului);
  • Programarea cu seturi speciale de instructiuni SIMD pate implica numeroase provocări low-level.
    • SSE (Streaming SIMD Extension) are restricții privind alinierea datelor, programatorii familiarizați cu arhitectura x86 nu se pot aștepta la acest lucru.
    • Colectarea datelor în registrele SIMD împrăștie destinația corectă a locațiilor ceea ce este dificil și ineficient.
    • Instructiunile specifice cum ar fi rotatiile sau three-operand addition nu există în seturile de instrucțiuni SIMD.
    • Seturile de instrucțiuni au o arhitectură specifică: procesoarele vechi și procesoarele ce nu utilizează arhitectura x86 le lipsește în intregime SSE-ul, de exemplu, programatorii trebuie să furnizeze implementări non-vectorizate.
    • În trecut, setul de instrucțiuni MMX partaja fișierul registru cu stiva floating-point,lucru care a provocat ineficiență, atunci când s-a folosit în același timp floating-point și codul MMX. Cu toate acestea SSE2 corectează acest lucru.

Cronologie[modificare | modificare sursă]

Prima utilizare a instrucțiunilor SIMD a fost în supercomputerele vector la începutul anilor 1970, cum ar fi Star CDC-100 și Texas Instruments ASC. Vectorul de prelucrare a fost popularizat în special de Cray în anii 1070 și 1980.

Mai târziu, mașinile încep să utilizeze un numar mult mai mare de procesoare relativ simpe, cu o configurație tip procesare masivă. Câteva exemple de acest tip de mașină:

  • ILLIAC IV, 1974;
  • ICL Distributed Array Processor (DAP), 1974;
  • Burroughs Scientific Processor, 1976;
  • Geometric-Arithmetic Parallel Processor, de Martin Marietta, începând în anul 1981, continuat de Lockheed Martin, apoi de Teranex și Silicon Optix;
  • Massively Parallel Processor (MPP), de NASA/Goddard Space Flight Center, 1983-1991 ;
  • Connection Machine, modelul 1 si 2 (CM -1 si CM-2), de Thinking Machines Corporation, 1985;
  • MasPar MP-1 and MP-2, 1987-1996;
  • Zephyr DC computer de Wavetracer, 1991;
  • Xplor, de Pyxsys, Inc., 2001.

Multe alte exemple de acest tip de mașină existau în acea eră.

Hardware[modificare | modificare sursă]

SIMD-urile la scară mică (64 sau 128 biți) au devenit populare pe procesoarele de uz general la începutul anilor 1990, a continuat până în 1997 și mai târziu cu Motion Video Instructions (MVI) pentru Alpha. Instrucțiunile SIMD pot fi găsite, la un grad sau altul, pe cele mai multe procesoare, inclusiv produsul AltiVec al IBM-ului și SPE pentru PowerPC, PA-RISC Multimedia Acceleration eXtensions (MAX) al HP-ului, Intel MMX, SSE, SSE2, SSE3 și SSS3, AMD 3DNow!, ARC Video subsystem, SPARC VIS si VIS2, Sun MAJC, ARM NEON, MIPS' MDMX (MaDMaX) și MIPS-3D. IBM, Sony, Toshiba au co-dezvoltat setul de instructiuni SPU al procesorului Cell și se bazează puternic pe setul de instrucțiuni SIMD. NXP fondată de Philips a dezvoltat mai multe procesoare SIMD numite Xetal. Xetal are 320 de elemente procesare pe 16 biti concepute special pentru sarcici de vizualizare.

Unitățile moderne de procesare grafică(GPU-urile) sunt deseori largi implementari ale SIMD, capabile de a încarca sau de a memora pe 128 și 256 biți la un moment dat.

Viitoarele procesoare promit o capacitate mai mare de SIMD: instructiunile Intel's AVX vor procesa pe 256 biti, si microarhitectura grafică Intel Larrabee promite două registre SIMD pe 512 biți pe fiecare din nucleele sale (VPU - Wide Vector Processing Units) [ deși, la începutul anului 2010, proiectul Larrabee a fost anulat la Intel].[necesită citare]

Software[modificare | modificare sursă]

Instrucțiunile SIMD sunt utilizate pe scară largă pentru procesarea de grafică 3D, deși plăcile grafice moderne, cu SIMD integrat au preluat în mare parte această sarcină de la procesor(CPU). Unele sisteme includ, de asemenea, funcții de permutare in interiorul vectorilor, ceea ce le face deosebit de utile pentru prelucrarea datelor de compresie. Acestea sunt, de asemenea, folosite în criptografie.[2][3][4] Tendința de calcul de uz general pe GPU (GPGPU) poate duce la folosirea pe scară mai larga a SIMD-ului în viitor. Adoptarea de sisteme SIMD în software-ul de pe calculatoarele personale a fost la început lentă, datorita numărului de probleme. Una a fost că multe dintre instrucțiunile SIMD au tendița de a încetini performanța generală a sistemului datorită reutilizării regiștrilor existenți în floating point. Alte sisteme, cum ar fi MMX și 3DNow!, oferă suport pentru tipurile de date care nu au fost interesate pentru publicul larg si au avut contexte costisitoare de schimbare a instrucțiuniilor pentru comutarea între utilizarea regiștrilor FPU și MMX. Compilatoarele, de asemenea, de multe ori nu ajutau programatorii. Astfel încât aceștia trebuiau să recurga la limbajul de asamblare de codificare.

SIMD pe x86 biți a avut un start lent. Introducerea de 3Dnow! de AMD și Intel Sse au provocat probleme confuze, dar astăzi sistemul pare a fi stabilit ( dupa ce AMD a adoptat SSE) și compilatoarele noi ar trebui să conțină software pentru SIMD. Intel și AMD, furnizau biblioteci matematice optimizate ce folosesc instrucțiunile SIMD și alternativele open source ca libSIMD și SIMDx86.

Computerele Apple au avut un succes mai mare, chiar dacă au intrat în piața SIMD mai târziu decât restul. AltiVec oferea un sistem bogat și poate fi programat să foloseasca compilatoare din ce în ce mai sofisticate de la Motorola, IBM, GNU, prin urmare, un limbaj de programare de asamblare fiind necesar foarte rar. În plus, multe dintre sistemele, care ar beneficia de SIMD au fost furnizate de către Apple, de exemplu: iTunes și QuickTime. Cu toate acestea, în anul 2006, computerele Apple s-au mutat pe procesoarele Intel x86. APl-urile Apple și instrumentele de dezvoltare (XCode) au fost rescrise pentru a utiliza SSE2 si SSE3 în loc de AltiVec. Apple a fost cumpărătorul dominant de cipurile PowerPC de la IBM și Freescale Semiconductor și chiar dacă ei au abandonat platforma, dezvoltarea AltiVec continuă.

SIMD într-un registru, sau SWAR reprezintă o gamă de tehnici și trucuri folosite pentru efectuarea SIMD în registrele de uz general pe hardware, care nu oferă nici un spijin direct pe instrucțiunile SIMD. Acest lucru poate fi folosit pentru a exploata paralelismul în anumiți algoritmi chiar și pe hardware care nu suportă SIMD direct.

Exemplu de implementare[modificare | modificare sursă]

Se poate folosi compilatorul GCC ca suport pentru a scrie cod ce utilizează operații cu vectorizare. Strategia fundamentală este de a defini un tip de dată vec_t care reține patru valori pe 4 octeți sau două valori pe 8 octeți. Primul pas este de a declara un tip de dată vectorizat. Având în vedere faptul că se dorește ca același cod să poată funcționa și pentur tipuri primitive de date precum int, float și double, se folosește typedef pentru declarații și definiri de constante pentru a generaliza codul. Se definiște VBYTES pentru a reprezenta numărul de octeți din vector. Pentru SSE, acesta este definit ca fiind 16, dar se va parametriza aceasă valoare pentru a garanta adaptarea pe alte sisteme. Un alt considerent este definirea VSIZE, numărul de elemente în fiecare vector.

/* Numărul de octeți dintr-un vector */
#define VBYTES 16
 
/* Numărul de elemente dintr-un vector */
#define VSIZE VBYTES/sizeof(data_t)  //data_t este tipul de bază
 
/* Definirea unui nou tip de vector */
typedef data_t vec_t __attribute__ ((vector_size(VBYTES)));

Această declarare sugerează faptul că tipul de dată vec_t este vector, cu elementele de tipul data_t și având dimensiunea VBYTES în octeți. Pentru a accesa elementele vectorului, o soluție este folosirea unui union:

typedef union {
    vec_t v;
    data_t d[VSIZE];
} pack_t;

Un exemplu simplu ce calculează produsul scalar pentru doi vectori SIMD:

data_t produs_scalar(vec_t av, vec_t bv){
    pack_t xfer;
    int i;
    vec_t pv = av * bv; // se înmulțesc elementele din av si bv
    data_t result = 0;
    xfer.v = pv;
    for (i = 0; i < VSIZE; i++)
    rez += xfer.d[i];
    return result;
}

Multe din instrucțiunile SSE impun cerințe stricte pentru alinierea operanzilor în memorie. Trebuie ca orice date citite din memorie într-un registru XMM sau scrise din XMM în memorie să satisfacă un aliniament de 16 octeți. O instrucțiune care încearcă să citească sau să scrie date nealiniate va cauza o eroare de tip segmentation fault care indică încercarea de a se accesa o locație invalidă de memorie. Începând de la SSE2 există instrucțiuni care pot accesa date nealiniate, însă datorită lipsei de eficiență a implementărilor de început, GCC nu generează cod care să le folosească. Ideea generală a următorului cod este de a defini o variabilă de tip vec_t (accum) care să acumuleze patru (date de tip int sau float) sau două (date de tip double) valori în paralel. Mai intâi se inițializează acumulatorii cu elementul identitate (IDENT), folosind tipul de dată pack_t pentru a seta elementele individuale dintr-un vector. Pentru a satisface cerința de aliniament se vor acumula câteva elemente din vector folosind operații scalare până când variabila dată va conține o adresă care este multiplu de VBYTES. E necesară o conversie explicită asupra pointerului data pentru a-l transforma într-un long. Astfel se poate testa dacă este un multiplu de VBYTES. De asemenea, e necesar să se cunoască numărul de elemente rămase cnt, luând în considerare cazul în care cnt este mai mic decât numărul de elemente rămase dintr-un singur vector.

void simd_combine(vec_ptr v, data_t* dest){
  long int i;
  pack_t xfer;
  vec_t accum;
  data_t* data = get_vec_start(v);
  int cnt = vec_length(v);
  data_t result = IDENT;
 
  /*  Se inițializează accum la valoarea IDENT */
  for (i = 0; I < VSIZE; i++0)
    xfer.d[i] = IDENT;
  accum = xfer.d;
 
  while ( ((long) data) % VBYTES && cnt ){
    result = result OP *data++; //aliniere în memorie
    cnt--;
  }
 
  while (cnt >= VSIZE){
    vec_t chunk = *((vec_t *) data);
    accum = accum OP chunk;
    data += VSIZE;
    cnt -= VSIZE;
  }
  /* iterare prin elementele rămase */
  while (cnt){
    result = result OP *data++;
    cnt--;
  }
  /*combinarea elementelor în vectorul acumulator */
  xfer.v = accum;
  for (i = 0; i < VSIZE; i++)
    result = result OP xfer.d[i];
  /* memorarea rezultatului */
  *dest = result;
}

Operațille vectorizate efectuate mai sus fac ca valori multiple (2 sau 4) să fie acumulate în paralel în variabila accum.

while (cnd >= VSIZE){
  vec_chunk = *((vec_t *)data);
  accum = accum OP chunk;
  data += VSIZE;
  cnt -= VSIZE;
}

În blocul de cod de mai sus se observă folosirea conversiei explicite pentru a crea un pointer la un vector având aceeași adresă cu a pointerului la data. Dereferențierea acestui pointer duce la obținerea unui întreg vector de date din memorie, definit aici prin variabila vectorizată chunk. Instrucțiunea accum = accum OP chunk combină valorile vectorizate citite din memorie cu valorile din acumulatorii paraleli. În cazul în care bucla de mai sus se termină înainte ca toate valorile să fie acumulate, bucla imediat următoare va itera prin toate elementele rămase. Apoi referențiem acumulatorii printr-un union și le combinăm pentru a acumula rezultatul final. [5]

Aplicații comerciale[modificare | modificare sursă]

Deși s-a dovedit, în general, dificil de a găsi aplicații comerciale durabile pentru procesoarele SIMD, doar unul care a avut o anumită masură de succes este GAPP, care a dost dezvoltat de Lockheed Martin. Încercări recente ale GAPP au devenit un instrument puternic în aplicațiile în timp real de procesare video cum ar fi conversia între diferite standarde video și viteze de cadre (NTSC la/de la PAL, NTCD la/de la formatele HDTV). O cerere mai des întâlnită pentru SIMD se regăsește în jocurile video: aproape fiecare joc video modern tip consolă, începând cu anul 1998, are încorporat un procesor SIMD undeva în arhitectura sa. Playstation 2 a fost neobișnuit în sensul că unitățile sale vector-float ar putea funcționa ca DSP-uri autonome, care execută propriile fluxuri de instrucțiuni, sau că coprocesoare conduse de instrucțiuni CPU obișnuite. Aplicații grafice 3D au tendința de a se potrivi bine la procesarea SIMD, deoarece acestea se bazează foarte mult pe operațiile cu vectori de 4 dimensiuni. Direct3D 9.0 de la Microsoft își alege în momentul rulării procesorului implementării specifice, cu propriile sale operații matematice, inclusiv SIMD-uri pentru instrucțiuni. Printre ultimele procesoare care folosește procesarea vectorizata este ăăCell (procesor)|Procesorul Cell]] dezvoltat de IBM, în colaborare cu Toshiba și Sony. Se folosește un număr de procesoare SIMD (fiecare cu RAM independent și controlate de un procesor de uz general) și este proiectat pentru seturile de instrucțiuni uriașe cerute de către 3D și aplicațiile de procesare video. Un progres recent al Ziilabs a fost producerea de un procesor tip SIMD, care poate fi utilizat pe dispozitive mobile, cum ar fi playere multimedia și telefoane mobile.[6] Procesoare SIMD pentru o scară comercială mai largă sunt disponibile de la ClearSpeed Technology, Ltd. și de la Stream Processors. ClearSpeed CSX600 (2004) are 96 nuclee fiecare cu două unități dublă-precizie în virgulă mobilă, în timp ce CSX700 (2008) are 192 de nuclee.

Referințe[modificare | modificare sursă]

  1. ^ Achievieng Greater Parallelism with SIMD Instructions - Randal E. Bryant, David R. O'Halloran - June 5, 2012
  2. ^ RE: SSE2 speed, indicând modul în care SSE2 este folosit pentru a implmenta algoritmi hash SHA
  3. ^ Salsa20 speed; Salsa20 software, modul de implementare al unui flux de cod utilizând SSE2
  4. ^ Subject: up to 1.4x RSA throughput using SSE2, sau indicând implementarea RSA folosind un o instrucțiune SSE2 non-SIMD.
  5. ^ Computer Systems: a programmer's perspective - Randal E. Bryant, David R. O'Halloran - 2nd edition, 2011
  6. ^ ZiiLabs Corporate Website https://secure.ziilabs.com/products/processors/zms05.aspx

Vezi și[modificare | modificare sursă]

Legături externe[modificare | modificare sursă]