DivideConcept.net

le blog de divide.

gains de la parallelisation CPU, assembleur, et Qt 4.6 beta [update: tutorial installation]

Mon projet actuel nécessitant du traitement CPU temps réel sur de gros paquets de données, je me suis penché sur les possibilités de parallelisation CPU et le gain réel qu’on pouvait en tirer.
Il existe pour cela 2 techniques cumulables: le SSE et le multicore.



Gains réels de la parallélisation

Le SSE, introduit en 1999 par Intel (puis repris par AMD) et successeur du MMX, et ses dérivés SSE2 (2001) et SSE3 (2004), permet de traiter 4 nombres simple précision (32bit) en parallèle, en utilisant des registres 128 bits (quand au SSE2 il traite 2 nombres double-précision (64bit), et le SSE3 permet de faire des operations au sein des nombres stockés dans une unité 128 bit). On est donc censé avoir un gain théorique de x4. Il s’avère en pratique que ce gain est plus proche de x3, même utilisé à plein rendement.

Les processeurs multi-coeurs devenant un standard depuis quelques années, et avec l’arrivée récente de la nouvelle génération Intel les quad-core devenant de plus en plus répandus, il est logique de prendre en compte cette nouvelle manière de programmer les traitements. D’autant qu’une fois l’architecture multi-thread mise en place, celle-ci ne nécessite pas de reprogrammation pour tenir compte des futurs coeurs supplémentaires.
Ayant récemment acquis un core i5, je m’attendais donc à un gain de x4 en utilisant 4 threads simultanément au lieu d’une seule. Et bien les résultats sont tout autre: non seulement la création d’une thread prend du temps -quelques milliseconds, pas grand chose donc, mais dans un contexte temps réel cela a toute son importance-, mais les gains réels sont bien en deça de x4: avec de 2 threads lancé le gain est de x1.5, et avec 4 thread seulement de x2 ! Les 4 coeurs sont pourtant censé travailler indépendament les uns des autres sans se ralentir mutuellement…

edit 12/11/2009: cela est peut-être aussi du au fait que mes tests dépassaient le cache processeur. L’execution est beaucoup plus rapide lorsqu’on reste dans cette limite (buffer de 2-3 MB tout au plus). L’écart est donc probablement moins important et le gain quad-core plus proche du x3 que d’un x2.

Il y a donc une sacré palier entre les gains théoriques et réels: SSE et quad-core cumulé, le gain aurait du être de 4*4=x16, il n’est que de 3*2=x6. Toujours bon à prendre ceci dit !

edit 12/11/2009: le gain peut plutot être considéré de 3*3=x9

Et l’assembleur ?

Tentant de tirer la moindre parcelle de performance du CPU, j’ai également écris quelques routines en assembleur. Pour arriver au constat suivant: ce n’est vraiment plus d’actualité !

 Au dela du fait que l’écriture de routines assembleur est pénible (le langage est simple, mais au bout de quelques lignes l’ensemble devient rapidement très abstrait et le raisonnement dur à reconstruire), à mon grand désarrois j’ai constaté que les routines équivalentes écrites en langage C++ clair étaient quasiment aussi rapides à l’execution ! Et les fonctions pré-écrites tels que memcpy() et memset() sont déjà optimisés pour tirer partie des registres 128bits…
Pire, les compilateurs semblent connaitre certaines subtilités concernant les processeur modernes qui échappent au commun des mortel, rendant même du code assembleur moins rapide que certains code C++… Dans les 2 cas, les différences de performance se jouent à 2% près, et du code C++ pourra indifférement être compilé en 32bit ou 64bit contrairement à de l’assembleur qui necessitera une réécriture.
Bref il est loin le temps ou Carmack utilisait l’assembleur pour coder les routines de rendu de Wolfenstein 3D…



Qt 4.6beta

La beta de l’environnement de développement Qt 4.6 vient d’être publié aujourd’hui: au dela des corrections de bug de la 4.6techpreview1, elle apporte des binaires officiels et un installeur pour Windows/Mac, et surtout Qt Creator 1.3 qui a bien évolué depuis la 1.2.90: encore plus d’inline completion, structures des dossiers, nouvelles possibilités de debuggage.

-Qt 4.6 beta
-Qt Creator 1.3 beta
-mon article précedent sur Qt qui contient quelques astuces/tutoriaux.

Pour installer l’environnement 4.6beta1 sur Windows, voici un step-by-step:

Telecharger qt-win-opensource-4.6.0-beta1-mingw.exe et qt-creator-win-opensource-1.3.0-beta.exe

1. Installer qt-win-opensource-4.6.0-beta1-mingw en cochant la case pour telecharger MingW
2. Installer qt-creator-win-opensource-1.3.0-beta en laissant toutes les options par défaut
3. Lancer Qt Creator, aller dans Tools/Options/Qt4, cliquer sur “+” et rajouter:
Version Name: 4.6beta1
QMake Location: c:\qt\4.6.0-beta1\bin\qmake.exe
MinGw Directory: C:\MinGW
4. Cliquer sur “Rebuild”, et mettre Default Qt Version sur “4.6beta1″
5. Dans Help\Documentation, cliquer sur “Add…”
et sélectionner tous les fichiers dans C:\Qt\4.6.0-beta1\doc\qch, puis cliquer sur apply

14 commentaires pour “gains de la parallelisation CPU, assembleur, et Qt 4.6 beta [update: tutorial installation]”

  1. skaven dit :

    Pour le multicore, je crée mes threads au lancement de l’appli et je les ferme quand l’appli termine. C’est mon programme qui dispatch les traitements.
    Le ‘faible’ gain entre 1, 2 et 4 core peut aussi être du au cache CPU et à la manière dont tu traites tes données. Sur PS3, on ‘compilait’ toutes les datas dans des formats cache-friendly.
    A l’inverse, le rechargement des caches peut-être très long et contre-performant. Sur PS2, on désactivait le cache de l’EE pour traiter certaines données.
    Aligne tes données sur 4octets ou plus. Le padding est ton amis.
    Si tu as utilises beaucoup le FPU, le controlleur x87 peut être paramétré pour faire ses calculs internes dans différentes précisions (23bits, 31 bits,…). Plus il y a de bits, plus ses calculs seront lents et précis. (regarde la fonction control87).
    Profite d’avoir un linux sous la main pour tester valgrind avec ton code. Il y a un outil de détection de défauts de cache. Utilise un profiler pour détecter les goulots.

  2. divide dit :

    Yup toutes mes données sont paddés sur 128bits (SSE oblige).
    J’ai pensé aux 4 threads permanentes, faut que je vois comment concilier ça élégament avec Qt (dont le système de gestion des threads est remarquablement user-friendly).
    Sinon je ne connaissait pas le controlleur x87, j’y jetterai un coup d’oeil !

  3. ChevalZombie dit :

    Je ne comprend pas la moitié, mais c’est intéressant :)

  4. ap0 dit :

    Rien que pour pouvoir dire “J’ai codé mes routines en asm”, ça vaut le coup.

  5. divide dit :

    Ouai t’as vu !
    Mais c’est con qu’au moment où ça aurait pu m’être utile, ça soit devenu inutile… Bref j’ai perdu 2 jours pour rien :]

  6. Pipou dit :

    Pourquoi parler de temps de création de thread ? En théorie, tu peux créer tes threads au début d’un programme et les utiliser au besoin (du coup, t’évites le cout de création).
    Y a un truc pas mal pour .NET, le CCR, qui gère la programmation multi-thread avec une approche originale et assez plaisante à programmer et qui assure une bonne utilisation du temps des CPU

    http://www.microsoft.com/ccrdss/ (c’est payant, mais c’est fourni gratos avec la version Express de Microsoft Robotics Studio)
    (DSS, ça rajoute une couche réseau pour faire de l’appli “orientée service”, où plutot que répartir entre CPU, tu répartis entre machine)

  7. divide dit :

    Dans mon appli je n’ai besoin que ponctuellement de faire des gros calculs, à ce titre ça me semblait plus propre de lancer des threads avec chacune ses parametres quand c’était necessaire (la classe QThread de Qt est parfaite pour ça), et ne pas garder des thread inutiles le reste du temps… A priori je conserverai ce principe sauf si je vois que la perte de temps à la création est trop importante à l’usage.

  8. deltree dit :

    quand tu pense que les vieux jeux style “le 5eme axe” ont été codé 100 en ASM….
    pinaise, tu te dis qu’on est des gamins a coté.

  9. mODE ON dit :

    THAles thales, bac s, vien a la rescousse, des pulsion NAISSEnt dans mon pouce, la ganga pousse SANSCESSE;

    sliders bienvenue dans les mondes parralles.

  10. Lhelico dit :

    C’est clair que depuis une paire d’année, mieux vaut utiliser les intrinsics que coder directos en ASM, le compilo saura arranger plus intelligemment que toi les appels ASM qu’il y a derrieres.

    Pour le multithread, fait gaffe a la localité de tes données, genre sur des images, mieux vaut splitter le travail d’une image en N, que traiter N images en parrallèle. Apres ca depend aussi beaucoup de ton algo. Enfin, check OpenMP, je l’ai utilisé pas mal au taff (multithreading de calcul de grosses matrices creuses), et putain, avec une ligne de pragma alacon, j’étais a 1.8x sur deux cores ! (avec divers optims de plus, j’arrivais pas loin des perfs de la MKL ).

    Ha ouais, d’ailleurs, jette un coup d’oeuil a la MKL, voire juste GotoBLAS (tu fais pas mal de traitement d’images j’ai cru comprendre, ca se fout facile dans des matrices ces bricoles), t’aura un gain du SIMD/Multithread de taré pour pas beaucoup d’effort de dev.

  11. billiob dit :

    Sur les tous derniers noyaux linux (2.6.32…), il a “perf” (http://perf.wiki.kernel.org) qui est assez génial pour faire du profiling.

  12. wat dit :

    mODE ON a dit :
    THAles thales, bac s, vien a la rescousse, des pulsion NAISSEnt dans mon pouce, la ganga pousse SANSCESSE;
    sliders bienvenue dans les mondes parralles.

    wat

  13. Wiz dit :

    iN DA BUTT ?

  14. emule dit :

    what?

Laisser un commentaire

Si vous avez un compte sur WeFrag, connectez-vous pour publier un commentaire.

Vous pouvez, entre autres, utiliser les tags XHTML suivant :
<a href="" title="">...</a>,<b>...</b>,<blockquote cite="">...</blockquote>,<code>...</code>,<i>...</i>