Doua componente esentiale ale structurii unui sistem de calcul sunt reprezentate de catre procesor si placa de baza. Astfel, in acest laborator vom vorbi despre:
Masina Turing executa cate o instructiune la un moment dat. Cand programatorul scrie un program, ii este foarte simplu sa considere ca programul sau va fi executat in acest mod. Pe de alta parte, o masina care executa cate o instructiune este mai lenta decat una care executa mai multe instructiuni in paralel. Pentru a cumula avantajele celor doua abordari, ar trebui ca programatorul sa poata inca scrie cod ca pentru o masina seriala, iar procesorul sa execute acest cod cu un nivel de paralelism cat mai ridicat. Cum este posibil asa ceva? Cineva trebuie sa faca trecerea dintre perspectiva seriala a programatorului si perspectiva paralela pe care ne-ar placea sa o aiba procesorul. Acest cineva poate fi ori un compilator, ori un hardware specializat aflat in structura procesorului.
Aceste considerente influenteaza structura procesorului si au dus la aparitia conceptului de Instruction Level Paralelism (ILP). Astfel, procesorul ia instructiuni dintr-un singur flux de control, le decodifica si executa in paralel. De exemplu, un procesor cu ILP poate sa scrie simultan rezultatele a doua instructiuni in registre, sa faca operatii aritmetice pentru alte trei, sa citeasca operanzii pentru alte doua, sa decodifice alte patru si sa ia (fetch) din fluxul de intrare inca patru instructiuni.
ILP-ul mareste asadar performanta procesorului. Dar de ce nu executam toate instructiunile deodata in paralel? Acesta ar fi de fapt modul cel mai rapid de a executa un program. Acest lucru nu se intampla deoarece ILP-ul are si anumite limitari, respectiv:
Mai multe detalii despre Explicitly Parallel Instruction Computing pot fi gasite aici EPIC.
Cand a aparut CISC, ideea era sa se aduca in hardware stilul de programare specific unui limbaj care sa se aproprie (pe cat e posibil la nivelul hardware) de un limbaj cat mai inalt. Astfel, instructiunile complexe au acelasi efect ca micile secvente de instructiuni simple. Implemenarea acestor instructiuni complexe in hardware insemana insa:
Datorita setului redus de instructiuni de asamblare, compilatoarele optimizate pentru RISC sunt capabile sa organizeze mai eficient fluxul de instructiuni de asamblare. Pe de alta parte insa, compilatoarele optimizate pentru RISC necesita mai mult timp de compilare decat cele pentru CISC. Aceasta deoarece trebuie sa se ocupe si de management-ul benzii de asamblare, anticiparea ramificatiilor (branch prediction) sau reorganizarea codului.
Ca principiu, o arhitectura RISC are mai multe registre generale, in timp ce CISC are mai multe registre speciale. Practic toate procesoarele moderne imprumuta atat caracteristici CISC cat si RISC.
Exista trei tipuri de categorii de instructiuni CISC, si anume:
Formatul instructiunilor RISC are o lungime fixa, cu lungimea unei instructiuni in general egala cu lungimea cuvantului de memorie; in cazul CISC, lungimea unei instructiuni variaza in functie de formatul instructiunii. RISC are un numar mic de moduri de adresare, spre deosebire de CISC, care are un numar mare de moduri de adresare (utilizate mai rar).
Setul de instructiuni RISC este orientat pe registre (peste 32 de registre). Pentru ca accesul la memorie este mult mai lent decat lucrul cu registrele, RISC incurajeaza lucrul cu acestia. Face acest lucru prin cresterea numarului de registre si prin limitarea explicita a acceselor la memorie. In general instructiunile au 2 operanzi (registre) si un registru destinatie.
Fie urmatorul exemplu de cod in C:
#include <stdio.h> #define N 100 int main() { int a[N], i; for(i=0;i<N;i++) a[i] = 2*i; return 0; }
Rezultatul compilarii codului pana la nivel de asamblare, pe arhitectura CISC si RISC este urmatorul:
O schema clasica pentru un sistem CISC este prezentata in Figura 1. Aici se poate distinge usor in partea de sus Procesorul, legat de restul sistemului prin Front-Side-Bus (FSB) de 400/533/800MHz catre North Bridge (i.e. 82865PE MCH). Pe North Bridge se afla controllerul de memorie, si ca atare si memoriile sunt conectate direct aici prin canale intre 2.1GB/s si 3.2GB/s. De asemenea pe North Bridge se conecteaza atat placa grafica (AGP 8x/4x) cat si interfata de retea de mare viteza Gigabit Ethernet.
La randul sau North Bridge-ul este conectat printr-o legatura de 266MB/s catre South Bridge (i.e. 82801EB ICH5 / 82801ER ICH5R). Dupa cum se poate vedea, North Bridge-ul impreauna cu South Bridge-ul formeaza impreauna ceea ce se numeste Chipsetul Intel® 865PE. Urmarind in continuare schema din Figura 1, se observa ca pe South Bridge se conecteaza o multitudine de componente periferice cu o viteza si rata de transfer de date considerabil mai scazuta decat elementele conectate pe North Bridge, cum ar fi: AC97 (placa audio), porturi ATA si Serial ATA, porturi USB, sistem de management si de control al consumului, etc.
Din aceasta schema se poate usor deduce ca punctul vulnerabil al acestor sisteme il constituie integrarea controllerului de memorie pe North Bridge, si in special legaturile de marime limitata intre South si North Bridge, precum si intre North Bridge si procesor. In mod evident, dimensionarea acestora este un compromis de design al sistemelor Intel, menit sa deserveasca majoritatea sistemelor hardware bazate pe acest Chipset, si a aplicatiilor ce ruleaza pe ele.
Pentru a atinge insa performante mai inalte, mai ales in contextul aparitiei sistemelor multi-procesor si multi-core, este insa nevoie de imbunatatiri ale acestei abordari, cum se poate observa la Chipsetul Intel 7300 din Figura 2.
Aici se poate observa conectarea a patru procesoare catre North Bridge (MCH) prin canale distincte FSB, de 1066MHz fiecare, menite sa asigure o alimentare eficienta cu date a acestora. Controllerul de memorie ramane pe North Bridge insa memoria se conecteaza prin patru canale de 8GB/s. Apar pe North Bridge conexiuni multiple PCI-Express (PCI-E), placa de retea devine doar “una dintre acestea”;, iar largimea de banda este crescuta pentru fiecare dintre acest componente fata de versiunile anterioare de Chipseturi.
Pentru simplitate, si conexiunea intre North Bridge si South Bridge (631xESB I/O Controller) este realizata prin conexiuni PCI Express 2x sau chiar 4x. Este sugestiv de asemenea faptul ca South Bridge-ul poarta acum numele de “I/O Controller” si se consfinteste astfel si prin nume direct rolul South Bridge-ului. Porturile ATA sunt inlocuite acum de SATA si PATA, apar din nou numeroase porturi PCI-E si PCI-X, USB, de gestiune a consumului, a biosului sau placi aditionale de retea pentru management.
Din prezentarea celor doua chipseturi 865PE si 7300 se poate vedea evolutia arhitecturala din jurul procesoarelor CISC de la Intel, cu o modularitate si o flexibilitate considerabil mai mare a chipsetului 7300, care ofera un potential de performanta mult crescut pentru sistemele ce il utilizeaza. Atentie, atat procesoarele Intel considerate pentru Chipset-urile prezentate, cat si cele AMD din sectiunile urmatoare, sunt din familii dedicate sistemelor de inalta performanta si cele mai puternice din clasa lor. Discutia prezentata este insa relevanta, la o scara corespunzator mai scazuta, si pentru celelalte sisteme si procesoare oferite de cele doua mari firme.
Anexa: Magistrale uzuale si largimea lor de banda maxima
Bus | Max Bandwidth |
---|---|
PCI | 132 MB/s |
AGP 8X | 2,100 MB/s |
PCI Express 1x | 250 [500]* MB/s |
PCI Express 2x | 500 [1000]* MB/s |
PCI Express 4x | 1000 [2000]* MB/s |
PCI Express 8x | 2000 [4000]* MB/s |
PCI Express 16x | 4000 [8000]* MB/s |
PCI Express 32x | 8000 [16000]* MB/s |
IDE (ATA 100) | 100 MB/s |
IDE (ATA 133) | 133 MB/s |
SATA | 150 MB/s |
Gigabit Ethernet | 125 MB/s |
IEEE 1394B [Firewire] | 100 MB/s |
Din familia Hammer, sau AMD64, face parte cel mai puternic procesor de la AMD, si anume Opteron. Opteronul este echivalentul familiilor Intel Itanium si Intel Xeon, destinat serverelor si sitemelor de inalta performanta. Opteron este un procesor out-of-order si in interiorul unitatii de executie ordinea instructiunilor este schimbata, pentru a maximiza eficienta. Pentru utilizatorul extern insa, instructiunile par a se executa in aceeasi ordine in care au fost lansate. De asemenea, el este 3-way superscalar, adica poate decoda, executa si incheia trei instructiuni x86 la fiecare ciclu masina. Desi poate lucra in paralel la 3 instructiuni, aceasta nu insemna neaparat ca cele 3 instructiuni sunt procesate in intregime pe acea perioda de ceas. Opteronul a fost creat pentru a putea lucra in sisteme multiprocesor si fiind primul care a oferit o scalabilitate sporita, el a acaparat la vremea respectiva o portiune semnificativa din piata comerciala de servere.
Printre cele mai importante imbunatatiri arhitecturale cu care vine Hammer (generatia 8) fata de Athlon si AthlonXP (generatia 7) se numara: doua stagii in plus la pipeline, algoritmi imbunatatiti de predictie a ramificatiilor, suport pentru SSE2 (Streaming Multimedia Instructions), controller de memorie integrat in CPU si extensie completa pentru setul de instructiuni pe 64 biti pentru x86. Toate procesoarele Hammer au viteze de maxim 2.5GHz. Pe de alta parte, Intel s-a concentrat mai mult pe cresterea vitezei, fara a se preocupa excesiv de paralelism, acest trend a fost insa oprit din 2007-2008, cand si Intel, si AMD au trecut la producerea de sisteme multi-core. Acest lucru este important in lumea serverelor, unde disiparea caldurii este o problema principala. Intel insa a venit si cu o noua “arma” si anume tehnologia de integrare bazata pe dielectrici High-K, ce a dus la o scadere drastica a consumului, si a permis de asemenea performante considerabile la frecvente de executie scazute.
Dupa cum am spus, Hammer pastreaza compatibilitatea cu 16 si 32 biti (fata de Intel, care renunta complet la x86 si trece la IA-64). Pentru a putea face acest lucru, Hammer are doua moduri de operare: Legacy- si Long-Mode. Long Mode este subdivizat si el in Compatibility mode si 64bit Mode. Legacy mode este destinat exclusiv sistemelor de operare pe 16 si 32 biti. Compatibility mode este destinat sistemelor de operare pe 64 de biti, dar care ruleaza programe scrise pentru 32 biti. Astfel, desi programul in sine nu beneficiaza de facilitatile 64 biti, managamentul resurselor, facut de sistemul de operare pe 64 de biti beneficiaza de totate avantajele date de rularea pe 64 biti.
In general, un procesor foloseste doua cipuri de pe placa de baza pentru a accesa memoria si perifericele. Aceste sunt numite North Bridge si South Bridge, dupa cum au fost descrise in sectiunile anterioare. Se observa ca North Bridge-ul joaca un rol esential, el facand legatura cu memoria. De acea, de la generatia Hammer, AMD a integrat in cipul procesorului North Bridge-ul. In felul acesta se obtine o latenta de acces la memorie redusa cu cel putin 20%. Acest controller are o legatura de 128 biti cu memoria. In plus, el functioneaza dupa ceasul procesorului, acest lucru marind inca o data viteaza; permite de asemenea ca marirea frecventei de ceas a procesorului sa imbunatateasca si performantele controller-ului.
Controller-ul de memorie are grija si de coerenta cacheului. Cipul integrat se concentreaza acum doar pe comunicarea cu memoria. Alte functionalitati ale North Bridge-ului, cum erau de exemplu comunicarea cu AGP sau Placa de Retea, au fost mutate pe un cip extern.
Hypertransport este o tehnologie pentru I/O dezvoltata initial de AMD. Ea este o alternativa la sistemele actuale de bus. Foloseste legaturi duble, punct la punct, pentru a lega componentele intre ele. Este, in termeni de retele, echivalentul unei legaturi full-duplex punct la punct fata de o topologie buss.
E folosit pentru a lega controller-ul de memorie integrat (fostul NorthBridge) de memorie. In mod similar este folosit in sistemele multiprocesor pentru comunicarea interprocesor, folosind modul coerent.
AMDOpteron are 3 legaturi Hypertransport. Seria 100 are 3 legaturi non-coerente, deoarece, fiind destianta monoprocesoareleor, nu are nevoie de comunicatie interprocesor. Seria 200 are 2 linii non-coerente si una coerenta, pentru unica legatura dintre cele doua procesoare (seria 200 e pentru dual-procesor). Si seria 300 are toate cele 3 legaturi coerente.
In mod evident Intel nu putea ramane indiferent avantajelor oferite de sistemul de interconectare oferit de catre HyperTransport. Si astfel putem vedea in figura urmatoare cum a aparut QuickPath Interconnect:
Acest sistem de interconectare este practic identic functional cu HyperTransport. Intre timp, procesoarele Intel au incorporat si ele controller-ul de memorie, si astfel cei doi mari competitori pe piata procesoarelor de uz general sunt pregatiti in aceeasi masura pentru sisteme multi-core cu multe procesoare, memorie multa si aplicatii multi-pthreading pe scara larga:
Sistemul QuickPath ofera o rata de transfer de pana la 25.6GB/s pentru fiecare port (pereche de linii). Legatura poate fi utilizata atat pentru interconectarea controller-ului I/O cu CPU-urile, sau a CPU-urilor intre ele. Astfel atat sisteme mono- cat si multi-procesor pot fi realizate cu usurinta cu acest tip de interconectare. Mai multe detalii pot fi vazute in figura urmatoare:
In mod similar cu sistemul Hypertransport, si interconectarea QuickPath poate fi utilizata pentru a lega sisteme HPC cu mai multe procesoare si siteme de intrare iesire, dupa cum se poate observa in urmatoarea figura:
Familia Hammer a fost creata pentru a putea oferi un multiprocesor scalabil, eficient din punctul de vedere al pretului raportat la numarul de procesoare. AMD a mai avut o tentativa in trecut de a crea procesoare pentru sisteme multiprocesor, cu AthlonMP. Desi acesta nu a fost o reusita de piata, datorita lui AMD am putut studia problemele aparute in astfel de sisteme. La Athlon MP, memoria (care era partajata) era botleneck-ul principal. Fiind memorie partajata, toate procesoarele imparteau FSB (Front Side Bus). Cu alte cuvinte viteza cu care procesoarele puteau teoretic accesa memoria era mult mai mare decat viteza cu care putea fi aceasta accesata. Solutia de la Hammer ar fi fost sa ofere fiecarui CPU propria sa conexiune la North Bridge, dar acest lucru ar fi fost foarte scump. Solutia relativ ieftina si care nu are nici penalizari de performanta a fost includerea controller-ului de memorie in procesor, ceea ce s-a si facut. Astfel, fiecare procesor are propria sa legatura de 128 biti cu memoria, avand pana la 5.3 Gbytes/sec.
In plus, datorita hypertransport, fiecare procesor poate accesa memoria celorlate procesoare la viteze de 3.2Gbytes/sec. Datorita acestui fapt, implementarea unui sistem dual-procesor e la fel de “usoara” ca a unuia cu 8 procesoare, deoarece partile componenete sunt scalabile prin utilizarea Hypertransport. AMD numeste acesta abordare “glueless multiprocessing”, deoarece procesoarele sunt legate slab prin Hypertransport. De fapt, e diferenta dintre o cuplare puternica gen circuit-switched versus o cuplare slaba, gen packet-switched, cum se intampla in cazul de fata. Figura de mai jos face o comparatie intre arhitecturile de la Intel (Xeon) si AMD (Athlon/Opteron).
Se observa ca cele doua procesoare Athlon (a) impart acelasi controller de memorie. Desi aceasta abordare nu are repercusiuni asupra performantei, sistemul nu e scalabil, adica pentru un sistem cu 3 procesoare ar trebui creat un controller separat. Este practic un sistem puternic cuplat (circuit-switched). Cum am mai mentionat, sistemele puternic cuplate sunt greu de scalat. In sistemul (b) cu Intel Xeon, procesoarele impart FSB-ul care, dupa cum am arata mai sus, duce la un botleneck semnificativ. In final, la (cde) avem sisteme cu Hammer Opteron. Acestea, fiind slab cuplate prin HyperTransort sunt usor de scalat la 2, 4 sau 8 procesoare. In plus, fiecare are propria sa legatura la memorie, neaparand botleneckuri, ca in cazul Intel Xeon.
Generatia Phenom de microprocesoare de la AMD este competitorul direct al Intel Xeon si Intel Itanium. Cele doua arhitecturi, Intel versus AMD sunt fundamental diferite, dar ofera performante comparabile, in functie de domeniul de aplicatie ales pentru comparatie.
O prima mare diferenta intre cele doua arhitecturi este modul in care cele doua abordeaza compatibilitatea cu 32 de biti. Astfel, de la Hammer incoace, AMD a ales sa extinda setul actual de instructiuni x86 pentru 32biti cu instructiuni pentru 64, in timp ce Intel a renuntat complet la setul x86, trecand in mod radical la IA64. Compatibilitatea la AMD este asigurata automat, noul set de instructiuni fiind doar o extensie e acelui vechi. La Intel, compatibilitatea cu 32 biti se face prin emularea vechiului set. Fiind o emulare, exista penalizari de performanta. Pe de alta parte insa, Intel a reusit sa scape in acest fel de complicatii de arhitectura inutile intr-o lume numai de 64 biti. Ambele tipuri mari de arhitecturi de procesoare, Intel si AMD, au trecut in ultimele generatii de procesoare la emularea setului de instructiuni x86 catre micro-operatii specifice fiecarei generatii de procesoare.
O alta diferenta este legatura dintre performanta, viteza ceasului si gradul de paralelism oferit. Astfel, la inceput Intel s-a concentrat pe marirea frecventei de ceas, si mai putin pe efectuarea de mai multe operatii in paralel. AMD ofera frecvente mai mici, dar a pus mult accent pe paralelism. Astfel performanta e oferita de AMD la frecvente mult mai mici decat Intel. Un avantaj al acestui fapt este ca AMD elimina astfel problemele de disipare a caldurii. Aceste aspecte sunt esentiale mai ales in domeniul serverelor. In ultimii ani Intel merge pe aceeasi cale, si se axeaza in principal pe cresterea numarului de core-uri si nu a frecventei de procesare, cu aceleasi avantaje mentionate anterior.
O alta diferenta e numarul de registre generale; acest aspect are efecte imediate asupra costului de productie. Intel are 128 de registre pentru numere intregi si 128 pentru numere in virgula mobila, in timp ce AMD are numai 16 registre generale. AMD a decis aceasta abordare in urma constatarii ca 80% din cod foloseste maxim 16 registre. Aceasta abordare i-a permis sa reduca semnificativ costurile.
In sfarsit, o serie de exemple de utilizare ale sistemului de interconectare QuickPath pot fi observate in urmatoarea figura. Aici procesoare din generatia Xeon - modelele Bloomfield si Nehalem - sunt legate de controller-ele placilor de baza si de sistemele de intrare - iesire prin legaturi Intel QuickPath. Acelasi tip de interconectare este utilizat si pentru legatura mai multor chipseturi intre ele.
Dupa cum se poate observa, scalabilitatea sistemelor de calcul de-a lungul vremii este dependenta puternic de solutiile de interconectare a elementelor de procesare. Astfel, de la magistrale simple, la magistrale multiple, la solutii complexe si scalabile cum sunt Hypertransport si QuickPath Interconnect, toate s-au dezvoltat in paralel cu modelele de procesoare si chipseturi pe care le interconecteaza.
Laboratorul poate fi realizat atat pe sistemul propriu (linux) cat si pe clusterul nostru, accesibil prin: fep.grid.pub.ro astfel:
ssh -Y username@fep.grid.pub.ro
(puneti utilizatorul vostru in loc de username)srun --x11 -p nehalem --pty /bin/bash
- va permite conectarea pe coada Nehalem cu 14 servere. Alternativ puteti folosi scriptul de la laboratorele de GPU-uri pentru a crea imaginea de mai jos in mod neinteractiv pe nodurile din coada nehalem.apptainer run docker://gitlab.cs.pub.ro:5050/asc/asc-public/c-labs:1.3.1 /bin/bash
- accesăm imaginea de docker în cadrul căreia avem permisiunile necesare realizării laboratoruluiwget https://ocw.cs.pub.ro/courses/_media/asc/lab4/lab4_skl.tar.gz
va permite downloadul arhivei de laborator pe cluster. tar xvfz lab4_skl.tar.gz
realizeaza dezarhivarea containerului tar.gz unde se afla laboratorul. Puteti acum explora intregul schelet al laboratorului si rezolva taskurile specificate in TASKS.md.Alte comenzi utile:
sinfo
- va arata cozile existentesqueue
- va arăta informațiile despre joburile în execuțiesbatch -p nehalem ./script.sh
- va lansa în execuție un task pe una dintre cozisrun -p nehalem –pty -w nehalem-wn17 /bin/bash
permite conectarea pe un anumit nod din cadrul unei cozi (17 in acest caz), si nu doar conectarea pe orice nod dintr-o coada
Task 0 - Alocați un vector de elemente struct particle
în următoarele moduri: global, pe stivă și dinamic.
task01.c
(pentru alocare globală), task02.c
(pentru alocare pe stivă) și, respectiv, task03.c
(pentru alocare dinamică).make task0<n>
.size <executabil>
pentru a vedea bss
unde se afla stocate variabilele globale.ulimit -s unlimited
. Pentru vizualizare si verificare a limitelor sistemului puteti incerca ulimit -a
.
Task 1 - Alocați dinamic o matrice de elemente struct particle
, in mod liniarizat. Populați aleator matricea astfel încât liniile pare să conțină particule care au componentele vitezei pozitive, iar liniile impare să conțină particule care au componentele vitezei negative. Scalați apoi vitezele tuturor particulelor cu 0.5, ignorând structura matricii, prin folosirea unui cast. Introduceti o verificare pentru alocarea dinamica vs. alocarea “clasica” pe linii. Porniti de la task1.c
Task 2 - Studiați alinierea variabilelor în C in fisierul task2.c
sizeof
. Explicați cele observate.Task 3 - Determinați dimensiunea cache-urilor L1 și L2 folosindu-vă de metoda prezentată în curs ( slide-urile 67-77). Utilizati variabile char/int8_t pentru acest task.
task3.c
Task 4 - Determinați dimensiunea unei linii de cache folosindu-vă de metoda prezentată în curs ( slide-urile 67-77).
task4.c
Pentru verificarea rezultatelor obtinute pentru dimensiunea cache-ului puteti folosi si rezultatele obtinute cu:
[student@localhost ~]$ getconf -a [student@localhost ~]$ cat /sys/devices/system/cpu/cpu1/cache/index0/coherency_line_size [student@localhost ~]$ cat /proc/cpuinfo
[student@localhost ~]$ sudo dmidecode | less
Cautati dupa “Cache” si veti afla informatiile despre memoria cache instalata
[student@localhost ~]$ valgrind --tool=cachegrind ./program_test
Acesta va simula rularea programului si va afisa informatii legate de accesul la L1, L2 cache si miss rate.
Un tutorial interesant si util pentru utilizarea gdb poate fi gasit in pagina echipei de SO, aici: http://ocw.cs.pub.ro/courses/so/laboratoare/resurse/gdb