Intel Threading Building Blocks Markku Vajaranta Esko Pekkarinen
TBB Pähkinänkuoressa C++ luokkamallinen rinnakkaisuus Abstrahoi rinnakkaisuutta korkean tason tehtävät (tasks) ja niiden skedulointi suuri määrä tehtäviä suhteessa säikeisiin Kaupallinen ja avoin versio saatavilla uusi lisenssi $299, lisenssin uusinta $120
Intel lupaa Intel Threading Building Blocks (Intel TBB) is a library that supports scalable parallel programming using standard ISO C++ code. It does not require special languages or compilers. It is designed to promote scalable data parallel programming. Additionally, it fully supports nested parallelism, so you can build larger parallel components from smaller parallel components. To use the library, you specify tasks, not threads, and let the library map tasks onto threads in an efficient manner. The net result is that Intel Threading Building Blocks enables you to specify parallelism far more conveniently than using raw threads, and at the same time can improve performance.
Vaatimuksia Intelin CPU: Vähintään: Intel(R) Pentium(R) 4 Suositus: Intel(R) Core(TM) 2 Duo processor tai Intel(R) Xeon(R) processor SSE2, SSE3, SSSE3 parantavat suorituskykyä Käyttöjärjestelmät: Windows: 7, Vista, Xp Linux OS X: 10.6.7 tai uudempi Release notes v. 4.0
Kääntäjä Tukee yleisimpiä kääntäjiä: Intel C++ Composer XE 2011 Intel C++ Compiler 11.1 Microsoft Visual C++ 8.0 Linux: gcc 3.4 OS X gcc 4.0.1 Xcode tool suite 3.2.5 Käännökseen otettava mukaan tbb kirjasto, joka on saatavilla Intelin sivuilta esim. g++ -O3 -o software source.cc -ltbb
Valmiita menetelmiä Silmukoiden rinnakkaistaminen parallel_for parallel_do Rinnakkain käsiteltävät säiliöt Hajautustaulu: concurrent_hash_map<t> Vektori: concurrent_vector<t> Jono: concurrent_queue<t> Poissulkeminen Lukko ja semafori Atomiset muuttujat, atomic<t> Muistin varaus scalable_allocator<t> cache_aligned_allocator<t> Tehtävät Liukuhihnoitus
Tehtävät Tyypillisesti pieniä yksittäisiä rutiineja Huomattavasti nopeampia käynnistää ja tuhota kuin säikeet Linux: 18x Windows: yli 100x Rinnakkaisuuden toteutus, kun valmiita rakenteita ei voida käyttää Luokka task execute(): tehtävän suoritus, paluuarvona osoitin seuraavaksi suoritettavaan tehtävään tai NULL spawn(task &child): siirtää tehtävän child odottamaan pääsyä suoritukseen spawn_and_wait_for_all(task &child): siirtää tehtävän child odottamaan pääsyä suoritukseen ja odottaa lapsitehtävien lopettamista recycle-funktiot: tehtävän uudelleensuoritus
Tehtävien skedulointi Epäreilu tehtävien skedulointi Kuorman tasaus jakamalla tehtäviä säikeille Säikeen suoritusjärjestys Syvyys-ensin suoritus Leveys-ensin varkaus 1. Edellisen tehtävän suorituksen palauttama tehtävä 2. Oman jonon alin (uusin) tehtävä 3. Satunnaisen jonon ylin (vanhin) tehtävä Task Y 3 1 Task X spawn() Task B 2 Task Z Task A Thread 1 Thread 2 Top (oldest) 2 1 Bottom (newest)
Esimerkki: Helppo liukuhihnoitus 1/2 Verkkoreitittimen simulointi - Tiedostosta data sisään, Bandwidth management, NAT, IP routing - IP paketit toisistaan riippumattomia -> tbb::paralellel_pipeline
Esimerkki: Helppo liukuhihnoitus 2/2 Teoreettinen suorituskyvyn parannus: 24x -> ~7.2sec suoritusaika Todellinen: ~19x -> 9.094sec -http://software.intel.com/en-us/articles/network-router-emulator/
Testiympäristö Debian GNU/Linux Intel Core2Duo E6550 @2.33GHz, SSSE3 gcc 4.4.5 export CPLUS_INCLUDE_PATH=/home/username/tbb/include/ Paketti suoraan Intelin sivuilta, tbb40_233oss_lin.tgz edit bin/tbbvars.sh export TBBROOT=/home/username/tbb/include/tbb source tbbvars.sh intel64
Piin likiarvon laskeminen mpci (ei-säikeistetty) mcpi_omp (OpenMP) mcpi_tbb (TBB) Suoritusaika (s) 18,53 9,29 (-49,9%) 9,27 (-50,0%) Koodia (riviä) 34 36 67 (+76,5%) Esimerkkiajo: 500 000 000 näytepistettä OpenMP: tarvitaan kaksi #pragma-riviä TBB: tarvitaan SumMCpi_Parallel-luokka
Alkulukujen laskeminen 1/2 Eratostheneen seula on algoritmi kaikkien alkulukujen, jotka ovat pienempiä kuin n, löytämiseksi 1. Kirjoitetaan lista kaikista luonnollisista luvuista 2-n 2. Poistetaan listasta kaikki luvun 2 monikerrat (4, 6, 8 jne.). 3. Listan seuraava jäljellä oleva luku q (=3) on alkuluku. 4. Poistetaan listasta kaikki ne luvun q monikerrat, jotka ovat suurempia kuin q (6,9,12 jne.) 5. Toistetaan vaiheita 3 ja 4, kunnes listan seuraava jäljellä oleva luku on suurempi kuin listan suurimman luvun n neliöjuuri. 6. Lopulta listassa on jäljellä vain alkulukuja. Tehokkain tapa löytää pienet alkuluvut (alle 10 000 000) http://fi.wikipedia.org/wiki/tiedosto:new_animation_sieve_of_erat osthenes.gif
Alkulukujen laskeminen 2/2 Toteutuksesta: Lukujen listana concurrent_vector<bool>, jossa n alkiota Aloittetaan pienimmästä alkuluvusta q=2 q:n monikerrat merkitään yhdistetyksi luvuksi (ei-alkuluku) rinnakkain parallel_for:in avulla Etsitään seuraava alkuluku, joka on suurempi kuin q ja pienempi kuin n. Toistetaan edellinen. Lopulta vektorissa on jäljellä true kaikkien alkulukujen kohdalla Rinnakkainen toteutus nopeampi yli 200 000 alkiolla 2 4 6 8 15 16 18 20 29 30 32 34 3 9 12 15 31 32 33 35 60 63 65 68
Joitakin käyttökohteita Unreal 3 engine Autodesk Maya 3D (plugin) Dreamworks animation säikeiden muistinvarauksen nopeuttaminen: tbb_malloc