Documente Academic
Documente Profesional
Documente Cultură
1
• Structura: Pentru a putea rula orice cod, calculatoarele personale şi
serverele mari au de obicei un sistem de operare care mediază între
aplicaţii şi hardware. Pentru a uşura dezvoltarea software-ului, majoritatea
sistemelor de operare de mari dimensiuni sunt structurate cu grijă, ca un
software pe niveluri; pentru a proteja sistemul de operare de alte aplicaţii,
sistemele de operare implementează un set de mecanisme de protecţie; în
final, rutinele nucleului sistemului de operare, cum sunt planificatoarele si
procedurile de alocare, sunt scrise folosind mecanisme generale, orientate
spre o clasă de aplicaţii cât mai largă posibil. Din păcate, combinaţia între
software-ul pe niveluri, mecanismele de protecţie, şi generalitatea excesivă
poate duce la încetinirea semnificativă a software-ului reţelei, chiar şi cu
procesoarele cele mai rapide.
• Scala/dimensiunea: Apariţia serverelor mari oferind Web şi alte
servicii duce la apariţia altor probleme, de performanţă. In particular, un
server mare cum este un server de Web, va avea de obicei mii de clienţi
concurenţi. Multe sisteme de operare folosesc structuri de date ineficiente
şi algoritmi care au fost proiectaţi pentru o epocă în care numărul de
legături a fost mic.
In figura 1.1 sunt prezentate principalele strangulări ale nodurilor
terminale, împreună cu cauzele şi soluţiile lor. Prima strangulare are loc
deoarece structurile sistemului de operare convenţional impun copierea
pachetelor de date între domeniile protejate; situaţia se complică şi mai
mult în cazul serverelor de Web prin copieri similare pentru sistemul de
fişiere şi alte manevre, ca sumele ciclice de control, care verifică toate
pachetele de date. Se descriu un număr de tehnici de reducere a acestor
supraincarcari, menţinând ca scop abstractizările sistemului, ca protecţia
şi structura. A doua supraîncărcare majoră este cea generată de control,
cauzată de comutarea între firele de control (sau domeniile de protecţie) în
timpul procesării unui pachet.
4
Suportul pentru securitate este parţial inclus deja în rutere. Datorită
sofisticării crescute, agresivităţii, şi ratei de atacuri asupra reţelei, este
esenţială implementarea securităţii în rutere sau dispozitive de reţea
specializate detectării/prevenirii intruziunilor. Dar dacă dispozitivul de
securitate nu poate ţine pasul cu legăturile de mare viteză, pot fi omise
informaţii vitale, necesare pentru detectarea unui atac.
Filtre Bloom: structură de date aleatorizată ingenios pentru reprezentarea concisă a unui
set/mulţime, care suportă interogări/queries despre apartenenţa aproximativă la
mulţime.Are o mare eficienţă spaţială, iar riscul/costul este de a detecta falsuri pozitive.
5
bufferului/depăşirea capacităţii bufferului, când codul maşinii C se
plasează în antetul de reţea F.
Daca staţia destinaţie alocă un buffer prea mic pentru câmpul F al
antetului şi nu are grijă să verifice depăşirea/inundarea, codul C poate
ajunge în stiva staţiei destinaţie. Cu un mic efort suplimentar, intrusul
poate face ca staţia destinaţie să execute codul rău C. C va prelua controlul
staţiei destinaţie. In figura 1.3 este reprezentat un astfel de atac, incorporat
într-un câmp familiar, Web URL (Uniform Resource Locator) destinaţie.
Cum poate monitorul detecta prezenţa unui URL suspect? O cale este să
observăm că URL-urile care conţin un cod dăunător sunt deseori prea
lungi (o verificare uşoară) şi deseori au o mare parte de caractere
neobişnuite pentru URL-uri, cum este #. Monitorul poate marca astfel de
pachete (cu o lungime prea mare sau cu prea multe caractere neobişnuite),
printr-o examinare amănunţită.
Dar implicaţiile acestei strategii asupra securităţii trebuie gândite atent.
De exemplu, pot exista programe inofensive, cum sunt scripturi CGI în
URLuri, ce duc pe piste false. Fără a intra în prea multe amănunte legate
de toate implicaţiile arhitecturale, să presupunem că aceasta a fost o
specificare trimisă arhitectului de chip-uri, de către arhitectul de
securitate.Vom folosi o problemă ca model, pentru a observa modul de
lucru al teoriei algoritmilor.Având de a face cu o astfel de specificare,
proiectantul de chip-uri poate folosi următoarele procese de proiectare,
care ilustrează unele principii ale algoritmicii de reţea. Procesul începe cu
proiectarea strawman şi rafinarea proiectarii, prin proiectarea unui
algoritm mai bun, relaxarea specificaţiilor şi exploatarea hardware-ului.
Cod dăunător
FIGURA 1.3 Găsirea unui pachet dăunător, observand frecventa caracterelor nelistabile
Tabloul Tabloul
Prag Contor Cod dăunător
0 2% 5
AIM://depăşire # * # ! * # ...... *
• •
• •
# 1% 3
Incrementează
• •
• •
255
FIGURA 1.4 Soluţia strawman pentru detectarea unui pachet dăunător: se contorizează
fiecare caracter într-un tablou contor şi apoi în pasul final se compară valorile cu cele din
tabloul de praguri
6
1.2.2 Soluţia strawman
Verificarea lungimii totale este implementată direct, deci ne concentrăm
la verificarea unor caractere suspicioase predominante. Prima soluţie
strawman este ilustrată în figura 1.4. Chip-ul păstrează două tablouri, T şi
C, cu câte 256 de elemente fiecare, unul pentru fiecare valoare posibilă, pe
caractere de 8 biţi. Tabloul de praguri, T, conţine procentul acceptabil (ca
o fracţiune din lungimea totală a URLului) pentru fiecare caracter. Dacă
apariţiile unui caracter într-un URL trec peste prag, pachetul este marcat.
Fiecare caracter are un prag diferit.
Tabloul de contorizare C, în mijloc, conţine contorul curent C[i] pentru
fiecare caracter i posibil. Când chip-ul citeşte un nou caracter “i” in URL,
se incrementează C[i] cu 1. C[i] are iniţial valoarea 0 pentru toate valorile
lui i când un nou pachet este întâlnit. Procesul de incrementare începe
numai după ce chip-ul analizează antetul HTTP şi recunoaşte începutul
URL-ului.
In HTTP, sfârşitul URL-ului este reprezentat cu două caractere de rând
nou; aşa că lungimea unui URL se poate şti doar după ce s-a parcurs
întregul şir URL. Astfel, după ce a fost întâlnit sfârşitul URLului, chip-ul
realizează o ultimă parcurgere a tabloului C. Dacă C [ j ] ≥ L ⋅ T [ j ] pentru
orice j, unde L este lungimea URL-ului, pachetul va fi marcat.
Presupunem că pachetele vin cu viteză mare în monitor şi dorim să
terminăm procesarea pachetului înainte de sosirea următorului. Această
cerinţă, numită procesare la viteza liniei/wire speed processing, este des
întâlnită în reţele; se previne amânarea procesării chiar şi în ce mai
defavorabil caz. Pentru a îndeplini cerinţele de procesare la viteza liniei,
ideal chip-ul ar trebui să facă un număr mic şi constant de operaţii pentru
fiecare octet al URL-ului. Presupunem că pasul principal de incrementare
al contorului poate fi făcut pe durata recepţiei octetului. Dar, cele două
treceri prin tablou, pentru iniţializare si verificare a depăşirilor de prag, fac
această proiectare lentă. Dimensiunea minimă a unui pachet este de 40 de
octeţi, incluzând doar antetele de reţea. Adăugând 768 operaţii în plus (1
scriere şi 1 citire pentru fiecare element din C, şi 1 citire din T pentru
fiecare din cei 256 indici) modelul de proiectare devine irealizabil.
7
Tabloul Tabloul
Prag Contor Cod dăunător
0 2% 5
AIM://depasire # * # ! * # ...... *
• •
• •
# 1% 3
1) Incrementează
• • 3) Dacă C[i]/T[i] > Max, Max = C[i]/T[i]
• 2) Citire •
255
FIGURA 1.5 Evitarea buclei finale prin tabloul cu praguri, urmărind doar Max, cel mai
mare contor relativ la valoarea de prag, întâlnit până acum.
8
nu aproximăm pragul cu o putere a lui 2, în loc să folosim valoarea exactă
a pragului respectiv? Astfel dacă pragul este 1/29, de ce să nu îl
aproximăm cu 1/32?
Tabloul Prag
plus Contor Cod dăunător
0 2% 5
AIM://supraincarcare # * # ! * # ...... *
• •
• •
# 1% 3
1) Citeşte un cuvânt lung
• • 2) Compară şi marchează dacă e necesar
• • 3) Scrie valoarea incrementată
255
FIGURA 1.6 Folosirea unui cuvânt lung şi un tablou compus pentru a combina 2 citiri
într-una
9
banală prin hardware, prin cablarea adecvată a firelor între registre, sau
prin folosirea multiplexoarelor.
1.2.5 Ştergerea
Deşi bucla terminală a fost eliminată, nu a fost rezolvată problema
delicată a buclei de iniţializare. Pentru a trata această problemă, chip-ul are
la dispoziţie un timp de iniţializare, dupa analiza URL-lui pachetului
curent şi înainte de tratarea URL-lui următorului pachet.
Din păcate, dimensiunea minimă a pachetelor poate fi mică, de până la
50 bytes, inclusiv antetul HTTP. Presupunând că sunt 40 bytes non-URL
şi 10 bytes URL, iniţializarea unei zone de 256 de bytes nu poate fi
făcută fără un cost suplimentar de 256/40 =6 operaţii per byte, necesare
prelucrării unui URL. Ca şi la bucla de procesare a URL-lui, fiecare
iniţializare presupune o citire şi o scriere a zonei comasate.
O metodă este amânarea lucrului până nu e absolut necesar, în speranţa
că nu va mai fi necesar. De fapt, chip-ul nu trebuie să iniţializeze C [i ]
până când caracterul i e accesat prima dată în pachetul următor. Dar cum
poate să ştie chip-ul că accesează caracterul i pentru prima dată? Pentru a
implementa evaluarea relaxată, fiecare cuvânt de memorie, reprezentând o
intrare în zona comasată, trebuie extins pentru a include G [i ] , numărul
generaţiei. Acest număr de generaţie, pe 3 biţi, poate fi văzut ca un contor,
care numară de câte ori e întâlnit pachetul, cu excepţia faptului că e limitat
la trei biţi. Astfel, chip-ul are un registru suplimentar g pentru fiecare i, pe
lângă G [i ] , cu 3 biţi; registrul g este incrementat modulo 8 la fiecare
pachet intâlnit. In plus, de câte ori C [i ] este actualizat, chip-ul
actualizează şi G [i ] pentru a reflecta valoarea curentă a lui g.
Având numerele generaţiei, chip-ul nu mai trebuie să iniţializeze zona de
numărare dupa ce pachetul curent a fost procesat. Totuşi, să considerăm
cazul unui pachet cu numărul generaţiei h, care conţine un caracter i în
URL-ul său. Când chip-ul întâlneşte caracterul i în timpul procesării
pachetului, citeşte C [i ] şi G [i ] din zona de numărare. Dacă G [i ] ≠ h
înseamnă că intrarea i a fost accesată anterior de un pachet şi nu a fost
iniţializată în consecinţă. Astfel, logica va repune pe 1 valoarea lui
C [i ] (iniţializare plus incrementare) şi va pune pe h valoarea lui G [i ] (fig.
1.7).
Apare imediat o obiecţie.Deoarece numărul generaţiei are doar 3 biţi, iar
valoarea lui g este ciclică, pot apare erori. Dacă G [i ] = 5 iar intrarea i nu
este accesată până când nu au trecut deja 8 pachete, valoarea curentă a lui
g este 8. Dacă următorul pachet conţine caracterul i, C [i ] nu va mai fi
iniţializat şi contorul va număra eronat valoarea de ordine a caracterului i
din pachetul curent, cu valoarea din urmă cu opt pachete.
Chip-ul poate evita această eroare printr-o buclă de filtrare separată, care
citeşte tabelul şi iniţializează toate contoarele cu numerele de generaţie
învechite. Pentru corectitudine, chip-ul trebuie să realizeze o scanare
completă a zonei pentru toate cele opt pachete procesate. Incetinirea
existentă, de 40 non-URL octeti per pachet, garantează o încetinire de 320
10
bytes non-URL pentru cele opt pachete, ceea ce este suficient pentru a
iniţializa o zonă de 256 de elemente, utilizând o citire şi o scriere per octet
indiferent de tipul de octet, URL sau non-URL. Se poate câştiga mai multă
întârziere dacă este nevoie, crescand numărul de biţi ai numărului
generaţiei, cu preţul unei uşoare creşteri a necesarului de memorare a
zonei.
Fig 1.7 Soluţia finala cu numere de generaţie pentru rafinarea buclei de iniţializare
Frecventa estimata [i ]
Chip-ul ar trebui să semnalizeze dacă rezultatul final depăşeşte un
anumit prag (ca exemplu, o valoare de 14,2 semnifică că sunt 1,4% şanse
ca diferenţa să se datoreze unor variaţii aleatoare). Găsiţi o cale de
implementare eficientă a acestei metode, presupunând că lungimea este
cunoscută doar la sfârşit.
13
CAPITOLUL 2
2.1 Protocoale
Secţiunea 2.1.1 descrie protocolul de transport TCP şi protocolul de
rutare IP. Aceste două exemple sunt utilizate pentru a asigura un model
abstract de protocol şi funcţiile acestuia din &2.1.2. Secţiunea 2.1.3 se
încheie cu ipoteze asupra performanţelor reţelelor. Cititorii familiarizaţi cu
TCP/IP ar putea dori să sară peste &2.1.2.
14
Rutarea în Internet este impărţită în două părţi “forwarding and routing”,
înaintare/dirijare. Inaintarea reprezintă procesul prin care pachetele sunt
transmise între sursă şi destinaţie trecând prin ruterele intermediare.
Pachetul reprezintă un segment TCP care are ataşat un antet de rutare care
conţine adresele internet destinaţie.
In timp ce procesul de înaintare trebuie să se realizeze la viteze mari,
tabelele de rutare din cadrul fiecărui ruter trebuie construite de către un
protocol de rutare, mai ales în cazul unor modificări de topologie cum este
cazul unor legături întrerupte. Sunt câteva protocoale de rutare mai
cunoscute, cum este protocolul bazat pe vectorii distanţă (RIP), sau pe
starea legăturii (BGP).
Figura 2.2 Funcţii comune ale protocolului, folosind tabela de stări (înegrită)
17
Exemplele includ: Rational’s Quantify (http://www.rational.com) pentru
aplicaţii software, Intel’s Vtune (www.intel.com/software/products/vtune),
şi chiar osciloscoape hardware. De asemenea sunt utile programele de
monitorizare a reţelelor aşa cum este tcpdump (www.tcpdump.org).
2.2 Hardware
Pe măsură ce legăturile de date se apropie de viteze de 40 gigabit/s
(OC-768), un pachet de 40 bytes trebuie transmis în 8 nsec. La aşa viteze,
transmisia mai departe a pachetelor este de obicei implementată hardware,
şi nu de un procesor programabil. Nu se poate participa la procesul de
proiectare a unui astfel de hardware, fără înţelegerea condiţiilor impuse
proiectanţilor şi mecanismelor unui asemenea hardware competitiv.
Câteva modele simple pot permite înţelegerea şi facilitează lucrul cu astfel
de modele de hardware.
Căutările Internet sunt implementate de obicei folosind logica
combinatională, pachetele Internet sunt stocate în memoriile ruterelor, şi
un ruter Internet este pus laolaltă cu comutatoare şi chip-uri de căutare. În
consecinţă, se începe cu implementarea logică, se continuă cu descrierea
memoriilor, şi se termină cu schema bazată pe componente. Pentru detalii,
dăm spre referinţa clasicul VLSI, care încă se mai foloseşte, şi arhitectura
clasică a calculatorului.
18
şi un proiectant de software trebuie să-şi dea seama că această funcţie se
pretează la o implementare hardware, pentru un n rezonabil. Funcţia este
descrisă mai detaliat în exemplul 2.
19
Un alt model mai economic din punct de vedere al suprafeţei este bazat
pe observaţia că fiecare bit de ieşire O ( j ) necesită poarta SI componentă
a primilor j − 1 biţi de intrare. In consecinţă definim rezultatele parţiale
P[ j] = I[1]...I[ j −1] pentru j = 2...N . Este clar că O [ j ] = I [ j ] P [ j ] . Dar P [ j ]
poate fi construită recursiv folosind ecuaţia P[ j] = P[ j −1]⋅ I[ j] care poate fi
implementată folosind N porţi SI de câte două intrări, conectate în serie.
Aceasta conduce la un model, modelul 2 care necesită O ( N ) tranzistoare
dar care ia O ( N ) timp.
Modelul 1 este rapid şi mare, şi modelul 2 este lent şi redus. Acesta este
un compromis familiar spaţiu-timp care sugerează că putem avea o soluţie
intermediară. Calculul lui P [ j ] în modelul 2 seamană cu un arbore binar
neechilibrat de înălţime N. Totuşi, este evident că P [ N ] poate fi calculat
folosind un arbore binar complet echilibrat de porţi SI cu 2 intrări, de
înălţime log N . Rezultatele parţiale ale arborelui binar pot fi combinate în
feluri simple astfel încât să avem P [ j ] pentru toate j < N folosind
acelaşi arbore binar.
De exemplu dacă N=8, pentru calculul lui P[8] calculăm X = I[0]...I[3] şi
Y = I[4]...I[7] şi calculăm SI din X şi Y la rădăcină. Deci este uşor să
calculăm P[5] spre exemplu, folosind una sau mai multe porţi SI,
calculând X ⋅ I[4] . O astfel de metodă este foarte utilizată de proiectanţii
hardware pentru înlocuirea lanţului de calcul aparent lung de O ( N ) , cu
lanţuri de lungime 2 log N . Deoarece a fost folosită prima dată ca să
grăbească lanţurile carry, este cunoscut sub denumirea de carry lookahead
sau simplu look-ahead. Chiar dacă tehnicile look-ahead par complexe,
chiar şi programatorii le pot stăpâni pentru că la baza lor, folosesc tehnica
dezbină-şi-cucereşte.
20
Un multiplexor (mux) conectează una din mai multe intrări la o ieşire
comună, în timp ce dualul său: demultiplexorul, rutează o intrare la una
din mai multe posibile ieşiri. Mai precis, un multiplexor conectează unul
din n biţi de intrare I j la ieşirea O dacă un semnal de selecţie S de log n
biţi codează valoarea j în binar. Dualul său, demultiplexorul, conectează
intrarea I la ieşirea O j dacă semnalul S codează valoarea j în binar.
21
slotul al doilea; intrarea aleasă expediează un pachet în al treilea interval
temporal.
Pentru a lua decizia de servire, L poate să stocheze cererile primite la
sfârşitul slotului 1 într-un vector R de N-biţi, unde R [i ] = 1 dacă legătura de
intrare i doreşte să transmită la L. Pentru corectitudine, L ar trebui să reţină
ultima intrare P servită. După aceea, L ar trebui să servească prima legătură
de intrare de după P, care are o cerere. Aceasta este o problemă PPE cu R şi P
ca intrări. Deoarece un ruter trebuie să facă o arbitrare pentru fiecare poziţie
temporală şi pentru fiecare legătură de ieşire, este nevoie de un model PPE
rapid şi eficient ca arie. Chiar şi un programator poate să înţeleagă, şi posibil să
repete procesul folosit pentru a proiecta PPE-ul din Tiny Tera, un switch
construit la Stanford şi mai târziu comercializat. Ideea de bază este reducerea:
reducerea proiectării unui PPE la proiectarea unui PE (exemplul 2).
Prima idee este simplă. PPE este în esenţă un PE a cărui prioritate mazimă
începe de la pozitia P în loc de 0. Un barrel-shifter poate fi folosit pentru a
deplasa I mai întâi spre stânga cu P biţi. După aceasta se poate folosi un
simplu PE. Bineinţeles că vectorul bitilor de iesire este acum deplasat; deci
trebuie restabilită ordinea originală deplasând ieşirea lui PE la dreapta cu P
biţi. Un bloc de deplasare cu împrumut pentru N-biti de intrare poate să fie
implementat folosind un arbore de multiplexoare de 2 intrări într-un timp în
jur de log N . Astfel două blocuri de deplasare cu împrumut şi un PE
echivalează cu aproximativ 3log N întârzieri de porţi.
Un proiect mai rapid, care necesită numai 2 log N întârzieri de porţi
este următorul. Problema se poate împărţi în două părţi. Dacă intrarea
are nişte biţi setaţi la poziţia P sau mai mare, atunci rezultatul poate fi
găsit folosind un PE care operează pe intrarea originală după ce au fost
setaţi pe 0 toţi biţii de intrare a căror poziţie este mai mică decât P. Pe pe
de altă parte, dacă intrarea nu are nici un bit setat la poziţia P sau mai
mare, atunci rezultatul poate fi găsit folosind PE-ul care operează pe
intrarea originală fără nici o mascare. Acest rezultat din modelul din
figura 2.4, testat pe Texas Instrument Cell Library, a fost aproape de
două ori mai rapid şi a însemnat folosirea unei suprafeţe de trei ori mai
mică decât modelul blocului de deplasare cu împrumut, pentru un ruter
cu 32-porturi.
Deci logica modelului pentru o componentă de timp critică, un switch,
poate fi realizată folosind reduceri şi modele simple.
2.2.4 Memorii
In punctele terminale şi rutere, înaintarea/expedierea pachetelor se face
folosind logica combinaţională, dar pachetele şi stările necesare înaintării
trebuiesc stocate în memorii. Deoarece accesarea memoriilor este
semnificativ mai lentă decât întârzierile logice, memoriile sunt cele care
generează strangulări masive în rutere şi în puncte terminale.
În plus, diferitele subsistemele necesită memorii cu caracteristici diferite.
De exemplu, vânzătorii de rutere cred că este important un buffer de 200 de
msec pentru a evita pierderea pachetelor în timpul perioadelor de congestie.
La, să zicem 40 Gbit/sec per legătură, un astfel de buffer de pachete necesită o
cantitate enormă de memorie. Pe pe de altă parte, căutările ruterelor necesită o
22
cantitate mai mică de memorie, accesată aleator. Astfel este bine să avem
modelele simple pentru memorii cu diferite tehnologii.
REGISTRE
Un bistabil (flip-flop) conectează două sau mai multe tranzistoare într-o
buclă, astfel încât (în absenţa căderilor tensiunii) cifra binară să stea nedefinit
de mult timp pe ieşire fără să se modifice valoarea tensiunii. Un registru este o
colecţie ordonată de bistabile. Cele mai moderne procesoare au registre pe
chip de 32 sau 64 biţi. Un registru pe 32 biţi conţine 32 de bistabile,
fiecare pentru a memora 1 bit. Accesul de la logică la un registru, pe
acelaşi chip, este extrem de rapid, în jur de 0.5-1 nsec.
SRAM
O memorie statică cu acces aleator (SRAM) conţine N registre adresate cu o
adresă A, pe log N biţi. SRAM este numită astfel deoarece reîmprospătarea
bistabilelor este de tipul “static”. În afară de bistabile, SRAM are nevoie şi de un
decodor care decodează A, într-o valoare unară, folosită pentru accesarea
registrului potrivit. Accesarea unui SRAM pe-chip este doar puţin mai lentă decât
accesarea unui registru, din cauza întârzierii introduse de decodare. În momentul
actual, este posibil să se obţină SRAM pe chip cu timp de acces de 0.5 nsec. Timpi de
acces de 1-2 nsec pentru SRAM pe-chip şi 5-10 nsec pentru SRAM care nu este pe chip,
se întâlnesc în mod uzual.
DRAM
O celulă binară SRAM necesită cel puţin cinci tranzistoare. Astfel
SRAM este întotdeauna mai puţin densă sau mai scumpă decât tehnologia
de memorie bazată
FIGURA 2.4: Proiectul Tiny Tera PPE foloseşte codor de prioritate 1, pentru a găsi
setul cel mai mare de biţi, dacă există, a tuturor biţilor mai mari decât P folosind o mască
de codare a lui P. Dacă nu e găsit nici un bit, e validată ieşirea codorului 2 de prioritate
(poarta SI de jos). Rezultatele celor două codoare sunt apoi combinate cu o poartă SAU
cu N intrări.
FIGURA 2.5: Memoriile mai mari sunt organizate pe două dimensiuni în rânduri şi
coloane. Selectarea unui cuvânt constă în selectarea mai intâi a rândului şi apoi a coloanei
din acel rând.
Figura 2.5 arată că cele mai multe memorii sunt organizate intern pe
două dimensiuni, în rânduri şi coloane. Cifrele binare de adresă de sus sunt
decodificate pentru a selecta rândul, şi după aceea cifrele binare de adresă
de jos sunt folosite pentru a decodifica coloana. Utilizatorul furnizează
mai întâi biţii de adresă a rândului şi activează un semnal numit RAS(Row
Address Strobe); apoi utilizatorul furnizează biţii de adresă ai coloanei şi
activează un semnal numit CAS(Column Address Strobe). Dupa un timp
specificat, cuvântul dorit din memorie poate fi citit. Presupunând rânduri şi
coloane egale, se reduce complexitatea porţii de decodare de la O ( N ) la
O ( ( N ) ) cu preţul creşterii întârzierii cu timpul necesar pentru încă o
decodare. In afară de timpul de întârziere necesar, dintre RAS şi CAS, mai
este de asemenea necesară şi o întârziere de preîncărcare între invocări
succesive ale lui RAS şi CAS, timp ce permite încărcarea
condensatoarelor.Cele mai rapide chip-uri DRAM au nevoie în jur de 40-60 nsec
(latenţa) pentru acces, cu timpi mai lungi ca de exemplu 100 nsec, între citiri
succesive (consum) din cauza restricţiilor de preîncărcare. Acesta latenţă include
timpul necesar pentru a adresa liniile externe de interfaţă la pinii memoriei DRAM;
inovaţiile recente permit realizarea de DRAM pe chip, cu timpi de acces mai mici,
în jur de 30 nsec. DRAM va fi întotdeauna mai densă dar mai lentă decât SRAM..
Page-Mode DRAM
Unul din motivele înţelegerii DRAM este înţelegerea artificiului
utilizat pentru accelerarea timpului de acces, numit page mode/modul
pagină. Acest mod de acces este benefic pentru a accesa structuri de date
care au o localizare spaţială, în care cuvintele de memorie adiacente sunt
24
accesate succesiv. Dar accesând un rând (fig. 2.5), se pot accesa cuvinte
din rând, fără întârzieri suplimentare de RAS şi preîncărcare. RAM–urile
video exploatează această structură având o citire de rând într-un SRAM,
care poate fi citit serial, pentru a reîmprospăta un ecran (display) la viteze
înalte. In afara de page mode şi video RAM, mai sunt şi alte idei care
exploatează structura DRAM, care pot fi folositoare în reţele.
Multe chip-uri de DRAM au avantajul că adresele de linii şi coloane nu sunt cerute în
acelaşi timp astfel ca pot fi multiplezate pe aceeaşi pini, reducând necesarul de pini per
chip.
FIGURA 2.6: Ideea RAMBUS, SDRAM, etc., este crearea unui singur chip cu
DRAM multiple paralele, câştigând astfel lăţime de bandă de memorie şi folosind doar
un set de linii de adrese şi de date.
25
bancurilor. Exemple importante includ SDRAM cu 2 bancuri şi RDRAM (Remote
DRAM)cu 16 bancuri.
Exemplul 4. Căutări/lookup de fluxuri pipeline: un flux este caracterizat de
existenţa unei adrese IP a sursei şi a destinaţiei, şi de porturi TCP. Unii clienţi doresc
ca ruterele să ţină evidenţa pachetelor trimise de fiecare flux de reţea, pentru
contorizare. Sunt deci necesare structuri de date care să stocheze un contor pentru
fiecare flux ID şi care să suporte două operaţii: Insert (FlowID) pentru inserarea
unui nou ID de flux şi Lookup (FlowID) pentru găsirea locaţiei contorului de flux
ID. Căutarea necesită o potrivire exactă a ID-ului fluxului – care este în jur de 96 biţi
– în timpul recepţionării pachetului. Aceasta poate fi făcută prin orice algoritm de
potrivire exactă, cum ar fi cel de dispersare/hashing.
Totuşi, pe măsură ce tot mai mulţi vânzători de rutere vor să limiteze timpul
de lookup pentru cazul cel mai defavorabil, căutarea binară este cea mai bună.
Presupunem că aceste căutări ale ID-urilor fluxurilor trebuie făcute la viteza
liniei, pentru cazul cel mai defavorabil de pachete de 40 bytes la viteze de 2.5
Gbit/sec/viteze OC-48. In consecinţă chip-ul are la dispoziţie 128 nsec pentru a
găsi un ID de flux.
Pentru a mărgini întârzierile de căutare, considerăm un arbore binar simetric, ca
arborele B. Logica parcurgerii arborelui este uşoară. Pentru creşterea vitezei, ar
trebui ca ID-urile fluxurilor şi numărătoarele să fie stocate într-o memorie
SRAM.. Estimările actuale actuale în ceea ce priveşte nucleul ruterelor arată în
jur de 1 milion de fluxuri concurente. Păstrarea stării pentru 1 milion de fluxuri în
SRAM este scumpă. Chiar dacă folosim doar DRAM-uri, cu arbori binari cu
factor de branşament de 2, ar necesita log21.000.000=20 accese de memorie.
Chiar cu un timp de acces optimist al memoriei DRAM de 50 nsec, timpul
necesar întregii căutări este de 1 μsec, care este prea lent
O soluţie este folosirea pipelining-ului (fig. 2.7), în care accesul logic prin
pipeline la ID-urile fluxurilor stocate într-o memorie RDRAM cu 16 bancuri este
ca în figura 2.6. Toate nodurile de înălţime i din arborele binar sunt stocate în
bancul i al RDRAM-ului. Chip-ul de căutare face16 căutări de ID-uri de fluxuri
(pentru 16 pachete) deodată. De exemplu după ce a căutat în nodul rădăcină
pentru pachetul 1 în bancul 1, chip-ul poate să caute, la nodul arborelui de nivel
doi, după pachetul 1 în bancul 2 şi (foarte repede dupa asta) poate să caute la
nodul rădăcină al arborelui pentru pachetul 2 din bancul 1. Când firul/thread
procesului de căutare a pachetului 1 accesează bancul 16, firul procesului de
căutare a pachetului 16 accesează bancul 1. Deoarece RDRAM-ul direct
funcţionează la 800 Mhz, timpul dintre cererile de adresare a magistralei RAM-
ului este mic comparativ cu timpul de acces de citire de 60 nsec. Astfel, în timp
ce unui singur pachet îi trebuie16 ∗ 60 nsec, procesarea concurentă a 16 pachete
permite debitul de o găsire de ID de flux la fiecare 60 nsec.
26
FIGURA 2.7: Găsirea identităţii fluxului, cu un chip de căutare pipeline, care lucrează la găsirea a
până la 16 ID-uri de fluxuri în acelaşi timp, fiecare din ele accesând un banc DRAM independent. Chip-
ul de căutare returnează un index procesorului de reţea care actualizează numărătorul ID a fluxului.
Dar, un arbore binar cu 16 nivele permite doar 216 = 64 K ID-uri de flux, prea
puţin. Din fericire RAMBUS permite o variantă de page mode, unde 8 cuvinte de
32 biţi pot fi accesate aproape în acelaşi timp ca 1 cuvânt. Astfel putem găsi două
chei de 96 biţi şi 3 pointeri de 20 biţi într-un acces la memorie de 256 biţi. Se
poate deci folosi un arbore cu branşament de 3, care permite potenţial 316 sau 43
milioane de ID-uri de fluxuri.
CPU Memorie
MMU, Cache
Magistrală sistem
Adaptor magistrală
Interfaţă reţea
Magistrală I/E
31
Comutator programabil
paralel
Procesor Memorie 1
Figura 2.9. Folosirea conexiunilor paralele într-un nod terminal pentru a permite
procesarea concurentă şi trafic de reţea printr-un comutator paralel.
Ruter
B2
Legături
Comutare de ieşire
B3
Legătura de
intrare i
Planificare
B1
Căutare adresă
Comutarea
După identificarea adresei, procesorul spune sistemului de comutaţie
intern să transfere pachetul de pe intrarea i spre ieşirea corespunzătoare
(ieşirea 6 din exemplu). În procesoarele mai vechi, comutatorul era o
simplă magistrală, ca în figura 2.8. Acest mod de abordare s-a dovedit a fi
o mare limitare de viteză, deoarece, daca comutatorul are N intrări, fiecare
cu B biţi/s, magistrala trebuia să aibă o lăţime de bandă de B·N. Pe măsură
ce N creşte, efectele electrice (capacitatea electrica a magistralei) vor
deveni predominante, limitând viteza magistralei.
Din acest motiv ruterele cele mai rapide de azi folosesc un comutator
paralel (figura 2.9). Rata de tranfer a comutatorului creşte folosind N
magistrale paralele, una pentru fiecare intrare şi una pentru fiecare ieşire.
33
O intrare este conectată cu o ieşire prin comandarea tranzistoarelor care
conectează magistralele de intrare şi ieşire corespunzătoare. În timp ce
realizarea legăturii între magistrale este relativ simplă, partea mai dificilă
este planificarea comutatorului, deoarece mai multe intrari ar putea să
dorească să comunice cu o anumită ieşire în acelaşi timp. Problema
planificării comutatorului se rezumă la identificarea intrărilor şi ieşirilor
disponibile la fiecare interval de sosire a pachetelor.
Procesarea rutei
Ruterele din interiorul unor domenii implementează RIP şi OSPF, în
timp ce ruterele care leagă domenii diferite trebuie să implementeze şi
BGP(*). Aceste protocoale sunt implementate în unul sau mai multe
procesoare de rutare. De exemplu dacă un pachet de stare a legăturii este
trimis spre ruterul din figura 2.10, procesul de căutare va recunoşte că
acest pachet este destinat ruterului însuşi şi va determina comutarea
pachetului spre procesorul de rutare. Procesorul de rutare menţine baza de
date cu starea legăturilor şi calculează drumurile cele mai scurte. După
calcul, procesorul de rutare încarcă noua tabelă de rutare în fiecare dintre
procesoarele de rutare, fie prin comutator, fie printr-o cale separată din
afara benzii. La început CISCO procesa nu numai pachete Internet dar şi
alte protocoale precum DECNET, SNA sau Appletalk. La ora actuală s-a
introdus comutarea multi-protocol după etichetă (MPLS – Multi Protocol
Label Switch) care este esenţială pentru ruterele core, ale retelelor de
tranzit. În MPLS, antetului IP i se adauga un alt antet care conţine indici
întregi simpli, care pot fi identificaţi direct fără cautarea prefixului.
(*)E posibilla achizitionarea acestor protocoale, dar software-ul trebuie personalizat
conform cu noile platforme hardware. O problema si mai delicata este, in special pentru
BGP si OSPF, ca multe dintre primele implementari ale acestora variaza in mod subtil
fata de specificatiile actuale. Noile implementari care indeplinesc specificatiile ar putea sa
34
nu poata interopera cu ruterele existente. Astfel ca ISP-urile opun rezistenta la
cumpararea noilor rutere, daca acestea nu asigura „calitatea”codului BGP, in sensul
capacitatii de interoperare cu ruterele existente.
Procesarea protocolului
Toate ruterele din ziua de azi trebuie să implementeze protocolul SNMP
(Simple Network Management Protocol) şi să furnizeze un set de contoare
care să poată fi verificate de la distanţă. Pentru a permite comunicarea la
distanţă cu ruterele, majoritatea ruterelor implementează şi protocoalele
TCP şi UDP. Pe lângă acestea ele mai trebuie să implementeze protocolul
ICMP (Internet Control Message Protocol) care este de fapt un protocol de
transmisie a mesajelor de eroare, precum „depăşirea timpului de viata
TTL”.
37
Figura 2.12 Procesul de primire a pachetelor de pe internet este impartit intre adaptorul
de retea, nucleu si procesul destinatie
39
Figura 2.13 Programatorul are iluzia unei memorii virtuale continue; in realitate este
asociata din parti ale memoriei principale si pagini de pe discul de memorie, folosind
tabele de pagini
Figura 2.14 Programatorul vede dispozitivele, ca discul sau adaptorul de retea, ca piese
disparate ale memoriei, care pot fi citite/scrise utilizand apelul de sistem, dar de fapt
nucleul administreaza o gazda cu detalii specifice dispozitivului.
2.5 Sumar
S-a lucrat pe patru niveluri de abstractizare care afecteaza performanta:
hardware-ul, arhitectura, sistemul de operare si protocoalele. Acest fapt
este util deoarece viteza de procesare a pachetelor poate fi limitata: de
traseele cu tranzistoare care implementeaza procesarea pachetelor, de
limitarile arhitecturale ca viteza magistralei, de suprasolicitarea sistemului
generata de abstractizarile OS ca apelurile la sistem, si in final chiar de
mecanismele protocolului.
Proiectantii, care vor incerca sa tina cont de simultan de toate cele
patru nivele de abstractizare pentru fiecare problema, se vor pierde in
detalii. Totusi, sunt cateva rezultate importante referitoare la performanta
si decizii arhitecturale majore pentru care intelegerea simultana a tuturor
nivelelor de abstractizare este esentiala. De exemplu, modelele simple
prezentate in acest capitol permit lucrul impreuna al arhitectilor,
proiectantilor de circuite, de logica, de microcodoare si implementatorilor
de protocoale software pentru a crea rutere de clasa mondiala. Ele permit
proiectantilor de sisteme de operare, expertilor in algoritmi si celor care
creaza aplicatii sa lucreze impreuna pentru a concepe un server Web de
clasa. La viteza de 40 Gps pe legatura, echipele interdisciplinare devin
extrem de importante.
Exista un alt aspect al creativitatii. Am vorbit despre mari contributii
individuale, dar atunci cand creezi tehnologie este necesara o activitate in
grup, deoarece astazi tehnologia este atat de complexa incat trebuie sa fie
interdisciplinara…, in esenta, fiecare isi vorbeste propriul limbaj, chiar
42
daca despre aceleasi concepte. Stabilirea unui limbaj comun dureaza luni
de zile… o tehnica pentru a face oamenii sa-si depaseasca limitele
gandirii ar fi : se da o problema, de procesare a semnalelor lingvistilor, si
vice versa, fiind lasati sa aplice cunostintele cu care sunt familiarizati unei
probleme complet diferite. Abordarea rezultata este in majoritatea
cazurilor una complet noua, la care expertii in domeniul original nici nu s-
ar fi gandit. Munca in echipa da creativitatii o noua dimensiune.
2.6. Exercitii
1. Protocoalele TCP si atacuri de tip refuz de serviciu DOS (Denial-
Of-Service Attacks ). De obicei, un hacker incearca sa atace un serviciu
cunoscut, precum Yahoo, printr-un atac de tip DOS. Un atac DOS simplu
este cel de tip TCP Syn-flooding, in care hacker-ul trimite cateva pachete
SYN catre destinatia aleasa D (ex. Yahoo), folosind adrese sursa alese la
intamplare. D trimite inapoi un SYN-ACK catre presupusa sursa S si
asteapta raspunsul de la S. Daca S nu este o adresa IP activa, atunci nu va
primi un raspuns de la S. Din pacate, starea lui S este mentinuta in coada
de asteptare a conexiunilor lui D, pana la expirarea sa. Trimitand periodic
incercari false de conectare, pretinzand ca sunt de la surse diferite,
atacatorul se poate asigura ca la D, coada de asteptare finita va fi
intodeauna plina. Prin urmare, o cerere legitima de conectare spre D va fi
refuzata.
Presupunand ca exista un monitor care supravegheaza tot traficul, ce
algoritm poate fi folosit pentru a detecta atacurile de tip DOS ?
Presupunem ca programul monitor realizeaza ca are loc un atac prin
inundare TCP. De ce e greu sa deosebseti traficul legitim de cel prin
inundare?
2. Proiectarea numerica: Multiplexoarele si Barrel Shifters (*) sunt
foarte folositoare in partea hardware a retelei, deci lucrul la aceasta
problema poate ajuta chiar si un softist sa construiasca un hardware in mod
intuitiv.
(*) Barrel shifter este un dispozitiv hardware care poate depasa sau roti un cuvant de
date cu oricate pozitii intr-o singura operatie. E implementat ca un multiplexor, fiecare
iesire iesire putand fi conectata cu fiecare intrare
• Creati un multiplexor cu 2-intrari cu porti primare (SI,SAU,NU).
• Generalizati ideea creand un multiplexor cu N intrari din multiplexoare
cu N/2 intrari. Cu acestea descrieti un model cu log N intarzieri de porti si
O ( N ) tranzistoare.
• Aratati cum se creaza un barrel shifter folosind o reductie catre
multiplexoare (i.e. folositi cate multiplexoare aveti nevoie). In solutia
propusa, care sunt complexitatile timpului si portilor?
• Incercati sa creati un barrel shifter direct la nivel de tranzistor. Care
este complexitatea de tranzistor si de timp a lui? Creatia directa e mai buna
decat reducerea simpla folosita anterior?
3. Proiectarea memoriei: Pentru proiectarea schemei seriala/pipelined
de cautare a ID-ului descrisa anterior, desenati diagramele in timp pentru
cautarile din pipeline. Folositi numerele descrise in capitol, si schitati clar
o mostra de arbore binar cu 15 noduri si arata cum poate fi inchis dupa
patru cautari in patru blocuri diferite. Presupune un arbore binar nu un
arbore tertial. De asemenea, calculati numarul de chei care poate fi
43
suportat folosind 16 blocuri de RAMBUS daca primele k nivele al
arborelui sunt depozitate in SRAM-ul de pe chip.
4. Memorii si arbori pipeline: Aceasta problema studiaza cum sa faci
un pipeline unei stive/heap. O stiva/heap este importanta pentru aplicatii
precum QoS, unde un ruter doreste sa transmita primul, pachetul cu
eticheta de timp cea mai recenta. In consecinta are sens sa ai o stiva
aranjata dupa eticheta de timp. Pentru a o face eficienta stiva/heap, trebuie
sa fie serializata/pipelined in aceeasi maniera ca si exemplul de arbore
binar de cautare din capitol; totusi sa faci o stiva asa de mare este greu.
Figura 2.15 arata un exemplu de P-stiva capabila sa stocheze 15 chei. O P-
stiva este un arbore binar complet, ca si o stiva/heap standard, exceptand
faptul ca nodurile de oriunde din stiva/heap pot fi vide cat timp toti copiii
nodului sunt de asemenea vizi (ex. nodurile 6, 12, 13).
(*) colectie de obiecte, plasate una peste alta ; arbore binar cu n-noduri complet, in care
toate nodurile, altele decat nodul radacina, satisfac proprietatea de ’’heap’’ .
Figura 2.15 Un exemplu de insiruire in cinci poze care se citesc de la stanga la dreapta
si apoi de sus in jos. In fiecare poza indexul reprezinta adancimea a subarborelui si
pozitia este numarul nodului asa ca valoarea este adaugata lui.
47
CAPITOLUL 3
PRINCIPII DE IMPLEMENTARE
I- Principiile sistemelor
II- Cresterea eficientei, cu mentinerea modularitatii
III-Accelerarea
48
Numar Principiu Exemple de procese in retele
P6 Creare de rutine speciale eficiente Control UDP
P7 Evitarea generalitatilor inutile Fbufs
P8 Fii flexibil in implementare Upcalls
P9 Paseaza indicatii interfetelor dintre Filtre de pachet
niveluri
P10 Paseaza indicatii antetelor protocolului Comutarea etichetelor
Fig. 3.2 Sumarul principiilor 6-10 – Refacerea eficientei pastrand modularitatea
Prefix Pasul
urmator
Liber Liber
010001* P5
110001* P5 P1
● ● 110001 P2
● ● P3
110* P3 P4
111* P2 P5
00* P1
01* P3
10* P4 Ruter
0* P4
Fig. 3.4. Exemplu utilizarii unei CAM ternare pentru cautari de prefixe
49
sa indice orice numar de caractere wildcard astfel ca 101* se potriveste cu
10100 si nu doar cu 1010.
Astfel, in fig. 3.4, un pachet trimis la o adresa destinatie care incepe cu
010001 se potriveste prefixelor 010001* si 01* dar ar trebui trimis la
portul P5 deoarece expedierea pachetelor prin Internet cere ca acestea sa
fie trimise utilizand cea mai lunga potrivire.Vom vorbi mai mult despre
aceasta problema in Capitolul 11. Deocamdata, este de retinut faptul ca
prefixele sunt aranjate intr-o CAM ternara astfel incat toate prefixele mai
lungi sa fie inaintea tuturor prefixelor mai scurte(ca in fig. 3.4); CAM
ternara sustine potrivirea saltului urmator intr-un ciclu de memorie.
Desi CAM-urile ternare sunt extrem de rapide in trimiterea mesajului,
ele cer ca prefixele mai lungi sa apara inaintea prefixelor mai scurte. Dar,
protocoalele de rutare/dirijare adauga sau sterg prefixe deseori.
Sa presupunem ca in fig. 3.4 un nou prefix, 11* , cu urmatorul nod
indicat la portul P1 trebuie sa fie adaugat in baza de date a ruter-ului.
Calea cea mai simpla de a-l insera ar produce spatiu in grupul de prefixe
de lungime 2 prin inaintarea cu o pozitie a tuturor prefixelor de lungime 2
sau mai mare.
Din pacate, pentru o baza de date mare cu aproximativ 100000 prefixe
detinuta de un router tipic, ar dura 100000 de cicluri de memorie, care ar
determina o adaugare lenta a unui prefix. Am putea obtine sistematic o
solutie mai buna prin aplicarea urmatoarelor doua principii(descrise mai
tarziu in acest capitol, ca si principiile P13 si P15).
Intelegerea si exploatarea „gradelor libertatii”
Privind tabelul din stanga fig. 3.4, vedem ca toate prefixele de aceeasi
lungime sunt aranjate impreuna si toate prefixele de lungime i apar dupa
toate prefixele de lungime j>i.
Spatiu liber
Fig. 3.5 Cautarea unui loc pentru noul prefix mutand X in pozitia lui Y , ne cere repetat
sa gasim un loc pentru a-l muta pe Y.
50
Totusi in figura toate prefixele de aceeasi lungime sunt si ele sortate
dupa valoare. Astfel, 00* apare inainte de 01*, care apare inainte de 10*.
Dar acest lucru nu impune CAM-ului sa returneze corect potrivirea de
prefixe cele mai lungi; se cere numai ordonarea prefixelor de lungimi
diferite, nu ordonarea prefixelor de aceeasi lungime.
Din fig. 3.4 abstractizata ca fig. 3.5, se vede ca daca vrem sa adaugam o
inregistrare la inceputul grupului de prefixe cu lungime i, trebuie sa cream
un spatiu liber la sfarsitul grupului de prefixe cu lungime (i+1). Astfel
trebuie sa mutam inregistrarea X, care exista deja in aceasta pozitie la alta
pozitie. Daca mutam X cu un pas mai sus, vom fi fortati la solutia
anterioara ineficienta.
Oricum, observatia despre „gradele libertatii” ne permite sa plasam pe
X oriunde intre alte prefixe adiacente de lungime (i+1). Astfel, o alta idee
este sa mutam X la pozitia detinuta de Y, ultimul prefix de lungime
(i+2),ceea ce ne forteaza sa gasim o noua pozitie pentru Y. Cum facem?
Avem nevoie de al doilea principiu.
52
Forward P
Pachetul P Test rapid
soseste pe probabilistic
fluxul F de suspiciune Adauga
copia lui P in
antet
Daca e stare de alerta, adauga F in tabel; F
Daca F e in tabel, stare de update Şir cu
ultimele
Tabel de F N
suspiciune pachete
Raport catre
manager periodic
sau dupa detectia Memoria
Mod căutare memorie
unui flux suspect judiciara
pentru pachete trimise cu
fluxul cu ID F, de adăugat
la memoria judiciara
Fig. 3.6 Pastrarea unui sir cu ultimele 100000 de pachete care contine informatii
judiciare despre fluxurile suspecte care fusesera trimise in trecut.
Q
Raport catre
manager periodic Memoria
sau dupa detectia Judiciara Daca pachetul Q
unui flux suspect al fluxului F este declarat
suspect in Tabelul de
suspiciune, adauga Q
Fig. 3.6 Pastrarea unui sir cu ultimele 100000 de pachete care contine informatii
judiciare despre fluxurile suspecte care fusesera trimise in trecut.
(proprietate P) (proprietate Q)
Subsistem 2 Subsistem 2
Specificaţii S Specificaţii W
mai slabe
Subsistem 1 Subsistem 1
Fig. 3.7 Pastrarea unui sir cu ultimele 100000 de pachete care contine informatii
judiciare despre fluxurile suspecte care fusesera trimise in trecut.
55
apar dificultati la implementare, trebuie refacuta structura sistemului (vezi
fig. 3.8).
Uneori dificultatile pot fi rezolvate relaxand conditiile impuse unuia
dintre subsisteme. Se relaxeaza de exemplu conditia impusa subsistemului
1 (conditia S mai severa devine conditia W mai putin severa), dar in
schimb conditia impusa sistemului 2 devine mai severa (P mai putin
severa devine Q mai severa).
Pot fi puse in evidenta trei tehnici ce rezulta din principiul relaxarii
conditiilor impuse initial sistemului.
P3a. Compromisul siguranta-timp. Proiectantii de sisteme se leagana in
iluzia ca sistemele lor ofera o comportare determinista, cand de fapt
comportarea este probabilista. Astfel ca, atunci cand algoritmii
deterministi sunt prea lenti e bine sa apelam la metode aleatoare.
In sisteme, milioane de utilizatori Ethernet folosesc aleatorizarea pentru
transmiterea de pachete dupa coliziuni. In retele un exemplu de
aleatorizare este software-ul de masurare a traficului NetFlow al firmei
Cisco. Daca ruteru nu are capacitatea sa contorizeze tot traficul de sosire,
el va lucra cu esantioane aleatoare de trafic fiind capabile sa identifice
fluxurile mari prin mijloace statistice. Al dolilea exemplu in retele este
servirea corecta stohastica a cozilor de asteptare (stochastic fair queuing),
in care in loc sa se urmareasca exact conversatiile care trec prin ruter, ele
sunt urmarite probabilistic, folosind dispersarea (hashing).
P3b. Compromisul precizie - timp. La fel, analiza numerica ne induce
iluzia preciziei calculatoarelor. Astfel am putea relaxa conditia preciziei de
dragul vitezei. In sisteme, multe tehnici folosesc compresia cu pierderi
prin interpolare (vezi MPEG).
Pentru a inlocui impartirile cu deplasari se folosesc praguri
aproximative. In retele, anumiti algoritmi de planificare a pachetelor
folositi in rutere implica sortarea pachetelor dupa termenle de timp de
plecare ; in retelele de viteze mari exista propuneri de reducere a antetelor
de sortare printr-o sortare aproximativa, care desi mai scade putin din
calitatea serviciului QOS, reduce din timpul de procesare.
P3c. Deplasarea in spatiu a calculelor. Exemplele de pina acum se
refereau la relaxarea conditiilor : esantionarea duce la omiterea unor
pachete, si astfel imaginea transmisa poate sa nu mai fie identica cu cea
originala. Dar alte parti ale sistemului, de exemplu subsistemul 2, trebuie
sa se adapteze acestor conditii ce conduc la pierderi. De aici rezulta si
ideea de deplasare in spatiu a calculului. De exemplu, recent,in retele, se
evita fragmentarea pachetelor in rutere obligand sistemele terminale sa
calculeze dimensiunile de pachete permise de rutere.
P4. Egalizarea componentelor sistemului
Proiectarea sistemului la nivel de schema bloc presupune
descompunerea sistemului in subsisteme si proiectarea separata a fiecarui
subsistem.desi aceasta abordare de sus in jos e convenabila din punct de
vedere al modularitatii, in practica, anumite componente critice ca
performanta sunt deseori create, cel putin partial si de jos in sus.Ca de
exemplu, algoritmii sunt adapatati la hardware-ul existent. Sunt date mai
jos cateva tehnici conforme acestui principiu :
-P4a : Exploatarea localizarii ; in cap.2 s-au aratat avantajele exploatarii
memoriilor atunci cand datele sunt continue/succesive-de exemplu acelasi
56
sector de disc, sau aceeasi pagina de DRAM. Algoritmii de cautare pe disc
folosesc acest lucruprin cautarea in arbore a radacinii superioare, ca la
arborii de tip B. Algoritmii de cautare in tabele IP folosesc acelasi artificiu
pentru a reduce timpul de cautare, plasind cateva chei in cuvintul extins.
-P4b : Compromisul memorie-viteza ; tehnica evidenta este extinderea
memoriei, ca de exemple tabelele de cautare (lookup tables), pentru a
economisi timpul de procesare. O tehnica mai putin evidenta este
comprimarea structurilor de date ca sa incapa in memoria cache, deoarece
accesul la cache este mai rapid decat la memoria obisnuita.
-P4c: Exploatarea facilitatilor hardware ; compilatoarele folosesc
reducerea complexitatii pentru optimizarea inmultirilor in bucla; de
exemplu, intr-o bucla in care adresele au 4 octeti si indexul i creste cu 1 la
fiecare pas, in loc sa se calculeze produsul 4*I, compilatorul calculeaza
noul index crescindu-l cu 4 fata de pasul precedent, deoarece inmultirile
sunt mai lungi decat adunarile. La fel se manevreaza datele, in multiplii ai
cuvintelor calculatorului, ca de ex. algoritmul sumei ciclice de control IP.
Evident ca daca se exagereaza cu aplicarea acestui acest principiu se
pune in pericol modularitatea sistemului. Pentru a evita acest lucru se
folosesc doua tehnici. Mai intai trebuie avut in vedere ca daca se folosesc
anumite caracteristici ale sistemului doar pentru a imbunatati
performantele sistemului, atunci schimbarile acestor caracteristici
afecteaza doar performanta si nu corectitudinea. Apoi, aceasta tehnica se
foloseste doar pentru componentele sistemului care se prevad a fi
strangulari .
P5 : Suplimentarea harware-ului pentru imbunatatirea
performantei
Cand totul esueaza, foloseste forta bruta. Adaugarea de hardware
suplimentar, ca de exemplu cumpararea de procesoare mai rapide poate fi
pina la urma mai simpla si mai economica decat implementarea de tehnici
sofisticate. Pe linga abordarea de tip forta bruta, prin folosirea unor
infrastructuri mai rapide (procesoare,memorii,magistrale si legaturi),
exista cateva compromisuri inteligente. Dar daca hardware-ul este mai
putin flexibil si implica costuri mari de proiectare, atunci este preferabil
ca suplimentarea de hardware sa fie minima.Pe masura cresterii dramatice
a vitezelor procesoarelor si densitatii memoriei sugereaza algoritmi noi in
software si dotarea cu procesoare mai rapide pentru cresterea vitezei.
Sistemele de calculatoare abunda de compromisuri hardware-software
stralucite. De exemplu, in sistemele multiprocesor, daca un procesor
doreste sa scrie date, el trebuie sa informeze toate celelalte procesoare care
acceseaza respectivele date din memoria cache. Aceasta interactiune poate
fi evitata, daca fiecare procesor are o componenta hardware care
supravegheaza magistrala pentru operatiile de scriere a altor procesoare si
cand e nevoie invalideaza automat locatiile respective din memoria cache.
Acest controler simplu de spionare a memoriei cache permite restului
algoritmului dedicat memoriei cache sa-si pastreze eficienta software.
Descompunerea functiilor intre harware si software este insa o arta in
sine. Hardware-ul ofera anumite avantaje. In primul rand nu e necesar
timp de aducere a instructiilor, deoarece instructiile sunt codate hard. In al
doilea rand, secvente de calcul commune (care ar necesita cateva
instructiuni in software) pot fi facute intr-un singur ciclu harware de ceas.
57
De exemplu, gasirea primului bit dintr-un cuvant de 32 de biti, ar necesita
cateva instructii pe o masina RISC, dar poate fi facuta cu un simplu codor
de prioritati (vezi capitolul precedent). In al treilea rand, haedware-ul ne
permite sa beneficiem de aplicarea paralelismului inerent problematicii.In
fine, productia hardware de masa poate fi mai ieftina decat a unui
procesor specializat. De exemplu un Pentium poate costa 100$ in timp ce
un ASIC cu performante similare pote costa doar 10$.
Pe de alta parte, proiectarea software poate fi usor translatata spre
urmatoarea generatie de chip-uri mai rapide. Hardware-ul, in ciuda
folosirii chip-urilor programabile, ramine mai putin flexibil. Totusi,
aparitia unor mijloace de proiectare ca VHDL pentru sintetizarea
hardware-ului, face ca timpul alocat pentru proiectarea hardware-ului sa
scada considerabil. Astfel, in ultimii ani, au fost proiectate chip-uri care
realizeaza functii complexe, ca de exemplu compresie de imagini sau
verificare de tabele IP.
Pe linga imbunatatirea unor anumite performante, noile tehnologii pot
determina abordari complet noi. Un proiectant vizionar ar putea sa
reproiecteze complet un sistem in vederea noilor aplicatii. De exemplu,
inventarea tranzistorului si a memoriilor rapide ne-a permis sa folosim
digitizarea vocii in retelele telefonice.
Cresterea densitatii chip-urilor a facut proiectantii de calculatoare sa
chibzuiasca asupra facilitatilor de calcul adugate memoriilor pentru a evita
strangularea procesor-memorie. In retele, aparitia liniilor de mare viteza in
anii ’80, a condos la folosirea adreselor si antetelor extinse . Ca o ironie,
folosirea calculatoarelor portabile in anii ’90, a dus la folosirea de banda
ingusta a legaturilor fara fir, si in consecinta a aparut problema
comprimarii antetelor.Tendintele tehnologice sunt oscilante.
-P5a:Folosirea pentru memorii a tehnicilor de intretesere si
serializae/pipelining.Tehnici similare sunt folosite la verificarea tabelelor
IP, la clasificare si in algoritmii de planificare care implementeaza QOS.
Bancurile multiple pot fi implementate folosind cateva memorii externe,
asu o memorie externa cum este RAMBUS, sau un SRAM pe un singur
chip care contine si logica de procesare.
-P5b : Folosirea paralelismului pe cuvinte extinse. O tema comuna in
multe proiectari de retele, ca de exemplu schema vectorului de biti de la
Lucent, este folosirea unor cuvinte de memorie extinse, care pot fi
procesate in paralel. Acest lucru se implementeaza folosind DRAM si
modul page-mode, sau folosind SRAM-uri si extinzand fiecare cuvint de
memorie.
-P5c : Combinarea DRAM cu SRAM. Stiind ca SRAM-urile sunt mai
scumpe si mai rapide, iar DRAM-urile sunt mai ieftine si mai lente, are
sens sa le combinam astfel incat sa obtinem un optim pentru amandoua.
Folosirea SRAM-urilor ca si memorii cache si a DRAM-urilor pentru
baze de date este clasica deja, dar exista multe plicatii mult mai creative
pentru ierarhizarea memoriilor. Pe moment se analizeaza efectul unui
volum redus de de SRAM la proiectarea chipurilor pentru tabelele de
verificare a fluxurilor ID. In capitolul 16 sunt descrise tehnici mai non-
uzuale de aplicare a acestei tehnici la implementarea unui numar mare de
numaratoare, unde bitii cei mai putini semnificativi sunt memorati in
SRAM.
58
II. Principii pentru modularitate si eficienta
Lucrari de profil (Dave Clark) au aratat ineficienta implementarilor
stratificate si a modularitatii, dar raspunsul altora (Radia Perlman) a fost ca
acest lucru nu arata decat faptul ca s-a ajuns in faza in care ne putem
plinge de ceva. Ideea este desigur, ca sitemele complexe cum sunt
protocoalele de retea nu pot fi implementate decat folosind stratificarea si
modularitatea. Urmatoarele principii arata cum poate fi redobindita
eficienta, pastrind modularitatea.
P6. Crearea unor rutine specializate eficiente si inlocuirea rutinelor
cu scop general
Folosirea abstractizarilor in proiectarea sistemelor de calcul poate face
sistemul mai compact, ortogonal si modular. Totusi cu timpul, folosirea
rutinelor cu scop general a dus la ineficienta. In cazurile importante trebuie
proiectate si optimizate rutine specializate.
Un exemplu poate fi gasit in cazul memoriilor cache pentru baze de
date. Cea mai generala strategie de utilizare a memoriilor cache prevede
mutarea pe disc a celor mai vechi inregistrari. Totusi sa consideram o
rutina a procesului de interogare (query-processing), care proceseaza in
bucla o secventa de tuple ale bazei de date. In acest caz, cea mai recenta
inregistrare va fi cel mai tirziu folosita in viitor, deci e candidatul ideal
pentru inlocuire. Astfel ca aplicatiile mai noi ale bazelor de date inlocuiesc
rutinele sistemului de memorare in cache cu ritine mai specializate. E bine
ca aceste specializari sa se faca doar pentru rutinele cheie, pentru a evita
extinderea peste masura a codului. Un exemplu din retele sunt rutinele
rapide de procesare UDP.
P7. Evitarea generalizarilor inutile
Tendinta de a proiecta subsisteme abstracte si generale poate duce la
crearea unor facilitati inutile sau rar folosite. Astfel, in loc sa mai
trebuiasca sa facem rutine specializate suplimentare (e.g. P6) cu care sa
inlocuim rutinele generale, am putea sa eliminam diverse facilitati
crescand astfel performanta. Ca si in cazul P3, eliminarea acestor rutine
impune utilizatorilor sa se dezobisnuiasca sa le foloseasca. De exemplu, la
procesoarele RISC, eliminarea instructiunilor complexe cum sunt
inmultirile, implica emularea lor prin firmware. Un exemplu din retele este
cazul fbuf-urilor care ofera un serviciu specializat memoriilor virtuale, ce
asigura o copiere eficienta intre spatiile de memorie virtuala.
P8. Nu te incurca cu implementarile de referinta.
Specificatiile sunt scrise pentru claritate, nu ca sa sugereze o
implementare eficienta. Deoarece limbajele abstracte ale specificatiilor
sunt nepopulare, multe specificatii contin indicatii ferme despre care
anume functie trebuie calculata si cum sa fie implementat calculul. Acest
fapt are doua efecte secundare.
Mai intai exista o tendinta reala spre specificarea exagerata. Apoi, multi
implementatori copiaza implementarea de referinta in specificatii, ceea ce
constituie o problema cand implementarea de referinte a fost aleasa pentru
claritate si nu pentru eficienta. Implementatorii sunt liberi sa schimbe
implementarea de rferinta atita timp cat efectele externe ramin aceleasi. De
fapt pot fi structurate alte implementari, care sa fie si eficiente si modulare.
59
In sisteme, Clark a sugerat folosirea la sistemele de operare a apelurilor
spre nivelurile superioare (upcalls). La aceste upcalls-uri un nivel inferior
poate apela unul superior, pentru avizare sau a cere date, incalcand
apparent regulile de decompozitie ale proiectarii de sisteme. Aceste apeluri
sunt astazi utilizate frecvent in implementarile protocoalelor.
P9. Paseaza indicatii interfetelor modulelor
O indicatie (hint) sau o sugestie este o informatie pasata de la client la
serviciu, care poate scuti serviciul de volume mari de calcul, daca este
corecta. Cuvintele cheie aici sunt paseaza si daca este corecta. Prin
pasarea indicatiei in cererea sa serviciul poate evita necesitatea unei citiri
asociate in tabele, necesare pentru accesul la memoria cache. De exemplu,
o indicatie poate fi folosita pentru a furniza receptorului un index direct in
starea de procesare. Dar, spre deosebire de memoria cache, nu se
garanteaza ca indicatia este corecta, astfel ca trebuie verificata cu alte
informatii a caror corectitudine este verificabila. In majoritatea cazurilor,
indicatiile imbunatatesc performanta, daca sunt corecte
Din insasi definitia hint-ului rezulta necesitatea verificarii corectitudinii
sale, scutind astfel receptorul de aceasta etapa. Un hint verificat se
numeste tip (sfat). Sfaturile sunt greu de utilizat, tocmai din cauza
conditiei de a le asigura corectitudinea. Un exemplu din sisteme este
sistemul Alto-File care are fiecare bloc de fisiere dotat cu un pointer
indicand urmatorul bloc de fisiere. Acest pointer este tratat doar ca hint,
si este verificat cu numele fisierului si numarul blocului memorate chiar
in interiorul blocului. Hinturile incorecte nu trebuie sa pericliteze
corectitudinea sistemului ci doar sa scada din performante.
P10. Paseaza indicatiile in antetele protocolului
Pentru sistemele distribuite, extensia logica a principiului P9 este sa se
paseze informatia ca indicatii in antetul mesajului. Acest lucru poate sa
constituie un principiu separat, pentru sistemele distribuite. Pentru
sistemele paralele acest principiu e folosit de arhitecti pentru a evita
ineficientele in pasarea mesajelor. Una din ideile de la mesajele active
este sa avem un mesaj ce transporta adresa handlerului de intreruperi
pentru expedierea rapida. Alt exemplu este comutarea etichetelor (tag
switching), in care pachetele transporta un indice suplimentar pe linga
adresa destinatie, pentru a permite verificarea rapida a acestei adrese.
Etichetele sunt folosite ca sugestii, deoarece nu este verificata
corectitudinea etichetelor ; pachetele pot fi dirijate spre o destinatie gresita
si acolo ele trebuie verificate.
60
memorie. Astfel, merita sa facem mai eficiente comportarile uzuale, chiar
daca devin mai costisitoare comportarile neuzuale.
Optimizarea euristica a cazurilor probabile nu da satisfactie
teoreticienilor, ei preferind mecanisme ale caror beneficii pot fi cuantizate
cu precizie, fie in medie fie pentru cazul cel mai defavorabil. In apararea
metodelor euristice, trebuie spus insa ca fiecare calculator in functie astazi,
optimizeaza cazurile cele mai probabile de cel putin un milion de ori pe
secunda.
De exemplu, la folosirea ”paging”-ului, cel mai defavorabil numar de
referiri la memorie pe care le poate avea o instructiune de PC este de
patru, (extragerea nstructiei din memorie, citirea primului nivel al
tabelului de pagini, citirea celui de al doilea nivel al tabelului de pagini si
extragerea operandului din memorie). Dar, folosind memoriile cache
numarul de accese la memorie poate fi redus la zero. In general, memoriile
cache permit proiectantilor sa foloseasca structuri modulare si adresari
indirecte, castigand astfel in flexibilitate si in final in performanta pentru
cazurile cele mai probabile. Deci merita sa tratam si sa subliniem
importanta memorarii in memorii cache.
P11a : Folosirea memoriilor cache
Principiul cazului probabil are utilizari subtile, asociat cu folosirea
memoriilor cache. De exemplu, daca in editorul EMACS dorim sa
schimbam bufferele, editorul ne ofera numele ultimului buffer folosit
(default buffer name). Acest lucru economiseste timpul de tiparire in cel
mai probabil caz, adica atunci cand se comuta mereu intre doua buffere.
Folosirea predictiei antetului este un alt exemplu de optimizare in retele a
cazului cel mai probabil. Costul procesarii pachetului poate fi mult redus
daca se presupune ca urmatorul pachet ce va fi receptionat e strans legat de
ultimul pachet procesat (de exemplu este urmatorul pachet din secventa),
si nu necesita exceptii la procesare.
Trebuie precizat ca determinarea cea mai buna a cazurilor cele mai
probabile se face prin masuratori si prin scheme care inregistreaza automat
cazurile comune. Dar depinde de multe ori si de intuitia proiectantului.
Cazul cel mai probabil poate fi incorect in situatiile speciale sau se poate
schimba in timp.
P12. Adauga sau foloseste starile pentru a castiga viteza
Daca o operatie este costisitoare, trebuie luata in considerare o stare
suplimentara dar redundanta, pentru accelerarea operatiei. La bazele de
date, un exemplu este adaugarea unui indice suplimentar. Bancurile de
inregistrari pot fi memorate si cautate folosind o cheie primara, ca de
exemplu numarul asigurarii sociale a clientului. Daca mai apar chestionari
suplimentare referitoare la numele acelui client (balanta de cont, etc.), se
poate plati folosind un index suplimentar (de exemplu o tabela hash sau un
arbore B). Dar starea suplimentara implica prevederea posibilitatii de
schimbarea a sa atunci cand apar modificari.
Totusi, uneori, acest principiu poate fi aplicat fara adaugarea de stari
suplimentare, doar folosind starile existente, fapt subliniat de principiul
P12a.
P12a. Calculul incremental
La sosirea sau plecarea unui client trebuie actualizata tabela de asteptare
pentru clienti. La fel este si in compilatoare, la siruri (vezi exemplul de la
61
P4c) unde se calculeaza incremental noua tabela de indecsi din cea veche,
si nu se folosesc inmultiri pentru calculul valorii absolute a indecsilor. In
retele, un exemplu de calcul incremental este calculul sumelor ciclice de
control IP, unde se modifica doar o mica parte din campurile pachetelor.
P13. Optimizarea gradelor de libertate
E utila la determinarea caror variabile se afla sub control si a celor care
le controleaza, precum si la determinarea criteriilor de obtinere a unei bune
performante. Apoi se trece la optimizarea acestor variabile pentru
maximizarea performantei. De exemplu clientii sunt inscrisi in tabele de
asteptare pe masura ce apar locuri libere, dar optimizarea asteptarii se
poate face prin asignarea la un set de tabele continue a fiecarui client in
asteptare.
Un alt exemplu, din compilatoare, este algoritmul coloring algorithm,
prin care se face asignarea registrelor in timp ce se minimizeaza depasirea
capacitatii registrelor. Un exemplu din retele este algoritmul de testare
multibit a tabelelor IP de cautare. In acesta un grad de libertate care poate
fi prezentat este ca numarul de biti care poate fi utilizat intr-un nod de test
poate fi variabil, si depinde de calea de test, si nu este fix la fiecare nivel.
Numarul de biti utilizati poate fi optimizat prin programare dinamica
pentru a cere cel mai mic volum de memorie la o viteza impusa.
P14: Folosirea unor tehnici specifice universurilor finite (cum sunt
numerele intregi)
Cand avem de-a face cu universuri mici, ca de exemplu intregii de
valori moderate, se folosesc tehnici specifice ca bucket sorting, array
lookup, bitmaps, care sunt mai eficiente decat algoritmii generali de
sortare si cautare.
Pentru a translata o adresa virtuala intr-p adresa fizica procesorul
incearca mai intai o memorie cache numita TLB. Daca nu reuseste,
procesorul trebuie sa caute in tabela de pagini.Se foloseste un prefix al
bitilor de adresa cu care tabela de pagini este indexata direct. Folosirea
cautarii in tabele evida folosirea tabelelor de dispersare (hash) sau cautarea
binara, dar duce la dimensiuni mari ale tabelelor de pagini. Un exemplu
din reteleal acestei tehnici sunt contoarele de timp,(vezi capitolul 7) unde
este construit un algoritm eficient pentru un ceas de timp cu domeniu
limitat, folosind zone circulare.
P15: Folosirea tehnicilor din teoria algoritmilor pentru crearea unor
structuri eficiente de date
Chiar in prezenta unor strangulari majore, ca translatarea adreselor
virtuale, proiectantii sistemelor resping algoritmii inteligenti cum sunt
transmiterea de indicatii, folosirea memoriilor cache sau a tabelelor de
cautare performante. Algoritmii eficienti pot imbunatati mult performanta
sistemelor. Primele 14 principii trebuie sa fie aplicate inainte ca oricare
dintre rezultatele teoriei algoritmilor sa duca la strangulari, cum se
intimpla in multe cazuri.
Abordarea algoritmica include folosirea structurilor standard de date la
fel ca si a tehnicilor algoritmice cele mai generale, ca de exemplu
aleatorizarea sau dezbina si cucereste. Pe de alta parte, proiectantul unui
algoritm trebuie sa fie pregatit sa faca fata si situatiei in care sa vada ca
algoritmul sau a devenit perimat, din cauza schimbarilor de tehnologie sau
de structura. Progresul real poate aparea mai degraba din aplicarea
62
gandirii algoritmice decat din reutilizarea vechilor algoritmi. In
calculatoare exista numeroase exemple stralucite de folosire a unor
algoritmi ca de exemplu: algoritmul de compresie Lempel-Ziv folosit in
utilitarul gzip din UNIX, algoritmul Rabin-Miller de test a proprietatii de
a fi numar prim din sistemele cu chei publice, si folosirea arborilor B
(datorat lui Bayer-McCreight) din bazele de date. In retele, exemple deja
prezentate includ algoritmul Lulea-IP-lookup si schema RFC pentru
clasificarea pachetelor.
63
CAPITOLUL 4
PRINCIPIILE IN ACTIUNE
Memorie
CPU Pagina X
Recepţionarea
Aplicatia P următorului ...
pachet în A
Kernel/nucleu Pagina A
ADAPTOR
Lista valida X, Y, ..., L, A
pt P
RETEA
Figura 4.1. În APDs, adaptorul de reţea primeşte un set de pagini valide (X, Y, L, A, etc.)
pentru o anumită aplicaţie P. Când aplicaţia P face o cerere de primire a datelor în pagina
A, adaptorul trebuie să verifice dacă A este în lista paginilor valide, înainte de a permite
recepţia lui.
65
Memorie
Page X
Recepţionarea
CPU următorului ...
pachet în A
Aplicatie P Page A
Kernel
RETEA
Figura 4.1. În APDs, adaptorul de reţea primeşte un set de pagini valide (X, Y, L, A,
etc.) pentru o anumită aplicaţie P. Când aplicaţia P face o cerere de primire a datelor în
pagina A, adaptorul trebuie să verifice dacă A este în lista paginilor valide, înainte de a
permite recepţia lui.
Figura 4.2: Evitarea necesităţii actualizării tabelei de dispersie, prin pasarea manevrei
prin interfaţa aplicaţie-adaptor
Exercitii
• Este ghidajul/handle o indicaţie/hint sau un tip ? să revenim la P1:
daca e un handle de ce să pasăm numărul paginii (e.g.A) interfeţei? De ce
să eliminăm accelerarea uşoară a vitezei task-ului de confirmare a
numărului paginii?
• Pentru a găsi tabela corespunzătoare aplicaţiei P e necesară o căutare
în tabelele de dispersie, folosind P ca şi cheie. Acest lucru atenuează
argumentul de a scăpa de căutarea în tabelele de dispersie ca să verificăm
dacă o pagină e validă sau nu, cu excepţia rafinării căutării în tabelele de
dispersie. Cum poate fi făcut acest lucru ?
68
CurrentMin iniţial pus pe 0 (ce corespunde costului lui S). De fiecare dată
când algoritmul doreşte să găsească nodul de cost minim care nu aparţine
arborelui, CurrentMin este incrementat cu 1 până este găsita o locaţie de
tablou care conţine o listă nevidă. Orice nod din această listă poate fi
adăugat la arbore. Costul algoritmului este O ( N + Diam ∗ MaxLinkCost )
deoarece acţiunea care dă în avans CurrentMin poate fi cel mult de
dimensiunea tabloului. Aceasta este mult mai bine dect N log N ,dacă N
este mare şi Diam şi MaxLinkCost sunt mici.
Factorul crucial care permite folosirea eficientă a cozii de aşteptare cu
sortare prin găleată a priorităţilor este faptul că costurile nodurilor sunt
întodeauna înaintea valorii lui CurrentMin. Aceasta este condiţia de
monotonie. Dacă nu ar fi aşa algoritmul ar începe de la 1 la fiecare iteraţie,
în loc sa înceapă de la ultima valoare a lui CurrentMin, şi să nu mai revină
niciodată. Această condiţie de monotonie este evidentă pentru algoritmul
Dijkstra deoarece costul nodurilor care nu aparţin arborelui trebuie să fie
mai mari decât costurile nodurilor din arbore.
Figura 4.6. arată starea cozii de aşteptare cu sortarea priorităţii cu găleată
după ce A a fost adăugat arborelui (cadrul din dreapta în fig.4.5). La acest
moment CurrentMin=2, care este egal cu costul lui A. La următorul pas,
CurrentMin va deveni 3, şi D va fi adăugat arborelui. Acest lucru duce la
reducerea costului lui C la 4. Astfel C va fi scos din lista din poziţia 5 şi
adăugat în lista vidă din poziţia 4. CurrentMin devine 4 şi abia atunci C
este adăugat arborelui.
Exerciţii:
• Algoritmul cere ca un nod să fie extras dintr-o listă şi adăugat altei
liste, precedentă. Cum poate fi făcut acest lucru eficient ?
• In fig.4.6 cum ştie algoritmul că a terminat, după adăugarea nodului C
arborelui, şi să nu mai parcurgă tabloul pîna la capăt ?
• In reţelele unde apar defectări, conceptul de diametru este foarte
suspect, deoarece el se poate modifica mult în caz de defectare.
Considerăm o topologie circulară, unde toate cele N noduri au diametrul 2
prin nodul zis central; dacă acesta se defectează, diametrul scade la N/2.
Deobicei, în practică, diametrul este mic. Acest lucru poate crea probleme
în dimensionarea tabloului ?
• Putem evita complet problema diametrului înlocuind tabloul liniar din
fig.4.6 cu unul circular de dimensiune MaxLinkCost ? Explicaţi. Soluţia
rezultată se numeşte algoritmul Dial.
70
Majoritatea protocoalelor fac demultiplexarea pe baza unor identificatori
în antetul/header-ul protocolului. Aceşti identificatori pot să varieze ca
lungime în diferite protocoale. De exemplu, câmpurile pentru Ethernet pot
fi de 5 octeţi, iar numerele portului TCP au 2 octeţi. Astfel x-kernel-ul
permite demultiplexarea pe baza identificatorilor de protocol cu lungime
variabilă. Cand se iniţializează sistemul, rutina protocolului înregistrează
legăturile între identificatori şi protocolul destinaţie cu nucleul-x. In timpul
rulării, când un pachet soseşte, rutina protocolului poate extrage
identificatorul protocolului din pachet şi apelează rutina nucleului-x de
demultiplexare pentru protocolul destinaţie. Cum pachetele pot veni la
viteze mari, rutina de demultiplexare trebuie să fie rapidă. Rezultă
următoarea problemă.
Problemă: In medie, cea mai rapidă cale de a face o căutare este folosirea
unui tabel de dispersie. Cum este prezentat în figura 4.9, sunt necesare folosirea
unor funcţii de dispersie asupra identificatorului K pentru generarea unui index
de dispersie, folosirea acestui index pentru a accesa tabelul de dispersie, şi
compararea cheii L, reţinută la intrarea în tabelul de dispersie, cu K. Dacă se
potrivesc, rutina de demultiplexare poate recupera protocolul destinaţie asociat
cheii L. Presupunem că funcţia de dispersie a fost aleasă să facă coliziunile rare.
Deoarece lungimea identificatorilor este un numar arbitrar de octeţi,
rutina pentru comparaţie pentru cele două chei trebuie, în general, să facă
comparaţia octet cu octet. Oricum, presupunem cazul cel mai des întâlnit a
identificatorilor pe 4 octeţi, care este dimensiunea unui cuvânt. In acest
caz, este mult mai eficient să facem comparatia la nivel de cuvânt. Astfel
scopul este (P4) să exploatăm comparaţia eficientă pe cuvânt pentru
optimizarea cazului cel mai probabil. Cum putem opera, daca se
manevrează diferite protocoale ?
Indicaţie: Dacă x-kernel-ul are de demultiplexat un identificator de 3
octeţi, trebuie să folosească rutina de comparaţie octet cu octet; dacă
identificatorul e pe 4 octeti, şi maşina lucrează cu cuvinte de 4 octeţi,
poate fi făcută comparaţia pe cuvânt. Primul grad de libertate care poate fi
folosit este să avem rutine de comparaţie diferite pentru cele mai comune
cazuri (comparare pe cuvânt, comparare pe cuvinte lungi) şi o rutină de
avarie/default pentru compararea pe octet. Acesta este un compromis
spaţiu-timp (P4b). Pentru corectitudine, trebuie ştiut care rutină de
comparaţie trebuie folosită în cazul fiecărui protocol. Trebuie invocate
principiile P9 de pasare de indicaţii interfeţelor şi P2a de realizare a
precalculelor.
Soluţie: Fiecare protocol trebuie să declare identificatorul şi protocolul
destinaţie nucleului-x când se iniţializează sistemul. Cand s-a realizat acest
lucru, fiecare protocol poate să-şi predeclare lungimea identificatorului, ca
nucleul-x să folosească rutine de comparaţie specializate pentru fiecare
protocol. Efectiv, informaţia este transmisă între protocolul client şi nucleul-x
mai devreme. Presupunem că nucleul-x are un tabel de dispersie pentru fiecare
protocol client şi că nucleul-x ştie contextul pentru fiecare client astfel încât să
folosească codul specializat pentru acel client.
Exerciţii
• Codaţi comparaţiile octet-cu-octet şi pe cuvânt pe calculatorul vostru,
faceţi un număr mare de comparaţii şi apoi comparaţi timpul global
necesar fiecărui tip.
71
• In primele soluţii ADC cautarile tabelelor hash au fost rafinate prin
pasarea unui index (în loc de lungimea identificatorului, ca la început). De
ce poate fi această soluţie dificilă în acest caz ?
72
Soluţie: Cum M<32, un bitmap de dimensiune 32 poate uşor să încapă într-
un cuvânt. Astfel pointerii nuli sunt scoşi după ce se adaugă un bitmap cu zero
biţi indicând pozitia originală a pointerilor nuli. Acest lucru este arătat în figura
4.11. Nodul arborelui cu prefix poate fi acum înlocuit cu un bitmap şi un nod al
arborelui cu prefix comprimat. Un nod al arborelui cu prefix comprimat este un
tablou ce conţine doar valorile nenule din nodul original. Astfel în figura 4.11
nodul rădăcina al arborelui cu prefix original (de sus) a fost înlocuit cu nodul
arborelui cu prefix comprimat (de jos). Bitmapul contine un 1 în prima şi a
şaptea pozitie, unde nodul rădăcină conţine valori nenule. Tabloul necomprimat
conţine acum doar 2 elemente, primul pointer şi KEY 3.
Având în vedere că atât nodurile comprimate cât şi cele necomprimate
sunt tablouri şi procesul de căutare începe cu un index I în nodul
necomprimat, procesul de căutare trebuie să consulte bitmapul pentru a
converti indexul necomprimat I într-un index comprimat C în nodul
comprimat. De exemplu, dacă I este 1 în figura 4.11, C ar trebuie să fie 1;
daca I este 7, C ar trebui să fie 2. Dacă I este oricare altă valoare, C ar
trebui să fie 0, indicând că este un singur pointer nul.
Conversia din I la C poate fi realizată uşor ţinând cont de următoarele.
Daca poziţia I în bitmap conţine un 0, atunci C=0. Altfel, C este un număr
de 1-uri în primii I biţi ai bitmapului. Astfel dacă I=7, atunci C=2,
deoarece sunt doi biţi setaţi în primii şapte biţi ai bitmapului. Acest calcul
necesită cel mult două referiri la memorie: una pentru a accesa bitmapul
(deoarece bitmapul e mic, P4a) şi una pentru a accesa tabloul comprimat.
Calculul numarului de biţi setaţi într-un bitmap poate fi făcut folosind
registre interne (în software) sau logica combinaţională (în hardware).
Astfel încetinirea efectivă este cu un factor ceva mai mare de 2 în software
şi exact 2 în hardware.
Exerciţii
• Cum puteţi folosi căutarea tabelelor (P14, P2a) pentru accelerarea
contorizării numărului de biţi din set, în software? Ar fi necesar al treilea
apel la memorie ?
• Presupunem că bitmap-ul e mare (sa zicem,M=64K). Ar părea că
contorizarea numărului de biţi din set cu asemenea bitmap mare e
imposibil de lentă, în software sau hardware. Puteţi găsi o cale de
accelerare a contorizării biţilor în bitmap-urile mari (P12 si P2a) ?
Figura 4.14 Pachetul de stare a legaturii a ruterului R1 (cu 500 de noduri vecine) poate
fi prea mare ca sa incapa intr-un cadru de nivel legatutra de date. Acest lucru implica
fragmentari si reasamblari ineficiente, la fiecare salt.
77
• La fel ca in exemplele de reducere a severitatii conditiilor, aceasta
solutie poate genera conditii incorecte neasteptate (temporare deobicei si
fara sa fie foarte grave). Tinand cont de solutia gasita la exercitiul
precedent, descrieti un scenariu in care un anume ruter, de exemplu R2,
poate gasi (la un moment dat) eroarea in care, in baza sa de date pentru
LSP-uri, acelasi nod terminal (de ex E1) apartine la doua pseudorutere,
R1a si R1b. De ce nu este acest caz mai rau decat rutarea obisnuita a LSP-
urilor ?
Figura 4.16 Folosirea naiva a unuia sau a mai multor timer-e (pentru a verifica daca
sursa nu transmite un volum de trafic mai mare decat B biti la fiecare T secunde)
T Aleator T Aleator
Figura 4.17 Daca se iau pauze aleatoare intre intervalele de supraveghere ruterele vor
detecta violarile de contract cu o probabilitate mare
81
din statia Y. Un server ocupat, ca cel de Web, poate avea o multime de
conexiuni concurente.
Starea conexiunii consta din lucruri ca numarul de pachete trimise de
statia X, neconfirmate de statia Y. Orice pachet de date neconfirmat de
statia Y intr-un anumit interval de timp, trebuie retransmis de X. Pentru a
face retransmisia, protocoalele de transport obisnuiesc sa aiba timere
periodice ce declanseaza retransmisia oricarui pachet a carui confirmare
intarzie sa apara dupa o anumita perioada de timp.
82
periodic si eficient prin toate conexiunile existente. Acest lucru duce la
urmatoarea problema.
Problema. Se poate scapa de pierderea cauzata de lista de conexiuni
explicita, dar sa se retina si tabela de dispersie? E rezonabila adaugarea
unei mici informatii suplimentare tabelei de dispersie. Cand facem acest
lucru, se poate observa ca lista originala de conexiuni a fost creata cu
dublu inlantuita, pentru a permite la terminare o stergera facila a
conexiunilor. Dar acest lucru duce la depozitare si dilueaza memoria de
date cache. Cum ar putea fi utilizata o lista simplu inlantuita, fara
incetinitirea procesului de stergere?
Indiciu: Prima parte este usor de reparat, inlantuind intrarile valabile din
tabela de dispersie intr-o lista. Cea de-a doua parte este mai dificil de
realizat (evitarea listei cu dubla inlantuire, care ar necesita doi indicatori
per intrare a tabelei de dispersie). O lista de legatura consta din noduri,
fiecare din ele contine o identitate a conexiunii (96 de biti pentru IP), plus
doi indicatori (sa zicem 32 biti fiecare) pentru o stergere facila. Din
moment ce tabela de disperse este necesara pentru o demultiplexare
rapida, lista de legaturi poate fi indepartata daca intrarile valide din tabela
de dispersie sunt conectate ca in figura 4.21, iar un indicator este pastrat in
capul listei. La un ticait de timer, rutina de retransmitere va scana periodic
lista. Scanarea intregii tabele de dispersie are o eficienta redusa, deoarece
pot exista o multime de locatii goale in interiorul sau.
Solutia implicita ar fi aceea de a adauga doi indicatori la fiecare intrare
valida a tabelei de dispersie in scopul de a implementa o lista cu dubla
legatura. Din moment ce acesti indicatori pot fi indecsi ai tabelei de
dispersie in loc de indicatori arbitrari catre memorie, indecsii nu trebuie sa
aiba dimensiunea mai mare decat dimensiunea tabelei de dispersie. Chiar
si cea mai mare tabela de dispersie ce contine conexiuni, nu ar avea nevoie
de mai mult de 16 bits (in general , mult mai putin). Solutia implicita da
rezultate bune, adaugand cel mult 32 de bits, in loc de 160 per intrare, deci
o economie de 128 de bits. In orice caz, este posibil de a face mai mult, in
sensul de a adauga numai 16 bits per intrare. Considerati utilizarea
evaluarii de viteza redusa (P2b) si specificatiile mai putin severe (P3).
85
transport de la emisie poate utiliza informatia data de aplicatie pentru a seta
un bit w de retinere, in fiecare pachet pe care il transmite; bitul w va fi
anulat cand emitatorul doreste o confirmare imediata.
De exemplu, in figura 4.23 nivelul transport de la emisie este informat de
catre aplicatia transfer de fisiere, ca fisierul de trimis are patru blocuri.
Astfel, nivelul transportde la emisie va valida bitul de retinere pentru
primele trei pachete, respectiv il va invalida pentru al patrulea pachet.
Receptorul va trimite in consecinta, o singura confirmare, in loc de patru.
Dar o aplicatie care este sensibila la intarzieri, poate sa nu trimita nici o
informatie privitoare la datele de transmis. Bitul de retinere este un indiciu,
pe care receptorul poate sa-l ignore si sa trimita oricum o confirmare. Desi
solutia pare ingenioasa, nu e o idee buna pentru protocolul TCP actual.
Exercitii:
• O tehnica de reducere a numarului de confirmari este returnarea
confirmarilor in pachetele de date dinspre receptor spre emitator. In acest
scop, majoritatea protocoalelor de transport, ca TCP, au campuri
suplimentare in pachetele de date pentru confirmarile in sens opus.
Returnarea confirmarilor in pachete de date e compromisul clasic
latenta/eficienta. Cat timp ar trebui sa astepte nivelul transport datele din
sens opus? Dar, exista aplicatii uzuale in care aplicatia de la emisie
cunoaste aceasta informatie. Cum poate fi extinsa solutia precedenta pentru
a permite si returnarea confirmarilor prin pachete de date, si comasarea lor?
Exercitii:
• O tehnica de reducere a numarului de confirmari este returnarea
confirmarilor in pachetele de date dinspre receptor spre emitator. In acest
scop, majoritatea protocoalelor de transport, ca TCP, au campuri
suplimentare in pachetele de date pentru confirmarile in sens opus.
Returnarea confirmarilor in pachete de date e compromisul clasic
latenta/eficienta. Cat timp ar trebui sa astepte nivelul transport datele din
sens opus? Dar, exista aplicatii uzuale in care aplicatia de la emisie
cunoaste aceasta informatie. Cum poate fi extinsa solutia precedenta pentru
a permite si returnarea confirmarilor prin pachete de date, si comasarea lor?
• Evaluarea imbunatatirilor pretinse se poate face cu intrebari de test. De
exemplu, schimbarea poate afecta restul sistemului ? De ce ar putea ca
86
retinerea confirmarilor sa afecteze alte parti ale protocolului de transport,
cum ar fi controlul fluxului si al congestiilor ?
Figura 4.24 Schimbari lente a bazei de date cu alimente la orele 2pm, 3pm, 6pm. Cel
care urmareste baza de date vrea sa vada doar schimbarile (aici, de la 2pm la 3pm s-a
schimbat pretul la bauturi nealcoolice, si de la 3pm la 6pm, la cereale)
Un cititor vrea la ora 18 sa vada doar diferenta fata de ora 14 : Coke fata
de Pepsi, Wheaties fata de Cheerios. Alt cititor vede pagina la ora 15:00 si
apoi la ora 18:00 vrea sa vada ce s-a schimbat la Wheaties fata de
Cheerios. Acest lucru genereaza urmatoarea problema.
Problema. Cum sa realizeze eficient baza de date asemenea interogari
incrementale (incremental queries) ? Ar fi dificil ca baza de date sa-si
aminteasca ce a citit fiecare utilizator ultima data, avand milioane de
utilizatori.
Indiciu: Daca baza de date nu memoreaza nici o informatie referitoare la
ultima citire a unui utilizator, solicitarea de citire a utilizatorului trebuie sa
contina ceva informatie (P10) despre ultima sa citire. Transmiterea
detaliilor despre ultima citire inseamna un efort urias si e total ineficienta.
Care ar fi partea de informatie care sa caracterizeze succint ultima cerere a
utilizatorului? Putem adauga o stare redundanta suplimentara (P12) la
baza de date ce permite usor indexarea, folosind informatia de la utilizator
pentru a facilita interogarea incrementala.
Solutie: Cererile de vizualizare ale utilizatorului trebuie sa contina o
anumita cantitate de informatie (P10) despre ultima solicitare de
vizualizare facuta de acesta. Cea mai succinta si relevanta informatie este
timpul la care a fost facuta ultima cerere. Daca cererea utilizatorului
contine timpul ultimei citiri, atunci baza de date trebuie organizata astfel
incat sa-si actualizeze eficient continutul la intervale date de timp.
Memorarea unor copii ale bazei de date din momentele anterioare este o
metoda ineficienta, si poate fi evitata daca se memoreaza doar
modificarilor incrementale (P12a). Acest lucru duce la urmatorul algoritm.
Se poate adauga bazei de date o lista a actualizarilor, care are in capul
listei ultimele actualizari. Cererile de citire contin momentul T al ultimei
87
citiri, deci cererea poate fi procesata prin scanarea inceputului listei, pentru
a gasi toate actualizarile ulterioare lui T.
De exemplu, in figura 4.25 in capul listei de actualizari se afla ultimele
modificari (comparati cu figura 4.24) la ora 18:00 de la Wheaties la
Cherios, si modificarea precedenta, de la ora 15:00 de la Coke la Pepsi.
Consideram o cerere de citire efectuata la ora 17:00. Cand scanam lista din
varf, procesarea cererilor va gasi actualizarea de la ora 18:00 si se va opri
cand va ajunge la actualizarea de la ora 15:00, deoarece 15:00 < 17:00,
deci cererea va returna doar prima actualizare.
Ultima reactualizare
Wheaties Æ Cheerios Coke Æ Pepsi 6 pm
6 pm 3 pm
Pepsi
Mere
Placinte
Actualizarea listei Cheerios
Å cuvinte de dimensiune W Æ
A C E
88
A D C
Å cuvinte de dimensiune W Æ
A C E
A D C
A Testul 3 Æ M Testul 4 Æ W
B M W
Testul 1Æ B Testul 2 Æ N X
B N Y
B N Z
A Testul 3 Æ M Testul 4 Æ W
B M W
Testul 1Æ B Testul 2 Æ N X
B N Y
B N Z
C N D
Figura 4.26 Cautarea binara a identificatorilor lungi poate duce la un factor de multiplicare
W (numarul de cuvinte din identificator). Metoda naiva, de reducere la un factor aditiv
prin mutare la dreapta in egalitate, esueaza.
Å W cuvinte Æ
A C E
A D C
A Tentativă 3 Æ M W
*B Testul 4 Æ *M Testul 5 Æ W
Testul 1Æ B Testul 2 Æ N X
B N Y
*B N Z
C N D
Figura 4.27: Adăugarea unui domeniu de gardă fiecarui element din coloana, pentru
căutarea binară corecta la schimbarea coloanelor
Switch
ATM
N CV 1-la-mai mulţi
91
folosirea a două conexiuni virtuale mulţi la mulţi, una C pentru
interlocutorul curent şi una L pentru ultimul interlocutor ca în figura 4.29
2 CV mulţi-la- mulţi
Exerciţii:
• Scrieţi pseudocodul părţii hardware a fiecărei staţii care actualizează
conexiunile la C şi L. Se presupune că detectorul de voce este o funcţie.
• Ce se întâmplă daca mai mulţi utilizatori vorbesc deodată? Ce
componentă hard se poate adăuga staţiei a.î. aplicaţia să afişeze ceva
rezonabil? De exemplu, nu ar fi rezonabil ca imaginile celor doi
interlocutori să fie combinate?
92
Tratarea nodurilor terminale
CAPITOLUL5
COPIEREA DATELOR
Intr-un birou, fiecare scrisoare primită este mai întâi trimisă la transport
si recepţie, unde scrisoarea este deschisă şi se decide cărui departament îi
este adresată şi se face o fotocopie pentru îndosariere.Este apoi înmânată
departamentului de securitate care verifică fiecare linie a scrisorii căutând
semne de spionaj industrial. Departamentul de securitate face si el o
fotocopie a scrisorii, pentru o eventuală utilizare ulterioară. Situaţia pare
ridicolă, dar majoritatea serverelor Web şi calculatoarele în general, fac un
număr de copii suplimentare ale mesajelor recepţionate şi transmise.Spre
deosebire de fotocopii, care consumă doar o mică cantitate de hârtie,
energie şi timp, copierea suplimentară în calculator consumă două resurse
preţioase: lăţimea de bandă de memorie şi memoria în sine. În cele din
urmă, dacă sunt k copii implicate în procesarea unui mesaj într-un server
Web, ieşirea serverului Web poate fi de k ori mai înceată.
Deci se trateaza aici eliminarea pierderilor (P1) generate de copiile
inutile. O copie este inutilă dacă nu este impusă de hardware. De exemplu,
hardware-ul cere copierea, biţilor recepţionaţi de un adaptor, în memoria
calculatorului. Totuşi, acesta nu este un motiv esenţial (în afara de cele
impuse de structurarea sistemelor de operare convenţionale) pentru
copierea între bufferul aplicaţie şi bufferul sistemului de operare.
Eliminarea copiilor redundante permite software-ului să se apropie de
capacitatea hardware-ului, unul din ţelurile algoritmilor de reţea.
Sunt expuse pe scurt alte operaţii (ca sumele de control şi criptarea) ce se
referă la toate datele din pachet şi alte tehnici pentru a unifica conditiile
impuse de software-ul protocolului si cele impuse de hardware, ca lăţimea
de bandă a magistralelor şi memoriei cache.Sunt revăzute sistemele de
operare mai reprezentative şi arhitecturile relevante, precum şi tehnicile de
93
reducere a costului manipulării datelor, păstrând modularitatea şi fără
schimbări majore în proiectarea sistemului de operare. În & 5.1. se
arată de ce/cum apar copii în plus ale datelor, &5.2 descrie o serie de
tehnici de a evita copiile prin restructurări locale ale sistemului de operare
şi ale codului reţelei la un nod final (endnode). In &5.3 se vede cum să se
evite copierea şi suprasarcinile din cazul transferurilor mari, utilizând
DMA la distanţă, care implică modificări de protocol. In $5.4 se extinde
problema pentru sistemul de fişiere dintr-un server Web şi se arată cum să
se evite copiile inutile dintre memoria cache pentru fişiere şi aplicaţie. In
&5.5. sunt discutate operaţii care includ toate datele (ca suma de control şi
criptarea) şi se introduce tehnica procesării integrate pe niveluri (integrated
layer processing).În &5.6 se extinde discutia dincolo de copiere, şi se arată
că fără analiza atentă a efectelor memoriei cache, efectele instrucţiunilor
cache pot eclipsa efectele copierii pentru mesaje mici.
Figura 5.1. Tehnici de evitare a copierii şi eficienţa cache discutate în acest capitol,
împreună cu principiile corespunzatoare
94
static(multe cereri sunt pentru continut dinamic fiind servite de un proces
CGI, computer-generated imagery).
Intuitiv, problema este simplă. Fişierul este citit de pe disc în buffer-ul
aplicaţiei printr-un apel la sistem, read()de exemplu. Combinaţia dintre
răspunsul HTTP şi buffer-ul aplicaţiei este trimisă apoi reţelei prin
conexiunea TCP către client printr-un apel de sistem, de exemplu write().
Codul TCP din subsistemul pentru reţea al kernel-ului împarte datele
răspunsului în segmente de câte un bit şi le trimite adaptorului de reţea
după ce adaugă fiecărui segment o sumă de control TCP.
CPU
Aplicatia server-ului Web Copia 3
write() read() Buffer-ul server-ului
Kernel Copia 2
TCP/IP Sist. de fisiere Buffer-ul socket
Magistrala
de memorie
Copia 1
Copia 4 Disc
Magistrala I/O
Adaptor de retea
Retea
Figura 5.2. Copii redundante implicate în manipularea unei cereri GET la un server
Detaliile reale sunt mai dificile. În primul rând fişierul este citit într-o
regiune a memoriei kernelului numită file cache (copia 1). Ideea este bună
deoarece cererile succesive la un fişier des utilizat pot fi servite din
memoria principală fără operaţiile lente de I/O la disc. Fişierul este apoi
copiat de serverul Web din file cache în buffer-ul aplicaţiei (copia 2).
Deoarece bufferul aplicaţiei şi file cache sunt în zone diferite a memoriei
principale, copierea se poate face doar de CPU, care citeşte datele din
prima locaţie de memorie şi le scrie în cea de-a doua, prin magistrala de
memorie.
Serverul Web face apoi un apel write() la socketul corespunzător.
Deoarece aplicaţia îşi poate reutiliza bufferul în orice moment (sau chiar
să-l dezaloce) după apelul write(), subsistemul de reţea din kernel nu poate
să retransmită pur şi simplu din buffer-ul aplicaţiei. Software-ul TCP
poate avea nevoie să retransmită unele părţi din fişier după un anumit timp,
timp în care aplicaţia poate reutilizarea buffer-ul în alte scopuri.
Astfel, UNIX şi multe alte sisteme de operare, oferă semantica copierii.
Buffer-ul aplicaţiei specificat în apelul write() este copiat într-un buffer
socket (un alt buffer din kernel la o adresă de memorie diferită atât de file
95
cache cât şi de buffer-ul aplicaţiei) (copia 3). În final, fiecare segment este
transmis reţelei (după ce au fost adăugate antetele de nivel legătura de date
şi IP-ul) copiind datele din buffer-ul socket-ului în memoria adaptorului de
reţea (copia 4).
Înainte de transmisia la reţea software-ul TCP din kernel trebuie să
parcurgă datele pentru a calcula suma de control TCP, pe 16 biţi, pentru
fiecare segment.
Fiecare din cele 4 copii şi suma de control consumă resurse: lăţimea de
bandă a magistralei de memorie. Copierile între locaţiile de memorie
(copiile 2 şi 3) sunt mai dezavantajoase decât celelalte, deoarece necesită
un read şi un write pentru fiecare cuvânt transferat prin magistrală. Suma
de control TCP necesită doar un read pentru fiecare cuvânt şi un singur
write pentru a ataşa suma finală. Copiile 1 şi 4 pot fi la fel de costisitoare
ca şi copiile 2 şi 3 dacă procesorul face o copiere folosind o I/O
programată; totuşi dacă dispozitivele fac singure copierea (DMA), costul
este un singur read sau write per fiecare cuvânt ce trece prin magistrală.
Copiile consumă şi lăţimea de bandă a magistralei de I/O şi lăţimea de
bandă de memoriei. O memorie care furnizează un cuvânt de W biţi la
fiecare x nanosecunde are o limită fundamentală la ieşire de W/x biţi/ns.
Chiar şi dacă folosim DMA aceste copii folosesc magistrala de memorie de
7 ori pentru fiecare cuvânt al fişierului trimis de server. Astfel ieşirea
server-ului Web nu poate depăşi T/7, unde T este cea mai mică dintre
vitezele memoriei şi a magistralei de memorie.
Mai important, copiile suplimentare consumă memorie. Acelaşi fişier
(figura 5.2.) ar putea fi stocat în memoria cache pentru fişiere, buffer-ul
aplicaţiei şi buffer-ul socket. Deşi memoria este ieftină şi multă, ea are
unele limitări şi server-ele Web vor să folosească cât mai multă memorie
cache pentru fişiere ca să evite operaţiile lente de I/O cu discul. Astfel,
exitenţa a trei copii pentru un fişier poate reduce de trei ori memoria cache
de fişiere, care la rândul său poate reduce rata de bit a cache-ului şi deci
performanţa globală a server-ului.
În concluzie, copiile redundante afectează performanţa în două moduri
fundamentale disjuncte. În primul rând, prin utilizarea unei lăţimi de bandă
a magistralei şi a memoriei mai mare decât strictul necesar, server-ul Web
rulează mai încet decât viteza magistralei chiar şi când trimite documente
care sunt în memorie. În al doilea rând, utilizând mai multă memorie decât
ar trebui, server-ul Web va trebui să citească mai multe fişiere de pe disc în
loc să le citească din file cache. A fost descris doar scenariul în care este
servit un conţinut static. În realitate, testele cu SPECweb afirmă că 30%
din cereri sunt pentru conţinut dinamic. Acesta este de multe ori servit de
un proces CGI separat (altul decât aplicaţia server) care comunică acest
conţinut server-ului prin intermediul unor mecanisme de comunicare inter-
proces cum ar fi UNIX pipe care implică de multe ori încă o copie.
Ideal, aceste traversări în plus ale magistralei ar trebui eliminate. Copia 1
nu este necesară dacă datele sunt în cache. Copia 2 pare inutilă: de ce nu
pot fi trimise datele direct la reţea din locaţia de memorie file cache? Copia
3 pare inutilă. Copia 4 nu poate fi evitată.
96
5.2. Reducerea copierii prin restructurări locale
Copia 3 este copia principală făcută de aplicaţie în buffer-ul kernelului
(sau vice versa) când un mesaj este trimis/primit pe reţea. Aceasta este o
problemă fundamentală a reţelelor, independentă de problemele sistemului
de fişiere. Soluţiile generale de eliminare a copiilor I/O redundante se
bazează pe tehnicile prezentate în secţiunea &5.4. Se presupune că
protocolul este fix dar implementarea locală poate fi restructurată (cel puţin
kernel-ul). E de dorit un numar minim de restructurări pentru a echilibra
sarcinile software-ului de aplicaţie şi ale kernelului. In & 5.2.1. sunt
descrise tehnici bazate pe o exploatare mai buna a memoriei adaptorului.
&5.2.2. descrie ideea principală pentru evitarea copiilor (prin reasocierea
paginilor fizice comune) şi pericololele sale. & 5.2.3. prezintă optimizarea
reasocierii paginilor utilizând pre-procesarea şi cache-uri pentru fluxurile
I/O, tehnici ce implică însă modificarea API (interfaţa programabila de
aplicaţie). & 5.2.4. descrie o tehnică ce utilizează memorie virtuală dar nu
modifică API.
CPU Memorie
Aplicatie
write() Buffer-ul server-ului
Kernel TCP/IP
Magistrala
de memorie
O singura copie
Magistrala I/O
Buffer socket
Adaptor de retea
Retea
Figura 5.3. Metoda Witless (afterburner) elimină nevoia copierii din kernel în adaptor
plasând buffer-ele kernelului în adaptor
Memorie
CPU
Server +buffer socket
Aplicatie Copiere la o
write() pagina libera
Kernel TCP/IP doar daca
aplicatia scrie
Magistrala de memorie
Magistrala I/O
Buffer socket
Adaptor
de retea
Retea
Figura 5.4. Utilizarea copierii-la-scriere
100
Pachet
date
Web FTP
(Domeniu 2)
Calea 1 Calea 2
IP OSI ?
(Domeniu 1)
(Domeniu 0) Calea 1 Buffer cache
Ethernet
Calea 2 Buffer cache
Figura 5.6. Preasocierea paginilor buffer in tabele de pagini ale fiecarui domeniu
intr-o cale evita costul remaparii paginii in calea de timp real dupa setarea initiala
Pachet
date
Scriitor Cititor
Proces 1 Proces 2
Tabel de pagini Tabel de pagini
Scris
VP 10 W odata R VP 10
(prealocat)
initial
Fbufs scriitoare
Fbufs libere
Structura agregata
……………… …………….
108
Numele buffer-ului B
Pagina 11
B, 1
B1
B2 Pagina 16
B, 2
ADAPTORUL
DESTINATIE
Fiber Channel
În 1988 ANSI Task Group X3T11 a început să lucreze la un standard
numit FiberChannel. Unul din scopurile FiberChannel era să ia standardul
SCSI dintre o staţie de lucru şi un disc local şi să îl extindă pe distanţe
mari. Astfel, în multe instalaţii FiberChannel, SCSI este încă utilizat ca
protocolul care rulează pe FiberChannel.
FiberChannel merge la fundamentele reţelei mai departe decât clusterele
VAX, utilizând tehnologii noi de reţele, cum ar fi legăturile punct-la-punct
pe fibră conectate cu switch-uri. Aceasta permite viteze de până la
1Gb/sec şi distanţe mai mari decât în reţeaua clusterelor VAX. Switch-
urile pot fi chiar conectate la distanţă, permiţând unei firme de comerţ să
aibă pe un site îndepărtat o memorie de rezervă a tuturor tranzacţiilor.
Utilizarea switch-urilor trebuie să aibă în vedere controlul fluxului, care
trebuie făcut cu grijă pentru a evita pierderea de pachete pe cât posibil.
FiberChannel face mai multe concesii asupra securitaţii decât
clustereleVAX, unde orice dispozitiv cu un nume potrivit poate scrie în
memoria oricărui alt dispozitiv. FiberChannel permite reţelei să fie
virtualizată în zone, si nodurile dintr-o zonă nu pot accesa memoria
nodurilor din alte zone. Produse mai recente merg mai departe si propun
chiar tehnici de autentificare ; dar ideile de bază sunt aceleaşi.
Infiniband
Infiniband porneşte de la faptul că PCI, magistrala internă I/O utilizată
în multe staţii de lucru şi PC-uri, e învechită si trebuie înlocuită. Cu o
lăţime de bandă maximă de 533 Mb/sec, magistrala PCI este inundată de
perifericele moderne de mare viteză, ca plăcile de interfaţă Gigabit
Ethernet. Deşi există câteva alternative temporare cum ar fi magistrala
109
PCI-X, magistralele interne din calculatoare trebuie redimensionate ca să
ţina pasul cu modificări de genul de la 10-Mbit Ethernet la Gbit Ethernet.
De asemenea, observăm că există trei tehnologii de reţea diferite într-un
calculator: interfaţa de reţea (ex.Ethernet), interfaţa de disc (ex.SCSI prin
FiberChannel) şi magistrala PCI. Principiul lui Occam,cea mai bună cale
este cea mai simplă, sugerează substituirea acestora trei cu o tehnologie de
reţea unică. Astfel, Compaq, Dell, HP, IBM şi SUN au format Infiniband
Trade Association. Specificaţiile Infiniband utilizează multe din ideile
tehnologiei FiberChannel. Interconectarea se face cu comutatoare şi
legături punct-la-punct. Infiniband are câteva schimbări: adresare IP pe
128 biti pentru Internet-ul de generaţie următoare, virtualizarea legăturilor
fizice individuale sub formă de căi, facilităţi pentru calitatea serviciului,
multicast si RDMA pentru evitarea copiilor.
iSCSI
FiberChannel pare să aibă un cost mai ridicat la viteză echivalentă,
pentru scrierea între părţi decât scrierea între părţile Gigabit Ethernet. Dat
fiind faptul că IP a pătruns în numeroase spaţii de reţea cum ar fi voce, TV
şi radio, natural ar fi să pătrundă şi în spaţiul de memorare. Aceasta ar
trebui să scadă preţurile (deschizând noi pieţe pentru furnizorii de
reţele).Pe mai departe, se extind FiberChannel şi Infiniband să conecteze
prin Internet centre de date distante. Aceasta implică folosirea de
protocoale de transport care nu sunt neapărat compatibile cu TCP, în ceea
ce priveşte reacţia la congestie. De ce să nu adaptăm TCP în acest scop, în
loc să modificăm celelalte protocoale ca să fie compatibile TCP?
Cel mai interesant lucru la iSCSI este modul de emulare a RDMA prin
protocoale IP standard. La RDMA, adaptorul gazdă implementează în
hardware protocoalele de transport ale Internet-ului. Protocolul de
transport din Internet este TCP. Deci adaptoarele trebuie să implementeze
TCP în hardware. Chip-uri care realizează TCP, fără a creşte efortul de
calcul, sunt pe cale să devină accesibile pe scară largă.
Mai dificile sunt următoarele părţi. În primul rând, TCP este un protocol
orientat pe flux. Aplicaţia scrie octeţii într-o coadă, şi aceşti octeţi sunt
segmentaţi arbitrar în pachete. RDMA, pe de altă parte, este bazată pe
mesaje, fiecare din acestea are un câmp “nume buffer”. În al doilea rând,
RDMA prin TCP necesită un antet pentru numele buffer-elor.
Propunerile RDMA rezolvă ambele probleme stratificând trei
protocoale peste TCP. Primul protocol, MPA, adaugă un antet care
defineşte limitele mesajelor în fluxul de biţi. Al doilea şi al treilea protocol
implementează câmpurile antetelor RDMA dar sunt separate dupa cum
urmeaza. Când un pachet transportă date are nevoie doar de numele
bufferului şi deplasarea. Acest antet este abstractizat prin antetul DDA
(Direct Data Access) împreună cu o comandă (read sau write).
Protocolul RDMA, stratificat peste DDA adaugă un antet cu câteva
câmpuri în plus. De exemplu, pentru o citire RDMA la distanţă, cererea
iniţială trebuie să specifice numele buffer-ului de la distanţă (de citit) şi
numele bufferului local (de scris). Unul dintre numele acestor două buffer-
e poate fi plasat în antetul DDA, dar celălalt trebuie plasat în antetul
RDMA. Astfel, cu excepţia mesajelor de control, cum ar fi iniţierea unei
citiri, toate datele transportă doar un antet DDA şi nu un antet RDMA.
110
În evoluţia de la clusterele VAX la RDMA, o generalizare interesantă a
fost înlocuirea buffer-ului cu nume cu un buffer anonim. În acest caz
antetul DDA conţine numele unei cozi şi pachetul este plasat în primul
buffer liber, din capul cozii de la recepţie.
112
CPU Memorie
Aplicatia server-ului Web Buffer server Cached response
header
write() read() Buffer socket
Cached checksum
Kernel TCP/IP Sistem fisiere Buffer fisier
cache
Buffer IO-Lite
Bus memorie
Copia 1
Copia 2 Disc
Bus I/O
Adaptor de retea
Retea
Figura 5.10. IO-Lite elimină toate copiile redundante din figura 5.2. pasând efectiv pointeri
(prin mapări VM) la un singur buffer IO-Lite. Presupunând că fişierul, suma de control TCP şi
răspunsul HTTP sunt toate memorate în cache, server-ul Web nu trebuie decât să transmită
aceste valori din cache într-o singură copie la interfaţa de reţea.
113
fiecărui buffer îi este dat un număr unic (P12, adaugă stări redundante) de
către IO-Lite, şi modulul TCP ţine un cache al sumelor de control indexate
cu numărul buffer-ului. Astfel, când un fişier este transmis de mai multe
ori, modulul TCP poate evita calcularea sumei de control, după prima
transmisie. Aceste modificări elimină toată redundanţa din figura 5.2 care
măreşte viteza de procesare a răspunsului.
IO-Lite poate fi utilizată şi pentru implementarea unui program pipe
modificat, care elimină copierea. Când acest mecanism IPC este utilizat
între procesul CGI şi procesul server, toate copiile sunt eliminate, fără a
compromite siguranţa şi izolarea defectelor, oferită de implementarea
celor două programe ca procese separate. IO-Lite permite deasemenea
aplicaţiilor să-şi particularizeze strategia de memorare-cache a buffer-elor,
permiţând strategii de memorare-cache mai deosebite, pentru serverele
web bazate pe dimensiunea şi frecvenţa accesului.
Este important de remarcat că IO-Lite realizează aceste performanţe fără
a elimina complet kernel-ul Unix şi fără a lega strâns aplicaţia de kernel.
Serverul Web Cheetah, cu sistemul de operare Exokernel, e şi mai radical,
permite fiecărei aplicaţii (inclusiv serverului Web) să îşi individualizeze
complet reţeaua şi sistemul de fişiere. Mecanismele Exokernel permit
astfel de individualizari, pentru fiecare aplicaţie, fără a compromite
siguranţa. În virtutea acestor modificări, serverul Web Cheetah poate
elimina toate copiile din figura 5.2. şi deasemenea poate elimina
calcularea sumei de control TCP utilizând un cache.
În timp ce Cheetah permite câteva artificii suplimentare, enorma
provocare în ingineria software de proiectare şi menţinere de kernel-uri
individualizate pentru fiecare aplicaţie, face mai atractive abordările ca
IO-Lite. IO-Lite se apropie de performanţa kernel-urilor individualizate ca
Cheetah avand de rezolvat mult mai putine probleme de inginerie
software.
CPU Memorie
Aplicatia sesver-ului Web
sendfile()
Magistrala de memorie
Copia 1
Copia 2 Disc
Magistrala I/O
Adaptor de retea
Retea
Figura 5.11. În I/O splicing, toate indirectările cauzate de copierea în şi din buffer-e din
spaţiul utilizator sunt îndepartate printr-un singur apel de sistem care “îmbină” fluxul I/O
de la disc cu fluxul I/O de la reţea. Ca de obicei, copia 1 poate fi eliminată pentru fişierele
din cache.
CPU
Stocare M9, R0 M9
(adaugare R0 la suma de
control)
Incarcare W10, R0
W10
Memoria adaptorului
Dimensiunea
I-cache Utilizarea frecventa a
Codul codurilor F1 si F2
F1
X
Utilizarea nefrecventa a
Codul codurilor F1 si F2
F2
Y
Re-localizare
Figura 5.13. În stânga este codul de reţea dispus în memorie, cu intercalare arbitrară a codului
frecvent utilizat (alb) şi rar utilizat (negru). Utilizarea unui cache direct mapat cu jumătate din
dimensiunea totală a codului poate conduce la coliziunea a două instrucţiuni frecvent utilizate,
cum ar fi X şi Y. Această problemă poate fi evitată reamplasând tot codul utilizat frecvent,
astfel încât să fie continuu, (dreapta).
Ambele efecte sunt cauzate de reflectarea imperfectă de către cache-uri a
localitaţii temporale. Prima cauză este o funcţie hash imperfectă, ce poate
cauza coliziuni între două adrese utilizate frecvent, iar a doua este
optimizarea localitaţii spaţiale. Ambele efecte pot fi diminuate prin
reorganizarea codului de reţea astfel încât tot codul utilizat frecvent sa fie
continuu (dreapta figurii 5.13). De exemplu, în cazul “dacă E eronat
119
execută X, altfel execută Z”, codul pentru Z poate fi mutat departe de X.
Aceasta necesită adăugarea unei instrucţiune de salt la cod lui Z pentru ca
acesta să poată reveni la codul ce urma după Z în versiunea neoptimizată.
Cum saltul se face doar în caz de eroare nu reprezintă un cost mare.
Deci localizarea codului în memorie (P13) permite prima optimizare, a
doua optimizare fiind a cazului cel mai probabil(P11), prin lungirea
codului rar utilizat.
Procesarea pe nivele
Reorganizarea codului poate ajuta până la un anumit punct, dar dă greş
dacă zona de lucru (setul de instrucţiuni accesat pentru aproape fiecare
pachet) depăşeşte dimensiunea I-cache. De exemplu, în figura 5.13. dacă
dimensiunea albului, adică a instrucţiunilor frecvent utilizate este mai
mare decât I-cache, reorganizarea codului va fi încă de folos (sunt
necesare mai puţine încărcări din memorie, deoarece fiecare încărcare
aduce instrucţiuni utile). Totuşi, fiecare instrucţiune va mai trebui adusă
din memorie.
Timp
P1
sosire P2 Procesare
convenţională
P1 P1 P1 P2 P2 P2
Legătura Reţea Transport Legătura Reţea Transport
de date de date
Procesare
P1 P2 P1 P2 P1 P2 localizata
Legătura Legătura Reţea Reţea Transport Transport pe
de date de date niveluri.
Dacă zona de lucru al stivei reţelei poate încăpea într-un I-cache modern
(care este din ce în ce mai mare) e posibil ca protocoalele mai complicate
(ce rulează TCP/IP ) să nu încapă. Ideea procesării pe nivele este utilizarea
efectivă a I-cache cât timp codul fiecărui nivel al stivei reţelei încape în
I-cache. Procesând repetat codul aceluiaşi nivel pntru mai multe pachete,
costul încărcării I-cache-ului este împărţit pe mai multe pachete(P2c). În
figura 5.14, la reprezentarea în timp a procesării convenţionale, toate
nivelurile reţea ale pachetului P1 sunt procesate înainte celor ale
pachetului P2. Dacă două pachete P1 şi P2 sosesc la un server, într-o
implementare convenţională, se termină toată procesarea lui P1 începând
cu nivelul legătură de date şi terminând cu nivelul transport, şi doar apoi
se începe procesarea pachetului P2.
Ideea principală în procesarea localizată pe niveluri este de a exploata un
alt grad de libertate (P13) şi de a procesa toate codurile unui nivel, pentru
cât mai multe pachete posibil, înainte de a trece la nivelul următor. Astfel,
120
după ce codul de nivel legătură de date pentru P1 este terminat, CPU trece
la executarea codului de nivel legatură de date pentru P2 şi nu la codul de
nivel reţea pentru P1. Corectitudinea ar trebui să nu fie afectată, deoarece
codul unui nivel n-ar trebui să depindă de starea nivelurilor
inferioare.Totuşi, procesarea integrată pe niveluri are câteva dependenţe
subtile şi deci cazuri de eşec.
Astfel, dacă codul pentru fiecare nivel încape în I-cache (de exemplu
codul nivelului legatura de date) dar nu încape codul pentru toate
nivelurile, atunci această optimizare amortizează costul încărcării I-cache
pentru mai multe pachete. Se utilizează procesarea pe loturi (P2c): cu cât
lotul este mai mare, cu atât I-cache este utilizată mai eficient.
Implementarea poate adapta dinamic dimensiunea lotului. Codul poate
procesa o serie de până la k pachete, din coada de pachete sosite( k este un
parametru care limitează latenţa). Dacă sistemul este slab încărcat, atunci
un singur mesaj va fi procesat la un moment dat. Dacă sistemul este
puternic încărcat, se creşte dimensiunea lotului, crescând astfel când e
nevoie, eficienţa utilizării lărgimii de bandă a memoriei.
121
între DMA şi PIO sunt complicate deoarece fiecare metodă are implicaţii
subtile pentru utilizarea per total a lărgimii de bandă de memorie.
De exemplu, PIO are avantajul că datele circulă prin procesor şi astfel
ajung în cache-ul procesorului, prevenind pierderile de lăţime de bandă a
memoriei la accesul secvenţial. Deasemenea, cu PIO e mai uşoară
integrarea altor funcţii, cum ar fi verificarea sumei de control, fără să fie
necesar un adaptor hardware care să facă aceeaşi funcţie.
Totuşi, unele studii au arătat că dacă datele sosite sunt utilizate mult mai
târziu de către aplicaţie, atunci plasarea datelor în d-cache prea devreme
este o risipă a d-cache şi mai degrabă scade decât creşte rata de succes a
cache. Pe de altă parte DMA poate fura cicluri de la CPU şi necesită
deasemenea o atentă invalidare a cache-ului când datele sunt scrise într-o
locaţie de memorie(care poate fi tot în cache). Alegerea se face de la caz la
caz, din considerente arhitecturale şi de aplicaţie
.
5.7. CONCLUZII
Pe măsură ce reţelele devin mai rapide legăturile, cum ar fi Gigabit
Ethernet, sunt deseori mai rapide decât magistralele interne şi memoriile
din calculatoare sau servere. Astfel, lărgimile de bandă de
memorie/magistrale sunt resurse cruciale. Au fost descrise tehnici de
optimizare a utilizării lărgimii de bandă de memorie/magistrală pentru
procesare de pachete IP şi Web, care reprezintă traficul Internet dominant.
S-a arătat cum să înlăturăm copiile redundante implicate în
procesarea unui pachet IP utilizând memoria adaptorului sau remaparea
memorie virtuale. Apoi s-a arătat cum să îndepărtăm copiile redundante
implicate în procesarea cererilor Web la un server, prin generalizarea
remapării memoriei virtuale, pentru a include sistemul de fişiere sau prin
combinarea sistemului de fişiere şi reţelei I/O într-un singur apel de
sistem. Apoi s-a arătat cum să combinăm diferite manipulări de date
simultan. Toate aceste tehnici necesită schimbări în aplicaţie şi kernel dar
schimbările sunt destul de localizate şi majoritatea păstrează
modularitatea.
În final s-a arătat că, dacă nu se are grijă, procesarea protocolului poate
face nesemnificativă suprasarcina datorată copierii şi au fost descrise
tehnici de optimizare a cache-ului de instrucţiuni. Serverele Web moderne
pot fi deja optimizate pentru implementări zero-copii utilizând apeluri de
sistem de tipul sendfile (). Totuşi, astfel de servere încă consumă cicluri de
processor aşteptând memorie. Astfel, tehnici de îmbunătăţire a eficienţei I-
cache pot oferi următoarea etapă de optimizări pentru serverele Web.
Figura 5.1. prezintă un sumar al tehnicilor utilizate în acest capitol,
împreună cu principiile majore implicate.
Dar nu au fost eliminate toate problemele de performanţă implicate în
construirea unui server Web modern. Site-uri Web complexe, cum ar fi
amazon.com utilizează adesea mai multe niveluri de procesare pentru a
răspunde cerinţelor Web (un server aplicaţie, un server Web şi un server
bază de date). Serverele Web bază de date introduc noi constrângeri care
pot necesita noi tehnici în afară de cele descrise aici. Totuşi, principiile de
bază ar trebui să rămână aceleaşi.
Referitor la principii, capitolul se ocupă cu utilizarea repetată a P1, de
evitare a pierderilor evidente, ca citiri şi scrieri inutile consumatoare de
122
lăţime preţioasă de bandă de memorie/magistrală. La prima privire,
principiul P1 pare stupid . Ceea ce face acest principiu mai profund este că
pierderea devine vizibilă doar dacă analiza este extinsă la întregul sistem,
sau la cea mai mare parte din el.În interiorul fiecărui subsistem local (de
exemplu aplicaţie-kernel, kernel-retea, disc-sistem de fişiere) nu există
risipă de lăţime de bandă de memorie. Doar atunci când se urmăreşte
traseul unui pachet recepţionat se descoperă redundanţa dintre copiile
aplicaţie-kernel şi kernel-reţea. Doar atunci când se extinde vederea şi mai
departe pentru a observa distorsiunile implicate în răspunsul la o cerere
Web se observă redundanţele care implică sistemul de fişiere. Doar atunci
când se extinde şi mai mult vederea se văd toate manipulările implicate în
procesarea unui pachet şi citirile inutile din memorie. În sfârşit, doar
atunci când se examinează încărcarea instrucţiunilor se vede posibilitatea
alarmantă ca codul protocolului să fie de câteva ori mai mare decât
dimensiunea pachetului.
Astfel, utilizarea primului principiu al algoritmilor de reţea necesită o
vedre sinoptică a întregului sistem, de la http şi anteteele sale la sistemul
de fişiere şi la cache-urile de instrucţiuni. Deşi complexitatea pare
descurajantă, s-a argumentat deja că modelele simple de hardware,
arhitectură, sisteme de operare şi protocoale pot face posibilă o astfel de
vedere globală. De exemplu, I-cache-urile au câteva variante complexe,
dar un model simplu, de mapare directă I-cache cu multiple instrucţiuni
per bloc, e uşor de ţinut minte de proiectantul unui sistem de operare.
Comparate cu eleganţa şi complexitatea tehnicilor teoretice, cum ar fi
algoritmul elipsoid pentru programarea lineară şi teoria lanţurilor Markov
cu mixaj rapid, tehnicile de sistem, cum ar fi evitarea copierii, par lipsite
de strălucire şi superficiale. Totuşi, se poate argumenta că complexitatea
sistemului nu se referă la profunzime(complexitatea fiecărei componente
în parte) ci la ansamblu(relaţiile complexe dintre componente). Poate că
gradul de înţelegere (HTTP, sistemul de fişiere, codul de reţea,
implementarea cache-ului de instrucţiuni) necesar pentru a optimiza
lăţimea de bandă de memorie într-un server Web pledează pentru această
lucrare.
5.8. EXERCIŢII
1. Memorii cache de date şi copii: o memorie cache de date normală
mapează de la o adresă de locaţie de memorie la o piesă de conţinut. Cand
conţinutul e accesat frecvent, atunci poate fi accesat direct din cache, în
loc sa se faca un acces la memorie. Presupunând că memoria cache este de
tip write-back, chiar şi scrierile pot fi facute în cache în loc de memorie şi
sunt scrise în memorie doar când cache-ul e supra-încărcat. Un bloc cache
modern e destul de mare (128 biţi), cu mapari de la adrese de 32 de biţi la
128 de biţi, de date începând cu acea adresă.
Abordăm problema copierii, unde diferite module(inclusiv reţeaua şi
sistemul de fişiere) copiază date prin intermediul buffer-elor care devin
curând supra-încărcate (de exemplu, buffer-ul socket, buffer-ul aplicaţie).
lucru făcut pana acum cu modificări software. Analizam acum dacă
schimbarea arhitecturii hardware poate ajuta, fără modificări software ca
IO-Lite, fbufs şi mmap.
123
• Chiar şi un cache de date obişnuit poate ajuta la îndepărtarea unor
supraincarcari când copiem date de la locaţia L la locaţia M. Explicaţi de
ce. (Presupunem că locaţia M este un buffer temporar care este în curând
supraînscris, ca si un buffer socket. Presupunem că dacă un singur cuvânt
este scris într-un bloc cache mare, cuvintele rămase pot fi marcate ca
invalide.) Intuitiv, problema e dacă există un echivalent al copierii-la-
scriere (utilizată pentru a reduce copierea între spaţiile adreselor virtuale)
folosind cache-uri de date.
• Acum presupunem o proiectare diferita a cache-ului de date, unde un
cache este o mapare de la una sau mai multe adrese la acelaşi conţinut.
Astfel, un cache s-a modificat de la o mapare unu-la-unu la o mapare mai
multe-la-unu. Presupunem un cache unde două locaţii pot pointa către
acelaşi conţinut. O intrare cache poate fi (L,M,C), unde L şi M sunt adrese
şi C este conţinutul comun al lui L şi M. Un acces la memorie la oricare L
sau M va returna C. Care este avantajul faţă de schema precedentă ?
• Totul e foarte ipotetic si ciudat. Comentaţi dezavantajele ideii din
cazul precedent. Multe cache-uri utilizează tehnica numită asociativitatea
multimilor/set associativity, unde o simplă funcţie hash (de exemplu biţii
de ordin inferior) este utilizată pentru a selecta un set mic de intrări cache,
pe care hardware-ul le parcurge în paralel. De ce ar putea adresarea
multiplă per intrare cache să interacţioneze slab cu căutarea prin
asociativitatea multimilor ?
2. Optimizări de nivel aplicaţie pentru servere Web: sisteme de
operare ca Exokernel permit aplicaţiei să particularizeze kernelul in
beneficiul său, fără a compromite securitatea altor aplicaţii. O optimizare
interesantă este combinarea TCP final FIN cu citirea ultimului segment de
date (optimizare permisă de TCP).
• De ce această optimizare ajută transferurile Web mici, obişnuite?
• De ce este această optimizare greu de realizat într-un server Web
obişnuit şi mai uşor de realizat dacă aplicaţia este integrată în kernel, ca în
Exokernel?
• Cum poate fi deplasată această optimizare într-un server Web obişnuit
pasând informaţie prin interfaţă (P9) fără a compromite siguranţa?
3. Copiere inversă: emularea copierii-la-scriere are un grad de libertate
interesant (P13) pentru copiere paginilor-aliniate de date între două
module (să zicem, sistem şi aplicaţie). Imaginaţi-vă că doriţi să copiaţi o
pagină parţială dintr-o pagină de aplicaţie, X, într-o pagină de sistem,Y.
Dacă pagina este plină presupuneţi că puteţi schimba cele două pagini
eficient. Presupuneţi că pagina parţială are date utile D şi o rămăşiţă R.
• Dacă volumul de date D este mic comparativ cu R e mai simplu să
copiem D în pagina destinaţie Y. Dar dacă D e mare (aproape toată
pagina) comparativ cu R, imaginaţi o strategie simplă pentru a minimiza
copierea. De reţinut că dacă pagina destinaţie Y are alte date în restul de
pagină aceste date trebuie să rămână şi după copiere.
• Care e criteriul de alegere între aceste două strategii?
124
CAPITOLUL 6
CONTROLUL TRANSFERULUI
Într-o companie plata unei facturi durează 6 luni. Factura ajunge prima
dată în poştă, petrece ceva timp pe biroul secretarei, ajunge pe biroul celui
care ia principalele decizii şi ajunge în sfârşit la contabil. La procesarea
facturii, fluxul de control îşi urmează calea prin diferite straturi de
comandă, fiecare adăugând un antet semnificativ. Un consultant de
management sugereaza scurtarea procesarii facturii elimininand straturile
intermediare când e posibil, şi facand fiecare nivel cât se poate de selectiv.
Totuşi, fiecare nivel are câteva motive de a exista. Camera de poştă îmbină
serviciul de livrare a poştei pentru toate departamentele companiei.
Secretara protejează şeful de întreruperi şi elimină cererile nepotrivite.
Şeful trebuie eventual să decidă dacă factura merită plătită. Detaliile de
alocare a banilor sunt decise de contabil.
Un CPU modern, care procesează un mesaj de reţea, trece prin nivele
similare de mediere. Dispozitivul (un adaptor Ethernet) întrerupe CPU,
solicitand atenţie. Controlul este pasat la kernel, care comasează
întreruperile cand e posibil, face procesarea pachetului la nivelul reţea şi
planifică să ruleze procesul aplicaţie (un server Web). Recepţia unui
singur pachet oferă o vedere limitată a contextului global de procesare. De
exemplu, un server Web va analiza cererea din pachetul de reţea, va căuta
fişierul şi va iniţializa extragerea fişierului de pe disc. Când fişierul este
citit în memorie, este trimis înapoi un răspuns conţinând fişierul cerut,
adăugând un antet HTTP.
A fost analizata reducerea supraincarcarii creata de operaţiile cu date
(copiere, verificarea sumei de control). Va fi analizata reducerea
supraincarcarii creata de controlul implicat în procesarea unui pachet
(trimiterea/recepţia unui pachet) si apoi la aplicatia de reţea, serverul Web.
125
6.1 Suprasarcina generata de control
Capitolul precedent a analizat suprasarcina cauzata de copiere într-un
server web (arătând potenţialele copii implicate în răspunsul unui server la
o cerere get, fig.5.2). Figura 6.2 arată potenţialele suprasarcini generate de
controlul dintr-un server Web mare care deserveşte mai mulţi clienţi (sunt
ignorate aspectele transferului de date). E prezentata o vedere arhitecturală
simplificată, axată pe interacţiunea controlulului dintre adaptorul de reţea
şi CPU (prin intreruperi), între aplicaţie şi kernel (prin apelul de sistem) şi
între diferite procese de nivel aplicaţie sau thread-uri (prin apeluri la
planificator). Pentru simplitate e dat doar un CPU în server (multe servere
sunt multiprocesor) şi un singur disc (unele servere utilizează discuri
multiple şi discuri cu capete multiple). Serverul poate servi un număr mare
/mii de clienţi concurenţi.
Pentru a înţelege posibilele suprasarcini generate de control, implicate in
deservirea unei cereri GET, presupunem că clientul a trimis o cerere TCP
SYN, care soseşte la adaptor, de la care este plasată în memorie. Kernelul
este apoi informat de această sosire prin intermediul unei întreruperi.
Kernelul anunţă serverul Web prin deblocarea unui apel de sistem
anterior; aplicaţia serverului Web va accepta conexiunea dacă are resurse
sufiente.
Kernel
TCP/IP Sistem fisiere
Pachet CPU
receptionat Memorie Disc
Bus
Adaptor de retea
Retea
Figura 6.2. Antetul de control implicat in manipularea unei cereri GET la un server
126
serverul trimite răspunsul HTTP, prin scrierea conexiunii corespunzătoare
(alt apel de sistem).
Pînă acum, singurele suprasarcini generate de control par să fie apelurile
de sistem şi întreruperile, dar asta deoarece nu au fost examinate
îndeaproape structura reţelei şi codul aplicaţiei.
În primul rand, pentru un cod structurat naiv, cu un singur process per
nivel în stivă, atunci suprasarcina generata de planificarea proceselor (de
ordinul sutelor de microsecunde) pentru procesarea unui pachet, poate fi
cu uşurinta mult mai mare decât timpul de sosire al unui singur pachet.
Această potenţială suprasarcina generata de planificare este arătată în
figura 6.2 cu linie punctată spre codul TCP/IP din kernel. Din fericire, cele
mai multe coduri de reţea sunt structurate mai mult monolitic, cu un antet
de control minim, deşi unele tehnici mai inteligente pot face si mai bine.
În al doilea rând, descrierea procesării web s-a axat pe un singur client.
Deoarece presupunem un server Web mare ce lucrează concurent pentru
mii de clienţi, nu e clar cum ar trebui structurat acesta. La o extrema,
fiecare client este un process separat (sau thread) rulând codul serverului
Web si concurenţa este maximizată (pentru că atunci când clientul 1
aşteaptă pentru o citire de pe disc, clientul 2 ar putea trimite pachete de
reţea) cu costul mare al suprasarcinii generata de planificarea procesului.
Pe de altă parte, dacă toţi clienţii sunt serviţi de un singur proces lansat
de evenimente, pierderea datorată schimbării contextului este minimizată,
dar procesul unic trebuie să-şi planifice intern clienţii, pentru a maximiza
concurenţa si trebuie să stie când sunt gata citirile fişierului şi când au
sosit datele de reţea.
Multe sisteme de operare oferă un apel de sistem in acest scop, numit
generic FindActive () în figura 6.2. In Unix, numele sau este select (). Dar
daca un apel de sistem gol e costisitor din cauza depăşirii limitei kernel-
aplicaţie, o implementare select() ineficientă poate fi si mai costisitoare.
Dar raman intrebări provocatoare ca structurarea reţelei şi a codului
serverului în ideea minimizarii suprasarcinii generata de planificare şi
maximizarii concurenţei. Din acest considerent, figura 6.2 arată clienţii
partiţionaţi în grupuri, fiecare din acestea fiind implementat într-un singur
proces sau thread. De remarcat ca suprasarcina generata de planificare
tuturor clienţilor într-un singur grup determina abordarea lansata-de-
evenimente, iar plasarea fiecarui client într-un grup separat determina
abordarea proces/thread -per-client.
Astfel, o implementare neoptimizată poate implica suprasarcini
considerabile datorate comutării proceselor (sute de μ s ) dacă aplicaţia şi
codul de reţea sunt prost structurate. Chiar dacă este eliminata
suprasarcina structurării-proceselor, apelurile-sistem pot costa zeci de μ s ,
iar întreruperile μ s (la o legătură Ethernet de 100 Gbps un pachet de 40
bytes poate sosi la PC la fiecare 3,2 μ s ).
Dat fiind faptul că legăturile de 10 Gbps se raspandesc, trebuie acordată
mai multă atenţie suprasarcinii generata de control. Dar, desi procesoarele
au devenit mai rapide, suprasarcina generata de control asociata cu
comutarea contextului, apelurile-sistem şi întreruperile nu s-au imbunatatit
in acelasi ritm. Unele progrese au fost făcute cu sisteme de operare mai
eficiente, ca Linux, dar progresul nu este suficient pentru a ţine pasul cu
vitezele pe legătură crescânde.
127
6.2. Evitarea suprasarcinii generata de planificare în codul de reţea.
Una din marile dificultăţi în implementarea unui protocol este de a
echilibra modularitatea (să implementezi un sistem mare pe părţi şi să faci
fiecare parte bine, independent de celelalte) şi performanţa (să faci să
funcţioneze bine intreg sistemul). Să considerăm exemplul simplu de
implementare a unei stive de reţea. “Modularitatea evidentă” ar fi
implementarea ca procese separate a protocolului de transport (TCP), a
protocolului de rutare (IP), şi a aplicaţiei. In acest caz, fiecare pachet
recepţionat ar trece prin cel puţin două comutari de context a procesului,
care sunt costisitoare.
Există totuşi alternative care permit si modularitate şi eficienţă. Fie o
aplicaţie simplă (fig.6.3) care citeşte date de la tastatură şi le trimite în
reţea, utilizând un protocol de transport. Când acestea sunt recepţionate de
un receptor din reţea sunt afişate pe ecran. Pe verticala sunt arătate diferite
nivele de protocol, sus fiind protocolul aplicaţie, apoi protocolul transport
şi jos protocolul de reţea. O implementare naiva a acestui protocol ar fi să
avem un protocol per secţiune, adica trei procese şi două schimbări
complete de context per pachet primit/trimis.
Pot fi utilizate doar două procese la transmiţător şi două la receptor (pe
verticala) pentru a implementa stiva protocoalelor de reţea. Procesele
receptorului sunt in stânga, iar procesele transmiţătorului in dreapta.
Astfel, transmiţătorul are un proces de manevrare a tastaturii/Keyboard
Handler care capteaza datele in/din tastatura, si cand are ceva date,
apeleaza transport-arm-to-send, care este o functie de nivel transport,
exportata spre procesul de manevrare a tastaturii si executata de acesta. In
acest moment, procesul de manevrare a tastaturii se poate autosuspenda
(comutarea contextului). Transport-arm-to-send spune protocolului de
transport ca acea conexiune doreste sa transmita date, dar el nu transfera
date.
Procesul transmisie-transport poate să nu transmită datele imediat, din
cauza limitărilor impuse de controlul fluxului. Dacă dispar condiţiile
impuse de controlul fluxului (datorită sosirii unor confirmări/ack),
procesul de transmisie, SendProcess va executa rutina transport-send
pentru această conexiune. Apelul send va chema mai intâi protocolul
aplicaţie care va exporta rutina display-get-data care furnizează de fapt,
aplicaţiei datele. Acest lucru este avantajos, deoarece e posibil ca aplicaţia
să fi recepţionat mai multe date de la tastatură în timp ce protocolul de
transport este pregătit pentu a trimite, şi se pot trimite deodată mai multe
date, câte incap într-un pachet. In final, în contextul aceluiaşi proces,
protocolul transport adaugă un antet de nivel de transport şi apelează
protocolul de nivel reţea pentru a transmite efectiv pachetul.
La partea de receptor, pachetul este primit de către handlerul
întreruperilor de recepţie care, folosind o rutină de reţea numită net-
dispatch, trebuie să găsească cărui proces să-i expedieze pachetul. Pentru a
afla procesul, net-dispatch apelează portul-primire-transport, care de fapt
este o rutină exportată de către nivelul transport, care citeşte numerele
portului din antet pentru a-şi da seama care aplicaţie (de ex. FTP) trebuie
să manevreze pachetul. Apoi se comută contextul şi handlerul de recepţie
128
recâştigă controlul şi atenţionează procesul de recepţie, care execută
funcţiile de reţea-transport, şi în final codul aplicaţiei pentru afişarea
datelor. De menţionat că un singur proces execută toate nivele
protocolului.
Proces de Manipulator
receptie de receptie Proces Manipulator
intreruperi transmitator tastatura
transport-
alocare port transport-
transport-date transmisie transport-
primite pregatit de
transmisie
retea-
expediere
retea- retea-
receptie transmisie
Intrerupere
Figura 6.3. Implementarea unui protocol utilizand apeluri de transmisie
129
“proces” nucleu/kernel-ul. Când un pachet soseşte prin intermediul unei
întreruperi, handlerul de întreruperi notează sosirea pachetului, posibil îl
memorează într-o coadă şi apoi planifică un proces nucleu (printr-o
întrerupere software) pentru procesarea propriu-zisă a pachetului.
Procesul nucleu execută codurile de nivel legatură de date-reţea-
transport (folosind upcalls-uri); citind numerele porturilor de transport,
procesul nucleu află aplicaţia şi o lansează. Astfel, fiecare pachet este
procesat, prin cel puţin două comutări; una de la contextul întreruperii la
procesul nucleu manevrând protocolul, şi una de la procesul nucleu la
procesul care rulează codul aplicaţiei (ex. Web, FTP).
133
performanţă, deoarece fişierele comune multor clienţi sunt replicate.
Serverul Web Apache e implementat în Windows cu cate un fir per client.
Suprasarcină generata de comutarea între firele de proces e mai mică
decât comutarea intre procese, dar este totuşi considerabilă. In esenţă,
sistemul de operare trebuie încă să salveze/repună contextul per fir de
proces, ca stivele/registrele. De asemenea, memoria necesară pentru
stocarea stării per fir de proces sau per proces ia din cache-ul pentru
fişiere, care duce probabil la o rată de erori mai mare.
Fig 6.6 Două alternative simple pentru structurarea unui server Web:(1) folosirea unui
singur proces (sau fir) per client; (2) implementarea unui proces unic care foloseşte un
manager de evenimente pentru a raporta procesului starea I/O a fiecărui client.
135
procesul ajutător a terminat, comunică cu procesul principal de pe server,
printr-o formă de comunicare interprocese, precum pipe.
Spre deosebire de modelul mutiproces, procesele ajutătoare sunt
necesare doar pentru fiecare operaţie concurentă pe disc, şi nu pentru
fiecare cerere client concurentă. Modelul exploatează un grad de libertate
(P13), observând că mai sunt şi alte alternative interesante între un singur
proces şi un proces per client.
In afara de citirea fişierelor, procesele helper mai pot fi folosite la căutări
în directoare pentru localizarea fişierelor pe disc. In timp ce Flash menţine
un cache, care face legătura între numele căilor directoarelor şi fişierele de
pe disc, dacă există cumva o greşeală a cache-ului, atunci trebuie căutat
prin structurile directoarelor de pe disc. Deoarece asemenea căutari de
directoare se pot bloca, sunt de asemenea necesare proceselor helper.
Crescând cache-ul pentru numele de căi, creşte de asemenea consumul de
memorie, dar reducerea ratei de erori a cache-ului poate reduce numărul
de procese ajutătoare necesare şi să scadă necesarul global de memorie.
Procesele helper ar trebui să evite întârzierea creării unui proces, de
fiecare dată când un process helper este invocat. Câte procese helper
trebuie să fie? Prea puţine cauzează pierderi de concurenţă şi prea multe
cauzează pierderi de memorie. Solutia în Flash este crearea dinamică şi
distrugerea proceselor helper în funcţie de încarcare.
136
Fig. 6.7 Două propuneri de arhitecturi Web ( diferite de cele din fig. 6.6) : (3) procese
lansate de evenimene (event-driven) si procese ajutatoare; (4) arhitectura pe niveluri a
proceselor lansate de evenimente
137
Dar într-un mediu LAN, cu ciclul de întârziere de 2 msec, numărul mediu
de conexiuni simultane scade la 6. Dacă numărul de conexiuni pe secundă
rămâne la fel, în WAN o mare parte din conexiuni trebuie să fie în starea
„idle”(aşteptând răspunsuri) în orice moment.
Două cauze principale de supraîncărcare au fost apelurile de sistem
folosite de către serverul event-driven:
• select(): serverele event-driven rulând pe UNIX utilizează apelul de
select() pentru apelul FindActive(). Experimentele făcute arată că mai mult
de jumătate din CPU este utilizat pentru kernel şi funcţii nivel-utilizator
select() cu 500 conexiuni;
• ufalloc(): de asemenea, serverul are nevoie să repartizeze cel mai mic
descriptor nealocat pentru socket-uri sau fişiere noi. Acest apel simplu
consumă a treia parte din timpul CPU.
Performanţele ufalloc() pot fi uşor explicate. In mod normal, găsind un
descriptor liber, acesta poate fi uşor implementat utilizând o lista liberă de
descriptori. Din păcate, UNIX cere alegerea celui mai mic descriptor
neutilizat. De exemplu, daca lista curentă de descriptori nealocaţi are
elementele (nesortate) 9, 1, 5, 4, 2, atunci nu poate fi găsit 3, ca fiind cel mai
mic număr nealocat, fără parcurgerea întregii liste nesortate. Din fericire, o
simplă schimbare în implementarea kernel (P15 utilizarea unor structuri de
date eficiente) poate reduce aproape la zero suprasarcina.
138
•Apel: apoi aplicaţia apelează select() cu bitmap-urile construite la
pasul anterior, şi se blochează dacă nici un descriptor nu e pregătit în
momentul apelului; dacă expiră timpul (timeout), aplicaţia face o
procesare de excepţie.
•Răspuns: după ce apelul revine, aplicaţia trece liniar prin bitmap-
urile returnate şi invocă antetele de citire şi scriere adecvate, pentru
descriptorii corespunzători poziţiilor cu biţi setaţi.
Costurile construirii bitmap-urilor, din pasul 1 şi scanării lor din pasul 3,
sunt suportate de către utilizator, deşi ele sunt atribuibile direct costurilor
de pregătire a răspunsului la apelul select().
Implementare
Este important să înţelegem implementarea select() în kernel-ul unei
variante tipice de UNIX. Kernel-ul face următoarele (adnotat cu surse de
supraîncărcare):
•Curăţare: kernel-ul începe cu folosirea bitmap-urilor, transmise ca
parametri, pentru a construi un sumar cu descriptorii marcaţi în cel puţin
unul din bitmap-uri (numit setul selectat).
Acest lucru necesită o căutare liniară printre bitmap-urile de dimensiune N, indiferent
de numărul de descriptori de care aplicaţia este interesată.
•Verificare: apoi, pentru fiecare descriptor din setul selectat, kernel-ul
verifică dacă descriptorul este pregătit; dacă nu, încarcă ID-ul firului
aplicaţiei în coada de aşteptare selectată a descriptorului. Kernel-ul pune
în adormire firul aplicaţiei apelante, dacă nu există descriptori pregătiţi.
Acest lucru necesită investigarea tuturor descriptorilor selectaţi, indiferent de câţi sunt
pregătiţi de fapt. Acest pas este mai costisitor decât simpla scanare a bitmap-ului.
•Reluare: când descriptorul devine pregătit din cauza unei operaţii de
I/O (de exemplu, un pachet soseşte la un socket, de la care serverul
aşteaptă date), modulul de I/O al kernel-ului îşi verifică coada de aşteptare
selectată şi „trezeşte” toate firele care aşteaptă un descriptor.
Acest lucru implică o supraîncărcare cauzată de planificare, care pare inevitabilă fără
un apel selectiv sau aşteptare de ocupat.
•Redescoperire: in final, select() redescoperă lista descriptorilor
pregătiţi făcând o scanare a tuturor descriptorilor selectaţi pentru a vedea
care a devenit pregătit în timpul în care select() fusese pus în adormire şi
„trezit” apoi. Aceasta necesită repetarea aceloraşi verificări costisitoare de
la pasul 2.
Verificările se repetă deşi modulul de I/O ştie care descriptori devenisera pregătiţi, dar
nu informează implementarea select().
139
select().De exemplu, dacă doar 10 biţi se schimbă la fiecare apel într-un
bitmap de dimensiune 6000, aplicaţia tot trebuie să treacă prin cei 6000
biţi pentru a seta fiecare bit dacă e nevoie.
Trebuie învinuită fie interfaţa API, fie lipsa calculului incremental in aplicaţie.
2.Reverificarea stării după fiecare reluare: nici o informaţie nu trece, de
la modulul protocolului (care trezeşte un fir adormit de pe socket) spre
apelul select() invocat când firul îşi reia activitatea. De exemplu, dacă
modulul TCP primeşte date pe socket-ul 9, pe care doarme firul 1,
modulul TCP se va asigura mai întâi ca firul 1 s-a trezit; dar nici o
informaţie nu-i e dată firului 1 la trezire. Astfel firul 1 trebuie să reverifice
toate socket-urile selectate pentru a stabili dacă socket-ul 9 are într-adevar
date, deşi modulul TCP ştia sigur acest lucru când l-a trezit.
Trebuie învinuită implementarea kernel-ului.
3.Kernel-ul reverifică disponibilitatea descriptorilor anterior
nepregătiţi: aplicaţia server-ului Web e interesată de un socket până la
eşecul/sfârşitul conexiunii. Atunci de ce se repetă testele pentru
disponibilitate dacă nu s-a observat nici o schimbare a stării? Presupunem
de exemplu, că socket-ul 9 este o conexiune spre un client distant, cu o
întârziere de 1 sec pentru trimiterea/ recepţia pachetelor. Presupunem că la
timpul t este trimisă o cerere la un client prin socket-ul 9 şi serverul
aşteaptă răspuns, care soseşte la t+1 secunde. Presupunem că în intervalul
dintre t şi t+1, firul serverului apelează select() de 15000 ori. De fiecare
dată când e apelată select(), kernel-ul face o verificare laborioasă a socket-
ului 9 pentru a determina dacă au sosit date sau nu. In schimb, kernel-ul
poate deduce aceasta, din simplul fapt ca socket-ul era verificat la timpul t
şi nici un pachet din reţea nu a fost recepţionat de la acest socket de la
momentul t. Astfel 15000 de verificări nefolositoare şi costisitoare pot fi
evitate; când pachetul soseşte în sfarsit, la timpul t+1, modulul TCP poate
transmite informaţia pentru a reporni verificarea acestui socket.
Trebuie învinuită implementarea kernel-ului
4.Bitmap-uri liniari în raport cu dimensiunea descriptorului: Atât
kernel-ul cât şi utilizatorul trebuie să scaneze bitmap-urile, proporţional cu
dimensiunea descriptorilor posibili, şi nu cu volumul de muncă utilă. De
exemplu, dacă sunt 6000 de descriptori posibili, un server Web ar trebui să
trateze un vârf de sarcină, bitmap-uri cu lungimea 6000. Presupunem că în
timpul unei perioade oarecare sunt 100 de clienţi concurenţi, din care doar
10 sunt pregătiţi în timpul fiecărui apel select(). Atât kernel-ul cât şi
aplicaţia scanează şi copiază bitmap-uri de dimensiune 6000, deşi
aplicaţia este interesată doar de 200 de biţi si doar 10 biţi sunt setaţi la
revenirea fiecărui select().
Trebuie învinuită API.
Strategii şi principii pentru a repara select()
Odată stabilite cauzele risipei, pot fi aplicate strategii simple, utilizând
principiile algoritmice:
•Recrearea interesului pentru fiecare apel: Consideră schimbarea API-
ului (P9) pentru a utiliza bitmap-uri separate pentru intrare şi ieşire. Sau
menţine API-ul şi foloseşte calculul incremental (P12a).
•Reverificarea stării după fiecare reluare: Pasează informaţia între
modulele protocolului care ştiu când un descriptor este pregătit şi modulul
selectat (P9).
140
•Să ai reverificări kernel a disponibilităţii descriptorilor ştiuţi a fi
nepregătiţi. Kernel îşi menţine starea în timpul apelurilor, asfel încât nu
trebuie să reverifice descriptorii ştiuţi a fi nepregătiţi (P12a, utilizează
calculul incremental)
•Să foloseşti bitmap-uri liniari în raport cu mărimea posibilă şi nu cu
mărimea descriptorului: Schimbă fundamental API-ul pentru a evita
necesitatea interogării asupra stării tuturor descriptorilor reprezentaţi de
bitmap-uri (P9).
141
la select(). Atunci I este actualizat la Inou=Ivechi ∪ S. Acesta incorporează
descriptorii proaspăt selectaţi fără a pierde descriptorii anterior selectaţi.
Apoi, kernel-ul verifică doar descriptorii care sunt în Inou , dar sunt fie:
(i) în setul de indicaţii H fie (ii) nu sunt în Ivechi sau (iii) în setul vechi de
descriptori pregătiţi Rvechi. Aceste trei afirmaţii reflectă cele trei categorii
discutate în urmă cu două paragrafe. Ele reprezintă fie activitatea recentă a
fiecăruia, interesul proaspăt declarat sau datele neconsumate rezultate
dintr-o activitate prioritară. Descriptorii găsiţi a fi pregătiţi în urma
verificării sunt înregistraţi în Rnou. La sfârşit, apelul select() returnează
utilizatorului elementele din Rnou ∩ S. Acest lucru se întâmplă deoarece pe
utilizator îl interesează doar disponibilitatea descriptorilor specificaţi în
setul selectat S.
Ca exemplu, socket-ul 15 poate fi verificat când e menţionat pentru
prima dată în apelul select() şi deci intră în I; socket-ul 15 poate fi verificat
apoi, când un pachet de 500 bytes soseşte din reţea, ceea ce face ca socket-
ul 15 să intre în H; în final, socket-ul 15 poate fi verificat repetat ca parte a
lui R până când aplicaţia consumă toţi cei 500 bytes, punct în care socket-
ul 15 părăseşte R (P12,suplimentarea stărilor pentru a creşte viteza) stă la
baza acestei optimizări. Optimizarea menţine starea peste apeluri (P12)
pentru a reduce verificările redundante.
142
• Rata excesivă a evenimentelor: aplicaţia e interesată de evenimentele
care cauzează schimbarea stării, nu de fluxul lor neprelucrat. Pentru un
transfer Web mare, mai multe pachete pot ajunge la un socket şi aplicaţia
ar dori să obţină o notificare pentru întregul lot, nu câte una pentru fiecare
pachet. Suprasarcina generată de fiecare notificare este echivalentă cu
memorarea fiecărei notificări, în termeni de costuri de comunicaţie(CPU).
Principiul P6 sugerează proiectarea rutinelor specializate eficiente
pentru a evita strangulările.
● Interogarea sincronă: ca şi în cazul apelului select() original,
aplicaţia poate interoga evenimentele în curs. Spre exemplu, în exemplul
anterior, aplicaţia continuă să servească socket-ul 5 şi toate celelalte
socket-uri active înainte să întrebe (şi să i se spună despre) evenimente ca
de pildă sosirea pachetului la socket-ul 5.
● Comasarea evenimentelor: dacă, în timp ce un prim eveniment a
fost introdus într-un şir pentru notificare, apare un al doilea eveniment
pentru descriptor, cea de-a doua notificare este omisă. Astfel per
descriptor, acolo poate fi cel mult o notificare de eveniment important.
Utilizarea noului API este directă dar nu prea conformă cu stilul
aplicaţiilor ce foloseau vechiul select() API. Aplicaţia stă într-o buclă, în
care are nevoie de sincronizare pentru setul următor de evenimente, şi
intră în repaus în caz contrar. Când apelul revine, aplicaţia trece prin
fiecare notificare de eveniment şi invocă antetele potrivite de scriere sau
citire. Implicit, setarea registrelor unei conexiuni interesează descriptorul
corespunzător, în timp ce deconectarea conexiunii înlătură descriptorul din
lista de interes.
Implementarea: fiecărui fir îi este asociat un set de descriptori de care
este interesat. Fiecare descriptor (socket de exemplu) păstrează o lista de
mapare inversa a tuturor firelor interesate de descriptor. In activitatea de
I/O (de exemplu, sosirea datelor la un socket), modulul I/O utilizează
propria sa lista de mapare inversă, pentru a identifica toate firele posibil
interesate. Daca descriptorul este în setul de fire interesat, un eveniment de
notificare este adăugat şirului evenimentelor în curs al acelui fir.
Un bitmap per fir simplu, un bit per descriptor, este utilizat sa
înregistreze faptul că un eveniment este în aşteptare în şir şi să evite
multiplele notificări de evenimente per descriptor. In final, când aplicaţia
cere următorul set de evenimente, acestea sunt returnate din şirul de
aşteptare.
143
kernel-ul trebuie să servească aceste apeluri de sistem (care pot fi
costisitoare) pentru fiecare pachet trimis sau primit.
Acest lucru pare a fi necesar deoarece pot fi câteva aplicaţii care primesc
şi trimit date de la un adaptor comun; din moment ce adaptorul este o
resursă partajată, este de neconceput pentru o aplicaţie să scrie direct în
registrele dispozitivului unui adaptor al reţelei fără ca kernel-ul să verifice
utilizarea eronată sau răuvoitoare.
144
(pentru această aplicaţie). In consecinţă ar trebui să considerăm cu atenţie
şi separat memoria descriptorului şi memoria actuală a buffer-ului.
Putem lucra uşor cu memoria descriptorului, ştiind că memoria
adaptorului este o memorie mapată. Presupunem că adaptorul are 10.000
bytes de memorie, considerată memorie pe magistrală, si că pagina fizică a
sistemului este de 1000 bytes. Rezultă faptul că adaptorul are 10 pagini
fizice. Presupunem că alocăm câte 2 pagini fizice fiecărei aplicaţii dintr-un
set de 5 aplicaţii de mare performanţă (ex.Web, FTP), aplicaţii care vor să
folosească adaptorul pentru a transfera date. Presupunem că aplicaţia Web
primeşte 2 pagini fizice, de exemplu nr.9 si 10. Kernel-ul mapează
paginile fizice 9 şi 10 la tabela de pagini a aplicaţiei Web, iar paginile
fizice 3 şi 4 le mapează la tabela de pagini a aplicaţiei FTP.
Acum, aplicaţia Web poate scrie direct în paginile fizice 9 şi 10, fără nici
un pericol; dacă va încerca să scrie în paginile 3 şi 4, hardware-ul
memoriei virtuale va genera o excepţie. Astfel (P4c) exploatăm hardware-
ul existent sub forma TLB, pentru a proteja accesul la pagini. Presupunem
acum că pagina 10 este o secvenţă de descriptori de buffer-e libere, scrise
de aplicaţia Web; fiecare descriptor de buffer descrie o pagină din
memoria principală (presupunem că avem la dispoziţie doar 32 biţi), care
va fi folosită pentru a recepţiona următorul pachet descris pentru aplicaţia
Web.Spre exemplu, pagina 10 poate conţine secvenţa 18, 12 (fig.6.9).
Aceasta înseamnă că aplicaţia Web are în coada curentă paginile fizice cu
numărul 18 şi 12 pentru recepţionarea următoarelor pachete. Presupunem
că paginile 18 şi 12 se află în memoria principală şi sunt pagini fizice
blocate, atribuite aplicaţiei Web de către kernel, la pornirea aplicaţiei
Web.
In momentul în care soseşte un nou pachet pentru aplicaţia Web,
adaptorul va demultiplexa pachetul către pagina 10, folosind un filtru de
pachete, iar apoi va scrie datele din pachet (folosind DMA) în pagina 18.
După ce a realizat aceasta, adaptorul va scrie descriptorul 18 într-o pagină
dedicată descriptorilor de pagini scrise (exact ca la fbufs), spre exemplu
pagina nr.9, pagina pe care aplicaţia Web este autorizată să o citească.
Este apoi sarcina aplicaţiei Web să termine procesarea paginilor scrise, şi
să pună periodic în coada adaptorului noi descriptori de buffer-e libere.
Totul pare frumos, dar există o problemă de securitate. Presupunem că
printr-o eroare/rea intenţie, aplicaţia Web scrie în pagina descriptorilor
secvenţa 155, 120 (lucru pe care-l poate face). Presupunem în continuare
ca pagina 155 este în memoria principală, şi că în această pagină kernel-ul
işi stochează structurile de date. Cand adaptorul primeşte un nou pachet
pentru aplicaţia Web, va scrie datele pachetului în pagina 155,
suprascriind structurile de date ale kernel-ului. Aceasta va cauza probleme
serioase, cel putin eşuarea sistemului.
Dar de ce nu poate detecta hardware-ul memoriei virtuale acest tip de
problemă? Motivul este ca hardware-ul memoriei virtuale (observaţi
pozitia TLB în fig.6.8) oferă protecţie doar împotriva accesului neautorizat
a proceselor care rulează pe CPU. TLB interceptează fiecare acces de tip
READ (sau WRITE) făcut de către procesor şi poate face verificari; însă
adaptoarele care fac acces de tip DMA, ocolesc sistemul memoriei virtuale
şi accesează memoria direct.
145
In practică, acest lucru nu reprezintă o problemă deoarece aplicaţiile nu
pot programa dispozitivele (precum discuri, adaptoare) să citească sau să
scrie la o anumită locaţie, la comanda aplicaţiei. Insă, accesul este mediat
mereu de către kernel. Dacă nu implicăm şi kernel-ul, trebuie să ne
asigurăm că instrucţiile pe care aplicaţia le-ar putea da adaptorului au fost
atent verificate.
Soluţia folosită la canalul dispozitivului aplicaţie ADC (application
device channel), este ca (P9, pasează indicaţii la interfaţă) kernel-ul să
trimită adaptorului o listă de pagini fizice valide, pe care fiecare aplicaţie
care foloseşte adaptorul, să le poată accesa direct. Acest lucru poate fi
făcut doar după ce aplicaţia a pornit şi înainte de a începe transferul de
date. Cu alte cuvinte, calculul implicat în autorizarea paginilor este decalat
în timp (P2), de la faza transferului de date la faza de iniţializare a
aplicaţiei. Spre exemplu, în momentul în care începe aplicaţia Web,
aplicaţia va cere kernel-ului 2 pagini, de exemplu 18 şi 12 iar apoi va cere
kernel-ului să autorizeze utilizarea acestor pagini de către adaptor.
Kernel-ul este apoi transpus în regim normal de operare de date. Daca în
acest moment aplicaţia Web pune în coadă descriptorul 155 şi apare un
nou pachet, adaptorul va verifica mai întâi dacă numarul 155 este în lista
autorizată a aplicaţiei (care conţine 18 şi 15). Deoarece 155 nu este în
listă, adaptorul nu va suprascrie structurile de date ale kernel-ului.
In concluzie, ADC-urile deplasează în spaţiu funcţiile de protecţie (P3c)
de la kernel la adaptor, folosind informaţii prelucrate anterior (lista
paginilor fizice autorizate, P2a) trimise de la kernel către adaptor (P9) şi
la care s-a adăugat hardware-ul memoriei virtuale (P4c).
In ultimii ani a fost promovată utilizarea mesajelor active pentru scopuri
similare. Mesajul activ conţine adresa procesului de nivel utilizator care va
manevra pachetul.Un mesaj activ evita intervenţia kernel-ului şi stocarea
temporară în tampoane, prin folosirea tampoanelor prealocate sau a
mesajelor de dimensiune mică, răspunsuri directe ale aplicaţiei,
ajungându-se astfel la o latenţă mică. Latenţa mică permite o suprapunere
a calculului şi comunicaţiei în maşinile paralele. Implementarea cu mesaje
active permite doar transferul mesajelor scurte sau a blocurilor mari.
Implemetarea mesajelor rapide merge mai departe şi combină interfeţele
de dispersie-regrupare la nivel-utilizator cu controlul fluxului, pentru a
permite o performanţă ridicată uniformă, atât pentru mesajele scurte cât şi
pentru cele lungi.
La ce folosesc kernelurile?
Problema este importantă deoarece ADC-urile şi mesajele active ocolesc
kernel-ul. Nucleele sunt bune pentru asigurarea protecţiei (protecţia
sistemului şi a utilizatorilor bine intenţionaţi, de programe rău intenţionate
şi erori) şi pentru planificarea resurselor între diferitele aplicaţii. Dacă
scoatem nucleul din funcţie, aceste servicii vor trebui îndeplinite de
altcineva. Spre exemplu, ADC-urile oferă protecţie folosind hardware-ul
memoriei virtuale (pentru a proteja descriptorii) şi constrângerea
adaptoarelor (pentru a proteja memoria tampon).
Trebuie de asemenea să multiplexeze legătura fizică de comunicare (în
special în partea de emisie) între diversele canale ale dispozitivelor
aplicaţiei şi să asigure un oarecare grad de corectitudine. Pentru aceasta
146
codul kernel-ului ar trebui replicat în fiecare dispozitiv; unele dispozitive
însă, precum discul sau adaptorul de reţea sunt mai speciale, în sensul că
necesită performanţă mai ridicată, şi trebuie tratate special. Există o
iniţiativă prin care se doreşte ca toate aceste idei să aibă şi o formă
comercială, bazat pe ideea ADC şi pe soluţia UUNet de la Cornell
(asemănătoare cu ADC şi propusă în paralel cu aceasta). Această
propunere, cunoscută sub numele de arhitectura interfeţei virtuale VIA
(Virtual Interface Architecture)este descrisă în cele ce urmează.
147
6.6. Reducerea intreruperilor
Deşi supraîncărcarea datorată întreruperilor este mai mică decât cea
apărută la planificarea proceselor sau apelurile sistem, ea poate fi totuşi
destul de substanţială. De fiecare dată când soseşte un pachet, apare o
întrerupere care are ca efect înteruperea procesorului şi o comutare de
context. Nu pot fi evitate de tot întreruperile, dar se poate reduce
supraîncărcarea datorată întreruperilor prin următoarele artificii.
• Intrerupere doar pentru evenimente importante: de exemplu, în
soluţia ADC, adaptorul nu trebuie să întrerupă procesorul la fiecare
recepţie a unui nou pachet, ci doar la recepţionarea primului pachet din
fluxul de pachete (presupunem că aplicaţia va verifica pachetele
recepţionate) şi când coada descriptorilor de tampoane libere este goală.
Aceasta poate reduce supraîncărcarea datorată întreruperilor, la un singur
pachet din N pachete recepţionate, presupunând că cele N pachete se
recepţionează într-o rafală.
• Polling/anchetarea: Procesorul (CPU) verifică dacă au apărut noi
pachete iar adaptorul nu întrerupe niciodată. Acest lucru poate duce la o
supraîncărcare mai mare decât în cazul procesării acţionate de întreruperi,
dacă numărul de pachete recepţionate este scăzut, dar metoda poate fi
eficientă pentru volume de trafic mari. O altă variantă a acestui concept ar
fi întreruperile de ceas: CPU verifică periodic, la expirarea unui timer.
• Controlul prin aplicaţie: Transmiţătorul poate determina momentul
când se întrerupe receptorul, setând un anumit bit din antetul pachetului.
De exemplu un transmiţător FTP poate seta bitul de întrerupere, doar în
ultimul pachet de date din cadrul unui transfer de fişiere (P10, pasează
indicaţii în antetele protocolului). Ideea este probabil prea radicală pentru
a putea fi folosită, însă a fost propusă o implementare care are la bază o
rafinare a acestei idei, într-un chip ATM, fabricat deja.
In general, folosirea simultana a mai multor metode funcţionează destul
de bine în practică. In unele implementări cum cum este “first bridge”,
utilizarea polling-ului este foarte eficace. De aceea, ideile mai radicale
precum întreruperile de ceas sau cele controlate de aplicaţie au devenit
mai puţin folositoare. Trebuie menţionat faptul că ideile RDMA au marele
avantaj de a înlătura, pentru transferurile de date de mari dimensiuni,
necesitatea apelurilor de sistem per pachet şi a întreruperilor per pachet.
6.7. Concluzii
Pe lângă restructurarea principală referitoare la evitarea copierii,
controlul supraîncărcării este o problemă foarte importantă, care trebuie
tratată când e vorba de aplicaţii de reţea. Serverele rapide trebuie să reducă
supraîncărcarea cauzată de planificarea proceselor, de apelurile la sistem,
şi de întreruperi. Sistemele de operare mai noi, precum Linux se străduiesc
enorm să reducă costul inerent pe care îl implică controlul supraîncărcării.
Arhitecturile moderne devin tot mai rapide în procesarea instrucţiunilor,
folosind date din memoria cache, fără o accelerare sensibilă a comutării
contextului sau a procesării întreruperilor.
Au fost trecute în revistă, pentru aplicaţiile de reţea, tehnicile de bază
pentru reducerea supraîncărcării cauzată de planificarea proceselor. Cu
149
greu se poate face ceva ieşit din comun, ca structurarea fiecărui nivel ca un
proces separat, fără apeluri la nivelurile superioare. Din fig.6.3 trebuie
desprinsă ideea profundă a procesarii la nivelul utilizatorului. Proiectarea
de reţele la nivel de utilizator, împreună cu canalele dispozitivelor de
aplicaţie fac posibilă existenţa unor tehnologii precum VIA, care vor face
parte în curând din sisteme reale, pentru a evita apeluri de sistem la
trimiterea/recepţionarea pachetelor.
Pe de altă parte, arta procesării structurate în contextul aplicaţiei, de
exemplu un server Web, s-a bucurat de tot mai multă atenţie în ultimul
timp. In timp ce serverele conduse de evenimente (împreună cu processele
ajutătoare) echilibrează maximizarea concurenţei şi minimizarea încărcării
datorată comutării de context, aspectele legate de ingineria software lasă
încă multe întrebări fără răspuns. Va fi suficientă abordarea lansată-de -
evenimente în mediul de producţie, cu modificări şi depanări frecvente?
Un pas inainte îl reprezintă abordarea condusă de evenimente, pe nivele,
însă ingineria serverelor Web mari va necesita cu siguranţă mai mult efort.
Abordarea condusă de evenimente se bazează pe implementarea rapidă a
apelului select() sau a funcţiilor echivalente cu acesta. Abordările Unix au
probleme fundamentale de scalabilitate ; sistemele de operare mai
populare, precum Windows, au API-uri mult mai eficiente
Ideea foarte importantă privind standardul VIA o reprezintă faptul că se
permite aplicaţiilor să comunice direct cu dispozitivele de reţea, folosind o
interfaţă virtuală protejată. Ideal, adaptorii sunt astfel proiectaţi încât să
permită funcţionarea mecanismelor de tip VIA sau similare. Intreruperile
sunt evident de neevitat, această problemă poate fi însă ameliorată
folosind amestecul şi polling-ul în medii potrivite.Figura 6.1 listează
tehnicile discutate în acest capitol şi principiile corespunzătoare.
6.8. Exercitii
1. Filtre de pachete şi apeluri : La descrierea apelurilor (fig.6.3)
sistemul şi-a dat seama pentru care aplicatie era destinat un anumit
pachet, prin faptul că apela o rutină de transport. De ce mai e necesară
filtrarea pachetelor? Ce presupuneri implicite au fost făcute aici?
2. Compararea modelelor de structurare a serverelor Web : au
fost comparate diferite mecanisme de structurare a serverelor prin
intermediul unor metrici simple ca eficienţa planificării şi concurenţa
CPU. Considerati şi celelalte două metrici în procesul de comparare.
• Concurenţa la disc : Unele sisteme au discuri multiple şi există o
planificare a discurilor. Intr-un asemenea mediu se pune întrebarea dacă
la o abordare condusă de evenimente ar putea apare probleme, în
comparaţie cu abordarea multiproces. Vor apare probleme şi la
abordarea condusă de evenimente care dispune şi de procese helper?
• Acumularea statisticilor: Serverele Web trebuie să deţină informaţii
statistice referitoare la structurile de utilizare pentru a ţine evidenţa. Vor
fi aceste statistici mai complexe la arhitecturile proces-per-client şi fir de
execuţie-per-client? De ce este mai simplu într-o arhitectură condusă de
evenimente?
3. Algoritmi versus algoritmică în reimplementarea ufalloc():
Se determina modul cel mai eficient de reimplementare a funcţiei
ufalloc(), pentru a găsi cel mai mic descriptor nealocat.
150
• Se folosesete o stivă/heap binară. Pentru N identificatori, câte accese
la memorie sunt necesare? Cât spaţiu este necesar, în biţi?
• Presupunem că maşina este pe W biţi (la Alpha W=64) şi că există o
instrucţiune (sau un set de instrucţiuni) pentru a găsi cel mai din dreapta
zero într-un cuvânt de W biţi. Presupunem că descriptorii alocaţi sunt
reprezentaţi ca un set de biţi de dimensiune N. Cum poate fi completat
setul de biţi cu o stare suplimentară (P12), pentru a calcula eficient cel mai
mic descriptor nealocat ?
• Care sunt costurile de spaţiu şi timp ale acestei scheme, în comparaţie
cu o stivă simplă? Se poate face stiva simplă mai rapidă folosind un
artificiu prin care se măreşte baza stivei, astfel încât să avem K>1
elemente în fiecare nod al stivei?
4. Implementarea modificată a unui fast select(): Textul explică
modul în care elementele sunt adăugate setului I, H şi R, dar nu specifică
în totalitate modul în care ele sunt scoase din set. Explicaţi modul în care
elemetele sunt scoase din set, în special la setul de indicaţii H.
5 Implementarea modificată a unui fast select(): Se consideră
următoarele modificări ale implementării fast select:
(a) Inew este egal cu S (şi nu cu Iold ∪ S).
(b) Rnew este calculat ca şi înainte.
(c) Utilizatorului i se returnează Rnew (şi nu Rnew ∪ S).
151
CAPITOLUL 11
152
11.1 Cautarea prefixelor
Această secţiune introduce notaţia prefix, explică de ce e folosită căutarea
prefixelor şi descrie principalele metrici pentru evaluarea schemelor de
căutare a prefixelor.
11.1.1 Notarea prefixelor.
Prefixele utilizate pe internet sunt definite prin biţi şi nu prin caractere
alfanumerice, având o lungime de până la 32 de biţi. Confuzia e creată de
faptul ca că prefixele IP sunt scrise deseori cu notaţii cu punct zecimal.
Astfel, prefixul de 16 biţi pentru UCDS, se scrie 132.239. Fiecare din cifrele
zecimale dintre puncte reprezintă un octet. Deoarece în binar 132 este
10000100 şi 239 este 11101111, prefixul UCDS în binar poate fi scris şi ca
1000010011101111*, unde caracterul “*” arată că biţii rămaşi nu contează.
Toate adresele IP de 32 biţi ale staţiilor UCSD încep cu aceşti 16 biţi.
Deoarece prefixele pot avea lungime variabilă, alt mod de notare a
prefixelor este de forma A/L, unde A e o adresă IP de 32 biţi în virgulă
zecimală şi L lungimea prefixului. Astfel, prefixul UCDS poate fi scris şi ca
132.239.0.0/16, unde lungimea 16 indică faptul că doar primii 16 biţi
(132.239) sunt relevanţi. Al treilea mod de a scrie prefixele este utilizarea
unei măşti în loc de o lungime explicită de prefix. Astfel prefixele pot fi
scrise în următorul mod: 128.239.0.0 cu masca 255.255.0.0. Deoarece masca
255.255.0.0 are 1 pe primii 16 biţi, se indică o lungime implicită de 16 biţi. 1
Din aceste trei modalităţi prin care se poate nota un prefix (binar cu asterix
la sfârşit, cu notaţie ”/ ” slash, şi prin intermediul măştii), ultimele două sunt
mai compacte şi deci mai potrivite pentru scrierea prefixelor mari. Din
motive pedagogice este mai simplu să se utilizeze prefixe mici pentru
exemple şi scrierea în binar. În acest capitol se va utiliza 01110* pentru a
indica un prefix ce se potriveşte cu toate adresele IP de 32 de biţi care încep
cu 01110. Este uşor de convertit această notaţie spre notaţiile slash sau
mască. Majoritatea prefixelor au lungimea minimă de 8 biţi.
154
de accesările memoriilor, cea mai simplă măsură a vitezei căutării este
numărul de accesări ale memoriei în cazul cel mai defavorabil. A patra
observaţie arată că deoarece bazele de date ale reţelelor backbone au prefixe
cu lungimea între 8 şi 32, schemele naive vor avea nevoie de 24 de accesări
ale memoriei în cel defavorabil caz, pentru a testa toate lungimile posibile
de prefix.
A cincea observaţie susţine că în timp ce bazele de date au în jur de
150.000 prefixe, posibila utilizare a rutelor pentru calculatoarele gazdă (cu
adrese de 32 biţi) şi a rutelor multicast, înseamnă că ruterele backbone
viitoare vor avea baze de date de prefixe cu 500.000 -1.000.000 de prefixe.
A şasea observaţie se referă la viteza de actualizare a structurilor de date
pentru căutări, pentru adăugarea/ştergerea unui prefix de exemplu.
Implementările instabile ale protocoalelor de rutare pot duce la actualizări de
ordinul milisecundelor. De observat că, indiferent dacă sunt de ordinul
secundelor sau a milisecundelor, sunt cu câteva ordine de mărime sub
necesarul căutării/lookup, permiţând astfel luxul precalculării informaţiilor
(P2a), sub formă de structuri de date, pentru accelerarea căutării, cu costul
creşterii timpilor de actualizare.
A şaptea observaţie se referă la memoriile standard ieftine, DRAM cu
timpi de acces de ≈ 60 nsec, şi memoriile de viteză mare (off/on-chip
SRAM, 1–10nsec) ce trebuie folosite la viteze mari. DRAM sunt teoretic
nelimitate, dar SRAM şi cele on-chip sunt limitate de costul mare şi
nondisponibilitate. Astfel a treia metrică este utilizarea memoriei; aceasta
poate fi scumpă şi rapidă (cache la software, SRAM la hardware), sau ieftină
şi lentă (DRAM, SDRAM).
O schemă de căutare care nu face o reactualizare incrementală, va avea
nevoie de două copii ale bazei de date de căutare/lookup, astfel încât în
prima să poată face căutarea, şi în cealaltă asocierea. Astfel actualizarea
incrementală reduce la jumătate necesarul de memorii de mare viteză..
A opta observaţie se referă la lungimea prefixelor. IPv6 foloseşte prefixe
de 128 biţi, iar lookup-urile multicast necesită asocieri pe 64 biţi (adresa de
grup şi adresa sursă pot fi concatenate în 64 de biţi). Este discutabila
generalizarea Ipv6 şi a multicast-ului, asa că lookup-urile IP pe 32 biţi
rămân actuale. Schemele descrise se scalează bine şi la prefixe lungi.
Pe scurt, metricile importante în ordinea importantei sunt: viteza lookup-
ului, memoriile şi timpul de actualizare. Ca exemplu, o proiectare buna on-
chip, folosind o memorie on-chip de 16 Mbiţi, poate suporta orice set din
500.000 prefixe, face un lookup în 8 nsec pentru a permite o expediere la
viteza firului la ratele OC-192, şi permite actualizarea prefixului în 1msec.
Datele sunt conform cu baza de date disponibilă pentru proiectul IPMA,
folosită pentru a compara experimental schemele de mascare. Cea mai mare
dintre acestea Mae East, e un model rezonabil pentru un suport larg de ruter.
Următoarea notaţie este utilizată în mod repetat pentru raportarea
performanţelor teoretice ale algoritmilor de mascare IP. N reprezintă numărul
de prefixe (150.000 pentru baze de date mari, în prezent ), iar W reprezintă
lungimea adresei (32 pentru IPv4) .
155
Observaţii Inferente
1)250000 de fluxuri concurente în backbone Memorarea cache lucrează slab în ruterele
backbone
2)50% sunt confirmări TCP Pentru pachetele de 40 biţi e necesară
căutarea cu viteza liniei
3)Căutare dominată de accesările memoriei Viteza căutării măsurată de numărul de
accesări ale memoriei
4)Lungimea prefixelor 8 - 32 Schemele naive cer 24 de accesări ale
memoriei
5)150.000 prefixe actuale şi rute multicast şi În urma creşterii
gazdă 500.000 -1.000.000 prefixe
6)BGP instabil, multicast Actualizare în timp de
milisecunde-secunde
7)Vitezele mari necesită SRAM Duce la minimizarea memoriei
8)Ipv6, întârzieri multicast Decisiv e lookup pe 32biţi
FIGURA11.2 Date curente despre problemele de lookup şi implicaţiile asupra soluţiilor
156
11.2.1 Şiruri de indici şi comutarea etichetelor
La folosirea şirurilor de indici, fiecare ruter pasează un indice tabelului de
retransmisie a următorul ruter; se evită astfel folosirea căutării prefixelor.
Indecşii sunt precalculaţi de către protocolul de rutare/dirijare de cate ori se
schimba topologia retelei. În figura 11.3, sursa S trimite un pachet către
destinaţia D prin primul ruter A; antetul pachetului conţine un index i spre
tabelul de retransmisie al lui A. Astfel, ruterul A precizează calea spre D prin
ruterul B, care la rândul lui conţine indicele j către destinaţia D. Astfel A
trimite pachetul spre B şi precizează indicele j al acestuia. Procesul se repetă
în fiecare ruter din reţea prin utilizarea indexului din pachet pentru căutarea
in tabelele de transmisie spre destinaţie.
Diferenţele majore între şirurile de indici, şi indicii circuitelor virtuale sunt
următoarele: şirurile de indici sunt per destinaţie, nu per perechea activa
sursă-destinaţie ca indicii circitelor virtuale tip ATM. Cea mai importantă
diferenţă este aceea că şirurile de indecsi cu sunt precalculate de către
protocolul de rutare de fiecare dată când se schimbă topologia. In figura
11.4 se prezintă topologia unui ruter ce utilizează protocolul Bellman – Ford
pentru găsirea distantelor spre destinaţie.
Cu protocolul Bellman–Ford (folosit de protocolul intradomeniu RIP,
Routing Information Protocol), un ruter R calculează calea cea mai scurtă
spre D, prin retinerea celui mai mic dintre costurile spre D, prin fiecare
vecin. Costul spre D printr-un vecin ca A, este costul lui A spre D (5 in cazul
nostru) la care se adună costul de la R la A (3, in exemplul nostru). În figura
11.4, costul cel mai scurt de la R spre D este prin ruterul B, cu costul 7. R
poate calcula aceste costuri deoarece fiecare vecin al lui R, (A si B aici)
paseaza costul propriu de la D spre R, cum se arată în figură. Pentru
calcularea si a indicilor, se modifică protocolul de baza astfel încât fiecare
vecin isi reportează indicii spre destinaţie in plus cu costul propriu spre
destinatie. În figura 11.4, A trimite pe i şi B pe j; astfel, cand R alege pe B, ii
foloseste si indexul j a lui B in intrarile tabelului de dirijare pentru D. Deci,
fiecare ruter utilizează indexul vecinului de cost minim pentru fiecare
destinatie, ca sir de indecsi pentru acea destinatie.
Cisco a introdus mai târziu comutarea etichetelor, a cărei concept se
aseamănă cu conceptul înşiruirii indecsilor, dar comutarea etichetelor
permite unui ruter utilizarea unei stive de etichete (indici) pentru ruterele
multiple care urmeaza. Cu toate acestea, ambele scheme nu lucrează bine cu
structurile ierarhice. Se consideră un pachet ce ajunge de la backbone la
primul ruter al domeniului de ieşire. Domeniul de iesire este ultima retea
condusa autonom traversata de pachet, sa zicem o retea de intreprindere
careia ii apartine destinatia pachetului.
Singura cale de evitare a căutării/lookup in primul ruter R, din domeniul de
ieşire, este sa avem un ruter inafara domeniului de ieşire care sa trimita
(pentru subreteaua destinatie) mai devreme un index către R. Acest lucru este
imposibil, deoarece ruterele backbone anterioare ar trebui să aibe doar o
intrare agregata de rutare către intreg domeniul destinaţie şi, astfel, poate
trimite doar un indice spre toate subretelele din acel domeniu. Soluţia este fie
adăugarea unor intrări suplimentare ruterelor din afara domenuilui (ceea ce e
nefezabil), sau sa se pretinda o cautare IP banala la punctele de intrare in
domeniu(soluţia folosită). Comutarea etichetelor s-a dezvoltat azi sub o
157
formă mai generala numită comutare de etichete multiprotocol (MPLS
MultiProtocol Label Switching). Totusi, nici comutarea de etichete nici
MPLS nu evita complet cautarea IP ordinara.
D i D j D -
B,j B, -
A, i
Nod A
Tabel rutare Tabel rutare
S A B D
Fig. 11.3 Căutarea destinaţiei prin utilizarea de către fiecare ruter a unui index de trecere
în tabelul de transmisie a următorului ruter
D, 5
D, 6
i Cost 3 j
Cost 1
Nod A
Nod B
D, 5, i D, 5, j D, 5, j
Tabel Tabel
trimis de A trimis de B
Nod R
Fig 11.4 Setarea indicelor înşiruirii, sau modificarea înşiruirii prin
rutarea Bellman Ford
R2 R1
I
I,L
L
M
D
Procesor
Slow path
Fast path
Fig. 11.5 Comutarea IP
159
complet căutarea cu prefix şi fiecare adauga un protocol complex. Sa vedem
acum cum e cu presupusa complexitate a cautarii IP.
Figura 11.7 Arbore ordonat unibit pentru baza de date din fig.11.6
In fig.11.7 acest lucru e facut folosind un sir text (de ex.”01”) pentru a
reprezenta pointerii care ar urma in ramura unicale. Astfel, in fig.11.7, doua
noduri ale arborelui ordonat (continand fiecare doi pointeri) din calea spre
P3, au fost inlocuiti de un singur sir text, de 2 biti. Dar nu s-a pierdut
informatie prin aceasta transformare (ca exercitiu, determinati daca mai e
vreo cale prin arbore care poate fi comprimata asemanator).
Pentru cautarea celei mai lungi potriviri a prefixului addresei destinatie D,
se folosesc bitii lui D pentru a trasa calea prin arbore. Calea incepe cu
radacina si continua pina ce cautarea esueaza prin terminare la un pointer vid
ori la un sir text care nu se potriveste complet.In timp ce urmareste calea,
algoritmul tine evidenta ultimului prefix numarat la un nod de pe cale. Cand
cautarea esueaza, acesta este cea mai lunga potrivire a prefixului si e
162
returnata.De exemplu, daca D incepe cu 1110, algoritmul porneste urmarind
pointerul-1 la radacina ca sa ajunga la nodul ce-l contine pe P4.Algoritmul
isi aminteste pe P4 si foloseste urmatorul bit al lui D ( un 1) pentru a urmari
pointerul -1 la urmatorul nod. La acest nod, algoritmul urmareste valoarea
(P4) prin prefixul (P2) gasit mai nou.In acest punct se termina cautarea,
deoarece P2 nu are pointeri de iesire.
Pe de alta parte, consideram ca facem o cautare pentru destinatia D’ ai
carui primii 5 biti sunt 11000. Inca odata, primul bit de 1, e folosit pentru a
ajunge la nodul ce-l contine pe P4. P4 este tinut minte ca ultimul prefix
contorizat, si pointerul 1 e urmarit pentru a ajunge la nodul cel mai din
dreapta de adincime 2.
Algoritmul urmareste acum al treilea bit din D’ (un 0) spre nodul sirului
text care contine ”01”. Astfel ne amintim ca P9 a fost ultimul prefix
contorizat. Al patrulea bit a lui D’ este 0, care se potriveste cu primul bit din
”01”. Dar, al cincilea bit a lui D’ este 0 (si nu 1 cum e al doilea bit din ”01” ).
Astfel cautarea se termina cu P9 ca cea mai lunga potrivire.
Literatura despre arborii ordonati nu foloseste sirurile text pentru a
comprima ramurile cu cale unica (fig.11.7).In schimb schema clasica
Patricia trie / testul Patricia, foloseste un contor de omisiuni / skip count.
Acest contor memoreaza numarul de biti din sirul text corespunzator, si nu
bitii in sine.De exmplu, ”01” din exemplul nostru va fi inlocuit cu contorul
de omisiuni ”2” in testul Patricia.
Algoritmul lucreaza bine atata timp cat testul Patricia e folosit pentru
pentru potriviri exacte, pentru care a si fost initial creat.Cand ajunge cautarea
la la un nod cu contor de omisiuni, omite numarul de biti potriviti si
urmareste pointerul nodului contorului de omisiuni pentru a continua
cautarea. Deoarece bitii omisi nu sunt comparati pentru potrivire, Patricia
pretinde ca la sfarsitul cautarii sa se faca o comparare completa dintre cheile
cautate si intrarile gasite de Patricia.
Din pacate, algoritmul lucreaza foarte prost pentru potrivirea prefixului/
prefix matching, pentru care Patricia nu a fost proiectat la inceput. De
exemplu, la cautarea lui D’, ai carui primii 5 biti sunt 11000 in echivalentul
lui Patricia a figurii 11.7, cautarea ar trebui sa omita ultimii doi biti si sa o ia
spre P3. In acest punct compararea va gasi ca P3 nu se potriveste cu D’ .
Cand se intampla acest lucru o cautare in arborele Patricia trebuie sa
revina inapoi si sa retesteze arborele pentru o posibila potrivire mai scurta. S-
ar parea ca in acest exemplu, cautarea ar trebui sa-si aminteasca P4. Dar
daca P4 a fost de asemenea contorizat pe calea care contine nodurile
contoarelor de omisiuni, algoritmul nu poate fi chiar sigur de P4. Astfel el
trebuie sa revina ca sa verifice daca P4 este corect.
Din pacate, implementarea BSD a inaintarii IP a decis sa foloseasca arborii
Patricia, ca baza pentru cea mai buna potrivire de prefix. Astfel,
implementarea BSD a folosit contoarele de omisiuni; de asemenea
implementarea memoreaza prefixele umplandu-le cu zerouri. Prefixele au
fost depozitate in frunzele arborelui, in loc sa fie in interiorul nodurilor, cum
e aratat in fig.11.7. Rezultatul e ca potrivirea prefixului poate, in cel mai rau
caz, sa duca la o reluare/ backtracking a arborelui pentru cazul cel mai
defavorabil de 64 de accesari ale memoriei (32 in josul arborelui si 32 in
susul arborelui).
163
Avand alternativa simpla a folosirii sirurilor text pentru evitarea
backtracking-ului, contoarelor de omisiuni sunt o idee proasta; in esenta,
deoarece transformarea contoarelor de omisiuni nu conserva informatia, in
timp ce transformarea sirurilor text o conserva. Totusi, din cauza influentei
enorme a BSD-ului, unii producatori si chiar algoritmi au aplicat contoarele
de omisiuni in implementarile lor.
Figura 11.8 Expansiunea controlata a bazei de date de prefixe originala (stanga, cu cinci
lungimi de prefixe 1,3,4,5,6) la o baza de date expandata (dreapta, cu doar doua lungimi de
prefixe 3 si 6).
164
mentionat este faptul ca prin expandarea lui P6= 1000 ∗ de la patru biti la
sase biti, se intra in coliziune cu P7= 100000 ∗ si astfel se renunta la P6.
Figura 11.9 Arbore ordonat expandat (care are doi pasi de cate 3 biti) corespunzator bazei
de date de prefixe din fig.11.8.
165
patru elemente si codand lungimea 2 cu pointerul spre nodul cel mai din
stanga. Codarea pasului necesita 5 biti. Dar, arborele ordonat cu pas variabil
din fig.11.10 are cu patru intrari in tabela mai putine decat arborele din
fig.11.9.
Exemplul motiveaza alegerea pasilor pentru minimizarea volumul de
memorie al arborelui. Deoarece expandarea face un compromis memorie-
timp, de ce sa nu minimizamnecesarul de memorie prin optimizarea gradului
de libertate (P13), pasii folositi in fiecare nod ? Pentru alegerea pasilor
variabili, proiectantul trebuie sa specifice mai intai numarul de accesari ale
memoriei in cazul cel mai defavorabil.De exemplu, cu un pachet de 40 de
octeti la 1 Gbps si un DRAM de 80 nsec, avand bugetul de timp de 320
nsec, sunt permise doar patru accesari ale memoriei. Acest lucru
conditioneaza numarul maxim de noduri in orice cale de cautare (patru
pentru exemplul considerat).
Daca inaltimea arborelui este data, pasul poate fi ales pentru a minimiza
memoria. Acest lucru poate fi facut in cateva secunde folosind programarea
dinamica, chiar si pentru baze mari de date de 150.000 de prefixe. Un grad
de libertate(pasii), e optimizat pentru minimizarea memoriei folosita pentru o
inaltime data cea mai defavorabila.
Un arbore ordonat se spune ca e optimal pentru o inaltime h si o baza de
date D, daca arborele are cel mai mic spatiu de memorare dintre toti arborii
ordonati cu pas variabil pentru baza de date D, si inaltimea nu mai mare
decat h. Se arata usor ca arborele din fig.11.10 e optimal pentru baza de date
din stanga figurii 11.8 si inaltimea 2.
Problema generala a alegerii pasul optim poate fi rezolvata recursiv (fig
11.11). presupunem ca inaltimea arborelui trebuie sa fie 3. Algoritmul alege
mai intai o radacina cu pasul s. Cei y = 2s pointeri posibili din radacina pot
conduce spre y subarbori nevizi T1 ,..., Ty . Daca multimea de s pointeri indica
spre subarborele Ti , atunci toate prefixele din baza de date originala D care
incep cu pi trebuie memorate in Ti . Numim setul de prefixe Di .
Presupunem ca putem gasi recursiv Ti optimal pentru inaltimea h − 1 si
baza de date Di . Avand un acces la memorie folosit la nodul radacina, au
ramas doar h − 1 accese la memorie pentru a parcurge fiecare subarbore Ti .
Notam cu Ci necesarul de spatiu de memorare, numarat in locatii de tabele,
pentru Ti optimal. Atunci, pentru un pas s al radacinii fixat, costul arborelui
optimal rezultat C ( s ) este 2 s (costul nodului radacina in locatii de tabel)plus
y
1 ≤ s ≤ 32 , care minimizeaza s.
O folosire naiva a recursivitatii duce la subprobleme repetate. Pentru a
evita subproblemele repetate. Algoritmul construieste mai intai un arbore
ordonat 1-bit.De mentionat este ca oricare subarbore ordonat Ti (fig.11.11)
trebuie sa fie un subarbore N al arborelui 1-bit. Apoi, algoritmul foloseste
programarea dinamica pentru construirea costului optim si pasii arborelui
pentru fiecare subarbore N din arborele original 1-bit, pentru toate valorile
1-h ale inaltimii, construind de jos in sus, de la subarborele de cea mai mica
166
inaltime spre subarborele de cea mai mare inaltime. Rezultatul final sunt
pasii optimi pentru radacina (subarborelui 1-bit) cu inaltimea h.
( )
Complexitatea finala a algoritmului este O N ∗W 2 ∗ h , unde N este
numarul prefixelor originale din baza de date originala, W este latimea
adresei destinatie, iar h este ponderea dorita pentru cazul cel mai defavorabil.
Aceasta este deoarece exista N ∗ W subarbori in arborele 1-bit, fiecare din ei
trebuie rezolvat pentru inaltimi in gama 1-h, si fiecare solutie implica o
minimizare fata de cel mult W alegeri posibile, pentru pasul initial s.
Complexitatea este liniara fata de N (numarul cel mai mare cunoscut actual
fiind de 150.000)si h, (care ar trebui sa fie mic, maxim 8), dar patratica ca
functie de latimea adresei (32, in mod curent). In practica, dependenta
patratica de latimea adresei nu e un factor major.
De exemplu, pentru o inaltime de 4, baza de date optimizata Mae-East
necesita 432 KB, fata de 2003 KB a variantei neoptimizate. Varianta
neoptimizata foloseste pasii „naturali”de 8,8,8,8 . Programul dinamic ia 1,6
sec timp de rulare pe un Pentium Pro de 300 MHz. Programul dinamic poate
fi chiar mai simplu pentru arborii cu pas fix, rularea durand doar 1msec, dar
necesita 737KB in loc de 423 KB.
Dar 1,6 msec este mult prea mult ca programul dinamic sa ruleze la fiecare
actualizare si mai permite actualizari de ordinul milisecundelor. Cu toate
acestea, instabilitatile backbone sunt cauzate de patologii de genul in care
acelasi set de prefixe S sunt inserate repetat si sterse de ruterul care e
temporar suntat. Deoarece a trebuit sa se aloce memorie pentru intregul set,
inclusiv S, oricum, faptul ca arborele este suboptimal la folosirea sa a
memoriei cand S este sters, este irelevant. Pe de alta parte, rata la care noile
prefixe sunt sterse sau adaugate de manager, pare ca e mai probabil ca acest
lucru sa fie facut in ordinea zilelor. Astfel, un program dinamic care ia
cateva secunde timp de rulare, e rezonabil sa fie rulat zilnic, si nu va afecta
timpul pentru cazul cel mai defavorabil de inserare/stergere, permitand arbori
optimali rezonabili.
167
Asfel, la adaugarea lui P10= 1100 ∗ , algoritmul trebuie sa adauge
expansiunea lui 0 ∗ inspre nodul X. In particular, intrarile 000 si 001 in
nodul X trebuie actualizate sa fie P10.
Daca se termina cautarea inainte de a atinge ultimul pas in prefix,
algoritmul creaza un nou nod al arborelui ordonat. De exemplu, daca prefixul
P11= 1100111 ∗ e adaugat, cautarea esueaza la nodul X, cand se gaseste un
pointer vid/nil la intrarea 011. Algoritul creaza atunci un nou pointer la
aceasta locatie, care e facut sa indice spre un nou nod al arborelui care
contine P11. Apoi P11 este expandat in acest nod nou.
Stergerea este similara adaugarii. Complexitatea inserarii si a stergerii este
data de timpul de realizare a unei cautari ( O (W ) ) plus timpul de reconstruire
completa a nodului (O ( S ) , unde S este dimensiunea maxima a nodului
arborelui). De exemplu, folosind noduri ale arborelui de 8-biti, acest al
doliea cost va necesita scanarea a aproximativ 28 = 256 intrari de nod ale
arborelui. Astfel, pentru a permite actualizari rapide, e crucial sa limitam de
asemenea dimensiunea oricarui nod din programul dinamic descris anterior.
169
dispersare, astfel încât L [i ] e un pointer spre tabela de dispersare care
conţine toate prefixele de lungime i.
Considerăm acelaşi tabel mic de rutare din figura 11.17, cu doar două
prefixe, P4 = 1* şi P1 = 101*, de lungime 1 şi respectiv 3. Acesta este un
subset al figurii 11.18. Zona tabelelor de dispersare este orizontală, în
partea de sus (A) a figurii 11.18. Tabela de dispersare de lungime 1,
conţinând prefixul P4, este verticală, în partea stângă şi indică spre
poziţia 1 din tabel; tabela de dispersare de lungime 3, conţinând prefixul
P1, este în partea dreapta şi indică spre poziţia 3 din tabel; tabela de
dispersare de lungime 2 este vidă, deoarece nu există nici un prefix de
lungime 2.
O căutare naivă a adresei D începe cu tabelul de lungimea cea mai
mare (3 în exemplu), extrage primii l biti din D în Dl şi apoi caută Dl
in tabelul de dispersie de lungime l. Dacă cautarea are succes, a fost
găsită cea mai bună potrivire; dacă nu, algoritmul ia în considerare
lungimea imediat mai mică (de ex. 2). Algoritmul caută, decrementând
lungimea posibilă a prefixului, până când găseşte o potrivire în mulţimea
prefixelor posibile, sau până când epuizează lungimile.
Schema naivă realizează o căutare liniară a lungimilor de prefixe
distincte. Analogia sugerează un algoritm mai eficient: căutarea binară
(P15). Spre deosebire de căutarea binară a domeniului/gamei de prefixe,
aceasta este o căutare binară asupra lungimii prefixelor. Diferenţa este
majoră. Cu 32 de lungimi, căutarea binară asupra lungimii durează 5
accesări în cel mai rău caz ; cu 32000 de prefixe căutarea binară asupra
gamei de prefixe durează 16 accesări. Căutarea binară trebuie să inceapa
de la lungimea mediana a prefixelor si fiecare dispersare trebuie sa
împartă în două lungimile posibile ale prefixelor. O căutare poate da
doar două rezultate: găsit sau negăsit. Daca s-a găsit o potrivire la
lungimea m, atunci lungimile strict mai mari decât m trebuie căutate
pentru o potrivire mai lungă. In mod corespunzător, dacă nu s-a gasit
nici o potrivire, căutarea trebuie sa continue printe prefixele de lungimi
strict mai mici decât m.
De exemplu, în figura 11.18.A, presupunem că începe căutarea la
lungimea medie-2 a tabelei hash, pentru o adresă care începe cu 101.
Evident că această căutare nu duce la găsirea unei potriviri. Dar există o
potrivire mai lungă în tabelul de lungime 3. Din moment ce doar găsirea
unei potriviri duce la translatarea căutării la jumătatea din dreapta,
trebuie introdusă o “potrivire artificială”sau marker/indicator care să
forţeze căutarea în jumătatea din dreapta în cazul în care există
posibilitatea unei potriviri mai lungi.
De aceea în partea B se introduce o intrare de marcare 10 reprezentată
îngroşat, care corespunde primilor doi biţi ai prefixului P1= 101 din
tabelul de lungime 2. In esenţă, starea a fost adaugată pentru creşterea
vitezei (P12).Markerul permite eşecuri de testare în zona mediană
pentru a exclude toate lungimile mai mari decât cea mediană.
170
Căutarea unei adrese D care începe cu 101 se face corect. Căutarea
pentru 10 în tabelul de lungime 2 (fig.11.18.B) duce la găsirea unei
potriviri ; căutarea continuă mai departe în tabelul de lungime 3, se
găseşte o potrivire cu P1 şi se încheie căutarea. In general, trebuie plasat
un marker pentru un prefix P, la toate lungimile prin care va trece
căutarea binară pentru găsirea lui P. Se adaugă doar un număr
logaritmic de marcatori. Pentru un prefix de lungime 32, markerii
necesari sunt doar la lungimile 16, 24, 28 şi 30.
Din păcate, algoritmul este încă incorect. In timp ce markerii duc la
prefixe posibil mai lungi, pot de asemenea să ducă la o căutare pe piste
greşite.Se consideră căutarea unei adrese D’ (fig.11.18.B) ai cărei primi
trei biţi sunt 100. Deoarece mijlocul tabelului conţine 10, căutarea în
tabela hash mijlocie conduce la găsirea unei potriviri. Acest lucru
forţează algoritmul să caute 100 în continuare în al treilea tabel ceea ce
va duce la eşuarea căutării. Cea mai bună potrivire corectă a prefixului
se află în primul tabel (P4 = 1*). Markerii pot cauza deraierea căutarii.
Dar, o revenire a căutării în jumătatea stângă duce la un consum liniar
de timp.
Pentru a asigura un timp de căutare logaritmic, fiecare nod marker
M va conţine o variabilă M.bmp, unde M.bmp reprezintă cel mai lung
prefix care se potriveşte cu şirul M. Această variabilă este precalculată
când M este introdus în tabela hash. Când algoritmul urmareşte markerul
M şi caută prefixele de lungime mai mare decât M, dacă eşuează în
găsirea unui asemenea prefix mai lung, atunci răspunsul este M.bmp. In
esenţă, cel mai potrivit prefix asociat fiecărui marker este precalculat
(P2a). Acest lucru evită căutarea tuturor lungimilor mai mici decât
lungimea medie dacă potrivirea se face cu ajutorul markerului.
171
Versiunea finală a bazei de date ce conţine prefixele P4 şi P1 este
prezentată în fig.11.18.C. A fost adăugat un câmp bmp markerului 10
care indică spre cea mai bună potrivire de prefix a şirului 10 (ex. P4 =
1*). De aceea, când algoritmul caută 100 şi găseşte o potrivire în tabelul
median de lungime 2, îşi aduce aminte valoarea bmp corespunzătoare
intrării P4, înainte de a căuta în tabelul de lungime 3. Când căutarea
eşuează (în tabelul de lungime 3), algoritmul returnează câmpul bmp al
ultimului marcator întâlnit (ex. P4).
Un algoritm banal pentru construirea unei căutări binare a structurii
de date din memoria de lucru/scratch este următorul. Prima dată se
determină lungimile de prefix distincte; se determină astfel secvenţa de
lungimi de căutat. Apoi se adaugă fiecare prefix P tabelei hash
corespunzător lungimii P, length(P). Pentru fiecare prefix, se adaugă de
asemenea un marker fiecărui tabel corespunzător lungimilor L <
lungimea (P) pe care căutarea binară le va parcurge (dacă nu există una
deja). Pentru fiecare astfel de marker M se utilizează o testare
suplimentară 1-bit pentru determinarea prefixului cu cea mai bună
potrivire a lui M.
In timp ce acest algoritm de căutare utilizează cinci căutări în tabelele
hash, în cel mai defavorabil caz pentru IPv4, în cele mai probabile cazuri
majoritatea căutărilor ar trebui să aibă două accesări ale memoriei.
Aceasta se datorează observării cazului aşteptat O1 care arată că
majoritatea prefixelor sunt de lungine 16 sau 24 de biţi. De aceea căutarea
binară la 16 iar apoi la 24 de biţi va fi suficientă pentru majoritatea
prefixelor.
Utilizarea hashing-ului face căutarea binară asupra lungimii prefixelor să
fie într-o oarecare măsură dificil de implementat hardware. Oricum,
scalabilitatea tehnicii la lungimi mari de prefixe, cum sunt adresele IPv6,
a făcut-o suficient de atractivă pentru anumiţi producători.
173
In fuzionare cadrelor se presupune că toate cele M cuvinte de
M
memorie sunt divizate în cadre de dimensiunea Max. Fuzionarea
Max
cadrelor caută să păstreze utilizarea memoriei la cel puţin 50%. In acest
scop toate cadrele nevide ar trebui să fie cel putin 50% pline.
Fuzionarea cadrelor păstrează urmatoarea invarianţă : toate cadrele
neumplute cu excepţia unuia singur sunt cel putin 50% pline. Dacă
M
lucrurile stau în felul acesta şi este mult mai mare decât 1, atunci
Max
utilizarea garantată va fi de aproape 50%.
Cererile de alocare şi dealocare sunt realizate cu ajutorul etichetelor
ataşate fiecărui cuvânt, care ajută la identificarea blocurilor de memorie
libere şi ocupate. Singura restricţie suplimentară este că toate spaţiile
libere să fie continute în interiorul cadrelor; spaţiilor libere nu li se
permite să se extindă înafara cadrelor.
Un cadru este imperfect/defect dacă nu este gol şi are utilizarea mai
mică de 50 %. Pentru a se menţine invarianţa, fuzionarea cadrelor
conţine un indicator suplimentar care să urmareasca cadrele curente
imperfecte, daca există. Acum, o alocare poate face ca un cadru anterior
gol să devină un cadru imperfect dacă alocarea este mai mică decât
Max
.
2
Similar, o dealocare poate face ca un cadru plin mai mult de 50% sa
devină plin mai puţin de 50%. Se consideră un cadru care conţine două
blocuri alocate de dimensiune 1 şi respectiv Max – 1 şi deci are o
1
utilizare de 100%. Utilizarea s-ar putea reduce la dacă blocul de
Max
dimensiune Max – 1 este dealocat. Acest lucru ar putea face ca cele
două cadre să devină imperfecte, fapt ce ar încălca regula de invarianţă.
In continuare e dat un artificiu simplu pentru a păstra invarianţa. Se
presupune că există deja un cadru imperfect F şi că apare un nou cadru
imperfect F’. Invarianţa este păstrată prin fuzionarea conţinutului
cadrelor F şi F’ într-un nou cadru F. Acest lucru este posibil deoarece
ambele cadre F şi F’ au fost ocupate într-o proporţie mai mică de 50%.
De reţinut este faptul că singura compactare utilizată este cea la nivel
local şi este limitată la două cadre imperfecte F şi F’. Asemenea
compactare locală duce la obţinerea unor timpi mici de actualizare.
Gradul minim de utilizare în cazul fuzionării cadrelor poate fi
îmbunătăţit prin creşterea dimensiunii cadrelor la kMax şi prin
schimbarea definiţiei cadrelor imperfecte, astfel încât utilizarea acestor
k
cadre să devină mai mică decât . Schema descrisă anterior este un
k +1
caz special în care k=1. Crescând valoarea lui k se imbunătăţeşte
utilizarea, cu costul creşterii compactării.
175
clasificare (de ex. antetele pachetelor ca şi chei şi regulile de potrivire ca
rezultate).
Oricare adăugare sau ştergere a unei chei poate duce la cererea unei
dealocări a unui bloc şi de alocare a unui bloc de dimensiune diferită.
Fiecare cerere de alocare poate fi în domeniul 1 la Max cuvinte de
memorie. Sunt în total M cuvinte de memorie care pot fi
alocate.Memoria actuală poate fi incorporată în chip, în exteriorul chip-
lui sau ambele cazuri.Chiar dacă se utilizează opţiunea de memorare
off-chip, primele niveluri ale oricărui arbore de căutare vor fi memorate
în interiorul chip-lui. Memoria on-chip este mai atractivă din punct de
vedere al costului şi al vitezei. Din păcate, memoria on-chip este
limitată de procesele concurente la aproximativ 32 Mbiţi. Acest lucru
face dificilă suportarea unei baze de date de 1 milion de prefixe.
Intern, chip-ul va utiliza din plin tehnica pipeline. Structura de date
de căutare este partiţionată în câteva bucăţi, fiecare din aceste bucăţi
fiind prelucrată concurent de către niveluri diferite ale logicii. Deci
memoria SRAM va fi probabilîimpărţită în câteva memorii SRAM mai
mici care pot fi accesate independent de către fiecare etapă a pipeline.
Exista o problemă referitoare la partiţionarea statică a memoriei
SRAM între nivelurile pipeline, datorită faptului că necesarul de
memorie pentru fiecare nivel poate varia pe măsură ce prefixele sunt
inserate şi şterse. O soluţie posibilă este aceea de a împărţi memoria
SRAM într-un număr mare de bucăţi care pot fi alocate dinamic
nivelurilor, prin intermediul unui switch crossbar de partiţionare.
Proiectarea unui asemenea switch crossbar care să lucreze la viteze mari
este dificilă.
Toate schemele descrise pot utiliza metoda pipeline, deoarece toate
se bazează pe structuri de date de tip arbore. Toate nodurile de la acelaşi
nivel a arborelui pot fi alocate aceluiaşi nivel pipeline.
11.13 Concluzii
Situaţia actuală din domeniul căutarii/lookup şi principiile de bază utilizate:
Starea actuală a lookups. Schemele de căutare au apărut din cauza
ruterelor de tranzit (core) la care cresc rapid atât dimensiunile tabelei
(până la 1 milion de prefixe) cât şi viteza (până la 40Gbps). MPLS
(Multi Protocol Label Switching) s-a considerat ca fiind o modalitate de
finisare a tehnicilor de căutare, iar în momentul de faţă este utilizat
pentru evitarea clasificării pachetelor din ingineria traficului. CMS-le
sunt înlăturate chiar şi din nucleele ruterelor, dar costurile ridicate,
puterea consumată a CAM-lor de dimensiuni mari rămâne o problemă.
Asa ca mulţi producători de rutere încă utilizează şi proiectează
algoritmi de căutare.
Desi e ciudat, după ce o bogăţie de algoritmi au fost exploraţi în acest
capitol, arborii simpli cu prefix unibit împreună cu memoria SRAM şi
tehnica pipeline lucrează bine chiar şi la viteze de 40 Mbps. Lucrul se
datorează faptului că arborii simpli cu prefix unibit cu comprimarea căii
sunt relativ compacti; timpii mari de căutare pot fi deplasaţi prin
pipeline împreună cu o zonă de căutare iniţială. Folosirea pipeline este
dificilă deoarece necesită partiţionarea memoriei între niveluri.
176
La viteze de până la 10 Gbps, arborii simpli simpli cu prefix multibit
ce utilizează extinderea controlată a prefixelor, lucrează bine cu
memoriile de tip DRAM. Memoriile DRAM sunt mai încete, dar sunt
ieftine şi uşor de găsit. Tehnicile RAMBUS pot permite utilizarea
pipeline în căutări/lookup chiar şi cu procesoare de reţea. Simplitatea
acestor scheme s-a dovedit atractivă pentru mulţi producători.
Unii producători utilizează căutarea binară a cărei viteze şi utilizare a
memoriei sunt rezonabile, în mod special în cazul arborilor-B cu
memorie extinsă pentru a se reduce înălţimea arborilor. Schemele de
căutare binară a gamelor nu sunt patentate.
La viteze mai mari, numărul de niveluri pipeline poate fi redus de la 20
la 5 utilizând arborii simpli cu prefix multibit. Arborii simpli cu prefix
multibit trebuie comprimate pentru a putea fi memorate într-o memorie
SRAM on-chip sau off-chip. Compresia la Lulea este remarcabilă, dar
se pare că algoritmul poate fi utilizat astăzi numai în soluţiile
personalizate per client oferite de o companie numită Effnet. Schema
Lulea are de asemenea o actualizare înceată. Schemele bitmap de tip
arbore au actualizări rapide şi pot fi tolerate de o gamă largă de setări
hardware.De asemenea pot exista patente ce pot restricţiona folosirea
lor. E utilizat în prezent în ruterul Cisco CRS-1.
In concluzie, căutarea binară asupra lungimii prefixelor este atractivă
datorita proprietăţilor de scalabilitate la lungimi mari ale adreselor. Din
păcate, utilizarea tehnicii de hashing face dificilă obţinerea unor timpi
buni de căutare. In mod similar, introducerea adresării IPv6 şi multicast
ce cresc importanţa căutării adreselor lungi, au făcut ca această schemă
să fie puţin atractivă. Schema este utilizată de anumiti producători in
implementări software.
Soluţiile algoritmice împreună cu pipeline pot ţine pasul cu vitezele
legăturilor atât timp cât memoriile SRAM pot respecta timpii de sosire a
pachetelor. Toate schemele studiate pot fi pipeline pentru a asigura o
căutare/lookup per timp de acces la memorie. Alegerea între CAM şi
schemele algoritmice va fi greu de cuantificat şi probabil alegerea se va
face ad hoc în funcţie de fiecare produs.
Dacă schemele cu arborii cu prefix comprimate pot utiliza mai puţin
de 32 de biţi per prefix atunci arborii cu prefix comprimaţi par a utiliza
mai puţine tranzistoare şi o putere mai mică decât CAM. Acestea se
datorează faptului că în CAM, logica de căutare/lookup este distribuită
în fiecare celulă N de memorie, în timp ce într-o solutie algoritmica
logica de căutare, deşi mai complicată, este distribuită de-a lungul unui
număr mai mic şi constant de niveluri. O analiză VLSI atentă a celor
două implementări ar fi foarte utilă.
Deşi capitolul e dedicat tehnicilor de căutare, in concordanta cu
tendinţele curente ale pieţei, să nu se uite că la baza acestora stau
anumite principii. Este plauzibil ca toate ruterele din viitor să utilizeze
comutarea şi procesarea optică chiar şi în cazul căutarii. In acest caz,
algoritmii specifici descrişi ar putea fi depaşiţi, dar principiile de
proiectare vor rămâne valabile.
Schemele descrise în acest capitol necesită într-o anumită măsură
gândirea algoritmică precum şi alte principii ce au fost prezentate.
Schemele utilizează precalcularea, care scurteaza timpii de
177
inserare/ştergere. Schemele se folosesc de asemenea de anumite
caracteristici hardware cum ar fi memoria extinsă, utilizarea dupa caz a
memoriilor rapide sau lente şi optimizarea gradului de libertate într-o
proiectare data (vezi fig. 11.1).
178
COMUTAŢIA
RUTER
B2
Comutaţie
Linie intrare i B3
Linie ieşire
Planificare
B1
Căutare adrese
FIGURA 13.1. Modelul ruterului
179
P13 Control distribuit al cozilor Gigaswitch
P5a prin bilete
Planifică în paralel ieşiri şi
grupuri de vânătoare
P11 Optimizat pentru o Knockout
P15 concurenţă de maxim k<N
la ieşiri
P3 Utilizarea unui arbore de
concentratoare aleatorizat
pentru corectitudine
Relaxează specificatiile
bufferului de ieşire
P13 Utilizeaza cozi de intrare AN-2
P14 per-ieşire
P15 Comunicaţie N2 , fezabilă
pentru N mic
Utilizeaza asociere iterativă
aleatorizata
P14 PPE-uri pentru corectitudine iSLIP
round-robin,
P3 fezabilă pentru N mic
Relaxează specificatiile
dependenţei
de acceptare-alocare
P15 Utilizează o reţea Clos cu Juniper
trei nivele T 640
P3b pentru reducerea costurilor
Aleatorizează distributia
sarcinii
pentru a reduce k de la 2n
la n
P15 Utilizează o reţea Benes cu Structura
log N -nivele Growth
P3a pentru reducerea costurilor
P15 Utilizează o schemă de
rutare aleatoare rapidă
Utilizează multicast cu
copiere dublă şi arbore binar
P13 Realizează grila utilizând Avici TSR
fire scurte
180
la 40 Gbps. Memoriile cache nu reduc căutările, datorită rarităţii
secventelor de pachete de mari dimensiune in aceeaşi direcţie. De
asemenea, este improbabil ca două pachete consecutive la un port de
intrare al comutatorului să fie destinate aceluiaşi port de ieşire. Aceasta
îngreunează echilibrarea sarcinii de comutaţie pentru pachetele multiple.
Deci, pentru a opera la viteza liniei, sistemul de comutaţie trebuie să
decidă intrările şi ieşirile ce trebuie asociate, în timpul minim de sosire al
unui pachet. Astfel, partea de control a unui comutator de Internet (care
stabileşte conexiunile), e mult mai greu de realizat decât în cazul unui
comutator telefonic. O altă diferenţă importantă între comutatoarele
telefonice şi cele de pachete este necesitatea conexiunilor multicast pentru
comutatoarele de pachete. Multicastul complică suplimentar problema
planificării, deoarece unele intrări vor să transmită spre ieşiri multiple.
Pentru a simplifica problema, majoritatea ruterelor segmentează intern,
pachetele de dimensiune variabilă în celule de dimensiune fixă, înainte de
a fi transmise spre structura de comutaţie. Matematic, comutaţia ruterului
este redusă la rezolvarea unei probleme de asociere bipartita: ruterul
trebuie să asocieze cât mai multe linii de intrare (la cât mai multe linii de
ieşire), în limita posibilităţilor, într-un timp fix de sosire a celulelor.
Deoarece algoritmii optimali pentru asociere bipartită rulează într-un timp
de ordinul milisecundelor, rezolvarea acestei probleme la fiecare 8 nsec
necesită gândirea unor sisteme. Soluţiile descrise în acest capitol
realizeaza un compromis precizie/timp (P3b), utilizeaza paralelismul
hardware (P5) şi aleatorizarea (P3a), şi exploateaza faptul că
comutatoarele tipice au 32-64 porturi, pentru a face operaţii rapide cu cozi
prioritare utilizând bitmap-uri(P14).
Pachet Pachet
Card de linie 1 CPU Card de linie 1 CPU 1
MAGISTRALĂ
MAGISTRALĂ
CPU M
Card de linie N Card de linie N
a) Magistrală, CPU comun b) Magistrală, CPU-uri comune
Pachet Pachet
CPU 1 FE 1
MAGISTRALĂ
CPU N FE N
Card de linie 2 Card de linie 2
c) Magistrală, CPU-uri pe fiecare d) Crossbar, motoare de înaintare pe fiecare
card de linie card de linie
182
Mai rău, în ruterele şi comutatoarele mai vechi, decizia de înaintare a
pachetelor a fost dată unui CPU cu scop general, partajat. CPU-urile cu
scop general au un software de înaintare mai simplu şi uşor de modificat.
Dar ele erau lente, datorită nivelurilor suplimentare de interpretare a
instrucţiunilor cu scop general. Le lipsea capacitatea de lucru/control in
conditii de timp real la procesarea pachetelor, din cauza
nedeterminismului cauzat de mecanisme ca memoriile cache. Fiecare
pachet traversează magistrala de două ori, o dată pentru a ajunge la CPU şi
o dată pentru a ajunge de la CPU la destinaţie, deoarece CPU se află pe un
card separat, accesibil numai prin intermediul magistralei.
Deoarece CPU a fost o strangulare, pasul urmator a fost adăugarea unui
grup de CPU-uri comune pentru înaintare, dintre care fiecare poate
expedia un pachet. De exemplu un CPU poate înainta pachetele de pe
cardurile de linie 1 până la 3, cel de-al doilea de pe cardurile de linie 4
până la 6 şi aşa mai departe. Aceasta creşte eficienta totală, sau reduce
cerinţele pentru fiecare CPU individual, conducând potenţial spre o
variantă cu un cost mai scăzut. In orice caz, fără o atenţie corespunzătoare
se poate ajunge la o ordonare greşită a pachetelor, ceea ce nu este de dorit.
Cu toate acestea, magistrala rămâne o strangulare. O singură magistrală
partajată are limitări de viteză, datorită numărului de surse şi destinaţii
distincte care trebuie tratate de o singură magistrală comună. Aceste surse
şi destinaţii adaugă sarcină electrică suplimentară, înrăutăţind timpii de
crestere ai semnalelor, şi în final viteza de transmitere a biţilor pe
magistrală. Alte efecte electrice includ conectorii multipli (de la fiecare
card de linie) şi reflexiile pe linie.
Metoda clasică de-a evita această strangulare este comutatorul crossbar
(fig. 13.3.d) care conţine în esenţă 2N magistrale paralele, o magistrală
pentru fiecare card de linie sursă, şi o magistrală pentru fiecare card de
linie destinaţie. Matricea de magistrale sursă (orizontale) şi destinaţie
(verticale) formează crossbar-ul.
Teoretic viteza pe o magistrală creşte de N ori, deoarece în cel mai bun
caz toate cele N magistrale vor fi utilizate în paralel, simultan pentru a
transfera date, în locul unei singure magistrale. Bineînţeles pentru a obţine
această creştere de viteză este necesară găsirea a N perechi distincte sursă-
destinaţie in fiecare diviziune de timp. Apropierea de această margine
reprezintă probema majoră de planificare studiată acum.
O altă modificare a comutatoarelor crossbar, produse in perioada 1995-
2002, este utilizarea de circuite integrate speciale dedicate (ASIC) şi a
motoarelor de înaintare, în locul CPU-urilor cu scop general, deşi
asocierea nu e obligatorie. Dezavantajele acestor motoare de înaintare ar fi
costurile de proiectare ale ASIC-urilor, şi lacunele de programabilitate
(ceea ce face ca eventuale modificări să fie dificile sau chiar imposibile).
Aceste probleme au condus din nou la procesoare de reţea rapide, dar
programabile .
Intrare 1
Intrare 2
Intrare 3
Intrare R
Ieşire S
FIGURA 13.5. Conectează intrarea de pe cardul de linie R la cardul de linie S, prin aducerea
tranzistorului în stare de conducţie. La modelele moderne de crossbar această variantă simplă
este înlocuită cu arbori de multiplexoare pentru a reduce capacitatea.
184
maximizeze numărul de perechi de carduri de linie care comunică în
paralel. Deşi paralelismul ideal asigura că toate cele N magistrale de ieşire
sunt ocupate în acelaşi timp, în practică paralelismul este limitat de doi
factori. In primul rând s-ar putea să nu existe date pentru unele carduri de
linii de ieşire. Apoi e posibil ca două sau mai multe caduri de linii de
intrare să dorească să transmită date aceluiaşi card de linie de ieşire. Dar o
singură intrare poate câştiga la un anumit moment dat, si astfel se
limitează traficul pentru intrările care au pierdut si nu pot transmite date.
Astfel, în ciuda paralelismului extins, concurenţa majoră are loc la portul
de ieşire. Cum poate fi soluţionată concurenţa pentru porturile de ieşire în
acelaşi timp cu maximizarea paralelismului? O variantă simplă şi elegantă
de planificare a fost pentru prima dată inventată şi utilizată în
Gigacomutatorul DEC. Un exemplu al aşa numitului algoritm „ia-ţi un
bilet” utilizat de DEC este dat în figura 13.6.
Ideea este ca fiecare card de linie de ieşire S să menţină o coadă
distribuită pentru toate cardurile de linie de intrare R care aşteaptă să
transmită înspre S. Coada pentru S este memorată in cardul liniei de intrare
(în loc de S) utilizând un mecanism simplu cu numere de bilet. Dacă
cardul de linie R doreşte să transmită un pachet spre cardul de linie S, mai
întâi trimite o cerere printr-o magistrală de control separată înspre S; S
trimite apoi un număr de coadă înspre R pe magistrala de control. Numărul
de coadă este numărul poziţiei lui R în coada de ieşire pentru S.
Apoi R monitorizează magistrala de control; când S termină acceptarea
unui nou pachet, S trimite pe magistrala de control numărul de coadă
curent pe care o serveşte. Dacă R observă că numărul său este „servit”, R
îşi plasează pachetul pe magistrala datelor de intrare pentru R. In acelaşi
timp S se asigură că punctul de conexiune între R şi S a fost activat.
In fig. 13.6 se vede algoritmul în acţiune ; cadrul de la cardul de linie A
conţine trei pachete destinate ieşirilor 1, 2 şi 3, B are 3 pachete destinate
aceloraşi ieşiri, iar C are pachete destinate ieşirilor 1, 3 şi 4. In acest
exemplu pachetele au aceeaşi dimensiune (acest lucru însă nu este necesar
pentru ca algoritmul „ia-ţi un bilet” să funcţioneze).
Fiecare port lucrează numai pentru pachetul din fruntea cozii sale. Deci
algoritmul începe cu fiecare intrare transmiţând o cerere, printr-o
magistrală de control înspre portul de ieşire căruia îi este destinat pachetul
din fruntea cozii de intrare. Astfel, în exemplu, fiecare intrare trimite o
cerere înspre portul 1 pentru permisiunea de-a transmite un pachet.
Numărul de bilet este un întreg mic care depinde de, şi este eliberat în
ordinea sosirii. Presupunem că cererea lui A ajunge prima pe magistrala de
control serială urmată de B, iar apoi de C. In figura din stânga sus aparent
cererile sunt transmise în mod concurenţial, nu secvential. Deoarece portul
de ieşire 1 poate servi un singur pachet la un moment dat, el pune cererile
în ordine serială şi returnează T1 lui A, T2 lui B, şi T3 lui C.
Astfel, în figura din mijloc în rândul de sus, portul de ieşire 1 difuzează
numărul de bilet curent care este deservit (T1) pe o altă magistrală de
control. Când A observă că are un număr corespunzător pentru intrarea 1,
în figura din partea dreaptă sus, A conectează magistrala sa de intrare la
magistrala de ieşire a lui 1 şi îşi trimite pachetele pe magistrala sa de
intrare. Deci la sfârşitul primului rând de imagini, A a trimis pachetul din
fruntea cozii sale de intrare la portul de ieşire 1.
185
Al doilea rând din figura 13.6 începe cu transmisia unei cereri de către
A pentru pachetul care este acum în fruntea cozii sale înspre portul de
ieşire 2. Lui A i se returnează un număr de bilet, T1, pentru portul 2. În
imaginea din mijlocul rândului 2, portul 1 anunţă că este pregătit pentru
T2, şi portul 2 anunţă că este pregătit pentru biletul T1. Aceasta rezultă din
figura din partea dreaptă a celui de-al doilea rând, unde A este conectat la
portul 2 şi B este conectat la portul 1 şi pachetele corespunzătoare sunt
transferate.
Etapa 1
3 2 1 A 1 3 2 1 A T1
1 3 2 1 A 1
B 2 2 2
3 2 1 3 3 2 1 B T2 3 3 2 1 B 3
4 3 1 C 4 4 3 1 C T3 4 4 3 1 C 4
Cerere Acordare bilet Conectare
Etapa 2
A A A 1
3 2 1 3 2 T2 1 3 2
2 2 2
3 2 1 B 3 2 1 B
T1
3 2 1 B 3 T1 3 3
4 3 1 C 4 4 3 1 C 4 4 3 1 C 4
Cerere Acordare bilet Conectare
Etapa 3
A 1 A 1 A 1
3 3 T1 T3 3
B 2 B T22 B 2
3 2 3 3 2 T2 3 3 2 3
4 3 1 C 4 4 3 1 C T14 4 3 1 C 4
Cerere Acordare bilet Conectare
FIGURA 13.6. În mecanismul de planificare „ia-ţi un bilet”, toate porturile de intrare au o singură
coadă de intrare care este etichetată cu numărul portului de ieşire căruia fiecare pachet îi este destinat.
Astfel în primul cadru, intrările A, B şi C trimit cereri înspre portul de ieşire 1. Portul de ieşire 1 (sus,
mijloc) îi acordă primul număr lui A, cel de-al doilea lui B, etc., şi aceste numere sunt utilizate pentru
a stabili o ordine serială pentru accesul la porturile de ieşire.
Al treilea rând de imagini din figura 13.6 începe similar cu transmisia de
către A şi B a unei cereri pentru porturile 3 şi 2, respectiv. Numai C mai
este încă blocat în aşteptarea pentru numărul său de bilet T3, care este
obţinut cu două iteraţii înainte pentru a fi anunţat la portul de ieşire 1.
Astfel C nu mai trimite alte cereri până ce pachetul din fruntea cozii sale
de aşteptare este deservit. Lui A i se returnează T1 pentru portul 3 şi lui B i
se returnează T2 pentru portul 2. Apoi portul 1 difuzează T3, portul 2
difuzează T2, şi portul 3 difuzează T1. Aceasta duce la ultima imagine din
partea stângă a rândului 3, unde comutatorul crossbar conectează A cu 3,
D cu 2 şi C cu 1.
Varianta „ia-ţi un bilet” este avantajoasă în starea de control necesitând
doar două numărătoare de log 2 N biţi la fiecare port de ieşire pentru a
reţine numărul de bilet curent care este deservit şi cel mai mare număr de
bilet dispensat. Aceasta a permis să se ajungă la o dimensiune de 36 porţi
la Gigacomutatorul DEC chiar şi în anii ’90 când dimensiunea memoriei
pe chip a fost limitată. Varianta a utilizat un planificator distribuit, iar
arbitrarea fiecărui port de ieşire a fost realizată de un aşa numit chip GPI
pe fiecare card de linie; chip-urile GPI comunică printr-o magistrală de
control.
Chip-urile GPI trebuie să arbitreze magistrala de control (serială) cu
scopul de-a prezenta o cerere la un card de linie de ieşire şi de-a obţine un
număr de ordine în coadă. Deoarece magistrala de control este o magistrală
186
de difuziune, un port de intrare îşi dă seama când îi vine rândul observând
activitatea acelora care au fost înaintea lui, şi apoi poate instrui
comutatorul să realizeze o conexiune.
Pe lângă simplitatea de realizare a controlului, varianta „ia-ţi un bilet”
are avantajul de-a fi capabilă să opereze direct cu pachete de dimensiune
variabilă. Porturile de ieşire pot difuza asincron numărul următor de bilet
în momentul în care acestea finalizează recepţionarea pachetului curent;
porturi distincte de ieşire pot difuza numărul lor de bilet curent la
momente de timp arbitrare. Astfel spre deosebire de toate variantele care
vor fi descrise mai târziu nu există antet şi trafic de control pentru
împărţirea pachetelor în „celule” şi reasamblarea lor ulterioară. Pe de altă
parte în cazul „ia-ţi un bilet ” paralelismul este limitat de „blocarea în
fruntea liniei”, fenomen analizat în următoarea secţiune.
Un alt avantaj al variantei „ia-ţi un bilet” se numeşte grupuri de
vânătoare. Orice set de carduri de linie (nu numai cardurile de linie
învecinate fizic) pot fi agregate pentru a forma o legătură cu banda mai
mare, numită grup de vânătoare. Astfel 3 legături de 100 Mbps pot fi
grupate într-o singură legătură de 300 Mbps.
Implementarea ideii necesită doar mici modificări ale algoritmului de
planificare original, deoarece fiecare dintre chip-urile GPI din grup poate
observa mesajele trimise unul altuia pe magistrala de control şi astfel să
păstreze copii locale ale numărului de bilet (comun). Următorul pachet
destinat grupului este servit de primul port de ieşire liber din grupul de
vânătoare. In timp ce grupurile de vânătoare de bază pot reordona
pachetele transmise spre legături diferite, o mică modificare permite ca
pachetele de la o intrare să fie transmise spre un singur port de ieşire într-
un grup de vânătoare, printr-o dispersare deterministă simplă. Modificarea
evită reordonarea cu preţul reducerii paralelismului.
Timp (conform cu
durata pachetelor)
3 2 1
A 1 A B C
3 2 1 2 A B
B
3 A B C
4 3 1
C 4 C
FIGURA 13.7 Blocare „în fruntea liniei” cauzată de variante de algoritmi „ia-ţi un bilet”.
Pentru fiecare port de ieşire, o scară de timp orizontală este etichetată cu portul de intrare
care trimite un pachet către acel port de ieşire în perioda de timp corespunzătoare sau cu un
pătrat gol dacă nu se transmit pachete. Se observă numărul mare de pătrate goale, ceea ce
denotă o risipă de oportunităţi, ceea ce limiteaza paralelismul .
187
13.5 BLOCAREA ÎN FRUNTEA LINIEI (HOL)
191
Pentru a motiva algoritmul de planificare utilizat in PIM, se observă în
fig.13.8 stânga sus, că portul 1 de ieşire primeşte 3 cereri, de la A, B şi C,
dar poate servi numai una singură în următorul slot. O soluţie simplă este
selecţia aleatoare (P3a). Astfel în faza de alocare (imaginea din mijlocul
primului rând din fig. 13.8), portul de ieşire 1 îl selectează aleatoriu pe B.
Similar presupunem că portul 2 îl selectează pe A aleatoriu (dintre A şi B),
şi portul 3 îl selectează pe A aleatoriu (dintre A, B şi C). In final, portul 4 îl
selectează pe singurul său solicitant C.
Etapa 1
1 A 1 1 A 1 1 A 1
2 2 2
3 2 3 2 3 2
1 B 1 B 1 B
2 3 2 3 2 3
3 3 3
1 C 4 1 C 4 1 C 4
3 3 3
4 Cerere 4 Acord 4 a=1 Acceptare
Etapa 2
1 A 1 1 A 1 1 A 1
- - -
3 2 3 2 3 2
- B - B - B
2 3 2 3 2 3
3 3 3
1 C 4 1 C 4 1 C 4
3 3 3
- a=1 Cerere - Acord - Acceptare
Etapa 3
1 A 1 1 A 1 1 A 1
- - -
- 2 - 2 - 2
- B - B - B
- 3 - 3 - 3
3 1 3 3
- C 4 - C 4 - C 4
3 3 3
4 a=1 - -
Cerere Acord Acceptare
FIGURA 13.8 Varianta iterativă paralelă de asociere (PIM ), presupune ca toate intrările să trimită în
paralel cereri către toate ieşirile la care doresc să se conecteze. PIM utilizează aleatorizarea pentru a
face asocierea, astfel că ieşirile care primesc cereri multiple aleg aleatoriu o anumită intrare, iar
intrările care obţin acorduri multiple aleg aleatoriu ieşirea înspre care să transmită. Acest proces în trei
etape poate fi repetat pentru a îmbunătăţi dimensiunea asocierii.
Nu e suficientă rezolvarea competiţiei de la porturile de ieşire, deoarece
are loc o competiţie şi la porturile de intrare. Două porturi de ieşire pot
aloca aleatoriu resurse aceluiaşi port de intrare, care trebuie să selecteze un
port înspre care să transmită o celulă. De exemplu în imaginea din
mijlocul primului rând din fig. 13.8, A primeşte alocări din partea ieşirilor
2 şi 3. Astfel este necesară o a treia fază Acceptare, în care fiecare port de
intrare selectează aleatoriu un port de ieşire (dacă aleatorizarea a fost
utilizată în faza de alocare, de ce să o nu utilizăm din nou?).
Astfel, în imaginea din dreapta sus a figurii 13.8, A selectează în mod
aleatoriu portul 2, B şi C nu au de ales şi selectează porturile 1 şi respectiv
4. S-a realizat conexiunea crossbar, şi pachetele de la A la portul 2, B la
portul 1 şi C la portul 4 sunt transferate. Deşi în acest caz asocierea a fost
maximală (adică nu mai poate fi îmbunătăţită), în unele cazuri selecţiile
192
aleatoare pot da o asociere ce mai poate fi îmbunătăţită ulterior. De
exemplu în cazul improbabil ca porturile 1, 2 şi 3 să selecteze toate A, vor
fi asociate doar două.
In aceste cazuri, neprezentate în figură, algoritmul poate fi
îmbunătăţit prin mascarea tuturor intrărilor şi ieşirilor asociate, după care
se fac mai multe iteraţii (pentru acelaşi interval de timp care urmează).
Dacă asocierea în cazul iteraţiei curente nu este maximală, o iteraţie
următoare va îmbunătăţi asocierea cu cel puţin 1. Iteraţiile următoare nu
pot înrăutăţi asocierea, deoarece asocierile existente se păstrează de la o
iteraţie la alta. Deşi cel mai defavorabil caz pentru a atinge o asociere
maximală pentru N intrări este de N iteraţii, se arată că numărul cel mai
probabil de asocieri este mai apropiat de logN. Implementarea DECAN 2 a
utilizat 3 iteraţii pentru un comutator cu 30 de porturi.
Exemplul din fig.13.8 utilizează o singură iteraţie pentru fiecare
asociere. Rândul din mijloc arată a doua asociere pentru al doilea timp de
celulă, în care, de exemplu A şi C ambele transmit o cerere pentru portul 1
(dar nu şi B deoarece celula dinspre B înspre 1 a fost transmisă în ultimul
timp de celulă). Portul 1 îl selectează aleatoriu pe C şi asocierea finală este
A-3, B-2 şi C-1. Al treilea rând arată a treia asociere, de data aceasta de
dimensiune 2. Dupa a treia asociere numai celula destinată portului 3 în
coada de intrare B nu este transmisă. Astfel în patru timpi de celulă (din
care al patrulea nu e utilizat optimal şi nu poate fi utilizat pentru a se
transmite mai mult trafic) s-a transmis întreg traficul. Varianta aceasta e
mai eficientă decât cea cu bilete din figura 13.6.
193
Mai precis fiecare port de ieşire/intrare menţine un pointer g, setat iniţial
spre primul port de intrare/ieşire. Daca un port de ieşire trebuie să
selecteze multiplele cereri de intrare, el va selecta cel mai mic număr de
intrare egal sau mai mare ca g. Similar dacă un port de intrare are de ales
între multiple cereri provenite de la porturile de ieşire, el alege cel mai mic
număr de port de ieşire mai mare sau egal cu a, unde a este pointerul
portului de intrare. Cand un port de ieşire este asociat unui port de intrare
X, atunci pointerul portului de ieşire este incrementat la primul număr de
port mai mare decât X, în ordine circulară (de ex. g devine X+1 în afară de
cazul în care X a fost ultimul port, caz în care g se va afla în jurul primului
număr de port).
„Prioritatea rotitoare” permite fiecărei resurse (port de ieşire, port de
intrare) să partajeze destul de echitabil toţi competitorii, cu preţul a 2N
pointeri, de dimensiune log2N, suplimentari fata de N2 stări de planificare
necesare fiecărei iteraţii.
In figurile 13.9 si 13.10 se prezintă acelaşi scenariu ca în figura 13.8 (şi
figura 13.6), dar cu doua iteraţii iSLIP. Dacă fiecare rând este o iteraţie a
unei asocieri, fiecare asociere este prezentată utilizând două rânduri. Deci,
cele trei rânduri ale figurii 13.9 prezintă primele 1,5 asocieri ale
scenariului. Figura 13.10 prezintă celelalte 1,5 asocieri rămase.
Etapa 1, iteratia 1
1 A 1 g=A 1 A 1 1 A 1 g=B
2 2 2
3 a=1 3 3 a=2
2 g=A 2 2 g=A
1 B 1 B 1 B
2
a=1 3 g=A 2 3 2
a=1 3 g=A
3 3 3
1 C 4 g=A 1 C 4 1 C 4 g=A
3 3 3
4 a=1 Cerere 4 4 a=1
Alocare Acceptare
Etapa 1, iteratia 2
1 A 1 g=B 1 A 1 1 A 1
2 2 2
3 a=2 3 3
2 g=A 2 2
1 B 1 B 1 B
2 3 g=A 2 3 2 3
3 a=1 3 3
1 C 4 g=A 1 C 4 1 C 4
3 3 3
4 a=1 4 4 a=1
Cerere Alocare Acceptare
Etapa 2, iteratia 1
- A 1 g=B - A 1 - A 1 g=C
2 2 2
3 a=2 3 3 a=3
2 g=A 2 2 g=B
1 B 1 B 1 B
-
a=1 3 g=A - 3 -
a=2 3 g=A
3 3 3
1 C 4 g=A 1 C 4 1 C 4 g=A
- a=1 - - a=1
Cerere Alocare Acceptare
194
Imaginea din stânga-sus a figurii 13.9 este identică cu figura 13.8,
fiecare port de intrare transmiţând cereri spre fiecare port de ieşire pentru
care are celule destinate. O diferenţă este că fiecărui port de ieşire i se
asociază un pointer de alocare g, iniţializat pentru toate ieşirile la valoarea
A. Similar, fiecărui port de intrare i se asociaza un asa-numit pointer de
acceptare a, iniţializat la valoarea 1 pentru toate intrările.
Determinismul în iSLIP cauzează o divergenţă, imediat în faza de
Alocare. Compară imaginea din mijloc sus a figurii 13.9 cu imaginea din
mijloc sus a figurii 13.8. De exemplu dacă ieşirea 1 recepţionează cereri
de la toate cele trei porturi de intrare, portul selectat va fi A, deoarece A
este cel mai mic număr de intrare mai mare sau egal cu g1 = A. In figura
13.8, portul 1 selectează aleatoriu portul de intrare B. In această etapă
determinismul la iSLIP se dovedeşte a fi un dezavantaj real deoarece A a
trimis cereri şi înspre porturile 3 şi 4. Deoarece 3 şi 4 au de asemenea
pointerii de alocare g3 = g4 = A porturile 3 şi 4 îl vor selecta deasemnea
pe A ignorând pretenţiile lui B şi C. C fiind singurul care trimite o cerere
înspre portul 4 va primi alocarea din partea portului 4.
Daca A a primit trei alocări din partea porturilor 1, 2 şi 3, A îl acceptă pe
1, deoarece 1 este prima ieşire egală sau mai mare ca pointerul de
acceptare a lui A, aA, care a fost egal cu 1. Similar C îl alege pe 4. Acestea
fiind făcute A îl incrementează pe aA la 2 si C incrementeaza aC la 1
(incrementarea circulară a lui 4 este 1). Numai la aceasta etapă ieşirea1
incrementează pointerul său de alocare, g1, la B (cu 1 mai mare decât
ultima alocare ce a avut loc cu succes) iar portul 4 în mod similar face
incrementarea la A (cu 1 mai mare decat C în ordine circulară). Se observă
că celelalte porturi care au dat alocări portului A, adică 2 şi 3 nu îşi
incrementează pointerii de alocare deoarece A a refuzat alocările lor. Dacă
aceştia ar fi făcut incrementarea, ar fi fost posibilă construirea unui
scenariu în care porturile de ieşire menţin incrementarea pointerului lor de
alocare, dincolo de un anumit port de intrare I dupa alocări fără succes,
astfel înfometând continuu portul de intrare I. Asocierea are doar
dimensiunea 2; dar spre deosebire de figura 13.8 acest scenariu poate fi
îmbunătăţit printr-o a doua iteraţie prezentată în figura 13.9. La sfarşitul
primei iteraţii intrările şi ieşirile asociate nu sunt conectate prin linii
îngroşate (însemnând transfer de date), ca în dreapta sus la figura 13.8.
Acest transfer de date va aştepta sfârsitul ultimei iteraţii (iteraţia a doua).
A doua iteraţie (rândul din mijoc al figurii 13.9) începe cu intrările care
nu au fost asociate într-o iteraţie precedentă (aceasta înseamnă B) adresând
cereri numai porturilor de ieşire neasociate până acum. Astfel B trimite
cereri lui 2 şi 3 (şi nu lui 1 deşi B are de asemenea o celulă destinată lui 1).
Ambele porturi de ieşire 2 şi 3 trimit alocări portului B, iar B îl selectează
pe 2 (cel mai mic număr de port care este mai mare sau egal cu pointerul
său de acceptare). Pentru evitarea înfometării, iSLIP nu-şi incrementează
195
pointerii în celelalte iteraţii în afară de prima. Deci B nu-şi va incrementa
pointerul de acceptare la 3 (1 plus 2-ultimul acceptat).
După conectarea lui B la 2, pointerul de alocare a lui 2 rămâne A şi
pointerul de acceptare al lui B rămâne 1. Aceasta fiind iteraţia finală, toate
perechile asociate incluzând perechi cum ar fi A,1 asociate în iteraţii
anterioare, sunt conectate şi are loc transferul de date (liniile îngroşate).
Etapa 2, iteratia 2
- A 1 g=C - A 1 - A 1 g=C
2 2 2
3 a=3 3 3 a=3
2 g=B 2 2 g=B
1 B 1 B 1 B
-
a=2 3 g=A - 3 -
a=2 3 g=A
3 3 3
1 C 4 g=A 1 C 4 1 C 4 g=A
3 3 3
- a=1 Cerere - - a=1
Alocare Acceptare
Etapa 3, iteratia 1
- A 1 g=C - A 1 - A 1 g=A
- - -
3 a=3 3 3 a=4
2 g=B 2 2 g=B
- B - B - B
- 3 g=A - 3 - 3 g=B
3 a=2 3 3 a=2
1 C 4 g=A 1 C 4 1 C 4 g=A
- - -
- a=1 - - a=2
Cerere Alocare Acceptare
Etapa 3, iteratia 2
- A 1 g=A - A 1 - A 1 g=A
- - -
3 a=4 3 3 a=4
2 g=B 2 2 g=B
- B - B - B
-
a=2 3 g=B - 3 -
a=2 3 g=B
3 3 3
1 C 4 g=A 1 C 4 1 C 4 g=A
- - -
- a=2 - - a=2
Cerere Alocare Acceptare
196
timp prin evitarea blocării în fruntea liniei. Se observă că iSLIP la fel ca şi
PIM comută acelaşi trafic de intrare în 4 timpi de celulă, si nu 6.
Comparand figurile 13.9 şi 13.8, iSLIP pare să fie inferior lui PIM,
deoarece sunt necesare două iteraţii pe asociere la iSLIP pentru a obţine
acelaşi număr de perechi asociate pentru care la PIM este nevoie de-o
singură iteraţie pe asociere. Aceasta ilustrează mai degrabă penalizarea pe
care iSLIP trebuie s-o plătească la pornire şi nu o penalizare pe termen
lung. In practică, pe moment ce pointerii iSLIP se desincronizează, iSLIP
functioneaza foarte bine cu o singură iteraţie şi unele implementări
comerciale utilizează doar o singură iteraţie: iSLIP este extrem de popular.
FIGURA 13.11 Evitarea blocării HOL de către iSLIP creşte debitul util din scenariul din figura 13.7
PRIORITĂŢI
Priorităţile sunt utile pentru a transmite traficul critic sau de timp real
mai rapid prin comutator. Cisco GSR permite traficului voice over IP, să
fie planificat cu o prioritate mai mare decat restul traficului, deoarece are o
rată limitată şi deci nu poate înfometa alte categorii de trafic.
197
Implementarea Tiny Tera manevrează patru niveluri de prioritate.
Fiecare port de intrare are 128 de cozi virtuale (una pentru fiecare
combinaţie de 32 de ieşiri şi 4 niveluri de prioritate). Deci, la planificator,
fiecare intrare are 128 de biţi pentru controlul intrărilor.
Algoritmul iSLIP este modificat foarte simplu pentru a trata priorităţi.
Pentru început fiecare port de ieşire păstrează un pointer de alocare separat
gk pentru nivelul de prioritate k, şi fiecare port de intrare păstrează un
pointer separat de acceptare ak pentru fiecare nivel de prioritate k. In
esenţă se aplică algoritmul iSLIP, astfel încât fiecare entitate (port de
intrare, port de ieşire) să aplice algoritmul iSLIP la cel mai mare nivel de
prioritate existent la intrări.
Fiecare port de ieşire face alocarea doar pentru cererea cea mai prioritară
recepţionata. Un port de intrare I poate face o cerere la nivelul de prioritate
1 pentru ieşirea 5, şi o cerere la nivelul de prioritate 2 pentru ieşirea 6,
deoarece acestea sunt cererile de cea mai înalta prioritate pe care le-a avut
portul pentru ieşirile 5 şi 6. Daca ambele ieşiri 5 şi 6 fac alocări pentru I, I
nu va face selecţia bazându-se pe pointerii de acceptare deoarece cele
două celule au priorităţi diferite, ci o va selecta pe cea de prioritate mai
mare. La o acceptare, în prima iteraţie, pentru prioritatea k, între intrarea I
şi portul de ieşire O, pointerul de acceptare a priorităţii k la I şi pointerul
de alocare corespunzător priorităţii k la O, sunt incrementaţi.
MULTICAST
Datorita aplicaţiilor (videoconferinta) şi protocoalelor (IP multicast) in
care ruterele transmit pachetele înspre un număr de porturi de iesire mai
mare ca unu, multicast în comutatoare, ca entitate de prima clasă, a
devenit importantă. Algoritmul ia-ţi un bilet a tratat multicastul ca o
entitate de clasa a doua, prin transmiterea întregului trafic de multicast la o
entitate/entităţi centrală, care apoi va transmite traficul de multicast
pachet-cu-pachet ieşirilor corespunzătoare. Mecanismul ia-ţi un bilet
iroseşte resurse de comutatie (lăţime de bandă de control, porturi) şi
asigură performanţe mai scăzute (latenţa mai mare, trafic mai scăzut)
pentru multicast.
Pe de alta parte, figura 13.4 arată că multicastul este suportat cu uşurinţă
pe calea de date a unui comutator crossbar. De exemplu dacă intrarea 1
(fig.13.4) transmite un mesaj pe magistrala sa de intrare şi punctele de
conexiune sunt conectate astfel încât magistrala de intrare a lui 1 este
conectată la magistralele de ieşire verticale ale ieşirilor 2 si 3, atunci
ieşirile 2 şi 3 recepţionează o copie a pachetului /celulei la acelaşi moment
de timp. Dacă pachetele au lungimea variabilă, mecanismul distribuit de
control al variantei ia-ţi un bilet, trebuie să aleagă între a aştepta eliberarea
simultană a tuturor porturilor, şi transmiterea pachetelor unul după altul.
Extensia iSLIP pentru multicast, numită ESLIP, acorda multicastului
aproape acelaşi statut ca şi unicastului. Ignorând priorităţile pentru
moment, există o coadă suplimentară pentru multicast pentru fiecare
intrare. Pentru evitarea blocarii HOL, ar fi ideal să existe o coadă separată
pentru fiecare subset posibil de porturi de ieşire, ceeace ar duce la un
număr impracticabil de cozi (216 pentru 16 porturi). Astfel se utilizează o
singură coadă pentru multicast şi poate apărea blocarea HOL, deoarece nu
198
se poate începe procesarea unui pachet pană ce pachetele de multicast
anterioare lui nu sunt transmise.
Presupunem că intrarea I are pachete destinate ieşirilor O1, O2 si O3 în
fruntea cozii de multicast a lui I. Se spune că I are un fan-out de 3. Spre
deosebire de cazul unicastului, ESLIP păstrează un singur pointer de
alocare comun pentru multicast si nici un pointer de acceptare pentru
multicast. Utilizarea pointerilor comuni implică o implementare
centralizată, diferită de planificatorul ia-ţi un bilet. Pointerul comun
permite întregului comutator să favorizeze o intrare particulară, încât să-şi
poată completa întregul fan-out mai repede decât daca ar fi mai multe
porturi de intrare, care transmit porţiuni mici din fanout-ul lor de multicast
în aceleaşi momente de timp.
In exemplu, I va transmite o cerere de multicast înspre O1, O2 si O3.
Dar porturi de ieşire cum este O2 pot recepţiona cereri de unicast de la alte
porturi de intrare, de exemplu J. Cum va decide un port de ieşire între
pachete de unicast şi de multicast? ESLIP acorda traficului de multicast şi
de unicast prioritate mai mare în sloţi alternanţi de celulă. De exemplu în
sloţii impari O2 va selecta unicastul iar in sloţii pari multicastul.
Pentru a continua exemplul presupunem un slot impar şi presupunem că
O2 are cereri de unicast în timp ce O1 şi O3 nu au cereri de unicast.
Atunci O2 va transmite un mesaj de alocare de unicast în timp ce O1 şi O3
vor transmite alocări de multicast. O1 şi O3 aleg pentru alocare intrarea
corespunzătoare primului număr de port mai mare sau egal faţă de
pointerul comun de alocare G. Presupunem că s-a selectat I şi astfel O2 şi
O3 vor trimite alocări de multicast înspre I. Spre deosebire de unicast, I
poate accepta toate alocările de multicast.
Spre deosebire de planificarea unicast, pointerul de alocare la multicast e
incrementat doar după ce I şi-a completat fanoutul. Astfel în următorul slot
de celulă, când multicastul are prioritate, I va putea transmite la O2. Acum
fanout-ul e completat, pointerul de alocari multicast se incrementeaza la
I+1, si planificatorul transmite inapoi lui I un bit prin care-i spune ca s-a
terminat transmisia din capul cozii sale multicast, deci poate fi luat in
lucru urmatorul pachet multicast.Un multicast nu trebuie terminat intr-o
singura diviziune de celula(ceea ce ar presupune ca toate iesirile implicate
sa fie libere), dar prin folosirea fanout splitting pe mai multe diviziuni.
Desigur ca iSLIP poate induce blocarea HOLpentru multicast. Daca
pachetul P1din capul cozii multicast este destinat iesirilor O1si O2 si
ambele sunt ocupate, atunci urmatorul pachet P2, destinat lui O3 si O4
libere amandoua, trebuie sa astepte dupa P1. Ar fi mult prea dificila
implementarea fanout splitting-ului pemtru alte pechete decat cele din
capul cozii si asta deoarece nu ne putem permite cate un VOQ separat
pentru fiecare combinatie posibila de porturi destinatie.
Algoritmul final ESLIP care combina patru niveluri de prioritate si
multicastingul este implementat in ruterul CISCO GSR.
202
Mai există posibilitatea de folosire a unui algoritm aleator, prin care
fiecare comutator de pe nivelul de intrare alege aleator un comutator de pe
nivelul mijlociu, pentru fiecare celulă care trebuie transmisă. În acest caz,
d.p.d.v. probabilistic fiecare comutator de pe nivelul mijlociu va
recepţiona N/n celule, numărul de ieşiri ale comutatorului de pe nivelul
mijlociu. Astfel, dacă avem un flux de celule care merg spre ieşiri diferite
vom avea un debit de 100% pentru algoritmul aleator.
Dar algoritmul de aleatorizare e greu de realizat, existând şi
probabilitatea de coliziune, când mai multe comutatoare de intrare doresc
să folosească acelaşi comutator de ieşire. Acest fenomen va reduce debitul
şi va impune folosirea bufferelor.Scăderea debitului poate fi compensată
prin cresterea vitezei de operare internă a comutatoarelor.
Un algoritm de aleatorizare relativ uşor de implementat şi cu eficienţă
crescută este generatorul de numere aleatoare Tausworth compus din trei
registre de deplasare cu reacţie care apoi sunt insumate SAU-EXCLUSIV.
Algoritmul de reasamblare a celulelor în pachete este mai complex dacă
se foloseşte echilibrarea aleatoare a încărcării, decât dacă se foloseşte
metoda deterministă de echilibrare a încărcării. În ultimul caz, logica de
reasamblare ştie de unde tebuie să sosească următoarea celulă.
203
Figura 13.14: Construirea recursivă a unei reţele Delta
Dacă ieşirea este în jumătatea superioară (MSB al ieşirii este 0), atunci
intrarea este direcţionată către reţeaua Delta N/2 superioară, dacă însă
ieşirea este în jumătatea inferioară (MSB=1) atunci intrarea este
direcţionată către reţeaua Delta N/2 inferioară.
Pentru a economisi la primul nivel 2 comutatoare de intrare, trebuie
grupate intrările în perechi consecutive, fiecare pereche făcând uz de
acelaşi comutator cu 2 intrări, cum se vede în fig.13.14. În acest fel, dacă
cele 2 celule de intrare dintr-o pereche merg către 2 jumătăţi de ieşire
diferite, atunci ele pot fi comutate în paralel, altfel una va fi comutată iar
cealaltă va fi abandonată sau stocată într-un buffer. Bineînţeles, acelaşi
proces poate fi repetat în mod recursiv pentru fiecare dintre reţelele Delta
de dimensiune N/2, unde din nou există un nivel de 2 x 2 comutatoare,
apoi 4 N/4 comutatoare e.t.c. Extinderea completă a unei reţele Delta este
vizibilă în prima jumătate a figurii 13.15. Se poate observa cum
construcţia recursivă din fig.13.14 se regăseşte în conexiunea dintre
primul nivel şi cel de-al doilea nivel din fig.13.15.
204
Figura 13.15: Efectuarea rutării multicast copiază de două ori folosind o reţea Benes.
Prima jumătate este o reţea Delta şi a doua jumătate este o reţea Delta oglindită.
205
ieşire pentru care debitul reţelei Delta se reduce la o legătură, spre
deosebire de N legături.
O cale de a face reţeaua Delta mai puţin susceptibilă la congestionare în
cazul permutărilor arbitrare a cererilor de intrare, este adăugarea mai
multor căi între o intrare şi o ieşire. Generalizând ideile discutate la reţeua
Clos (fig.13.12), putem construi o reţea Benes (fig,13.15), care constă din
2 reţele de adâncime logN: jumătatea din stânga este o reţea Delta standard
iar jumătatea din dreapta este o reţea Delta inversată prin oglindire. Dacă
privim invers la jumătatea din dreapta, mergând de la ieşiri spre stânga
putem observa că conexiunile dintre ultimul nivel şi penultimul nivel sunt
identice cu conexiunile dintre primul şi cel de-al doilea nivel.
Se poate privi reţeaua Benes şi recursiv, adăugând la fig.13.14 al treilea
nivel de comutatoare 2 x 2, conectând acest nivel la cele 2 reţele de
dimensiune N/2 din mijloc, în aceaşi manieră în care comutatoarele din
primul nivel sunt conectate la cele 2 reţele de dimensiune N/2 (fig.13.16).
Această procedură recursivă poate fi folosită pentru a creea direct schema
din fig.13.15, fără a crea 2 reţele Delta separate.
206
Ca şi la reţelele Clos, se poate arăta că dacă se foloseşte un algoritm
aleator, nici o legătură internă nu devine congestionată atâta timp cât nici
o intrare sau ieşire nu devine congestionată. Intuitiv: jumătatea
responsabilă de împărţirea încărcării preia traficul destinat oricărei ieşiri
de la oricare intrare şi îl distribuie în mod egal spre toate cele N legături de
ieşire ale primei jumătăţi. În a doua jumătate, datorită structurii simetrice,
tot traficul este dirijat spre legătura de ieşire destinaţie.
De exemplu, considerăm că legătura de sus ajunge la primul comutator
de pe etajul final din figura 13.15. Această legătură de sus va purta
jumătate din traficul legăturii de ieşire 1 (deoarece legătura de sus
transportă tot traficul destinat ieşirii 1 din jumătatea de sus a nodurilor de
intrare şi datorită proprietăţii de împărţire a încărcării se obţine jumătate
din traficul destinat ieşirii 1). Tot aşa se poate observa că legătura de sus
poartă jumătate din traficul destinat ieşirii 2, etc.
În timp ce unele dintre aceste proprietăţi erau cunoscute dinainte, Turner
a extins aceste idei pentru traficul multicast. Problema nu a fost tratată la
ruterele multişasiu bazate pe reţeaua Clos. Tratarea multicast este bazată
pe modelul server ca în schema de acordare a unui bilet („take a ticket”).
Pentru a extinde ideile de rutare Benes şi pentru multicast, Turner a
elaborat o formă mai simplă de multicast numită „copiază de două ori”. În
această formă, fiecare intrare poate specifica două ieşiri. Mai departe este
treaba reţelei să trimită două copii ale celulei de la intrare spre porturile de
ieşire specificate. Dacă acest lucru este posibil şi legăturile de ieşire pot fi
reciclate spre intrare, atunci cele două copii create la prima parcurgere pot
fi extinse la 4 copii în parcurgerea a doua şi la 2i copii la parcurgerea i prin
reţeaua Benes.
Spre exemplu în figura 13.15 se observă faptul că cea de-a cincea intrare
are o celulă care este pusă în legătură atât cu 1000 (adică ieşirea 8) cât şi
cu 1111 (adică ieşirea 15). În prima jumătate, celula este rutată în mod
aleator către ieşirea 7 a celei de-a doua jumătăţi. În cea de-a doua
jumătate, se urmăresc biţii ieşirii reale, întâi MSB, până se ajunge prima
dată într-un loc în care cele două adrese de ieşire diferă. Deobicei, dacă
bitul curent are valoarea 0 se comută în sus, iar dacă are valoarea 1 se
comută în jos. De aceea, la primul nivel al reţelei copiate, celula este rutată
spre legătura de jos, pentru că ambele adrese de ieşire încep cu un 1.
Lucrurile se complică la nivelul doi, deoarece la poziţia a doua dinspre
dreapta adresele diferă. Astfel, comutatorul din nivelul doi (adică
comutatorul al patrulea de la vârf) trimite celulele în două direcţii. Cele
două căi de ieşire s-au despărţit la primul bit care diferă. Din acest
moment, fiecare dintre cele două celule urmăreşte adresa corespunzătoare
ieşirii sale. În figura 13.15, dacă se iau în considerare ultimii 2 biţi ai 1000
şi 1111, se observă faptul că cele 2 celule ajung la ieşirea 8 şi 15.
Se poate demonstra că dacă copierea se face la nivelul primului bit care
diferă, aceasta nu duce la nici o supraîncărcare a vreunei legături interne,
dacă legăturile de intrare şi ieşire nu sunt supraîncărcate. Rezultatul e
valabil şi la reţele copy-3 (reţea capabilă să producă 3 copii la o trecere).
În momentul în care o celulă ajunge la un comutator, ea poartă un
specificator multicast cu legătura de ieşire, care trebuie transformat în 2
sau mai mulţi specificatori unicast pentru fiecare parcurgere. În mod
similar, fiecare celulă trebuie să poarte cu ea 2 sau mai multe adrese pe
207
parcursul drumului. Utilizarea unui număr mic, precum 2 limitează
complexitatea operaţiei de mapare a porturilor şi dimensiunea antetului.
Utilizarea unor numere mai mari va duce la micşorarea numărului de
parcurgeri necesare pentru a replica o celulă muticast.
O proprietate îmbucurătoare a proiectării multicast a lui Turner este
faptul că fanout-uri cu valori mari, de tip multicast, pot fi prelucrate în mai
multe iteraţii. Acest lucru poate fi vizualizat ca un arbore binar multicast,
din cadrul mai multor reţele Benes conectate în serie. În realitate, este
refolosită aceaşi reţea Benes, astfel reducând costul. Imaginea
demonstrează eficienţa adăugării de noi conexiuni multicast. Aceasta
presupune de fapt adăugarea unei frunze la arborele existent, cauzând o
perturbare minimă la nivelul celorlalte noduri existente ale arborelui şi
celorlalte conexiuni.
În consecinţă, comutatorul Turner tinde să folosească resursele în mod
optim datorită reciclării. Proiectul permite o scalabilitate a resurselor de
N ∗ log N , poate trata orice configuraţie de trafic unicast şi multicast şi
poate adăuga sau şterge un punct terminal dintr-un arbore multicast într-un
interval de timp constant. Alte arhitecturi de comutatoare nu îndeplinesc
aceste condiţii, iar în practică pot face faţă doar la un trafic multicast de
dimensiune limitată. În prezent importanţa traficului multicast este
limitată, însă având în vedere creşterea importanţei videoconferinţelor prin
Internet se poate spune că va exista un viitor, în care comutatoare
multimedia de mari dimensiuni vor avea un rol cheie.
În concluzie trebuie menţionat faptul că la fel ca la comutatorul Clos,
simplitatea conceptuală a unei strategii de echilibrare aleatoare a
încărcării pentru o reţea Benes aduce o complexitate de implementare. În
primul rând, deoarece echilibrarea aleatoare a încărcării nu este perfectă,
comutatorul Turner necesită buffere şi controlul fluxului. În al doilea rând,
aleatorizarea trebuie facută corect. Primul prototip al comutatorului de la
Universitatea Washington a folosit echilibrarea simplă a încărcării, bazată
pe un numărător, însă atunci când a fost reproiectat la compania Growth
Networks, comutatorul a folosit un circuit de aleatorizare mult mai
sofisticat, care să poată rezolva chiar şi cele mai patologice modele de
intrare. În final, o resecvenţiere eficientă a celulelor a necesitat un doesebit
efort în această arhitectură.
208