C'est tellement pris en compte qu'à une époque pas si éloignée, le scheduler de linux avait un léger problème : il migrait « automatiquement » des threads même quand il n'en avait pas besoin (heureusement depuis le comportement a été corrigé). Ça donnait quelque chose du genre :
cpu0 - thread 0 fait qq chose.
cpu1 - « rien » à faire.
[INT - on repasse dans l'ordonnanceur, qui s'aperçoit que cpu1 ne fait rien.]
sched: Bon, on va lui filer du boulot hein. Hey, thread 0, va donc sur cpu1 !
thread0 : Euh mais en fait, je bosse déjà sur cpu 0 moi.
sched : On ne discute pas ! On partage le travail ici, monsieur ! Il faut que tout le monde bosse la même charge ! Et n'oublie pas de remplir les formulaires de changement de bur^Wcontexte !
thread0 : OK chef.
[INT - cpu0 ne fout « rien »]
sched: Hey, thread 0, va donc bosser avec cpu0 !
thread 0 : hein ? Mais vous m'avez dit d'aller voir cpu1 !
sched: ON NE DISCUTE PAS !
thread 0 : bureaucrate à la con ...
[thread 0 change de contexte, avec remplissage des formulaires correspondants ...]
Blague à part, je ne fais que fixer un thread sur un processeur/coeur donné, rien de plus, rien de moins. L'ordonnanceur du noyau a tout loisir de préempter ce thread pour y faire passer un job de plus haute priorité s'il en a le besoin. En pratique c'est assez rare que ça arrive, parce que je bosse sur un cluster : je lance mon batch, ça attaque un noeud dont je connais par avance la topologie (important ça, parce que certains noeuds sont NUMA et d'autres non, ce qui change beaucoup la stratégie de parallélisation).
La première chose que fait l'openmp d'intel (qui n'est pas mal du tout, avec un overhead assez minime comparé à d'autres implémentations que je connais) c'est de spawner des pthreads (donc un « bête » pthread_create()) et de les fixer sur des processeurs, parce que l'objectif quand tu fais de la programmation parallèle, c'est d'optimiser à fond la localité des données, et de bien séparer les tâches/les ensemble de données sur lesquelles tu veux bosser.
Ta référence à « thread private », etc., n'est valable que pour OpenMP (qui peut être très bien hein, mais qui a aussi de sérieuses limitations).
« De plus, vu l'architecture Intel, le goulot d'étranglement doit rapidement être la RAM. »
Sur Montecito on a 12 Mo de cache L3, et une architecture plutôt très bien foutue dans le cas des calculs flottants et de calcul sur des flux de données. La bande-passante mémoire est plutôt bonne (de l'ordre de 10Gio/s), donc non, ce n'est pas particulièrement gênant.
Je crois que tu ne saisis pas bien la nature de mon travail, et les outils avec lesquels je bosse. :-) Les pthreads sont gérés par linux, mais par contre j'ai des threads de niveau utilisateur (ce qui revient peu ou prou à un ensemble de couples [pointeur de fonction, pointeur sur arguments à traiter]), qui ont donc un overhead quasi-nul pour mon calcul, mais que je peux affecter au thread noyau qui m'intéresse (et donc au processeur qui m'intéresse, puisque mes threads sont vissés sur un proc particulier). Ça me permet de faire des opérations très fines sur mes sections parallèles (et comme je suis au cycle près, j'ai besoin de ce niveau de contrôle, car même comme ça, il existe de nombreux effets indésirables qui peuvent survenir et qui sont difficiles à diagnostiquer : cache thrashing, faux partage, alignement des données ...).
[^] # Re: Le fortran
Posté par lasher . En réponse au journal Qu'est-ce qu'un langage sécurisé ?. Évalué à 2.
cpu0 - thread 0 fait qq chose.
cpu1 - « rien » à faire.
[INT - on repasse dans l'ordonnanceur, qui s'aperçoit que cpu1 ne fait rien.]
sched: Bon, on va lui filer du boulot hein. Hey, thread 0, va donc sur cpu1 !
thread0 : Euh mais en fait, je bosse déjà sur cpu 0 moi.
sched : On ne discute pas ! On partage le travail ici, monsieur ! Il faut que tout le monde bosse la même charge ! Et n'oublie pas de remplir les formulaires de changement de bur^Wcontexte !
thread0 : OK chef.
[INT - cpu0 ne fout « rien »]
sched: Hey, thread 0, va donc bosser avec cpu0 !
thread 0 : hein ? Mais vous m'avez dit d'aller voir cpu1 !
sched: ON NE DISCUTE PAS !
thread 0 : bureaucrate à la con ...
[thread 0 change de contexte, avec remplissage des formulaires correspondants ...]
Blague à part, je ne fais que fixer un thread sur un processeur/coeur donné, rien de plus, rien de moins. L'ordonnanceur du noyau a tout loisir de préempter ce thread pour y faire passer un job de plus haute priorité s'il en a le besoin. En pratique c'est assez rare que ça arrive, parce que je bosse sur un cluster : je lance mon batch, ça attaque un noeud dont je connais par avance la topologie (important ça, parce que certains noeuds sont NUMA et d'autres non, ce qui change beaucoup la stratégie de parallélisation).
La première chose que fait l'openmp d'intel (qui n'est pas mal du tout, avec un overhead assez minime comparé à d'autres implémentations que je connais) c'est de spawner des pthreads (donc un « bête » pthread_create()) et de les fixer sur des processeurs, parce que l'objectif quand tu fais de la programmation parallèle, c'est d'optimiser à fond la localité des données, et de bien séparer les tâches/les ensemble de données sur lesquelles tu veux bosser.
Ta référence à « thread private », etc., n'est valable que pour OpenMP (qui peut être très bien hein, mais qui a aussi de sérieuses limitations).
« De plus, vu l'architecture Intel, le goulot d'étranglement doit rapidement être la RAM. »
Sur Montecito on a 12 Mo de cache L3, et une architecture plutôt très bien foutue dans le cas des calculs flottants et de calcul sur des flux de données. La bande-passante mémoire est plutôt bonne (de l'ordre de 10Gio/s), donc non, ce n'est pas particulièrement gênant.
Je crois que tu ne saisis pas bien la nature de mon travail, et les outils avec lesquels je bosse. :-) Les pthreads sont gérés par linux, mais par contre j'ai des threads de niveau utilisateur (ce qui revient peu ou prou à un ensemble de couples [pointeur de fonction, pointeur sur arguments à traiter]), qui ont donc un overhead quasi-nul pour mon calcul, mais que je peux affecter au thread noyau qui m'intéresse (et donc au processeur qui m'intéresse, puisque mes threads sont vissés sur un proc particulier). Ça me permet de faire des opérations très fines sur mes sections parallèles (et comme je suis au cycle près, j'ai besoin de ce niveau de contrôle, car même comme ça, il existe de nombreux effets indésirables qui peuvent survenir et qui sont difficiles à diagnostiquer : cache thrashing, faux partage, alignement des données ...).