Sortie de la version 4.7 du compilateur GCC

84
22
mar.
2012
GNU

La nouvelle version majeure du compilateur GCC du projet GNU vient de sortir (voir l'annonce).
Écrit à l'origine par Richard Stallman, le logiciel GCC (GNU Compiler Collection) est le compilateur de référence du monde du logiciel libre. Il accepte des codes source écrits en C, C++, Objective-C, Fortran, Java, Ada, Go et il fonctionne sur une multitude d'architectures.

Dans la suite de la dépêche, vous pourrez découvrir les nouveautés et les optimisations mises en œuvre dans cette version 4.7 de GCC, ainsi qu'un entretien avec Torvald Riegel, qui a développé avec Richard Henderson et Aldy Hernandez le code gérant la mémoire transactionnelle.

Sommaire

Prise en charge de la mémoire transactionnelle

Le compilateur GCC en version 4.7 propose, pour la première fois, une gestion de la technique dite de « mémoire transactionnelle » (TM pour Transactional Memory). Cette prise en charge est considérée comme expérimentale à l'heure actuelle mais elle est amenée à s'étoffer dans les versions futures.

Pour créer un programme capable d'exploiter simultanément plusieurs processeurs, il est nécessaire de mettre en place un mécanisme empêchant les divers cœurs de calcul d'effectuer des actions contradictoires au même moment ou d'accéder aux mêmes ressources simultanément. Le modèle traditionnel de programmation concurrente est celui qui utilise des verrous, pour interdire ces accès simultanés aux ressources partagées.
Le programme va simplement poser un verrou sur une ressource bien précise, afin de pouvoir travailler avec elle sans risquer une interférence de la part des autres processeurs.

Les verrous (locks) constituent donc une solution acceptable mais, hélas, ce paradigme n'est pas sans défauts. On peut opter pour un verrou simple qui protège une grande partie du système, mais dans ce cas les performances sont faibles puisque les autres processeurs restent souvent en attente. On peut également implémenter une multitude de petits verrous ne protégeant que des zones limitées. Les performances s'améliorent mais la complexité du code devient dangereuse et le risque de bug est élevé (interblocages, inversions de priorité, etc).

Au lieu de créer ainsi des verrous de plus en plus fins, peut-être faudrait-il reconsidérer le problème et partir sur une solution complètement différente ?
Le mécanisme de « mémoire transactionnelle » a l'ambition d'être cette solution alternative, permettant d'exploiter les machines multiprocesseurs, sans avoir à utiliser le très complexe verrouillage à grains fins.

Pour comprendre en quoi consiste cette fameuse mémoire transactionnelle, il faut tout d'abord prendre conscience qu'il s'agit là d'une technique optimiste. Dans le cas des verrous, on protège les ressources partagées parce qu'on craint une modification simultanée de la part d'un autre processeur. On est pessimiste puisqu'on pense qu'un concurrent va, lui aussi, faire des changements au même moment. Le verrou n'est donc posé que pour être certain que tout va bien se passer dans tous les cas.
Avec la mémoire transactionnelle, on est optimiste et on parie sur la fait que tout va bien se passer sans avoir besoin de verrouiller l'accès. En effet, dans la plupart des cas, la compétition pour l'accès à une ressource n'est pas si féroce que ça. Un seul cœur de calcul pourra faire son travail sans que les autres n'essayent à tout prix d'effectuer d'autres changements sur la même ressource juste au même moment.
Le mécanisme de mémoire transactionnelle tire parti de cet état de fait puisqu'il se contente de vérifier, a posteriori, que tout s'est bien passé lors d'un changement.
Si c'est bien le cas, alors la vie est belle et on peut passer à autre chose.
Si, au contraire, on s'aperçoit qu'un autre processeur a lui aussi fait des modifications sur la même ressource, alors on effectue un retour arrière pour annuler le changement.

Techniquement, ce mode de fonctionnement se rapproche de celui d'une base de données, avec les notions de transaction atomique de commit en cas de succès et de rollback en cas d'échec.

On distingue la mémoire transactionnelle matérielle (HTM) de la mémoire transactionnelle logicielle (STM). Dans le premier cas, il faut une prise en charge par le processeur, ce qui est encore très rare à l'heure actuelle. La puce Rock a été annulée par Sun/Oracle mais les puces IBM du supercalculateur BlueGene/Q) et surtout la prochaine génération de processeur Intel (nom de code Haswell) utilisent ce mécanisme de mémoire transactionnelle matérielle.
Dans le second cas de la STM, on se contente d'émuler ce support via des routines logicielles (qui utilisent des instructions atomiques et mêmes des verrous). Bien entendu, on peut aussi utiliser une approche hybride, mêlant HTM et STM, pour avoir une sémantique plus riche et de meilleures performances.
Les partisans de la technique de mémoire transactionnelle soulignent que ce paradigme simplifie grandement le travail du développeur. Ce dernier doit simplement indiquer dans son code, à l'aide du mot-clé __transaction, quels sont les blocs qui seront considérés comme « atomiques », c'est-à-dire les blocs qui devront s'exécuter au sein d'une transaction.

Bien entendu, il faudra voir à l'usage quels seront les réels bénéfices de cette approche de la programmation via la mémoire transactionnelle. Est-ce que les gains de productivité promis seront au rendez-vous ? Est-ce qu'il y aura vraiment moins de bugs qu'avec les verrous classiques et si oui, quelle sera la déperdition en matière de performances ?
Linus Torvalds n'est pas très optimiste (every single time somebody has tried transactional memory, the failure costs swamp the advantages) mais au moins, grâce à GCC 4.7, il est possible d'essayer ce nouveau paradigme.

Dans GCC, la nouvelle fonction de mémoire transactionnelle s'active en passant la commande -fgnu-tm au compilateur. L'implémentation de ces fonctions se fait via la bibliothèque libitm et la prise en charge n'est assurée, dans les langages C et C++, que pour les architectures x86-64, x86-32 et Alpha. Le travail d'optimisation n'a pas encore été fait et les performances seront donc sans doute assez faibles mais les développeurs insistent sur le fait que cette lenteur n'est pas inhérente à la technique de STM :

Cette prise en charge est expérimentale. Cela signifie en particulier que plusieurs parties de l'implémentation TM ne sont pas encore optimisées. Si vous constatez un niveau de performance plus bas que ce qui est attendu, vous ne devriez pas en conclure que la mémoire transactionnelle est inéluctablement lente. Au contraire, profitez-en pour ouvrir un bug.

L'implémentation de la mémoire transactionnelle dans GCC 4.7 est le résultat d'un financement de l'Union européenne (programme-cadre de recherche FP7).
Le projet Velox s'est déroulé sur trois ans, entre 2008 et 2010, et nous en voyons maintenant les résultats avec cette intégration du code écrit à cette occasion.
En dehors de divers essais dans le monde académique et de versions expérimentales chez Intel, GCC 4.7 est le tout premier compilateur de production à proposer cette prise en charge de la mémoire transactionnelle.

Pour aller plus loin dans la découverte de la fonction de mémoire transactionnelle dans GCC, j'ai posé quelques questions à Torvald Riegel, qui est maintenant un développeur Red Hat, mais qui a travaillé sur TM au sein du projet Velox.

Entretien avec Torvald Riegel

LinuxFr : Pourquoi est-ce que GCC est le premier des grands compilateurs à proposer cette fonction de mémoire transactionnelle ? Est-ce vraiment difficile à implémenter ?

Torvald Riegel : Il y a eu des implémentations de TM dans des versions prototypes d'autres compilateurs (ICC par exemple). TM n'est pas plus difficile à implémenter que les autres fonctions d'un compilateur.
Je ne peux pas faire de commentaires à propos des roadmaps des autres compilateurs, mais nous voudrions que GCC offre un bon support et de bonnes abstractions de programmation pour le parallélisme et la concurrence. Des fonctionnalités comme la mémoire transactionnelle et le support du modèle mémoire de C++11 font partie de cet effort.


LinuxFr : Pourquoi avoir choisi GCC par rapport à LLVM ? Penses-tu que LLVM aura lui aussi bientôt une implémentation de TM ?

Torvald Riegel : La gestion de TM dans GCC est le résultat du travail de plusieurs personnes de la communauté GCC, donc la question devrait plutôt être : pourquoi les communautés GCC et LLVM ont ou n'ont pas implémenté la mémoire transactionnelle jusqu'à présent ?
Un travail sur la gestion de TM dans LLVM avait été entrepris il y a quelque temps, mais la communauté GCC a été bien plus réceptive et intéressée pour travailler sur ce sujet.


LinuxFr : Est-il réellement possible de rivaliser avec les verrous en termes de performances ou bien est-ce que TM est surtout un mécanisme de synchronisation alternatif, plus lent mais plus facile à utiliser ?

Torvald Riegel : La réponse courte est oui. Pour la réponse longue, nous devons d'abord réaliser que les verrous, comme la mémoire transactionnelle, sont avant tout des abstractions permettant la programmation. Il y a différentes sortes de verrous, avec des caractéristiques très différentes en termes de performances, et la même chose est vraie pour les implémentations TM (par exemple les différents algorithmes, les différentes approches hybrides logiciel/matériel, etc.). En plus de toute cette variété, les programmeurs utilisent ces abstractions de toute sorte de façons (par exemple le verrouillage à grains fins contre l'utilisation de gros verrous) et pour toutes sortes de tâches.
En conséquence, on ne peut pas comparer de manière pertinente les verrous et la mémoire transactionnelle sans préciser d'autres paramètres. Si on ne le fait pas, alors on risque de simplifier outrageusement les choses.

Il faut également prendre en compte le fait que le développement logiciel est souvent un processus en best effort, en particulier en ce qui concerne l'optimisation pour les performances. Si une abstraction est plus facile à utiliser (par exemple vous n'avez pas à vous préoccuper de l'ordre d'acquisition des verrous quand vous utilisez TM), alors cela peut permettre au programmeur de passer plus de temps sur l'optimisation (par exemple sur les transactions) et peut donc conduire à un programme plus rapide au final.

Nous voulons effectivement que l'utilisation de la mémoire transactionnelle soit plus simple que la technique des verrous, mais je pense que, à temps de développement égal, TM peut avoir dans un grand nombre de situations des performances qui sont au moins aussi bonnes, si ce n'est meilleures qu'une implémentation à base de verrous.
Toutefois, il faudra sans doute attendre quelques itérations des implémentations TM (qu'il s'agisse du hardware ou de la partie logicielle). La mémoire transactionnelle est encore une technologie nouvelle. Des techniques comme les ramasse-miettes ont, elles aussi, nécessité du temps avant de pouvoir exploiter tout leur potentiel.


LinuxFr : Est-ce qu'il est important qu'apparaissent des implémentations matérielles comme dans le futur Intel Haswell ?

Torvald Riegel : La gestion par le matériel de la mémoire transactionnelle (HTM) permettra sans aucun doute d'atteindre plus facilement de bons niveaux de performances. Je suis vraiment impatient que les processeurs avec gestion HTM deviennent plus répandus.


LinuxFr : Que penses-tu de cette citation de Linus Torvalds: « Chaque fois que quelqu'un a essayé la mémoire transactionnelle, les désavantages l'ont emporté sur les avantages ».

Torvald Riegel : Cette phrase, que tu as citée seulement partiellement, débute par « afaik ».
Tu peux aussi remarquer que les échanges sur ce thread portent sur une implémentation matérielle spécifique (Haswell) et se concentrent sur la technique de « lock elision » (c'est-à-dire se servir de la gestion HTM et des possibilité d'exécutions spéculatives et de transactions pour optimiser l'exécution d'un code utilisant les verrous). En outre, il semble s'agir du noyau Linux ou d'autres types de codes très optimisés qui ont déjà une architecture sophistiquée basée sur les verrous.
Les études pour d'autres implémentation HTM montrent des résultats différents pour d'autres types de code, même quand il s'agit d'implémentations HTM aussi limitées que celle du processeur Sun Rock (voir l'article ASPLOS 2009 pour les détails).

Le but premier de la gestion de la mémoire transactionnelle dans GCC, c'est d'offrir aux développeurs normaux une abstraction de programmation basée sur les transactions.


LinuxFr : Est-ce que tu prévois d'améliorer l'implémentation TM dans les futures versions de GCC ? Il y a une roadmap quelque part ?

Torvald Riegel : Oui, nous voulons continuer à travailler pour améliorer le support de la mémoire transactionnelle dans GCC (que ce soit au niveau du compilateur ou dans libtm, la bibliothèque de runtime TM de GCC). Par exemple l'amélioration des performances fait, bien entendu, partie de notre liste des choses à faire (ce qui comprend l'exploitation du support HTM).

Il n'y a pas de roadmap définitive pour le moment, nous espérons plutôt un retour de la part des utilisateurs de façon à ce que nous puissions définir des priorités sur les aspects à améliorer en premier. Donc les commentaires des utilisateurs sont tout à fait bienvenus.


LinuxFr : Est-ce que tu peux dire un mot sur le projet Velox ? Est-ce qu'il a été important pour la création de cette implémentation de mémoire transactionnelle ?

Torvald Riegel : Une part importante de l'implémentation TM dans GCC a été créée pendant le déroulement de ce projet Velox. Nous sommes impatients de continuer à collaborer avec des groupes de recherche.

LinuxFr : Au nom de tous les lecteurs, merci pour tes réponses et pour ton travail dans GCC.


En bref

Architecture x86-64

GCC 4.7 permet maintenant d’optimiser spécifiquement le code pour les nouvelles générations de processeurs x86.
La version améliorée de l'architecture Bulldozer d'AMD est connue sous le nom de code « Piledriver ». Elle promet un gain d'environ 15% en termes d'instructions par cycle d'horloge (IPC), de nouvelles instructions (FMA3, BMI, TBM) ainsi qu'une montée en fréquence permise par la très intrigante technologie Cyclos « resonant clock mesh ». GCC 4.7 prend d'ores et déjà en charge cette architecture « piledriver » de seconde génération et il est possible d'optimiser les binaires générés en passant l'option -march=bdver2 lors de la compilation.

Du côté d'Intel, l’option -march=core-avx-i est dédiée spécifiquement aux processeurs de type Ivy Bridge et elle permet d'utiliser trois nouvelles instructions ajoutées dans AVX. On trouve donc FSGSBASE pour manipuler les registres FS/GS, F16C pour convertir efficacement des nombres flottants 16 bits et enfin RDRND pour exploiter le générateur matériel de nombres aléatoires Bull Mountain.
Le support de la génération suivante des processeurs Intel, la puce Haswell qui sortira en 2013, est également déjà intégrée dans cette version de GCC. Ces processeurs intégreront le jeu d'instructions vectorielles AVX2 qui est très largement étendu par rapport à AVX (manipulation d'entiers sur 256 bits, opération de multiplication-accumulation à trois opérandes, etc). Ce support d'AVX2 est contrôlé dans GCC par l'option -march=core-avx2.

Architecture ARM

Il n'y a pas que les x86 dans la vie et l'architecture ARM à le vent en poupe en ce moment. Cet article du site LWN fait le point sur l'organisation Linaro qui regroupe plusieurs industriels travaillant à un meilleur support ARM dans le monde du libre. Par exemple une équipe dédiée GCC, le toolchain working group, a développé des patchs permettant le support du processeur Cortex-A7 (le petit frère très économe du puissant Cortex-A15).
Le compilateur GCC 4.7 du projet GNU intégre donc le résultat de ce travail et la compilation vers ce type de processeur s'active avec l'option -mcpu=cortex-a7.
D'autre part, toujours dans le monde ARM, on peut noter un changement qui concerne la gestion de l'untité vectorielle SIMD de type NEON. À partir de GCC 4.7 la taille des vecteurs sera de 128 bits par défaut lors des passes d'auto-vectorisation avec un secours (fallback) en 64 bits en cas d'échec. On peut forcer l'ancien comportement avec la nouvelle option -mvectorize-with-neon-double.

Architecture Sparc

Plus exotique et moins tendance que l'architecture ARM, on trouve également dans cette nouvelle version de GCC diverses optimisations pour SPARC.
Le support pour le SPARC T3, avec 16 coeurs in-order et 8 threads par coeur, et du SPARC T4, avec 8 coeurs out-of-order et 8 threads par coeur, a été ajouté par David Miller. Si vous voulez que vos binaires exploitent au mieux ces modèles de processeurs, il vous faudra passer les options -mcpu=niagara3 ou -mcpu=niagara4 lors de la compilation.
C'est également David Miller qui s'est occupé d'écrire les patchs permettant à GCC d'exploiter la fonction FMA pour SPARC. Cette fonction FMA, pour Fused Multiply–Add, permet de faire en une seule étape une multiplication suivie d'une addition.
En ce qui concerne le jeu d'instruction vectoriel SPARC VIS 2.0, qui s'active avec l'option mvis2, il est encore mieux pris en charge dans cette version du compilateur GNU. Les instruction BSHUFFLE (concaténation de deux registres flottants 64 bits) et BMASK (addition de deux entiers avec masquage des derniers 32 bits de poids faible) sont maintenant pleinement supportées.

Link Time Optimization

La fonction d'optimisation lors de l'édition des liens (Link Time Optimization) qui avait fait une entrée en fanfare dans la version 4.5 de GCC, a été très largement améliorée lors de ce cycle de développement.
C'est tout d'abord la consommation mémoire qui a fait l'objet d'une attention soutenue de la part des développeurs. Sur les systèmes 64 bits, une passe d'optimisation des liens lors de la compilation de Firefox ne nécessite plus que 3 Go de mémoire au lieu de 8 Go précédemment. L'étape non parallélisable de l'édition des liens a également été améliorée puisque les développeurs ont mesuré un gain d'un ordre de magnitude en vitesse !
Enfin on note également un progrès en matière de souplesse d'utilisation puisque l'édition des liens incrémentale (option -r de ld) est maintenant compatible avec la technique de Link Time Optimization.

Fortran

Le support des versions modernes du langage Fortran devient plus complet dans GCC 4.7.
La possibilité d'utiliser la programmation orientée objet, introduit par la norme Fortran 2003, s'améliore avec le support des « polymorphic arrays ». En ce qui concerne Fortran 2008 et sa gestion du parallélisme, on peut maintenant utiliser DO CONCURRENT pour indiquer au compilateur les boucles de code sans interdépendances. Le support du modèle d'exécution Co-array Fortran a été également grandement amélioré pour le mode simple image. Le mode multi-image n'est pas encore intégré et il n'est que partiellement supporté via une bibliothèque nommée Coarray Communication Library.
Toujours pour Fortran on trouve également des changements dans la gestion des erreurs (-fbacktrace est activé par défaut) et la nouvelle option de compilation -fstack-arrays qui met tous les tableaux dans la pile mémoire. Dans certains cas cela peut augmenter grandement les performances.

OpenMP

Un domaine dans lequel GCC reste très en avance par rapport à son concurrent LLVM est celui du support de la norme OpenMP. Cette interface de programmation permet de faire du calcul parallèle sur les architectures à mémoire partagée en introduisant notamment des directives à la compilation de type #pragma omp.
La toute dernière spécification 3.1 d'OpenMP, sortie en juillet 2011, est maintenant officiellement supportée par GCC 4.7 pour les langages C, C++ et Fortran. Même s'il ne s'agit que d'une mise à jour de la norme 3.0 parue en 2008, on trouve quand même certaines nouveautés intéressantes comme, par exemple, la possibilité d'assigner des fils d'exécution à des processeurs spécifiques (bind threads).

Nouvelles architectures

Le support de plusieurs nouvelles sortes de processeurs exotiques a été ajouté dans GCC 4.7. On trouve notamment la famille C6X de Texas Instruments dont le port dans GCC a été assuré par la firme CodeSourcery (et qui a fait également son apparition dans le noyau 3.3). Il s'agit d'une nouvelle génération de DSP avec instructions 256 bits de type VLIW (Very Long Instruction Word). A l'autre extrémité du spectre en matière de puissance on peut citer le support dans GCC 4.7 de la puce Renesas RL78. C'est un micro-contrôleur 8/16 bits à faible consommation et qui a une architecture très proche du mythique Z80.
Enfin, dernier ajout notable, la société Embecosm qui est spécialisée dans l'embarqué, a écrit le code permettant le support de l'architecture Adapteva Epiphany dans cette version de GCC. Ce nouveau processeur est formé d'une multitude de coeurs RISC très simples partageant un espace mémoire unique et reliés par un réseau en topologie maillée (un peu comme les puces de Tilera).

Nouvelles commandes

En ce qui concerne les nouvelles commandes disponibles dans GCC 4.7 la liste est longue mais on peut citer la possibilité d'activer (avec -fenable) ou de désactiver (avec fdisable) chacune des passes d'optimisation individuellement. On obtient facilement la liste des passes qui sont activées ou pas avec la commande -fdump-passes.
La commande -Wstack-usage=len permet d'activer une alerte si la taille de la pile dépasse la valeur spécifiée par len.
La commande -Wvector-operation-performance est utile au moment du travail d'amélioration des performances du programme puisqu'elle envoie une alerte si des opérations portant sur des vecteurs ne sont pas implémentés via le module SIMD du processeur.

Nouvelles optimisations

Diverses passes d'optimisations ont été ajoutées dans GCC 4.7 et plusieurs passes qui existaient déjà ont été améliorées.
On peut citer par exemple la nouvelle passe -foptimize-strlen qui s'occupe des multiples fonctions de manipulations de chaînes de caractères de votre code: strlen(), strchr(), strcpy(), strcat() et stpcpy(). Quand elle est activée, cette passe va regarder les endroits dans votre code qui utilisent ces fonctions et va chercher à remplacer ces parties par du code optimisé plus rapide (voir les explications de Jakub Jelinek avec un exemple de code).
Une autre passe intéressante qui a été ajoutée est -ftree-tail-merge. Ici il s'agit de regarder les séquences de code identiques à la fin des fonctions. Quand une seconde séquence semblable est trouvée alors le code est simplement remplacé par un jump vers la première séquence. Comme cette passe est coûteuse en temps de compilation il est possible d'indiquer une limite avec la commande max-tail-merge-comparisons.
Un autre exemple de nouvelle passe d'optimisation intégrée dans GCC 4.7 est l'option -fshrink-wrap qui modifie les prologues de fonctions. En assembleur les fonctions sont précédées par des « prologues », c'est à dire des lignes de code qui vont préparer un espace sur la pile. Normalement GCC ne se pose pas de question et il insère ce prologue en tête de la fonction. Avec -fshrink-wrap l'insertion du prologue ne se fera plus de façon aussi générique mais juste avant les parties de la fonction qui en ont vraiment besoin.
D'après Nick Clifton:

Cette optimisation sera particulièrement utile pour améliorer les scores des benchmarks synthétiques du type dhrystone ou coremark.

C++11

Le travail sur la prise en charge de la norme ISO C++11 continue dans cette nouvelle version du compilateur GNU. Parmi les nombreuses nouveautés (template aliases, delegating constructors, etc) on peut notamment remarquer tout ce qui tourne autour de la gestion de la mémoire et des threads. Il s'agit d'un des points clés de C++11 qui a pour ambition de proposer aux programmeurs de nouveaux outils pour gérer la concurrence. On retrouve donc les fonctions préfixés par __atomic qui remplacent les anciennes __sync et on note également les options -finline-atomics et -Winvalid-memory-model liées à ces fonctions.
Il faudra toutefois attendre GCC 4.8 pour bénéficier de la bibliothèque libatomic qui est utilisé en dernier recours quand il n'est pas possible d'avoir des instructions sans verrous. Une page du wiki GCC est dédiée à ces questions complexes de gestion de la mémoire avec C++11.

C11

Du côté du bon vieux langage C il y a là aussi des nouveautés puisque les développeurs de GCC travaillent sur la norme C11 (voir cette dépêche LinuxFr de GeneralZod pour un récapitulatif des nouveautés).
Quand on active l'option -std=c11 on retrouve donc la gestion des chaînes unicode et des macros __STDC_UTF_16__ et __STDC_UTF_32__. GCC 4.7 intégre les fonctions d'alignement _Alignas et _Alignof, la gestion du mot-clé _Noreturn, la fonction __builtin_complex pour profiter des macros CMPLX, etc.
Maintenant que la norme C11 a été officiellement ratifié par l'ISO le 8 décembre 2011, il est probable que le travail d'intégration dans GCC va s'accélerer.

Extensions GNU pour DWARF

Quand on veut traquer les bugs d'un programme il faut utiliser un débogueur, GDB par exemple. Pour faire son travail, ce débogueur va se servir des diverses informations générées lors de la compilation et qui ont été stockées dans l’exécutable ELF (Executable and Linkable Format). Le format de ces informations de débogage se nomme DWARF (elfe, nain…humour) et, depuis juin 2010, nous en sommes à la version 4 de ce format.
GCC 4.7 propose plusieurs nouvelles extensions qui sont spécifiques au projet GNU et qui permettent d'étendre les fonctionnalités de DWARFv4.
On trouve par exemple DW_OP_entry_value qui suit les valeurs passées en argument des fonctions ou encore DW_TAG_call_site qui repère mieux les appels de fonction (ces deux extensions feront sans doute partie de DWARFv5 : 1 - 2).
Un autre ajout fort utile consiste à remplacer la section debug_macinfo classique du format DWARF par une nouvelle section nommée debug_macro. Habituellement la section debug_macinfoest utilisée pour stocker un tableau de correspondance (lookup table) de tous les objets globaux et de toutes les fonctions. On comprend donc que ce tableau puisse atteindre des tailles démesurées (plusieurs centaines de Mo). Le développeur Jakub Jelinek a eu l'idée de ne stocker que les informations non redondantes en mettant à profit les informations de la section debug_str qui existe déjà.
Selon les tests effectués le gain est saisissant puisqu'on passe de 350 Mo stockées dans debug_macinfo à seulement 1 Mo dans debug_macro plus 1,5 Mo de données additionnelles dans debug_str. Un gain d'un facteur 100 !
Bien entendu, si vous n'aimez pas ces extensions GNU qui ne sont pas encore standardisés dans le format DWARF, alors vous pouvez passer l'option -gstrict-dwarf et vous retrouverez le comportement précédent.

Le futur de GCC

Contrairement aux autres années, il n'y a pas eu de sommet GCC en 2011. La prochaine réunion officielle, le GCC Summit 2012, est prévue pour les 23, 24 et 25 mai prochain.
Lors de l'année écoulée, les développeurs et les chercheurs de la communauté GCC ont cependant eu plusieurs occasions d'échanger leurs idées. On peut citer notamment le workshop « GROW 2011 » (GCC Research Opportunities) qui s'est déroulé en avril. Les articles présentés à cette occasion sont disponibles sur le site de l'INRIA. On peut également évoquer la rencontre « GCC Gathering 2011 » de juin dernier dans les locaux londoniens de Google. Le compte-rendu au format pdf est disponible sur le wiki du projet.

Toutes ces rencontres permettent aux développeurs de tenter de définir en commun ce que doit être le futur de GCC. De nombreuses améliorations sont prévues pour la prochaine version 4.8 (voir par exemple les projets concernant l'infrastructure Graphite) mais qu'en est-il du long terme ?
On sait que l'adoption en 2005 de la technique SSA (Static Single Assignement) avait été jugée suffisament importante pour passer GCC en version 4. Des discussions sont actuellement en cours qui pourraint bien conduire, à terme, au passage en version 5 du compilateur GNU. Cette fois c'est la modularisation de l'architecture qui justifierait ce saut de version.

En décembre dernier Diego Novillo et Joseph Myers ont publié en ligne un très intéressant document sur l'architecture de GCC. Le but était de passer en revue tous les axes d'améliorations possibles (listés dans une page annexe du wiki) afin d'assurer la pertinence à long terme du projet.
Un point important de cette remise à plat concerne la modularisation de GCC qui, très récemment, a suscité de nombreux échanges sur la liste de diffusion du projet. David Malcolm, employé par Red Hat mais parlant en son nom, a envoyé un long mail sur cette liste de diffusion. Dans son message il souligne le fait que le compilateur LLVM rencontre du succès, en tant que JIT, grâce à son architecture modulaire. Selon lui il faut que GCC adopte progressivement ce modèle en composants disjoints puisqu'il facilite la réutilisation par d'autres projets.
Basile Starynkevitch est également intervenu sur ce sujet avec un mail qui cite à plusieurs reprises GTK comme exemple à suivre au point de vue de la modularisation.
La page consacrée à la modularisation dans le wiki GCC n'a pas encore été mise à jour mais on peut penser que les discussions en cours vont permettre de faire avancer la réflexion sur ce sujet.

Aller plus loin

  • # Lien cassé

    Posté par  (site web personnel) . Évalué à 3.

    L'implémentation de la mémoire transactionnelle dans GCC 4.7 est le résultat d'un financement de l'Union européenne (programme-cadre de recherche FP7).

    Le lien vers "résultat d'un financement" ne marche pas.

    Je retourne à la lecture.

    Commentaire sous licence LPRAB - http://sam.zoy.org/lprab/

    • [^] # Re: Lien cassé

      Posté par  . Évalué à 3. Dernière modification le 22 mars 2012 à 20:03.

      Moi aussi j'ai voulu en savoir plus sur ce financement européen…
      Du coup, j'ai pris le temps de vérifier TOUS les autres liens :
      Il manque un tiret dans l'adresse pour "Bull Mountain" : noyau-linux-3-2 au lieu de noyau-linux-32

  • # Merci !

    Posté par  (site web personnel) . Évalué à 8.

    Encore un passionnant article, merci :)

    ce commentaire est sous licence cc by 4 et précédentes

  • # Exemple de gain avec la mémoire transactionnelle ?

    Posté par  . Évalué à 2.

    Je pense n'avoir pas compris le principe de la mémoire transactionnelle car je ne vois pas du tout comment cela peut arriver à la cheville des verrous.

    Si un seul fil d'exécution à besoin d'une ressource, verrou ou mémoire transactionnelle, c'est kif-kif. Sauf que le verrou ne nécessite pas 10000 transistors supplémentaires dans le processeur et/ou une vérification logicielle.

    Si deux fils d'exécution on besoin d'une même ressource:
    - avec verrou, le premier pose le verrou, le second est en attente (donc libère le processeur pour faire potentiellement autre chose)
    - avec mémoire transactionnelle, les deux fils bossent. Celui qui termine en dernier a gaspillé du temps processeur, et de l'autonomie de batterie de portable

    L'avantage réside peut-être dans le fait que les verrous nécessitent d'être correctement implémentés, et que des bugs sont possibles dans chaque application. Alors que la mémoire transactionnelle évite au programmeur de se casser la tête. Mais ce qui est mis en avant est que c'est plus rapide, et là, je ne pige pas.

    Un exemple concret pour m'éclairer ?

    • [^] # Re: Exemple de gain avec la mémoire transactionnelle ?

      Posté par  . Évalué à 4.

      Et bien je pense que si tu mets un gros verrous ou si tu utilise des transactions plus fines pour le STM alors il est possible que l'implémentation avec STM soit plus performante.
      Certes la réponse est alors: tu ne compares pas des choses comparables, mais ce n'est pas tout à fait vrai si la référence est la simplicité d'utilisation pour le programmeur.

      • [^] # Re: Exemple de gain avec la mémoire transactionnelle ?

        Posté par  . Évalué à 2.

        Si j'utilise un gros verrou, je compare avec un transaction qui couvre aussi large. Cela me semble comparable.

        Encore une fois, la simplicité est un atou, mais ce qui est mis en avant c'est la plus grande rapidité. Et ça, je ne vois pas.
        Bien que la simplicité… il faut bien que le programmeur indique les bornes de la transaction. Donc mêmes bugs qu'avec un verrou mal mis/enlevé. Finalement, il ne reste rien comme avantages. Donc je n'ai pas compris un truc.

        • [^] # Re: Exemple de gain avec la mémoire transactionnelle ?

          Posté par  . Évalué à 10. Dernière modification le 23 mars 2012 à 06:52.

          Bien que la simplicité… il faut bien que le programmeur indique les bornes de la transaction.

          La différence fondamentale :

          • verrous : approche pessimiste : quelqu'un va venir me faire chier pendant que je bosse, donc je protège
          • transaction : approche optimiste : si quelqu'un est venu m'emmerder, pas grave, je vais refaire après

          Quand une ressource est partagée, 99,9% du temps, il n'y a pas de contention sur cette ressource. L'approche par verrou est pénalisante, car elle protège tout le temps, ce qui est assez coûteux en terme de performances : instruction atomique test-and-set, invalidation des caches de tous les processeurs, etc… Ce sont tous les accès à la ressource qui payent ce prix.

          A contrario, l'approche par transaction a moins d'impact au global, car seuls les accès avec contentions payent le prix d'un rollback et d'une nouvelle transaction. Certes, c'est plus cher unitairement qu'un verrou, mais ça arrive beaucoup, beaucoup moins souvent.

          Du moins, c'est l'idée.

          Hop,
          Moi.

          • [^] # Re: Exemple de gain avec la mémoire transactionnelle ?

            Posté par  . Évalué à 2.

            Comme le signale Torvald Riegel, puisque le développeur se prend moins la tête a corriger des problèmes difficiles de concurrence d’accès sur les verrous, il peut passer plus de temps a optimiser son application.
            Certes, c'est un effet indirect de la mémoire transactionnelle.

            A choisir, je préfère largement ça plutôt que les développeurs perdent leur temps sur des problèmes complexes de multithreading. Et cela même si les dit développeurs devaient être très forts et parvenir a résoudre le problème plus rapidement que la moyenne des devs.

            La programmation concurrente n'est pas facile du tout :-(

          • [^] # A voir Re: Exemple de gain avec la mémoire transactionnelle ?

            Posté par  . Évalué à 4.

            Tout d'abord merci une fois de plus à PatriceG pour un journal où de nouvelles notions que j'ignorais me deviennent plus ou moins accessibles, et lorsqu'elle ne le sont pas totalement de pouvoir aller sur les liens ad-hoc.

            Cela dit je reviens sur :

            Quand une ressource est partagée, 99,9% du temps, il n'y a pas de contention sur cette ressource

            1/ je souhaiterai savoir d'où tu tire cette information
            2/ j'aimerai dire pour l’interrogation générale qu'il est un peu tôt pour tirer des conclusions du pour ou contre ce fameux gain de mémoire transactionnelle. Autant faire un benchmark comparatif des 2 ( verrou MT ) pour connaitre l'intérêt de chacun. Je comparerai presque ça à du cache mémoire : il n'est pas utile dans 100% des cas(cache miss par ex) , peut-être qu'en utilisant les transactions on s'apercevra qu'effectivement l'approche optimiste fait gagner du temps et que les verrous étaient trop lourds, ou finalement qu'à force de "roll-backs" sur erreurs on perd plus que l'on gagne.

            Bref, pour moi : "wait and see"__

            • [^] # Re: A voir Re: Exemple de gain avec la mémoire transactionnelle ?

              Posté par  . Évalué à 6. Dernière modification le 23 mars 2012 à 15:05.

              Quand une ressource est partagée, 99,9% du temps, il n'y a pas de contention sur cette ressource

              1/ je souhaiterai savoir d'où tu tire cette information

              La probabilité est liée à plusieurs facteurs (je ne connais pas l'équation, cependant) :

              • la taille de la ressource critique, et donc le nombre d'instructions pour la lier et la modifier, et donc le temps CPU passé en section critique --> t_crit
              • le nombre d'instructions exécutés par chaque processus en dehors de la section critique, et donc le temps CPU plus le temps d'éviction (processus qui n'est pas élu pour tourner sur le CPU) passé en dehors de la section critique --> t_triv
              • le nombre de processus qui veulent accéder à la ressource critique --> nb_procs
              • le nombre de CPU utilisables --> nb_cpu

              La probabilité évolue ainsi (à mon avis) :

              • augmente avec t_crit
              • augmente avec nb_procs
              • augmente avec nb_cpu
              • diminue avec t_triv

              Dans la plupart des cas, le critère le plus important est t_triv, donc la probabilité de contention est faible, très faible. Par exemple pour deux processus qui exécutent l'un 100k et l'autre 50k instructions hors section critique, et partagent une section critique de 20 instructions, et qui tournent en permanence (toujours élus, sur deux processeurs) :

              Pcrit(x) : probabilité que le processus x ne soit pas dans sa section critique.
              Pcritsys : probabilité qu'aucun processus du système ne soit dans leur section critique.

              Pcrit(0) = 1 - (20/100000) = 0.9998 = 99.98%
              Pcrit(1) = 1 - (20/50000) = 0.9996 = 99.96%
              Pcritsys = Pcrit(0) * Pcrit(1) ~= 0.9994 = 99.94% (arrondi par défaut)

              50k instructions, ce n'est déjà pas beaucoup, quand tu vois le nombre d'instructions exécutées pour afficher une fenêtre à l'écran, par exemple.

              Et les systèmes dans lesquels un très grand nombre de processus (>10) se battent pour la même ressource critique, est assez faible.

              Alors oui, 99.9% est un nombre tiré de mon chapeau. C'est peut-être plus, peut-être moins ; mais assez proche de la réalité. Dans la plupart des cas, ça ne doit pas descendre beaucoup en dessous de 99%.

              Hop,
              Moi.

              • [^] # Re: A voir Re: Exemple de gain avec la mémoire transactionnelle ?

                Posté par  (site web personnel) . Évalué à 2.

                Mais en fait c'est le contraire, la mémoire transactionelle est surtout utile lorsqu'il y a de la contention.

                Si il n'y a pas de contention, alors bloquer n'est pas un problème. Verouiller et déverouiller prennent seulement quelques instructions. Et les autre thread ne seront pas ralenti car il n'ont pas esoin de la ressource à ce moment.

                C'est quand il y a contention que les problème se posent, et que de nombreux thread sont en attente.
                C'est là que la mémoire transactionelle aide: On espère que les autre threads qui utilise les même resources au même moment n'entrent pas trop en conflits. Et en cas de conflit, on suppose que ça coute moins cher de recalculer la transaction que de bloquer.

                • [^] # Re: A voir Re: Exemple de gain avec la mémoire transactionnelle ?

                  Posté par  . Évalué à 8.

                  Mais en fait c'est le contraire, la mémoire transactionelle est surtout utile lorsqu'il y a de la contention.

                  Au contraire. S´il y a contention, alors la mémoire transactionnelle implique que les transactions vont être refaites plus souvent que nécessaire. Dans le case de forte contention, les verrous sont plus adaptés.

                  • peu de contention --> mémoire transactionnelle
                  • beaucoup de contention --> verrous

                  Encore une fois, la mémoire transactionnelle est un mécanisme optimiste, qui suppose que les différents accès à une ressource ne se feront que très rarement en même temps, et donc préfère perdre beaucoup de temps (annuler la transaction, et refaire le travail) de temps en temps, plutôt que perdre un peu (prendre un verrou et le relâcher) à chaque fois.

                  Hop,
                  Moi.

                  • [^] # Re: A voir Re: Exemple de gain avec la mémoire transactionnelle ?

                    Posté par  . Évalué à 3.

                    Et puis il y a d'autres paradigmes pour la résolution des problématiques liées à la concurrence [1]. Là on oppose les TM au locking, soit. Mais la première question est : veut on que notre réponse soit réellement déterministe ? Si une solution me permet de gagner 99% du temps de calcul et d'avoir un résultat acceptable à 99%, je vais favoriser cette solution.

                    Alors oui nos relans d'informaticiens qui arrivons tous un moment ou un autre de la programmation impérative nous fait dire que, oui, le déterminisme est nécessaire. Mais comparons ça à ce que l'on peut observer dans la nature : le choix d'un système globalement fiable et localement imprévisible peut être préférable.

                    tout ça commence juste à émerger au final.

                    Le souci, dans l'immédiat, et certaines réactions ici semblent le confirmer, c'est que les TM vont être vues comme une abstraction genre "nan mais c'est cool, avec les TM ça juste marche plus besoin de locking" et toutes les jolies blagues que l'on va croiser dans la vie réelle à cause de ça …

                    [1] Voir les travaux de Ungar, dont ce slide de la SPLASH 2011 :
                    http://www.dynamic-languages-symposium.org/dls-11/program/media/Ungar_2011_EverythingYouKnowAboutParallelProgrammingIsWrongAWildScreedAboutTheFuture_Dls.pdf

                  • [^] # Re: A voir Re: Exemple de gain avec la mémoire transactionnelle ?

                    Posté par  . Évalué à 4.

                    ui suppose que les différents accès à une ressource ne se feront que très rarement en même temps

                    Non, on suppose que les modifications ¹ d'une ressource se feront très rarement

                    ¹: et même les modifications lors d'accès concurrent.

                    « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

                    • [^] # Re: A voir Re: Exemple de gain avec la mémoire transactionnelle ?

                      Posté par  . Évalué à 1.

                      on suppose que les modifications ¹ d'une ressource se feront très rarement
                      ¹: et même les modifications lors d'accès concurrent.

                      Bien vu ! Merci pour la précision.

                      D´un autre côté, lire à des données qui ne sont jamais modifiées, c´est un peu inutile… ;-)

                      Hop,
                      Moi.

                      • [^] # Re: A voir Re: Exemple de gain avec la mémoire transactionnelle ?

                        Posté par  . Évalué à 2.

                        Non pas du tout, c'est même le principe de la parrallélisation via message passing : personne ne modifie une ressource partagée, tout se fait par passage de messages immutables. C'est d'ailleurs à mon goût plus facile de coder avec ce genre de paradigmes, et en plus ça a loe bon goût de scaler au travers du réseau (cependant, les perfs en local sont a priori moins bonnes).

      • [^] # Re: Exemple de gain avec la mémoire transactionnelle ?

        Posté par  . Évalué à 3.

        la simplicité d'utilisation pour le programmeur

        Mauvais programmeur, changer programmeur.

        Bein, oui, quoi. Si vous vous faites opérer par un chirurgien qui ne sait pas poser un clamp, mais qu'à la place il vous dit qu'il a plein de poches de sang au cas où, ça vous rassure ? Pas moi.

        La mémoire transactionnelle, dans le principe, c'est bien. Je suis même plutôt impatient de pouvoir faire mu-muse avec. Mais il ne faut pas présenter ça comme un palliatif à un mauvais niveaux des programmeurs. Et pour avoir fait de gros systèmes embarqués critiques, la compréhension des verrous fait partie des connaissances de base attendues d'un programmeur.

        Hop,
        Moi.

        • [^] # Re: Exemple de gain avec la mémoire transactionnelle ?

          Posté par  . Évalué à 8.

          la compréhension des verrous fait partie des connaissances de base attendues d'un programmeur.

          Entièrement d'accord avec ça, mais ce n'est pas parce qu'on comprend très bien comment fonctionnent les verrous que ça que ça n'amène pas à des situation très complexes dans certains cas ce qui amène à plus de bug et le temps perdu à les corriger n'est pas passer à optimiser le temps d'exécution. Je ne dis pas que c'est un raisonnement universellement applicable mais ça arrive.

          « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

        • [^] # Re: Exemple de gain avec la mémoire transactionnelle ?

          Posté par  . Évalué à 7.

          Non, c'est un argument débile. Les développements logiciels se font en temps limité, donc gagner du temps sur une partie permet de mieux optimiser le reste (ou bien d'ajouter des fonctionnalités, etc.). C'est aussi pour cela qu'on utilise de plus en plus des langages de haut niveau avec gestion automatique de la mémoire.

          Ensuite, dire qu'un programmeur qui ne maîtrise pas les verrous est un mauvais programmeur, c'est également stupide. Peut-être que ton programmeur qui ne maîtrise pas les verrous est un spécialiste du traitement d'images ou un concepteur d'APIs hors pair.

          • [^] # Re: Exemple de gain avec la mémoire transactionnelle ?

            Posté par  . Évalué à -1.

            Alors, qu'un développeur ait en charge la décision d´où mettre les verrous, c'est une aberration.

            Ça devrait être fait lors de la phase de conception. Cette phase est trés souvent "oubliée", pour passer directement de l'architecture au développement. C'est stupide.

            Et, comme tu le dis, Les développements logiciels se font en temps limité. Certes. Mais bruler les étapes ne permet pas de gagner en robustesse (aka fiabilité), ni même en performances. Au final, comme la phase de conception n'a pas eu lieu, le développement se termine par la mise en place de méchantes verrues dans tous les coins pour ajouter les dernières fonctionalités, corriger les derniers bugs, prendre un raccourci car c'est trop lent, etc… Tout cela au détriment de la maintenance.

            Certes, le problème des verrous n'est qu'une partie du problème. Mais à la base, laisser au développeur la responsabilité de décider où mettre des verrous, c'est absurde.

            Quand je parle de programmeur, je ne parle pas de développeur. Le programmeur (de mon point de vue, du moins), c'est une personne qui intervient plus en amont, dès la conception, et aussi dans le développement au besoin.

            Ensuite, dire qu'un programmeur qui ne maîtrise pas les verrous est un mauvais programmeur, c'est également stupide.

            Je n'ai pas dit maîtrise, j'ai dit compréhension. Et si ; un programmeur qui ne comprend pas le principe et le fonctionnement des verrous, c'est un mauvais programmeur. Valable aussi pour le développeur.

            Hop,
            Moi.

    • [^] # Re: Exemple de gain avec la mémoire transactionnelle ?

      Posté par  (site web personnel) . Évalué à 4.

      le pari est que le temps perdu à recalculer la transaction est moindre que le temps perdu à bloquer et faire un context switch

      • [^] # Re: Exemple de gain avec la mémoire transactionnelle ?

        Posté par  (site web personnel) . Évalué à 4.

        Aussi…

        Un des problème avec les locks est le suivant. Imaginez que vous utilisez les locks de la meilleur façon possible, et n'avez qu'une minuscule section critique, il y a toujours le risque que par malheur, (cache miss, ou temps écoulé), le noyaux passe la main à un autre thread/process sur le core, alors que ce thread a le lock.
        Résultat, les autre thread qui normalement auront aussi besoin de la ressource tôt ou tard, vont aussi se retrouver bloquer et devoir attendre que le noyau repasse la main au premier thread. Celà ralenti considérablement.

        Avec la programmation transactionelle (lock-free) ceci n'est plus un problème

        • [^] # Re: Exemple de gain avec la mémoire transactionnelle ?

          Posté par  . Évalué à 1.

          Oui et non, en fait il y a trois façon de faire: le mutex multi instructions qui a les défauts que tu décrits, la mémoire transactionnelle et le cas intermédiaire, beaucoup utilisé aujourd'hui par les gens qui veulent éviter les mutex: les instructions atomiques au niveau processeur (test-and-set, etc.), et comme c'est une seule instruction dans le CPU, il ne peut pas y avoir de context switch.

          • [^] # Re: Exemple de gain avec la mémoire transactionnelle ?

            Posté par  (site web personnel) . Évalué à 3.

            Tu peux implémenter lock() et unlock() en une seule instruction mais entre les deux tu vas généralement en avoir plusieurs et c'est là que tu peux être préempté et bloquer tout le monde.

            pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.

          • [^] # Re: Exemple de gain avec la mémoire transactionnelle ?

            Posté par  (site web personnel) . Évalué à 4.

            Le problème des instructions atomique est que dés que tu veux faire quelque chose d'un peu plus compliqué que juste changer une variable, ça deviens extrêmement difficile à programmer. Avec le ABA problem, et la gestion de la mémoire (comment peux-t-on libérer la mémoire si on ne sais pas si un thread n'a pas gardé un pointeur vers cette zone?).

            Bref, la mémoire transactionelle est juste un moyen simplifié de faire des algorithmes un peux plus compliqués qui utilise test-and-set en interne.

        • [^] # Re: Exemple de gain avec la mémoire transactionnelle ?

          Posté par  (site web personnel) . Évalué à 2.

          Yaka implémenter une instruction atomique qui prend la lock et augmente la priorité du thread (et l'inverse : lock_release(); setpriority(pri_saved)). Le risque d'erreur de programmations est évidemment augmenté puisqu'il faut faire encore plus attention a ne pas bloquer dans la section critique.

          pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.

    • [^] # Re: Exemple de gain avec la mémoire transactionnelle ?

      Posté par  . Évalué à 6.

      Si deux fils d'exécution on besoin d'une même ressource:

      Ce n'est pas un bon exemple pour la mémoire transactionnelle. Si tu as 20 fils d'exécution qui ne modifient pas la ressource critique à chaque fois qu'ils y accèdent, ça devient plus intéressant d'utiliser la mémoire transactionnelle.

      « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

    • [^] # Re: Exemple de gain avec la mémoire transactionnelle ?

      Posté par  . Évalué à 4.

      Bravo! Tu viens de démontrer que les verrous fonctionnent mieux si tu as des fils d’exécution qui accèdent a la même ressource :)

      Sauf que la mémoire transactionnelle c'est du verrouillage optimiste, c'est a dire que si la majorité de ton code s’exécute sans conflit, alors cela te fait gagner du temps (Et ce sont des maux de tête évités au développeur). Cette technique existe déjà avec les bases de données ou lors de chaque mise a jour d'une ligne, tu vérifies sa pour être sur tu as bien travaillé avec la version la plus a jour:

      UPDATE MA_TABLE
       WHERE MA_COLONNE = 'nouvelle valeur'
         AND VERSION = 3                               -- c’était la dernière version lue depuis la base de donnée
      
      

      ou bien:

      UPDATE MA_TABLE
       WHERE MA_COLONNE = 'nouvelle valeur'
         AND LAST_UPDATE_DATE = '23/03/2012 14:57:23'  -- c’était la date de dernière mise a jour lue depuis la base de donnée
      
      

      Si ça foire, et bien tu rééxecute ta transaction, mais c'est pas un drame car ça arrive relativement peu souvent.

      Quoiqu'il en soit, je préfères utiliser des algorithmes lock free lorsque c'est possible, c'est beaucoup plus sympa pour la maintenance :)

    • [^] # Re: Exemple de gain avec la mémoire transactionnelle ?

      Posté par  . Évalué à 10.

      Pour prendre une analogie de la vie de tous les jours, prenons le cas de la bouteille de lait dans le frigo. Tu rentres à la maison, ouvres le frigo, constate qu'il n'y a plus de lait et tu décides d'aller en acheter. Pendant ce temps ta femme rentre, vois qu'il n'y a plus de lait et va en acheter aussi. Accès concurrent au frigo.

      La solution bourine est de mettre un cadenas sur le frigo. Ca marche pas trop mal pour un couple (tes deux fils concurrents) et ça éviter un tâche inutile. Maintenant imaginons une collocation de 50 personnes (oui, ça commence à faire). Si quelqu'un met un cadenas sur le frigo pour être sûr d'éviter les accès concurrents, il emmerdera probablement certains parmi les 49 autres pour un cas qui peut se produire (mais pas sûr). Si au lieu de ça on laisse chacun libre d'accéder au frigo, il se peut que de temps en temps deux personnes aillent acheter du lait. Au pire en revenant, le dernier arrivé constate qu'il y a déjà du lait et qu'il est allé faire les courses pour rien.

      On risque de laisser des agents effectuer parfois un travail inutile mais on sait qu'on va vers des architectures de plus en plus parallèles avec des coeurs qu'on a du mal à occuper efficacement. Dans certains cas, certains bossent pour rien mais dans l'ensemble ils arrivent à eux tous à faire plus de boulot utile que si on avait bloqué la terre entière au cas où.

  • # Merci

    Posté par  (site web personnel) . Évalué à -2.

    Excellent article très complet au détail près que le lien sur le financement FP7 ne fonctionne pas. Merci.

  • # "In terms of"

    Posté par  (site web personnel) . Évalué à 10.

    Puisque tu apprécies la tournure "en termes de", (7 occurrences), il faut savoir que :

    L'académie en déconseille l'usage que tu en fais au profit de "en matière de" ou "quant à". Mais puisque la langue évolue, ce n'est pas impératif de suivre leur avis là dessus.

    En revanche,

    Il est essentiel de faire apparaître le "s" à termes.

    Pour en savoir davantage :
    http://www.academie-francaise.fr/langue/questions.html#enterme

    • [^] # Re: "In terms of"

      Posté par  (site web personnel) . Évalué à 3.

      Merci. J'ai rajouté des 's' et en ait remplacé certains.

    • [^] # Re: "In terms of"

      Posté par  . Évalué à 1.

      Elle promet un gain d'environ 15% en termes d'instructions par cycle d'horloge

      Cette tournure-là est peut-être juste (« dans le vocabulaire, dans le langage de »)…

      • [^] # Re: "In terms of"

        Posté par  . Évalué à 5.

        Elle promet un gain d'environ 15% en termes d'instructions par cycle d'horloge

        En nombre d'instructions par cycle d'horloge?

  • # Mémoire transactionnelle et verrous

    Posté par  . Évalué à 1.

    Les mécanismes de mémoire transactionnelles et de verrous sont-ils mutuellement exclusifs (je suis en béotien en la matière) ?

    • [^] # Re: Mémoire transactionnelle et verrous

      Posté par  . Évalué à 4.

      Non je ne vois pas pourquoi se serait mutuellement exclusif, sauf problème d’implémentation :).
      Si les verrous sont implémentés avec des primitives noyaux, et que la mémoire transactionnelle est implémentée au niveau du programme utilisateur, alors il n'y aura pas de problème.
      J’espère que les implémentations vont permettre de coder des applications en utilisant les 2 modes!

      Je vais essayer d'expliquer ma pensée:
      Alors que la plupart des commentaires semblent être du type "pour ou contre la mémoire transactionnelle", je vais prendre la voie du milieu (toujours la meilleure): Ça dépend des cas et de ton application. Si tu peux valider que les accès concurrents sur une ressource sont rares, alors la mémoire transactionnelle va être super. Sinon elle va te faire perdre plus de temps et les verrous sont ta solution.

      De même, rien n’empêche d'imaginer une application dans laquelle il y a plusieurs composants.
      Pour tous les composants sauf un, les accès concurrents a une ressource sont rares => utilisation de la mémoire transactionnelle.
      Pour le composant ou les accès concurrents sont nombreux, alors l'utilisation d'un verrou sera judicieuse même si le reste de l'application utilise une mémoire transactionnelle.

      Ainsi, je pense tout a fait possible de vouloir utiliser les deux.

      • [^] # Re: Mémoire transactionnelle et verrous

        Posté par  . Évalué à 5.

        Pour le composant ou les accès concurrents sont nombreux, alors l'utilisation d'un verrou sera judicieuse même si le reste de l'application utilise une mémoire transactionnelle.

        Non, c'est quand les modifications sont nombreuses qu'il faut éviter la mémoire transactionnelle, elle est justement adaptée à beaucoup de lecture (puisqu'il n'y a aucune opération contrairement à la pose d'un verrou).

        « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

        • [^] # Re: Mémoire transactionnelle et verrous

          Posté par  . Évalué à 3.

          Tout a fait, je suis passé un peu vite la dessus. Le SQL que j'ai posté dans un autre commentaire illustre mieux la situation (écritures concurrentes).

      • [^] # Re: Mémoire transactionnelle et verrous

        Posté par  . Évalué à 1.

        Donc a priori il n'y aura pas d'interaction entre ces deux mécanismes ; ils seront superposables.

        Leur cohabitation est une souplesse et une complexification à la fois à cause du choix. Si la mémoire transactionnelle est suffisante pour gérée correctement 80 % des cas, le jeu en vaudra la chandelle. Reste à juger sur pièce.

        Moi aussi je ne suis ni pour ni contre. Si les programmeurs ressentent la nécessité d'introduire un nouveau concept c'est qu'il existe une classe de problèmes dont la résolution est sous-optimale (ou impossible ?) en l'état actuel. Même si la mémoire transactionnelle ne devait pas être bonne réponse à cette difficulté, toutes les voies doivent être explorées pour y remédier.

        • [^] # Re: Mémoire transactionnelle et verrous

          Posté par  . Évalué à 1.

          une classe de problèmes dont la résolution est sous-optimale (ou impossible ?) en l'état actuel

          Je pencherais pour sous-optimal, sachant qu'on peut prouver qu'avec le hard actuel (compare&swap atomique) on peut implémenter correctement n'importe quel algo en wait-free (ie sans verrou, en garantissant l'absence de livelock si mes souvenirs sont bons).

          • [^] # Re: Mémoire transactionnelle et verrous

            Posté par  . Évalué à 1.

            Après, il y a une différence entre "possible en théorie" et "possible en pratique"; on peut théoriquement recoder quake 3 en lambda-calcul, ça ne veut pas dire que c'est faisable (ni souhaitable). De même, certains programmes concurrents sont théoriquement implémentables avec des verrous (ou des instructions atomiques, ça revient au même), mais éviter les deadlocks peut être trop difficile en pratique.

            C'est pour les mêmes raisons qu'on a inventé des solutions plus haut niveau que l'assembleur ou la gestion manuelle de la mémoire et qu'une bonne partie des programmeurs tiennent aujourd'hui pour acquis…

            The cake is a lie.

      • [^] # Re: Mémoire transactionnelle et verrous

        Posté par  . Évalué à 3.

        Je me répond: La page suivante explique bien que la mémoire transactionnelle est limitée sur une ou plusieurs portions précises du code (transaction statements, transaction expressions, and function transactions):
        http://gcc.gnu.org/wiki/TransactionalMemory

        Donc oui tu pourra clairement mélanger les deux approches selon tes besoins.

        • [^] # Re: Mémoire transactionnelle et verrous

          Posté par  . Évalué à 2.

          D'accord. C'est très localisé en fait. Je voyez plutôt ça comme un mode de fonctionnement implicite entre threads avec des modifications locales pour utiliser les verrous dans les sections critiques.

    • [^] # Re: Mémoire transactionnelle et verrous

      Posté par  . Évalué à 3.

      Non, mais mélanger les deux sur une même ressource n'est peut-être pas optimal.

      « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

    • [^] # Re: Mémoire transactionnelle et verrous

      Posté par  . Évalué à 2.

      Veux-tu dire "au même endroit" ? Si oui, ça m'a l'air d'être "ceinture et bretelles"…

      Sinon, j'imagine que l'expérience fera que l'on utilisera des fois et des fois, au sein d'un même programme, en fonction de la probabilité de voir 2 threads modifier "en même temps" la même zone-mémoire.

      • [^] # Re: Mémoire transactionnelle et verrous

        Posté par  . Évalué à 2.

        Oui, je pensais à l'intérieur d'un même programme découpé en tâches qui lisent seulement ou qui écrivent/lisent où on pourrait mixer la mémoire transactionnelle pour les lectures pures et les verrous pour le reste.

  • # LTO

    Posté par  (site web personnel) . Évalué à 9.

    Sur LWN un commentaire intéressant au sujet de la fonction LTO (Link Time Optimization).

    A small fact about the LTO work done for gcc 4.7: it can now LTO linux as well (needs a few minutes and a few GBs of memory on a quad-core SNB). that's quite an achievement compared to previous versions (4.5 dies an honourable death, 4.6 produces lots of symbol related errors after consuming 40 mins and 11GB of memory).

    Malheureusement il n'y a pas de bench pour voir si cela a un effet mesurable sur les performances du noyau ainsi buildé.

  • # Papa Capello

    Posté par  . Évalué à 4. Dernière modification le 25 mars 2012 à 18:07.

    sans que les autres n’essaient

    Les doubles négations, ce n’est pas bien de ne pas les éviter.

    Et « ordre de magnitude » → « ordre de grandeur » en presque vrai français quand tout le monde se mettra d’accord pour utiliser la base naturelle népérienne, ou 2.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.