Histoire d'être un peu plus précis : LLVM génère du code assembleur et objet (.o). Il s'appuie toujours (pour le moment) sur GNU ld/gold pour la résolution des liens (ça va bientôt changer). Donc si je reprends ton schéma :
Autant j'aime bien VS en tant qu'IDE, autant les rares fois où j'ai utilisé XCode (qui a fait des progrès depuis que je l'ai utilisé, certes), j'ai trouvé que c'était vraiment tout pourri. Après comme mon expérience date beaucoup, je me suis tourné vers des gens qui développent professionnellement pour Mac OS X / iOS. Ils trouvent que cet IDE est vraiment lourd est pas pratique, notamment comparé à VS. Mais aussi (surprise!) comparé à NetBeans!
Visual Studio n'implémentera sans doute jamais C99 dans sa totalité. Seules les fonctionnalités qui se recoupent avec C++ le seront. C'est dit quelque part sur le site de Herb Sutter. En gros : VSC++ != VSC (qui n'a jamais existé). Sutter dit qu'ils se concentrent uniquement sur l'implémentation de C++. Le reste est un effet de bord bonus.
Perso j'utilise/utilisais rdtsc parce que ca me permet d'avoir un nombre de cycles plutot qu'un nombre de nanosecondes. C'est important, car j'etais reellement au cycle pres, et que certains effets dus aux latences/debits memoire peuvent influer sur la performance finale (par ex: un processeur a 1GHz avec un bus a "1333MHz", la latence pour acceder a la memoire sera minime, alors que pour le meme bus memoire avec un proc. a 3GHz, les latences auront triple).
Non : c'est par défaut en fait sous Windows, c'était une exemple, mais chut, on note la non connaissance sur les autres OS.
Ma « nouvelle » machine sous Windows 7 y'a 1-2 ans avait le windows media player installé par défaut. J'ai essayé de l'utiliser histoire de voir comment ça avait changé. Bon ben, un « l'application ne répond plus » plus tard (et en fait, plusieurs, je voulais voir si c'était restreint à une seule vidéo), j'ai fini par faire comme d'hab : installer VLC. Et en règle générale sous Windows, j'ai toujours fini par avoir sous le coude une « check-list » des softs à installer (7zip, filezilla, vlc, etc.), car Windows est trop limité sinon.
Avec ces discours-là, on se retrouve avec des Américains qui disent que le parti démocrate est de gauche, et les républicains de droite. La bonne blague. La Gauche et la Droite sont effectivement bien définies. Je te propose d'aller sur le site de Political Compass pour te faire une idée. Ils ont une explication de la façon dont ils positionnent les hommes politiques sur leur grille 2D. Grosso-modo, ils ont un axe horizontal « Gauche-Droite » qui prend en compte la politique économique de la personne considérée, et un axe vertical « libertaire-autoritaire » concernant les contraintes imposées aux individus par l'État.
Un de mes collègue a aussi pu montrer un exemple de code multithreadé qui peut être « optimisé » en respectant les règles du modèle mémoire de Java, et qui malgré tout provoquera une exécution non conforme aux souhaits du programmeur.
Enfin, juste pour que nous soyons d'accord : je suis d'accord avec toi sur le fond : quand un langage intègre un modèle mémoire, c'est beaucoup mieux, et ça autorise la création de programmes concurrents dont le comportement est prévisible. Encore faut-il que le modèle en question soit correct/implémentable. Même un environnement tel qu'OpenMP qui est d'une certaine manière plus simple que le modèle mémoire de Java est extrêmement complexe à prouver en tant que modèle mémoire.
Bah, le modèle SPARC v9 (RMO, Relaxed Memory Order) propose différents types de barrières mémoire: celles qui stoppent tout tant que toutes les opérations en cours ne sont pas terminées; celles qui permettent d’exécuter des loads spéculativement; celles qui permettent d'exécuter des loads et des d’exécuter stores spéculativement (tant que les dépendances de données sont respectées); et même d'émettre des loads spéculativement malgré la présence d'une dépendance de contrôle.
Tu veux dire comme Java ? Parce que le premier modèle est cassé, et que le second (qui date de 2005) permet des trucs qui en pratique autorisent de briser la causalité.
Pour C++-11, ils ne se sont pas trop trop foulés : le principe-même d'un modèle mémoire c'est de définir la sémantique des "conflits" de lecture-écriture (data race). En disant "toute data race est un UB", en gros les gens de C-11 et C++-11 disent simplement "si tu as une data race, tout peut arriver, même que le compilo génère du code pour t'acheter 20000 big macs via le net en utilisant ta carte de crédit".
Le problème, c'est qu'il existe quelques (rares) cas ou les data races sont correctement contrôlées, i.e. on sait qu'il existe un conflit lecture/écriture sur une adresse mémoire, mais on sait évaluer l'amplitude de l'erreur, ou bien on n'a pas besoin de la toute dernière valeur de la variable, la n-keme valeur est OK aussi. C'est le cas dans les solveurs à relaxation chaotique par exemple. Avec C++, il est impossible de garantir quoi que ce soit, parce que le compilateur, pour des raisons d'optimisation, va peut-être mettre une valeur arbitraire a l'adresse de la variable ciblée.
Bon, "Sequential consistency" ça va beaucoup plus loin que "cohérent".
<pedantic>
Sequential consistency (SC—"Constance séquentielle" ?) garantit que tous les threads d'une machine a mémoire partagée voient les lectures et écritures mémoire dans un ordre identique. En pratique le matériel n'a pas a garantir que l'ordre des opérations est strictement identique, mais il doit apparaître comme si. Donc si j'ai 2 threads, dont l'un des deux au moins écrit dans une variable v, lorsque T0 écrit, alors T1 doit voir la séquence des valeurs de v changer au "même" moment. Les deux threads doivent donc s'accorder sur une séquence unique des valeurs successives de v.
La cohérence ("Cache consistency" ou "Coherence") relaxe fortement SC. Désormais, l'ordre des opérations se fait adresse mémoire par adresse mémoire. Ainsi, si j'ai 2 threads (T0,T1) et deux variables, x et y, Je me fiche de savoir si T1 et T2 voient les écritures de x et y de façon totalement identique en tant que "paire" d'adresses mémoire , tant que les accès individuels a x sont tous vus dans le même ordre par tous les threads, et que les accès a y idem. </pedantic>
Ah oui ? Mais quand j'installe un "flash blocker" (ou tout simplement que je n'ai pas de plugin flash installé avec mon navigateur), alors du coup j’empêche les sites web de diffuser leur pub "interactive" (lemonde.fr est un habitué du fait) ! Damn ! Vite, vite, il faut que j'installe Flash !
Et puis quand Flash aura disparu mais qu'une autre techno l'aura remplacé, au début ce sera OK, car une pub interactive en 3D et odoramat de temps en temps, ça va. Mais quand tout le monde voudra te faire sentir ton camembert en même temps que la nouvelle recette de Saupiquet, on verra si la recrudescence de bloqueurs d'odoramat ne se fera pas sentir. :-)
L’équipe dont je faisais partie se spécialise dans la création d'outils pour la mesure et l'analyse de performance. Ce sont loin d’être des manches. Tout ce dont tu parles, nous le savons bien. ;-) J'ai passé une soirée de rêve avec mon directeur à l’époque à utiliser gdb et essayer de comprendre ce qui se passait avec la MKL (multiplication de matrices) sur Itanium 2.
L’expérience joue un énorme rôle aussi. Faire la course aux cache misses (par exemple) n'est pas toujours payante car on sous-estime d'autres facteurs qui pourraient jouer sur la (non-)performance d'une application.
Pour répondre a ta deuxième question, je fais de la recherche dans une fac aux USA, mais pas en analyse/mesure de performance. Je fais dans les modèles d’exécution pour machines parallèles (c'est a dire : modèle de concurrence, modèle mémoire, et modèle de synchronisation). On implémente tout ça dans un runtime (que j’espère pouvoir libérer très bientôt).
Mon expérience sur du multicœur un peu massif (AMD Bulldozer/Interlagos 48 cœurs en mémoire partagée, NUMA, 4×12 cœurs) est contraire à la tienne. Tant qu'il n'y avait pas de frequency scaling et un FSB (sur archi Intel Core 2/Core 2 Quad), tout allait bien en utilisant la bonne version de rdtsc. Le moment où tu as de la variation dynamique de tension et de fréquence, avec en plus plusieurs processeurs reliés entre eux par un réseau d'interconnexion souvent un peu douteux, j'ai appris à mes dépends que rdtsc passait à la trappe (j'ai eu plusieurs fois droit à des comportements très étranges où je me trouvait au final avec un temps négatif, malgré mes précautions …).
Tu as tort. Utiliser rdtsc est parfaitement logique surtout si ton bench prend peu de temps (après tout, les risques de modification de fréquence sont bien moindres). Ça n'empêche pas qu'il faut une certain stabilité. Généralement lorsque je fais des micro-benchmarks, j'utilise un truc du genre:
for(outer=0;outer<MAX_OUTER;++outer){FLUSH_CACHES();#if OBSERVE_IN_CACHE_BEHAVIORrun_kernel();// warm up caches #endifuint64_texec_time=read_rdtsc();for(inner=0;inner<MAX_INNER;++inner){run_kernel();}exec_times[outer]=(double)(read_rdtsc()-exec_time)/MAX_INNER;}/* ... *//* exec_times[] contient un « histogramme » des différentes exécutions */REMOVE_OUTLIERS(exec_times,MAX_OUTER);// supprime les temps les plus courts et les plus longs en fonction de lubies statistiquesCOMPUTE_MEAN(exec_times,MAX_OUTER);// arithmétique, harmonique, etc., en fonction des besoins
Note que MAX_INNER/MAX_OUTER peuvent être extrêmement petits dans le cas de microbenchmarks, surtout si l'environnement de benchmarking permet de fixer un thread sur un cœur donné : on évite les variations dues à l'ordonnanceur qui est moins con qu'avant, mais qui va quand même réordonnancer certains threads pour les remettre sur le même cœur juste après… mais avec des caches et TLB qui ont eu droit à des entrées évincées.
Maintenant ce que j'appelle « micro-benchmarks », ce sont vraiment de minuscules benchs, où je teste un sous-système de mon micro-processeur. Genre je veux tester la latence réelle de mon cache L3 partagé : je vais faire tourner 4 threads en parallèle sur mon core i7, un par cœur. Ensuite je vais m'assurer que chaque thread copie un mot de 64 bits dans un registre, puis copie le (i+8×k)è mot dans le même registre à l'itération suivante, etc. J'ai besoin de faire i+8×k car les prefetchers des archis x86 ont tendance à rapatrier la ligne de cache adjacente lors d'un défaut de cache. Du coup il faut précharger au moins tous les 16 mots. L'autre problème étant que, au moins pour les micro-archis Intel, il existe un « stride préfetcher » (« préchargeur de distance » ? je ne sais pas comment traduire). Il détecte tout seul comme un grand si la distance entre deux mots mémoire est fixe. Si c'est le cas, il va précharger les mots mémoire suivants sans qu'on lui demande quoi que ce soit (dans la limite d'une page mémoire, donc pas au-delà de 4096 octets). Du coup il faut faire son sioux, et précharger un mot aléatoire dans la ligne de cache « suivante ».
Soupir…
Désolé pour le HS complet. J'ai pas pu m'empêcher. :)
Bon alors, dans le principe je suis d'accord. En pratique, comme dirait mon ancien directeur de thèse, « il y a peut-être 20 ou 30 personnes dans le monde qui savent réellement quels compteurs utiliser et ce qu'ils font (et ceux qui existent mais qui ne compte pas ce qu'on croit) ».
J'ai fait de l'analyse de performance pendant très longtemps. J'ai mis grosso modo un an à me retrouver avec un tout petit sous ensemble de compteurs qui comptent ce qu'il faut et dont je suis certain de ce qu'ils comptent. Et ce savoir est déjà dépassé : de Core 2/Core Quad on est passé à Nehalem, puis à Sandy Bridge… Ben mon savoir sur Nehalem était déjà à moitié faux (en plus du fait que certains compteurs avaient été renommés, et donc il fallait de nouveau tester ce qu'ils comptaient pour de vrai), et depuis les Sandy/Ivy Bridge, ben il y a peut-être 3 compteurs dont je suis sûr. :-)
Ceci étant dit, j'ai pas fait d'analyse de perf depuis un bail, mais mon directeur (avec qui j'ai causé y'a quelques jours) me disait que comparé aux autres outils existants (HPCToolKit, PAPI, PerfMon), Linuxperf est définitivement le plus fiable, au moins sur x86/Intel (à l'époque j'avais été regarder comment PAPI comptait certains événements dont j'avais besoin, et j'ai remarqué qu'ils prenaient le mauvais compteur… J'ai arrêté d'utiliser PAPI).
Je suis d'accord en ce que la méthodologie me semble peu rigoureuse. Mais en même temps, on peut sans doute faire en sorte de l'améliorer ! :-)
Ta suggestion de faire tout tourner sur un seul cœur les deux versions est à mon avis excellente : même s'il y a une race condition, les effets de bords ne seront pas réellement « visibles » dans le cas non thread-safe.
Les instructions atomiques sont certes plus lentes que des instructions normales, mais elles ont aussi quelques avantages/propriétés. Je vais en citer quelques uns:
Une instruction atomique sur x86 actuel (donc Core i5) effectue les opérations suivantes : load-modify-write. Pendant que ceci s'opère, le processeur verrouille la ligne contenant le mot à modifier, et souvent aussi le bus mémoire du cœur qui effectue la modification: le mot est chargé dans un registre, modifié/comparé en utilisant une des UAL du cœur qui a effectué l'op atomique, puis stocké à nouveau en mémoire.
Au sein d'un même processeur multi-cœur, lorsqu'on utilise une instruction atomique, seule la ligne de cache qui contient la donnée accédée est verrouillée. Ce qui est important avec ce constat, c'est que le cache lui-même n'est pas complètement verrouillé, et aussi qu'il n'y a pas « d'écriture retour » (write-back) vers la DRAM automatiquement après exécution d'une instruction atomique. Bref, il y a bien sérialisation des écritures/lectures sur une ligne de cache donnée, mais pas sur le bloc/niveau de cache complet (ce qui se faisait à une époque, le bus étant complètement verrouillé pour ce niveau de cache tant que l'op atomique avait lieu).
Si jamais tu n'utilises pas d'instruction atomique pour accéder à un mot partagé par plusieurs threads, et que ce mot n'est pas « isolé » tout seul sur sa ligne de cache, tu risques de provoquer un phénomène de faux partage (false sharing), c'est-à-dire que le mot est modifié et du coup indique que la ligne entière est modifiée. Si par hasard d'autres données étaient utilisées en lecture ou écriture par un autre thread sur un autre cœur (en L2 par ex), la ligne devient marquée invalide alors qu'en fait c'était pas le cas. Je ne sais pas si c'est ce qui se passe, mais il arrive qu'en induisant des délais supplémentaire, une opération « lisse » les effets de contention sur un certain composant mémoire (je ne sais pas si je suis clair).
Dans tous les cas, comme on te le faisait remarquer plus haut, si tu ne fournis pas ton code, on ne peut que spéculer.
clock_gettime() est la bonne fonction à appeler en effet. Avec l'option CLOCK_REALTIME si je me souviens bien.
En pratique sur un mono-socket multi-cœur comme décrit pas steckdenis, RDTSC reste OK.
Une autre façon de mesurer (avec rdtsc ou clock_gettime ou gettimeofday …) est simplement d'enrober le programme dans un thread que tu forces à s'exécuter sur un cœur donné, et lui laisser le soin d'appeler le reste du programme. Ensuite, tu peux utiliser des trucs genre pthread_barrier_* ou autres machins faits maison pour garantir que tous les threads sont synchronisés puis reprendre la mesure depuis le threads « launcher ».
Bon on va sans doute m'expliquer que je fais du code moche, mais qu'y a-t-il de mal à faire ce qui suit?
# on sait que le fichier contient que des entierscurrent_line=int(file_descriptor.readline())
Certes si jamais le fichier ne contient pas que des entiers, ça va casser, et donc au moment de debugger, il faudra séparer la ligne en deux. Mais bon de toute manière le bug existera même avec les deux lignes initiales.
Bon, j'ai fait un IUT. Pendant mes 2 ans a l'IUT, j'ai (je melange les deux annees):
Fait de l'algorithmique en C (en utilisant Visual Studio);
fait de la programmation événementielle en Visual Basic (avec VS aussi);
fait du C++ (la partie OO, pas de STL ou de templates);
fait du Java (en utilisant VisualAge a l’époque; d'autres faisaient du C++ plus avance a la place);
fait du XML et du XSL/T (d'autres faisaient du COBOL a la place);
fait de l'ASP (avec VS; d'autres faisaient du C++…);
fait du SQL (sur de l'Access et de l'Oracle).
En plus de cela, j'ai vu (je mélange encore les deux années):
De l'architecture des ordinateurs (de l'électronique numérique aux multi-processeurs, en passant par la façon dont les registres et la mémoire fonctionnent);
comment les principales fonctions d'un OS fonctionnent;
comment faire un makefile portable pour windows et linux;
les protocoles réseau (OSI, ethernet, TCP/IP, un tout petit peu de X25/frame relay);
comment faire de la prog système;
les bases de l'administration sous Linux et Windows;
comment concevoir des systèmes d'info avec le génie logiciel (aaaah, Merise et UML …);
comment modéliser des bases de données.
A cela s'ajoutent l'Anglais, les cours de communication et expression, les maths, la gestion et organisation, etc.
Bref. Les cours de système et environnement de programmation sont ceux qui m'ont appris comment la chaine de compilation se faisait en C. Je ne sais plus si j'ai vu comment on chaîne en Java en ligne de commande a l'époque, mais je suis certain qu'on m'a explique comment le système de packages fonctionnait.
Tout ça pour dire quoi ? En IUT, les profs on deux ans pour transformer des étudiants qui pour plus de la moitie (je dirais facilement les 2/3, voire les 3/4) ne savent pas réellement ce que signifie "faire de l'informatique" au moment ou ils arrivent en techniciens qualifiés. Ils n'ont pas toujours le temps de tout faire. Dans mon cas, le prof de Java était bien trop occupe a essayer de nous inculquer les principes de POO que nous n'avions qu'effleure en 1ere année en C++ (les trucs genre aller un peu plus loin dans la prog générique, l'overloading et le polymorphisme, la réutilisation de composants, etc.).
Comme tu le dis quelque part, compiler en Java ou en C c'est grosso modo la même chose. Tu as déjà appris la chaîne de compil en C. Pourquoi se faire chier a passer du temps a te faire passer par un shell alors que y'a tellement d'autres trucs a t'expliquer ?
[^] # Re: Il parait que...
Posté par lasher . En réponse au journal Overmon recherche des freelance. Évalué à 10.
Est-ce que quelqu'un a validé le formulaire avec le moteur du W3C?
… Quoi, qu'est-ce j'ai dit ?
[^] # Re: Superbe article !
Posté par lasher . En réponse à la dépêche LLVM 3.3 et Clang 3.3. Évalué à 5.
Histoire d'être un peu plus précis : LLVM génère du code assembleur et objet (
.o
). Il s'appuie toujours (pour le moment) sur GNU ld/gold pour la résolution des liens (ça va bientôt changer). Donc si je reprends ton schéma :Clang → LLVM → fichier objet → linker → executable.
[^] # Re: Pendant ce temps...
Posté par lasher . En réponse à la dépêche C++11 : sur le fil. Évalué à 2.
Autant j'aime bien VS en tant qu'IDE, autant les rares fois où j'ai utilisé XCode (qui a fait des progrès depuis que je l'ai utilisé, certes), j'ai trouvé que c'était vraiment tout pourri. Après comme mon expérience date beaucoup, je me suis tourné vers des gens qui développent professionnellement pour Mac OS X / iOS. Ils trouvent que cet IDE est vraiment lourd est pas pratique, notamment comparé à VS. Mais aussi (surprise!) comparé à NetBeans!
[^] # Re: Et pendent ce temps chez Microsoft...
Posté par lasher . En réponse à la dépêche C++11 : sur le fil. Évalué à 2.
Visual Studio n'implémentera sans doute jamais C99 dans sa totalité. Seules les fonctionnalités qui se recoupent avec C++ le seront. C'est dit quelque part sur le site de Herb Sutter. En gros : VSC++ != VSC (qui n'a jamais existé). Sutter dit qu'ils se concentrent uniquement sur l'implémentation de C++. Le reste est un effet de bord bonus.
[^] # Re: y'a trop peu d'infos pour t'aider.
Posté par lasher . En réponse au journal Performances des processeurs Intel et optimisation. Évalué à 2.
Perso j'utilise/utilisais
rdtsc
parce que ca me permet d'avoir un nombre de cycles plutot qu'un nombre de nanosecondes. C'est important, car j'etais reellement au cycle pres, et que certains effets dus aux latences/debits memoire peuvent influer sur la performance finale (par ex: un processeur a 1GHz avec un bus a "1333MHz", la latence pour acceder a la memoire sera minime, alors que pour le meme bus memoire avec un proc. a 3GHz, les latences auront triple).[^] # Re: Un utilisateur reconnaissant
Posté par lasher . En réponse au journal Attention au dépôt debian-multimedia.org !. Évalué à 3.
Ma « nouvelle » machine sous Windows 7 y'a 1-2 ans avait le windows media player installé par défaut. J'ai essayé de l'utiliser histoire de voir comment ça avait changé. Bon ben, un « l'application ne répond plus » plus tard (et en fait, plusieurs, je voulais voir si c'était restreint à une seule vidéo), j'ai fini par faire comme d'hab : installer VLC. Et en règle générale sous Windows, j'ai toujours fini par avoir sous le coude une « check-list » des softs à installer (7zip, filezilla, vlc, etc.), car Windows est trop limité sinon.
[^] # Re: Durée de l’épreuve
Posté par lasher . En réponse à la dépêche Concours de programmation CodinGame le 28 mai 2013. Évalué à 3.
Reponds en Anglais. Toujours repondre dans la langue dans laquelle on te parle, si tu sais la parler. :)
[^] # Re: Ai-je bien compris ?
Posté par lasher . En réponse au journal Performances des processeurs Intel et optimisation. Évalué à 2.
J'ai pas, mais il a enfin réussi à récupérer un visa, donc il est de retour. Je lui demanderai. :)
[^] # Re: manipulations ?
Posté par lasher . En réponse au journal Méthode de calcul. Évalué à 2.
Avec ces discours-là, on se retrouve avec des Américains qui disent que le parti démocrate est de gauche, et les républicains de droite. La bonne blague. La Gauche et la Droite sont effectivement bien définies. Je te propose d'aller sur le site de Political Compass pour te faire une idée. Ils ont une explication de la façon dont ils positionnent les hommes politiques sur leur grille 2D. Grosso-modo, ils ont un axe horizontal « Gauche-Droite » qui prend en compte la politique économique de la personne considérée, et un axe vertical « libertaire-autoritaire » concernant les contraintes imposées aux individus par l'État.
[^] # Re: Ai-je bien compris ?
Posté par lasher . En réponse au journal Performances des processeurs Intel et optimisation. Évalué à 2.
J'en profite pour rajouter une autre référence (mêmes auteurs) :
Verification of Causality Requirements in Java is Undecidable. C'est quand même ballot. :-)
Un de mes collègue a aussi pu montrer un exemple de code multithreadé qui peut être « optimisé » en respectant les règles du modèle mémoire de Java, et qui malgré tout provoquera une exécution non conforme aux souhaits du programmeur.
Enfin, juste pour que nous soyons d'accord : je suis d'accord avec toi sur le fond : quand un langage intègre un modèle mémoire, c'est beaucoup mieux, et ça autorise la création de programmes concurrents dont le comportement est prévisible. Encore faut-il que le modèle en question soit correct/implémentable. Même un environnement tel qu'OpenMP qui est d'une certaine manière plus simple que le modèle mémoire de Java est extrêmement complexe à prouver en tant que modèle mémoire.
[^] # Re: Ai-je bien compris ?
Posté par lasher . En réponse au journal Performances des processeurs Intel et optimisation. Évalué à 2.
Il y a des références dans cette présentation :
http://www.capsl.udel.edu/courses/eleg652/2012/slides/05_sm.pdf
[^] # Re: Ai-je bien compris ?
Posté par lasher . En réponse au journal Performances des processeurs Intel et optimisation. Évalué à 2.
Bah, le modèle SPARC v9 (RMO, Relaxed Memory Order) propose différents types de barrières mémoire: celles qui stoppent tout tant que toutes les opérations en cours ne sont pas terminées; celles qui permettent d’exécuter des loads spéculativement; celles qui permettent d'exécuter des loads et des d’exécuter stores spéculativement (tant que les dépendances de données sont respectées); et même d'émettre des loads spéculativement malgré la présence d'une dépendance de contrôle.
[^] # Re: Ai-je bien compris ?
Posté par lasher . En réponse au journal Performances des processeurs Intel et optimisation. Évalué à 2.
Tu veux dire comme Java ? Parce que le premier modèle est cassé, et que le second (qui date de 2005) permet des trucs qui en pratique autorisent de briser la causalité.
Pour C++-11, ils ne se sont pas trop trop foulés : le principe-même d'un modèle mémoire c'est de définir la sémantique des "conflits" de lecture-écriture (data race). En disant "toute data race est un UB", en gros les gens de C-11 et C++-11 disent simplement "si tu as une data race, tout peut arriver, même que le compilo génère du code pour t'acheter 20000 big macs via le net en utilisant ta carte de crédit".
Le problème, c'est qu'il existe quelques (rares) cas ou les data races sont correctement contrôlées, i.e. on sait qu'il existe un conflit lecture/écriture sur une adresse mémoire, mais on sait évaluer l'amplitude de l'erreur, ou bien on n'a pas besoin de la toute dernière valeur de la variable, la n-keme valeur est OK aussi. C'est le cas dans les solveurs à relaxation chaotique par exemple. Avec C++, il est impossible de garantir quoi que ce soit, parce que le compilateur, pour des raisons d'optimisation, va peut-être mettre une valeur arbitraire a l'adresse de la variable ciblée.
[^] # Re: Ai-je bien compris ?
Posté par lasher . En réponse au journal Performances des processeurs Intel et optimisation. Évalué à 2.
Bon, "Sequential consistency" ça va beaucoup plus loin que "cohérent".
<pedantic>
Sequential consistency (SC—"Constance séquentielle" ?) garantit que tous les threads d'une machine a mémoire partagée voient les lectures et écritures mémoire dans un ordre identique. En pratique le matériel n'a pas a garantir que l'ordre des opérations est strictement identique, mais il doit apparaître comme si. Donc si j'ai 2 threads, dont l'un des deux au moins écrit dans une variable
v
, lorsque T0 écrit, alors T1 doit voir la séquence des valeurs dev
changer au "même" moment. Les deux threads doivent donc s'accorder sur une séquence unique des valeurs successives dev
.La cohérence ("Cache consistency" ou "Coherence") relaxe fortement SC. Désormais, l'ordre des opérations se fait adresse mémoire par adresse mémoire. Ainsi, si j'ai 2 threads (T0,T1) et deux variables,
x
ety
, Je me fiche de savoir si T1 et T2 voient les écritures dex
ety
de façon totalement identique en tant que "paire" d'adresses mémoire , tant que les accès individuels ax
sont tous vus dans le même ordre par tous les threads, et que les accès ay
idem.</pedantic>
[^] # Re: Ça me choque
Posté par lasher . En réponse au journal Adblock maintenant installé par défaut sur Debian 7 : bonne chose ou initiative malheureuse ?. Évalué à 5.
Ah oui ? Mais quand j'installe un "flash blocker" (ou tout simplement que je n'ai pas de plugin flash installé avec mon navigateur), alors du coup j’empêche les sites web de diffuser leur pub "interactive" (lemonde.fr est un habitué du fait) ! Damn ! Vite, vite, il faut que j'installe Flash !
Et puis quand Flash aura disparu mais qu'une autre techno l'aura remplacé, au début ce sera OK, car une pub interactive en 3D et odoramat de temps en temps, ça va. Mais quand tout le monde voudra te faire sentir ton camembert en même temps que la nouvelle recette de Saupiquet, on verra si la recrudescence de bloqueurs d'odoramat ne se fera pas sentir. :-)
[^] # Re: Linux perf
Posté par lasher . En réponse au journal Performances des processeurs Intel et optimisation. Évalué à 2.
L’équipe dont je faisais partie se spécialise dans la création d'outils pour la mesure et l'analyse de performance. Ce sont loin d’être des manches. Tout ce dont tu parles, nous le savons bien. ;-) J'ai passé une soirée de rêve avec mon directeur à l’époque à utiliser gdb et essayer de comprendre ce qui se passait avec la MKL (multiplication de matrices) sur Itanium 2.
[^] # Re: Linux perf
Posté par lasher . En réponse au journal Performances des processeurs Intel et optimisation. Évalué à 4.
L’expérience joue un énorme rôle aussi. Faire la course aux cache misses (par exemple) n'est pas toujours payante car on sous-estime d'autres facteurs qui pourraient jouer sur la (non-)performance d'une application.
Pour répondre a ta deuxième question, je fais de la recherche dans une fac aux USA, mais pas en analyse/mesure de performance. Je fais dans les modèles d’exécution pour machines parallèles (c'est a dire : modèle de concurrence, modèle mémoire, et modèle de synchronisation). On implémente tout ça dans un runtime (que j’espère pouvoir libérer très bientôt).
[^] # Re: Linux perf
Posté par lasher . En réponse au journal Performances des processeurs Intel et optimisation. Évalué à 2.
Il fallait comprendre : "30 personnes par type de processeur". :)
[^] # Re: y'a trop peu d'infos pour t'aider.
Posté par lasher . En réponse au journal Performances des processeurs Intel et optimisation. Évalué à 5.
Mon expérience sur du multicœur un peu massif (AMD Bulldozer/Interlagos 48 cœurs en mémoire partagée, NUMA, 4×12 cœurs) est contraire à la tienne. Tant qu'il n'y avait pas de frequency scaling et un FSB (sur archi Intel Core 2/Core 2 Quad), tout allait bien en utilisant la bonne version de
rdtsc
. Le moment où tu as de la variation dynamique de tension et de fréquence, avec en plus plusieurs processeurs reliés entre eux par un réseau d'interconnexion souvent un peu douteux, j'ai appris à mes dépends querdtsc
passait à la trappe (j'ai eu plusieurs fois droit à des comportements très étranges où je me trouvait au final avec un temps négatif, malgré mes précautions …).[^] # Re: y'a trop peu d'infos pour t'aider.
Posté par lasher . En réponse au journal Performances des processeurs Intel et optimisation. Évalué à 8.
Tu as tort. Utiliser
rdtsc
est parfaitement logique surtout si ton bench prend peu de temps (après tout, les risques de modification de fréquence sont bien moindres). Ça n'empêche pas qu'il faut une certain stabilité. Généralement lorsque je fais des micro-benchmarks, j'utilise un truc du genre:Note que MAX_INNER/MAX_OUTER peuvent être extrêmement petits dans le cas de microbenchmarks, surtout si l'environnement de benchmarking permet de fixer un thread sur un cœur donné : on évite les variations dues à l'ordonnanceur qui est moins con qu'avant, mais qui va quand même réordonnancer certains threads pour les remettre sur le même cœur juste après… mais avec des caches et TLB qui ont eu droit à des entrées évincées.
Maintenant ce que j'appelle « micro-benchmarks », ce sont vraiment de minuscules benchs, où je teste un sous-système de mon micro-processeur. Genre je veux tester la latence réelle de mon cache L3 partagé : je vais faire tourner 4 threads en parallèle sur mon core i7, un par cœur. Ensuite je vais m'assurer que chaque thread copie un mot de 64 bits dans un registre, puis copie le (i+8×k)è mot dans le même registre à l'itération suivante, etc. J'ai besoin de faire i+8×k car les prefetchers des archis x86 ont tendance à rapatrier la ligne de cache adjacente lors d'un défaut de cache. Du coup il faut précharger au moins tous les 16 mots. L'autre problème étant que, au moins pour les micro-archis Intel, il existe un « stride préfetcher » (« préchargeur de distance » ? je ne sais pas comment traduire). Il détecte tout seul comme un grand si la distance entre deux mots mémoire est fixe. Si c'est le cas, il va précharger les mots mémoire suivants sans qu'on lui demande quoi que ce soit (dans la limite d'une page mémoire, donc pas au-delà de 4096 octets). Du coup il faut faire son sioux, et précharger un mot aléatoire dans la ligne de cache « suivante ».
Soupir…
Désolé pour le HS complet. J'ai pas pu m'empêcher. :)
[^] # Re: Linux perf
Posté par lasher . En réponse au journal Performances des processeurs Intel et optimisation. Évalué à 10.
Bon alors, dans le principe je suis d'accord. En pratique, comme dirait mon ancien directeur de thèse, « il y a peut-être 20 ou 30 personnes dans le monde qui savent réellement quels compteurs utiliser et ce qu'ils font (et ceux qui existent mais qui ne compte pas ce qu'on croit) ».
J'ai fait de l'analyse de performance pendant très longtemps. J'ai mis grosso modo un an à me retrouver avec un tout petit sous ensemble de compteurs qui comptent ce qu'il faut et dont je suis certain de ce qu'ils comptent. Et ce savoir est déjà dépassé : de Core 2/Core Quad on est passé à Nehalem, puis à Sandy Bridge… Ben mon savoir sur Nehalem était déjà à moitié faux (en plus du fait que certains compteurs avaient été renommés, et donc il fallait de nouveau tester ce qu'ils comptaient pour de vrai), et depuis les Sandy/Ivy Bridge, ben il y a peut-être 3 compteurs dont je suis sûr. :-)
Ceci étant dit, j'ai pas fait d'analyse de perf depuis un bail, mais mon directeur (avec qui j'ai causé y'a quelques jours) me disait que comparé aux autres outils existants (HPCToolKit, PAPI, PerfMon), Linuxperf est définitivement le plus fiable, au moins sur x86/Intel (à l'époque j'avais été regarder comment PAPI comptait certains événements dont j'avais besoin, et j'ai remarqué qu'ils prenaient le mauvais compteur… J'ai arrêté d'utiliser PAPI).
[^] # Re: Ai-je bien compris ?
Posté par lasher . En réponse au journal Performances des processeurs Intel et optimisation. Évalué à 10.
Je suis d'accord en ce que la méthodologie me semble peu rigoureuse. Mais en même temps, on peut sans doute faire en sorte de l'améliorer ! :-)
Ta suggestion de faire tout tourner sur un seul cœur les deux versions est à mon avis excellente : même s'il y a une race condition, les effets de bords ne seront pas réellement « visibles » dans le cas non thread-safe.
Les instructions atomiques sont certes plus lentes que des instructions normales, mais elles ont aussi quelques avantages/propriétés. Je vais en citer quelques uns:
Dans tous les cas, comme on te le faisait remarquer plus haut, si tu ne fournis pas ton code, on ne peut que spéculer.
[^] # Re: y'a trop peu d'infos pour t'aider.
Posté par lasher . En réponse au journal Performances des processeurs Intel et optimisation. Évalué à 3.
clock_gettime()
est la bonne fonction à appeler en effet. Avec l'optionCLOCK_REALTIME
si je me souviens bien.En pratique sur un mono-socket multi-cœur comme décrit pas steckdenis, RDTSC reste OK.
Une autre façon de mesurer (avec
rdtsc
ouclock_gettime
ougettimeofday
…) est simplement d'enrober le programme dans un thread que tu forces à s'exécuter sur un cœur donné, et lui laisser le soin d'appeler le reste du programme. Ensuite, tu peux utiliser des trucs genrepthread_barrier_*
ou autres machins faits maison pour garantir que tous les threads sont synchronisés puis reprendre la mesure depuis le threads « launcher ».[^] # Re: IDE python
Posté par lasher . En réponse au journal Point de vue : un IDE est il un outil de programmation indispensable ?. Évalué à 3.
Bon on va sans doute m'expliquer que je fais du code moche, mais qu'y a-t-il de mal à faire ce qui suit?
Certes si jamais le fichier ne contient pas que des entiers, ça va casser, et donc au moment de debugger, il faudra séparer la ligne en deux. Mais bon de toute manière le bug existera même avec les deux lignes initiales.
[^] # Re: Les IDE, c’est chiant
Posté par lasher . En réponse au journal Point de vue : un IDE est il un outil de programmation indispensable ?. Évalué à 3.
Bon, j'ai fait un IUT. Pendant mes 2 ans a l'IUT, j'ai (je melange les deux annees):
En plus de cela, j'ai vu (je mélange encore les deux années):
A cela s'ajoutent l'Anglais, les cours de communication et expression, les maths, la gestion et organisation, etc.
Bref. Les cours de système et environnement de programmation sont ceux qui m'ont appris comment la chaine de compilation se faisait en C. Je ne sais plus si j'ai vu comment on chaîne en Java en ligne de commande a l'époque, mais je suis certain qu'on m'a explique comment le système de packages fonctionnait.
Tout ça pour dire quoi ? En IUT, les profs on deux ans pour transformer des étudiants qui pour plus de la moitie (je dirais facilement les 2/3, voire les 3/4) ne savent pas réellement ce que signifie "faire de l'informatique" au moment ou ils arrivent en techniciens qualifiés. Ils n'ont pas toujours le temps de tout faire. Dans mon cas, le prof de Java était bien trop occupe a essayer de nous inculquer les principes de POO que nous n'avions qu'effleure en 1ere année en C++ (les trucs genre aller un peu plus loin dans la prog générique, l'overloading et le polymorphisme, la réutilisation de composants, etc.).
Comme tu le dis quelque part, compiler en Java ou en C c'est grosso modo la même chose. Tu as déjà appris la chaîne de compil en C. Pourquoi se faire chier a passer du temps a te faire passer par un shell alors que y'a tellement d'autres trucs a t'expliquer ?