http://alpha-thema-online.uv.ro
Fa-ti si tu propriul forum, pe www.myforum.ro!
Pagina de start a forumului http://alpha-thema-online.uv.ro Autentificare Inregistrare FAQ Membri Cautare

Pagina de start a forumului http://alpha-thema-online.uv.ro » C / C++ / C# » Optimizarea aplicatiilor Windows C++
Creaza un subiect nou  Raspunde la subiect Subiectul anterior :: Subiectul urmator 
Optimizarea aplicatiilor Windows C++
MesajTrimis: 19/07/2007 16:41 Raspunde cu citat (quote)
Ad_Infinitum
Administrator
Administrator
Ad_Infinitum
Data inscrierii: 23/Iun/2007
Mesaje: 212




Optimizarea - aliat sau dusman?

Când este necesarã optimizarea

Un programator versat nu va scrie niciodatã cod inefficient. Cel puþin nu în mod intenþionat. Optimizarea îºi are rostul îndată ce performanþa trebuie sã fie maximã. În momentul în care se doreºte o optimizare a codului, trebuie studiat foarte prudent locul în care are loc gâtuirea. Optimizarea se poate face în mai multe locuri – la prelucrarea imaginilor (acestea se încarcã prea încet ºi/sau consumã excesiv de multã memorie), la accesul la date (viteza de accesare ºi prelucrare a datelor este prea micã), asupra unor algoritmi (implementaþi necorespunzãtor), etc.

La capitolul optimizarea algoritmilor proprii implementaþi, se întâlnesc de obicei 3 mari cazuri:
- Se ignorã în întâia fazã cã tocmai propriul algoritm este cel care cauzeazã gâtuirea, acest lucru devenind periculos pentru că se evitã studirea problemei tocmai în locul în care aceasta existã.
- Se determinã algoritmul care cauzeazã gâtuirea ºi se rescrie complet acest algoritm.
- Se determinã algoritmul care cauzeazã gâtuirea dar mai întâi se testeazã impactul global pe care aceastã gâtuirea o are asupra întregii aplicaþii, înainte de modificarea sau rescrierea lui.

Aceastã ultimã abordare este cea mai indicatã, fiindcă uneori gâtuirea generatã de un algoritm poate sã aibã impact nememnificativ asupra sistemului în raport cu efortul de rescriere a întregului algoritm. Uneori, rescrierea întregului algoritm, mai ales în cazul algoritmilor complexi poate fi destul de dificilã, cauzând întârzieri pentru întregul proiect ºi costuri suplimentare pentru firmã.

În momentul în care se testeazã o aplicaþie, în vederea determinãrii gâtuirilor, se folosesc o serie de utilitare care mãsoare timpul în care aplicaþia executã o anume funcþie. Aceste unelte sunt însã cu douã tãiºuri.
Unele din ele par sã nu þinã cont cã, în deosebit sub sistemele Windows, în timpul în care se executã o anume funcþie a programului testat ruleazã ºi thread-uri ale altor programe de sistem. De exemplu, aplicaþia noastrã ruleazã în spaþiul utilizator. Dar tot în acest timp, în paralel lucreazã ºi kernelul sistemului de operare.
Alte unelte mai performante, þin cont de toate acestea ºi trateazã ca atare timpul consumat de kernel, oferind o fotografie cât de cât realã a timpului în care se executã efectiv aplicaþia.

În unele cazuri, din aplicaþia noastrã este apelat kernelul pentru a executa anumite operaþii, deci timpul în care ruleazã acest kernel este deosebit de important ºi nu trebuie ignorat. De la versiunea 4.0 a Windows NT, GDI-ul nu mai este un proces care ruleazã pe nivelul utilizator, ci este integrat în kernel.
În concluzie, la întrebare Ce sã optimizãm?, se poate rãspunde uºor: acele pãrþi ale programului care consumã timp excesiv. Dar ºi aici apare o problemã. O optimizare localã, unde se ignorã performanþele globale ale aplicaþiei este inutilã.

Aici pot sã dau un exemplu teribil de realist. Sã luãm de exemplu Visual Basic 5.0. Acesta venea în plus cu un compilator nativ, pe lângã interpretor. Problema a fost cã de un plus de vitezã au beneficiat numai aplicaþiile care foloseau calcule matematice intensiv. În cazul unei aplicaþii de baze de date, unde se foloseau mult tehnologii externe – MDAC, componente ActiveX, apeluri de funcþii API, nu se prea sesiza vreo diferenþã.
De ce? Pentru cã, codul compilat al programului conþinea în mare parte apeluri de funcþii API, apeluri de metode ºi proprietãþi ale obiectelor COM/DCOM/ActiveX, iar timpul consumat pentru aceste apeluri era infim faþã de timpul în care acest funcþii API, metode ºi proprietãþi ale obiectelor COM/DCOM rulau efectiv.
Sfaturi privind optimizarea

Chiar dacã compilatoarele moderne de C++ sunt nespus de capabile ºi îngăduie optimizarea aplicaþiilor d-voastrã, unele intervenþii în cod sunt încã necesare. Astfe, voi discuta mai departe aspecte generale ale optimizãrii programelor scrise în acest limbaj de programare.
O tehnicã pe care trebuie sã o aveþi în vedere este delegarea cãtre sistemul de operare. Delegarea permite utilizarea codului deja existent, care a fost verificat ºi optimizat pentru obþinerea unei performanþe cât mai mari.

Sistemul de operare de numeroase ori oferã aºa numitele hook-uri (cârlige) la hardware. Este cazul acceleratoarelor 3D ºi a plãcilor de reþea cu checksum hardware. Aproape întotdeauna, folosirea funcþiilor API implementate în hardware poate duce la performanþe mult mai bune decât dacã aþi scrie d-voastrã cod pentru implementarea acestor funcþii.
În cazul plãcilor grafice, cu accelerare 3D, emularea software produce efecte sensibil mai slabe decât folosirea funcþiilor API dedicate implementate hardware în acceleratorul 3D.

Alt exemplu este tehnologia OLE DB pentru accesul la bazele de date. Aceastã electronică este maturã, testatã ºi optimizatã ºi este de preferat sã o folosiþi în loc sã vã definiþi propriul motor de acces la bazele de date.
De exemplu SQL Server este dedicat pentru execuþia de instrucþiuni SQL, ºi va face aceastã treabã mult mai repede decât aþi face-o d-voastrã prin propriile rutine, indiferent de limbajul de programare folosit. O altã prolemã importantã pe care trebuie sã o luaþi în considerare este sistemul de operare folosit. Windows NT ºi succesorii lui merg mai fără întârziere ºi mai stabil decât sistemele de operare Windows pe automatizare 9x. Deci, dacã se poate, þintiþi sisteme de operare pe tehnologie NT, mai ales pentru serverele de aplicaþii ºi pentru sistemele de acces la bazele de date.

Algoritmii pe care îi folosiþi în aplicaþia d-voastrã pot sã influenþeze foarte mult performanþa de ansamblu a aplicaþiei. Folosiþi cel mai bun algoritm care vã poate rezlva o anumitã problemã. Implementaþi algoritmii ºi în funcþie de cantitatea de date pe care respectivul algoritm o proceseazã.
Alegeþi cel mai bun raport între uºurinþa de implementare a algoritmului ºi performanþele acestuia.

Pentru un set mic de date, a implementa un algoritm complex poate fi pierdere de timp. Luaþi în considerare tot timpul factorul timp ºi costurile pe care implementarea unui anumit algoritm le implicã. Nu veþi justifica costurile suplimentare sau întârzierea lansãrii aplicaþiei pentru un algoritm extrem de complex, aplicat unui set mic de date, care nu realizează performanþe vizibile mai mari decât un alt algoritm nu atât de complicat, dar mai iute de implementat.

Biblioteca STL de obicei este însoþitã de implementarea algoritmilor standard, deci puteþi folosi aceastã bibliotecã pentru anumite scopuri. În acest fel aveþi la îndemânã algoritmi de caracteristică deja implementaþi. Aici trebuie sã aveþi grijã, pentru cã unele implementãri sunt cumplit de generice.
De obicei compilatorul de Visual C++ este capabil sã recunoascã de exemplu constantele dintr-o buclã ºi sã le scoatã în afarã, dar nu îi este clar care apeluri de funcþii sau metode sunt constante. Ori de câte ori aveþi ocazia, folosiþi bucle în care contorul descreºte, căci se simplificã în acest fel generarea codului pe mãsurã ce contorul scade, urmat de un salt dacã nu este zero. (în ASM, pentru acest salt se foloseºte instrucþiunea jnz)

Altã tehnicã este folosirea operatorului ++ sau - -, de incrementare, respectiv decrementare, înaintea variabilei.
Ex, este mai bine sã scrieþi:

Citat:

++ nVariabila,


sau

Citat:

-- nVariabila


decât:

Citat:

nVariabila ++,


sau

Citat:

nVariabila --


Aceastã tehnicã este utilã mai ales în cazul procesoarelor Pentium, unde incrementarea nu se poate face pânã când comparaþia nu este completã. Nucleul procesoarelor Pentium pot folosi register antialiasing pentru a pornește incrementarea, utilizând „load effective address”, pentru a nu ruina testul de comparaþie.

Exemple:

Pentru linia:

Citat:


for(i=0;i<limit;++i)


Procesorul executã:

Citat:

inc ecx
cmp ecx, limit
jl loop_start


Pentru linia:

Citat:

for(i=limit+1;i>0;--i)


Procesorul executã:

Citat:

dec ecx
jgt loop_start


Pentru linia:

Citat:

for(i=0;i<limit;i++)


Procesorul executã:

Citat:

cmp ecx,limit
lea ecx, [ecx+1] ; fãrã influenþã asupra regiºtrilor
jl loop_start]


Pentru linia:

Citat:

for(i=limit+1;i>0;i--)


Procesorul executã:

Citat:

test ecx
lea ecx, [ecx-1]
jl loop_start


Apelurile de funcþii în C/C++ - cum afecteazã acestea performanþa globalã a aplicaþiei.

1. Funcþiile C
Apelul este simplu: pune argumentul pe stack, excutã o instrucþie CALL ºi apoi RET la sfârºitul apelului, dupã care extrage argumentul.
Apelurile de funcþii __fastcall sunt mai rapide pentru unul sau douã argumente, deoarece aceºtia sunt pasaþi în regiºtrii.
2. Funcþii C++ nonvirtuale
Nu sunt mai lente decât funcþiile C, dar toate funcþiile au pointerul this, aºa cã exitã întotdeauna un argument pe care sã-l punã sau sã-l extragã (push/pop).
3. Membrii virtuali ai funcþiilor C++
Acestia ar trebui evitaþi de tot, în cazul în care este posibil.
4. Apeluri de funcþii din obiecte COM In Process
Presupunând cã interfaþa COM poate fi accesatã direct din threadul care o apeleazã, apelurile de funcþii COM nu au impact mai mare decât apelurile de funcþii virtuale, ceea ce ºi sunt de fapt. Un alt înfățișare este cã marshalingul parametrilor poate fi mai mare consumator de timp decât pasarea pointerilor.
5. Apelurile de funcþii API
Orice apel care ruleazã pe ring 3 (modul utilizator ), are acelaºi impact ca ºi oricare alt apel al unei funcþii dintr-un fiºier .DLL. Problema stã altfel dacã apelul se face de pe ring 0 (modul kernel ), iar un apel care forþeazã o tranziþie de ring necesitã minim 600 de cicluri de tact.
Aliniamentul elementelor în structuri de date
Într-o structurã, încercaþi sã aliniaþi toate elementele la 4 sau 8 bytes. Pentru Visual C++ 6.0, prestabilit este 8 bytes, însã 4 bytes sunt la fel de buni pentru valorile pe 32 de biþi.
Aliniamentul pe 8 bytes este indicat pentru structuri cum ar fi fiºierele sau structurile de reþea, însã aceste înregistrãri ar trebui sã foloseascã întregi pe 64 de biþi. Pentru orice altceva, rãmâneþi la aliniamentul pe 4 bytes.

Software Pipelining
Aceastã tehnicã pipeline a fost implementatã în procesoarele Merced de la Intel, aºa cã, pentru a beneficia de avantajele pe care le oferã, este trebuință de compilatoare care sã ºtie sã o implementeze în software.
Software pipelining este un concept de construcþie a buclelor în care fiecare iteraþie lucreazã la o parte diferitã din task. De exemplu la procesarea pipeline a imaginilor, un pixel poate fi transformat în timp ce altul este scris pe disk.
Aceastã tehnicã este bine sã o lãsaþi în grija compilatorului, cu excepþia cazului în care lucraþi direct cu instrucþiuni în limbaj de asamblare.

Când sã nu optimizaþi
Nu încercaþi sã faceþi optimizãri care nu au sens. De exemplu, unii încearcã sã optimizeze interfaþa graficã (GUI), algoritmii de baze de date, etc. Nu pierdeþi timpul sã creaþi de exemplu propriul motor de acces la bazele de date, decât dacã aveþi un pretext extraordinar de serios. Motoare ca JET, ADO, DAO sunt implementate, optimizate ºi testate de echipe întregi de programatori profesioniºti. Deci folosiþi cât mai mult ceea ce deja existã ºi merge bine.

De exemplu, de ce nu este eficient sã optimizãm update-ul meniurilor sau controalelor dintr-o interfaþã graficã? Pãi hai sã luãm în considerare ºi factorul uman. O relatare interesantã am gãsit-o într-un articol pe internet:

Utilizatorul executã un click cu mouse-ul. Sã spunem cã mouse-ul se aflã la cam un metru de ureche. Se ºtie cã sunetul se propagã cu o vitezã de 380 m/sec.
Asta înseamnã cã este nevoie de aproximativ 2 ms pentru ca sunetul click-ului de mouse sau apãsãrii de tastã sã ajungã la urechea umanã.
Calea neuralã de la vârful degetului pânã la creier este de aproximativ 1 m. Propagarea impulsului nervos este de aproximativ 100 m/sec, asta însemnând cã senzaþia executãrii unui click sau a unei apãsãri de tastã are nevoie de 10 ms pentru a ajunge la creier. Durata de percepþie în creier variazã între 50 ºi 250 ms sau chiar mai mult.
Deci, câte instrucþiuni de procesor Pentium se executã în 2 ms? Dar în 10 ms? Dar în 250 ms? În 2 ms, într-un procesor Pentium !!!/500Mhz au loc circa 1.000.000 cicluri de ceas, timp în care se executã o mulþime de instrucþiuni!

Foarte interesant acest mod de abordare a problemei, nu-i aºa?
Toate acestea nu au împiedicat corporaþia Microsoft pentru a viola modelul obiectual al C++ referitor la tratarea mesajelor.
La apelul CWnd::OnCeva(...), în loc de a se apela funcþia DefWindowProc cu parametrii care îi specificaþi d-voastrã, se refoloseºte parametrul ultimului mesaj pentru a apela ::DefWindowProc.
Aceasta are ca scop final, dupã spusele lui Microsoft, de a reduce dimensiunea librãriei runtime MFC. Acest lucru este un exemplu de optimizare care nu-ºi are rostul, pentru cã într-un DLL imens, care conþine mii de instrucþiuni, cum este runtime-ul MFC, micºorarea bibliotecii prin aceastã tehnicã este atât insesizabilã cât ºi fãrã impact real asupra vitezei de rulare.

Concluzie
Optimizarea conteazã numai atunci când este nevoie de ea. Când este necesitate de ea, conteazã foarte mult, dar când nu este necesarã, nu pierdeþi timp ºi efort pentru a o implementa. Chiar dacã aþi ajuns la concluzia cã este necesarã, trebuie sã studiaþi vigilent în ce loc anume este necesarã. Toate astea se fac testând cu date concrete aplicaþia d-voastrã, în diverse situaþii. Dacã nu aþi definit concret partea aplicaþiei care trebuie optimizatã, s-ar putea sã optimizaþi ceea ce nu trebuie. Rezultatul acestui lucru va fi un cod obscur, greu de întreþinut ºi depanat ºi nu vã va rezolva adevãrata problemã. Asta sã nu mai vorbim de timpul ºi de costurile suplimentare pe care toate acestea le implicã.

Deci, atenþie ce optimizaþi ºi mai ales când optimizaþi. În funcþie de capacitatea d-voastrã de a identifica realele gâtuiri, optimizarea vã poate fi duºman sau aliat. Mult succes!

Ovidiu P. Tabla
SC CSR SA, Sef Grupa IT
Vezi profilul utilizatorului Trimite mesaj privat

Optimizarea aplicatiilor Windows C++
 Pagina de start a forumului http://alpha-thema-online.uv.ro » C / C++ / C#
Nu puteti crea un subiect nou in acest forum
Nu puteti raspunde in subiectele acestui forum
Nu puteti modifica mesajele proprii din acest forum
Nu puteti sterge mesajele proprii din acest forum
Nu puteti vota in chestionarele din acest forum
Ora este GMT + 3 ore  
Pagina 1 din 1  

  
  
 Creaza un subiect nou  Raspunde la subiect  


Fa-ti si tu propriul forum GRATUIT, pe www.myforum.ro
    Powered by phpBB © 2001-2004 phpBB Group. phpBB Skin by Vjacheslav Trushkin.