This shows you the differences between two versions of the page.
cpl:teme:concurs [2016/01/12 15:36] razvan.crainea [Hints/FAQ:] |
— (current) | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Concurs ====== | ||
- | Scopul acestui concurs este familiarizarea cu API-ul pus la dispoziție de framework-ul LLVM. Folosind acest API trebuie să implementați o serie de pași de analiză/optimizare de bitcode LLVM. Tema este compusă din patru părți: | ||
- | |||
- | - Analiză statică | ||
- | - Analiză dinamică/instrumentare | ||
- | - Optimizare | ||
- | - Concurs | ||
- | |||
- | ===== Informații organizatorice ===== | ||
- | * **Deadline**: Termenul limită până când se pot trimite rezolvări **13 ianuarie 2016, ora 19:59**. Pentru mai multe detalii, consultaţi [[:cpl:teme:general|regulamentul]] aferent temelor de casă. | ||
- | * **Atenție**: Deadline-ul este final - după **13 ianuarie 2016, ora 19:59** nu se vor mai putea trimite rezolvări. | ||
- | * **Colaborare**: Rezolvarea este **individuală**. | ||
- | * **Punctare** | ||
- | * **100p** pentru implementarea completă şi corectă a primelor trei părți | ||
- | * Pentru cea de-a patra parte se va face un clasament în funcție de **costul** obținut de fiecare rezolvare individuală. Cel mai **mic** cost va fi cel care va câștiga concursul. | ||
- | * Concursul valorează **12.5 puncte** din nota finală - poate fi folosit pentru a recupera punctajul pierdut în cursul anului. | ||
- | |||
- | ===== Infrastructură ===== | ||
- | * Rezolvarea cerințelor se va face folosind **LLVM 3.6.2** | ||
- | * Setup-ul de testare este identic cu cel din [[cpl:info:vm|mașina virutală]]. Vă recomandăm să folosiți mașina virtuală pentru rezolvare. | ||
- | |||
- | ===== Enunț ===== | ||
- | |||
- | Premisa acestul concurs este că avem la dispoziție o arhitectură fictivă care execută instrucțiuni LLVM IR. Pentru a executa o instrucțiune LLVM IR pe procesorul fictiv este necesar un anumit număr de cicluri de ceas. Astfel, putem estima cât de costisitoare este execuția unei instrucțiuni. | ||
- | |||
- | Pentru aceasta fiecare pas va folosi un fișier de intrare care conține pe fiecare linie numele unei instrucțiuni LLVM IR și un cost/scor asociat. | ||
- | Exemplu: | ||
- | <code> | ||
- | br 10 | ||
- | add 7 | ||
- | sub 7 | ||
- | alloca 10 | ||
- | default 1 | ||
- | </code> | ||
- | |||
- | Token-ul special ''default'' este folosit pentru a asocia un cost implicit pentru instrucțiunile care nu sunt menționate explicit în fișier. Dacă linia cu token-ul ''default'' lipsește, costul implicit este ''0''. | ||
- | |||
- | Fiecare pas LLVM implementat trebuie să citească costurile asociate instrucțiunilor din fișierul ''cpl-score-file.txt''. Pașii trebuie să poată permită folosirea unui alt fișier cu scoruri folosind argumentul ''-cpl-score-file''. Exemplu: | ||
- | |||
- | <code bash> | ||
- | # run the optimization pass with the default score file | ||
- | opt -load=/path/to/libLLVMCpl.so -cpl-opt test.bc > out.bc | ||
- | |||
- | # run the analysis/instrumentation pass with a custom score file | ||
- | opt -load=/path/to/libLLVMCpl.so -cpl-dynamic -cpl-score-file=my-custom-score-file.txt test.bc > out.bc | ||
- | </code> | ||
- | |||
- | <note important>Puteți considera că fișierul de intrare este întotdeauna corect formatat.</note> | ||
- | |||
- | ===== Analiză statică (30 puncte) ===== | ||
- | |||
- | Pentru a rezolva această cerință va trebui să implementați un pas LLVM care, pe baza unui fișier de intrare precum cel de mai sus, să afișeze suma scorurilor tuturor instrucțiunilor din program. | ||
- | |||
- | Analiza trebuie să nu țină cont de instrucțiunile de control-flow întâlnite, de evaluarea unor condiții, de bucle etc. Cu alte cuvinte, tot ce trebuie să faceți este să iterați pe fiecare instrucțiune din fiecare funcție a programului, să îi contorizați scorul asociat iar la final să afișați scorul/costul total. | ||
- | |||
- | Pasul **NU** trebuie să analizeze conținutul funcțiilor [[http://llvm.org/releases/3.6.2/docs/LangRef.html#intrinsic-functions|implicite]], al [[http://llvm.org/docs/LangRef.html#the-llvm-global-ctors-global-variable|constructorilor LLVM]] sau al [[http://llvm.org/docs/LangRef.html#the-llvm-global-ctors-global-variable|destructorilor LLVM]]. | ||
- | |||
- | Funcțiile implicite (intrinsics) sunt folosite intern de către LLVM. | ||
- | Aceste funcții pot fi identificate prin faptul că numele lor începe cu prefixul "llvm.*". Se poate verifica ușor dacă o funcție este sau nu implicită folosind [[ http://llvm.org/docs/doxygen/html/classllvm_1_1Function.html#a4b37898a6d26b0d5fcee66548f2621d3|API-ul]] | ||
- | |||
- | Constructorii și destructorii sunt menținuți în câte un array global. Funcțiile din ''llvm.global_ctors'' vor fi apelate atunci când modulul LLVM este încărcat (înainte de începerea efectivă a execuției programului), în ordinea //ascendentă// a priorității asociate. Funcțiile din ''llvm.global_dtors'' sunt apelate atunci când modulul LLVM este descărcat (după terminarea efectivă a execuției programului), în ordinea //descendentă// a priorității. | ||
- | |||
- | **Atenție! Nu confundanți cu destructori/constructori C++!** | ||
- | |||
- | Pentru lucrul cu contructori, puteți folosi clasa [[http://llvm.org/docs/doxygen/html/CtorUtils_8cpp_source.html|CtorUtils]]. | ||
- | |||
- | ==== Hints/FAQ: ==== | ||
- | |||
- | <note tip> | ||
- | * **Q:** Cum pot prelua o opțiune din linia de comandă în cadrul pasului LLVM? | ||
- | * **A:** Folosind API-ul [[http://llvm.org/releases/3.6.2/docs/CommandLine.html|CommandLine]] | ||
- | |||
- | * **Q:** Cum afișez scorul final? | ||
- | * **A:** Folosind clasa [[http://llvm.org/releases/3.6.2/docs/ProgrammersManual.html#the-statistic-class-stats-option|Statistic]] | ||
- | </note> | ||
- | |||
- | <note tip> | ||
- | * Exemplu de rulare: | ||
- | <code bash> | ||
- | $ opt -load=/path/to/libLLVMCpl.so -cpl-static -stats -cpl-score-file=cpl-score-file.txt test.bc > out.bc | ||
- | ===-------------------------------------------------------------------------=== | ||
- | ... Statistics Collected ... | ||
- | ===-------------------------------------------------------------------------=== | ||
- | |||
- | 263 cpl - Static score of all instructions | ||
- | </code> | ||
- | </note> | ||
- | |||
- | <note warning>Numele pass-ului pentru analiza statică este ''cpl-static''</note> | ||
- | ===== Analiză dinamică / Instrumentare (40 puncte) ===== | ||
- | |||
- | Scorul static ne poate da o idee despre cât de "costisitoare" este execuția unui program, însă nu reprezintă o estimare realistă pentru toate cazurile de execuție. In practică, o instrucțiune se poate executa de mai multe ori (de exemplu dacă face parte dintr-o buclă) sau niciodată (de exemplu dacă face parte dintr-o funcție neapelată). De asemenea căile de execuție depind de multe ori de setul de date de intrare al programului. Calculul static al scorului nu ia în considerare aceste cazuri. | ||
- | |||
- | Pentru a rezolva a doua parte a temei va trebui să implementați un pas LLVM care //instrumentează// un program astfel încât costul execuției acestuia să fie calculat la runtime. | ||
- | Codul original trebuie modficat astfel: <del>în interiorul fiecărui basic block trebuie adăugat cod care adună scorul total al BasicBlock-ului curent. Scorul total al BasicBlock-ului este egal cu suma scorurilor instrucțiunilor din care acesta este compus. | ||
- | </del> după fiecare instrucțiune trebuie adăugat cod care adună scorul acesteia la scorul total. | ||
- | ==== Hints/FAQ: ==== | ||
- | <note tip> | ||
- | * **Q:** Unde stochez scorul? | ||
- | * **A:** Va trebui să folosiți o variabilă globală pe care trebuie să o adăugați modulului LLVM IR. | ||
- | |||
- | * **Q:** Ce tip trebuie să aibă variabila globală în care stochez scorul total? | ||
- | * **A:** Folosiți o variabilă de tipul întreg, fără semn, pe ''64'' de biți. | ||
- | |||
- | * **Q:** Trebuie să tratez accesul concurent la variabila globală? | ||
- | * **A:** Nu. | ||
- | |||
- | * **Q:** Cum afișez scorul final? | ||
- | * **A:** Folosind [[http://llvm.org/releases/3.6.2/docs/LangRef.html#the-llvm-global-dtors-global-variable|destructori]]. Destructorii sunt apelați după ce execuția unui program se încheie. Trebuie să creați și să inserați o funcție destructor în variabila globală ''llvm.global_dtors''. Această funcție trebuie să afișeze scorul menținut pe parcursul rulării programului. | ||
- | </note> | ||
- | |||
- | <note tip> | ||
- | * Exemplu de rulare: | ||
- | <code> | ||
- | $ opt -load=/path/to/libLLVMCpl.so -cpl-dynamic -cpl-score-file=cpl-score-file.txt test.bc > out.bc | ||
- | $ clang out.bc -o out | ||
- | $ ./out | ||
- | 1113 cpl - Dynamic score for execution | ||
- | </code> | ||
- | </note> | ||
- | |||
- | <note warning>Numele pass-ului pentru analiza dinamică este ''cpl-dynamic''</note> | ||
- | ===== Optimizare (30 puncte) ===== | ||
- | Arhitectura pe care lucrăm are o particularitate: costul execuției instrucțiunilor ''br'' și ''switch'' (atât condiționale cât și necondiționale) este foarte ridicat. | ||
- | Pentru a rezolva a treia parte a temei, trebuie să creați un pas de optimizare care să micșoreze costul de execuție reducând numărul de instrucțiuni ''br'' __executate__ (ex: mai puține bucle). | ||
- | |||
- | Evaluarea se va face folosind un set de benchmark-uri: costul de execuție pentru arhivarea/dezarhivarea unui anumit set de date, folosind utilitarele zip/unzip. Costul de execuție se calculează instrumentând varianta optimizată a programului de test folosind pass-ul implementat în partea a doua. | ||
- | |||
- | ==== Hints/FAQ ==== | ||
- | |||
- | <note tip> | ||
- | * **Q:** Cum minimizez numărul de branch-uri? | ||
- | * **A:** Un număr mare de instrucțiuni de control-flow sunt executate în cadrul buclelor. Va trebui să implementați o variantă de "loop unrolling". Această optimizare țintită pe bucle reduce numărul de instrucțiuni ''br'' executate, crescând însă dimensiunea codului. | ||
- | |||
- | * **Q:** Cum primesc punctajul pentru această parte? | ||
- | * **A:** Veți primi punctajul complet dacă pasul vostru de optimizare a) realizează desfacerea //unor// bucle, b) respectă [[http://ocw.cs.pub.ro/courses/cpl/meta/notare#penalizare_pentru_teme_copiate|regulamentul]] de realizare a temelor și c) scade costul de rulare a benchmark-ului sub un anumit prag. | ||
- | |||
- | * **Q:** Ce pași de analiză LLVM am voie să folosesc? | ||
- | * **A:** Puteți folosi optimizările de promovare în regiștrii (''mem2reg'') și de propagarea constantelor (''constprop''), împreună cu pașii impliciți. | ||
- | |||
- | * **Q:** Ce pași de analiză LLVM NU am voie să folosesc? | ||
- | * **A:** NU puteți folosi niciun alt pas care nu a fost menționat explicit. | ||
- | </note> | ||
- | |||
- | ===== Concurs ===== | ||
- | |||
- | Regula este simplă: cine obține cel mai mic scor pentru benchmark-ul dat, câștigă. Pentru a micșora costul de execuție puteți implementa orice pași de optimizare doriți, pe care îi puteți apela în orice ordine. **Atenție** însă: nu aveți voie să folosiți pașii LLVM, nici direct (nu aveți voie să îi apelați), nici indirect (nu aveți voie să preluați cod - verificați ce înseamnă [[cpl:meta:notare##penalizare_pentru_teme_copiate|temă copiată]]). Aceeași regulă se aplică și pentru pașii de analiză. | ||
- | ===== Implementare ===== | ||
- | |||
- | Pentru implementarea pașilor LLVM, puteți urmării pașii de mai jos: | ||
- | |||
- | - Descărcați {{:cpl:concurs-arhiva.zip|arhiva de start}} **în afara** surselor LLVM și dezarhivați-o (Exemplu: ''zip concurs-arhiva.zip'') | ||
- | - Creați un director de build și intrați în el (Exemplu: ''mkdir build; cd build'') | ||
- | - Rulați ''cmake'' cu calea directorului unde ați dezarhivat arhiva (Exemplu: ''cmake ..'') | ||
- | - Compilați pasul (Exemplu: ''make'') | ||
- | - Dacă totul s-a compilat cu succes, ar trebui să se genereze biblioteca ''libLLVMCpl.so'' în directorul ''Cpl'' | ||
- | |||
- | ===== Resurse ===== | ||
- | |||
- | * {{:cpl:concurs-arhiva.zip|Arhiva de start}} | ||
- | * [[http://llvm.org/releases/3.6.2/docs/index.html|Documentația]] LLVM | ||
- | * Loop Unrolling: | ||
- | * Dragon Book: Capitolele 10.4.5, 9.6 | ||
- | * Muchnik: Capitolul 18 (Secțiunea 18.4), Capitolul 14 | ||
- | * Testare:<del> {{:cpl:concurs-teste.zip|Teste}}</del> {{:cpl:concurs-teste-v2.zip|Teste}} |