L’ordonnanceur de Linux : « une décennie de cœurs perdus »

L’ordonnanceur d’un système d’exploitation est une partie cruciale pour la performance. Il décide de l’affectation des fils d’exécution aux différents cœurs et processeurs d’une machine afin d’utiliser au mieux la machine à disposition, tout en garantissant une certaine réactivité pour les applications qui en ont besoin (notamment les interfaces graphiques : elles ne peuvent pas rester plusieurs minutes sans pouvoir exécuter la moindre instruction, car elles ne peuvent alors pas répondre aux stimuli de l’utilisateur, qui a alors toutes les raisons de râler).

Il y a de cela une quinzaine d’années, Linus Torvalds déclarait, en somme, que l’ordonnancement était un problème très facile et qu’il était déjà très bien résolu dans le noyau Linux depuis dix ans (c’est-à-dire depuis les toutes premières versions du noyau) : inutile d’en discuter, tout fonctionne pour le mieux, tout va très bien, madame la marquise. Linus Torvalds estime même que l’extrapolation de ces techniques aux cas de machines à plusieurs processeurs est « trivial » : une logique de répartition de la charge entre les différents processeurs ne devrait représenter que quelques centaines de lignes de code, que les développeurs « ne devraient pas trop merder », selon ses termes.

Cependant, avec l’avènement de machines avec de plus en plus de cœurs pour le plus grand nombre, l’ordonnancement s’est alors révélé bien plus compliqué que dans le cas à un seul processeur et cœur par machine. En effet, les taux d’utilisation du processeur restent très élevés, tout semble se passer pour le mieux… sauf que certains cœurs restent inutilisés par moments. Au niveau technique, cet ordonnancement reste très similaire à celui pratiqué au début des années 1990, à la différence de la répartition de la charge : régulièrement, le noyau répartit à nouveau les tâches à effectuer sur les différents cœurs, chacun suivant alors une politique équitable entre les tâches (selon l’algorithme CFS, completely fair scheduler).

Une équipe de chercheurs a remarqué des déficiences majeures du côté de l’ordonnanceur en tentant d’expliquer certaines dégradations importantes de performance en laissant le noyau Linux gérer lui-même l’affinité des processus par rapport aux cœurs, plutôt qu’en les assignant manuellement aux cœurs disponibles. De fil en aiguille, ils ont éliminé les causes les plus probables, comme une mauvaise localité en mémoire, des contentieux à l’accès à une ressource partagée ou les changements de contexte. Ils en sont venus à suspecter l’ordonnanceur du noyau. Pour récupérer des informations suffisantes, ils ont développé des outils de suivi à très haute résolution pour caractériser la répartition des tâches aux différents cœurs et processeurs d’une machine de test. Le résultat était sans appel : certains processeurs étaient surchargés, d’autres presque complètement désœuvrés, selon des motifs étranges et difficiles à expliquer rationnellement.

Par la suite, l’équipe a cherché dans le code source du noyau les parties à incriminer, elle a trouvé un premier défaut dans le code de l’ordonnanceur CFS : les chercheurs sont alors partis dans l’exploration plus approfondie du code. Ils ont fini par trouver quatre défauts majeurs dans le code : une fois analysés et corrigés (les patchs sont disponibles sur leur site pour le noyau en version 4.1, ils ne sont pas encore intégré dans Linux), le test de performance de bases de données TPC-H a vu une amélioration de douze à vingt-trois pour cent, le plus flagrant étant probablement une amélioration d’un facteur de cent trente-sept dans certaines charges de type HPC !

Ce travail de détection et de correction doit être très fin, car les techniques conventionnelles de test et de débogage sont totalement inefficaces pour comprendre ce genre de défauts : les symptômes sont très évasifs (les épisodes problématiques sont assez fréquents, mais chacun dure au plus quelques centaines de millisecondes), il est impossible de distinguer un véritable problème du bruit de fond dans un outil comme htop.

En réalité, les problèmes se situent principalement au niveau des heuristiques de CFS : pour éviter des calculs très lourds et de la communication (forcément lente) entre les différents processeurs, certaines données sont approchées à l’aide d’heuristiques (principalement, la charge de chaque cœur et processeur). Cependant, leur impact n’a pas toujours été analysé en profondeur, ce qui laisse une grande marge d’améliorations à ce niveau.

Cet article tire plusieurs conclusions, la première étant que Linus Torvalds est très loin de détenir la vérité quant aux résultats des ordonnanceurs : non, ce n’est pas un problème résolu, il faudra encore pas mal de recherche à ce niveau pour exploiter au mieux le matériel disponible (et éviter de laisser des cœurs totalement inoccupés). Les correctifs proposés par les chercheurs ne résolvent que les problèmes qu’ils ont remarqués : ils ne prétendent pas donner des solutions génériques à tous les problèmes, ils n’ont pas poussé les tests jusqu’à déterminer l’impact sur d’autres types de charges.

L’objectif est atteint : les ordonnanceurs doivent encore évoluer.

Source : The Linux Scheduler: a Decade of Wasted Cores (présentations courte et longue).

Retours du symposium annuel de TSMC : le 10 nm en 2017, le 7 nm en 2018

Fin mars avait lieu le symposium annuel de TSMC, où le fondeur de semiconducteurs présente l’état de son commerce, mais aussi les avancées (notamment technologiques), comme les nouveaux processus de fabrication de puces. Cette habitude persiste depuis 1995, avec une édition chaque année, sans interruption. Cette fois, le symposium avait pour slogan Unleash Your Innovation : en pratique, cela signifie que TSMC étend considérablement son offre pour faciliter l’innovation du côté de ses clients.

Le marché des semiconducteurs se divise en trois types de société : les intégrées, qui comme Intel conçoivent les puces au niveau abstrait (en manipulant des portes logiques, avec des outils d’EDA) et s’occupent de leur réalisation effective sur du silicium (y compris la recherche nécessaire pour améliorer le processus), puis celles qui se spécialisent dans l’une des deux branches. ARM, AMD, NVIDIA ou encore Apple font partie de celles qui ne s’occupent que de la conception des circuits, elles sont dites fabless ; au contraire, TSMC ou GlobalFoundries s’occupent de la réalisation de ces circuits.

TSMC est une société qui se porte bien : dans sa niche, elle compte 470 clients, avec une moyenne d’un nouveau client par semaine (!). Elle fabrique 8900 produits différents, avec ses 220 technologies en cours d’exploitation : ainsi, par an, TSMC produit 10 milliards de puces. L’entreprise investit toujours : elle prévoit un total de 2,2 milliards de dollars en recherche pour la seule année 2016, a achevé la construction d’un nouveau bâtiment dans son usine Fab 12 de Hsinchu (pour la production de circuits en 7 nm) et de trois nouveaux pour la Fab 14 à Tainan (pour le 16 nm), quatre autres sont prévus à Tainan (pour le 5 nm) et deux sont en cours de construction à la Fab 15 de Taichung (pour le 10 nm). Toutes ces usines se situent à Taïwan, un autre site est prévu en Chine pour une mise en production à la fin 2018.

Une diversification des processus existants

TSMC continue à produire des semiconducteurs dans différents nœuds, pas toujours très proches de sa plus haute finesse de gravure (le 16 nm, actuellement) : ces processus plus anciens ont l’avantage d’être mieux maîtrisés, notamment au niveau des coûts. L’objectif principal de TSMC est d’améliorer la consommation énergétique (de l’ordre de vingt à trente pour cent), notamment avec ses 55ULP et 40ULP (respectivement, en 55 nm et 40 nm), dont les premières versions ont été introduites dans la période 2006-2008 ; côté 28 nm, le 28HPC+ promet d’améliorer la performance (fréquence des puces) et de diminuer encore la consommation énergétique (tension d’alimentation). Ces trois améliorations de processus existants conviendront aux applications de type « Internet des objets » de milieu de gamme.

Le haut de gamme en très basse consommation revient aux processus les plus modernes, le 16FFC (avec des transistors FinFET plus compacts). Il s’agit d’une amélioration du 16 nm existant, le 16FF+, en production de masse depuis le troisième trimestre de 2015 : la principale différence est une tension d’alimentation de 0,55 V (par rapport au 0,7 V actuels), soit une diminution de consommation de l’ordre de cinquante pour cent. Cette évolution vient à contrecarrer les plans initiaux sur le 16 nm : les premières annonces indiquaient que les clients les plus sensibles aux questions de coûts resteraient probablement très longtemps sur le 28 nm ; maintenant, un an plus tard, TSMC prévoit d’augmenter sa capacité de production.

Les prochains processus : 10 nm en 2017, 7 nm en 2018

TSMC est plus que très confiant sur son 10 nm : les premières puces devraient sortir fin de cette année, la production en volume de puces arrive en 2017, avec de l’ordre de 200 000 galettes de silicium par trimestre (300 000 par trimestres prévues en 16 nm pour 2016).

Cependant, ce processus devrait être une transition très rapide vers le 7 nm : seulement deux bâtiments devraient produire dans ce processus (pas d’autre prévu en construction), le 7 nm devant arriver… l’année d’après. Par conséquent, certains clients comme Xilinx ont d’ores et déjà annoncé qu’ils passeront complètement le nœud 10 nm et ne quitteront le 16 nm que pour le 7 nm.

La justification du côté de TSMC est que le 7 nm réutilisera 95 % de l’équipement du 10 nm, qui sera donc maîtrisé. Par contre, la densité en transistors augmentera d’un facteur 1,63 entre le 10 et le 7 nm, à comparer à un facteur 1,9 entre le 28 et le 20 nm.

Le 7 nm sera disponible, dès le début, en deux versions : l’une orientée mobilité et basse consommation, l’autre pour la haute performance (l’habitude est plus de concentrer sur une version au début, puis d’en développer de nouvelles, comme les 55ULP, 40ULP ou encore 16FFC). La première gagnerait trente à quarante pour cent en consommation énergétique et quinze à vingt pour cent en performance, jusque vingt-cinq pour cent en performance pour la deuxième version (pour atteindre des fréquences de l’ordre de quatre gigahertz).

Sources : Key Takeaways from the TSMC Technology Symposium Part 1, Key Takeaways from the TSMC Technology Symposium Part 2, TSMC Adding Near-threshold Voltage Operation at 16nm.

Sortie de Qt Creator 4.0

Peu de temps après la RC, Qt Creator est maintenant disponible en version 4.0. Comme pour Qt, Digia a mis à disposition certaines fonctionnalités qui étaient autrefois réservées aux clients commerciaux, comme un meilleur profileur QML et l’intégration des tests automatisés dans l’interface — des parties du Qt Quick Designer l’ont été dans Qt Creator 3.6, comme les éditeurs de connexions et de chemins.

Le profileur QML vient notamment avec un diagramme en flammes pour décortiquer les portions du code qui prennent le plus de temps à l’exécution. Le thème par défaut de Qt Creator est maintenant entièrement plat (le précédent est toujours disponible dans les options).

L’intégration des projets CMake se fait maintenant plus naturellement, puisque l’outil est appelé dès que cela est nécessaire. La configuration des kits, avec notamment la version de Qt, se fait automatiquement.

Le modèle de code Clang, utilisé pour analyser le code C++ et fournir notamment la coloration syntaxique et l’autocomplétion, est activé automatiquement dès que l’extension est chargée (cette extension est toujours marquée comme expérimentale : Qt Creator ne l’active pas par défaut).

Côté débogage, bon nombre de problèmes avec LLDB ont été corrigés, notamment avec la version livrée dans Xcode 7.3.

Le mode Analyse a complètement disparu : il est maintenant intégré au mode Débogage. Ce dernier donne maintenant accès à une pléthore d’outils, intégrant un débogueur, l’analyseur statique de Clang, memcheck, callgrind et les outils de profilage QML.

Télécharger Qt Creator 4.0
Source : Qt Creator 4.0.0 released.

Un nouvel optimiseur de code pour Visual C++

Les compilateurs sont des programmes informatiques d’une importante complexité. Ils sont généralement structurés en une partie frontale, qui comprend le langage d’entrée, puis d’une partie arrière, qui s’occupe de traduire le programme d’entrée en du code binaire exécutable par le processeur. Les deux parties communiquent à l’aide d’une représentation intermédiaire (IR). Ainsi, pour qu’une même suite de compilateurs comprenne plusieurs langages et puisse générer du code pour plusieurs processeurs, il n’est pas nécessaire d’écrire un compilateur spécifique pour chaque paire langage-processeur : il suffit d’écrire les paires langage-IR et IR-processeur. Tout le travail effectué pour un processeur sera alors utilisable pour n’importe quel langage d’entrée.

Dès la génération du code intermédiaire, un compilateur utilise énormément de passes d’optimisation, afin de rendre le code plus rapide. Elle utilise des techniques comme la propagation des valeurs : si une variable a une valeur connue à un endroit du code (initialisation, condition…), alors cette valeur peut être propagée dans une série de calculs, qui seront alors effectués à la compilation au lieu de l’exécution. Ces passes sont effectuées en partie sur la représentation intermédiaire, pour les optimisations indépendantes du processeur, mais également sur du code machine déjà généré, pour tirer le meilleur parti possible du matériel.

Généralement, cette phase d’optimisation est extrêmement cruciale, étant donné que la représentation intermédiaire est suffisamment générale pour plusieurs types de processeurs et relativement simple dans les instructions disponibles : pour effectuer certaines opérations, il est parfois nécessaire d’écrire des dizaines d’instructions IR, alors que certains processeurs peuvent réaliser la même opération en une seule instruction. De plus, une représentation intermédiaire doit être prête pour les phases d’optimisation qui suivent, notamment en simplifiant toutes les étapes de raisonnement : dans les IR de type SSA, notamment, une variable ne peut être assignée qu’une seule fois, ce qui allonge d’autant plus le code.

Un nouvel optimiseur pour Visual C++

Le compilateur C++ de Microsoft, connu sous le nom de Visual C++, a longtemps été laissé dans un état proche de l’abandon. Depuis quelques années, les équipes de développement ont mis les bouchées doubles pour ramener le compilateur dans la course, avec une compatibilité avec les normes les plus récentes, au niveau de GCC ou Clang. Depuis lors, ils ont effectivement rattrapé en grande partie leur retard à ce niveau, mais pas encore pour les optimisations du code.

L’optimiseur actuel ne disposait que d’une série de transformations assez basiques, n’exploitant qu’une vue assez limitée des fonctions. Bon nombre d’optimisations fonctionnent en trouvant des motifs et en les remplaçant par une version améliorée, mais tous les motifs les plus utiles ne sont pas toujours implémentés. De plus, le code vectorisable n’est pas optimisé au meilleur de ses possibilités. Toutes ces limitations ont une origine historique : le compilateur C++ de Microsoft a des origines très anciennes, il provient de l’époque DOS où la mémoire était très limitée, ce qui limite les possibilités. Les efforts actuels portent principalement sur une modernisation du code, en éliminant les compromis d’un autre âge.

Le nouvel optimiseur exploite désormais une représentation intermédiaire SSA. Les algorithmes implémentés par-dessus peuvent ainsi être plus efficaces en temps par rapport aux approches par analyse du flux de données. Il se base sur une bibliothèque C++ avancée, exploitant les templates à foison, pour décrire les transformations à effectuer, ce qui a permis d’ajouter bon nombre d’optimisations simples en très peu de temps (surtout par rapport à l’infrastructure précédente).

Les développeurs de Visual C++ indiquent également avoir prêté attention à la correction de ces optimisations : il n’y a rien de plus désagréable que de passer des journées à déboguer son code pour trouver que, finalement, le problème n’est pas dû au code, mais bien au compilateur. Linus Torvalds a récemment torpillé GCC à ce sujet. Ici, les développeurs ont absolument cherché à éviter ces écueils, en testant leurs passes d’optimisation sur des programmes courants comme Chrome ou Firefox, puis sur des bibliothèques imposantes côté Microsoft comme CoreCLR ou Chakra.

Ils ont aussi employé des techniques de vérification formelle (à l’aide d’ALIVE et l’outil de démonstration automatique Z3, tous deux issus de Microsoft Research et aussi utilisés pour LLVM) et de la génération de code aléatoire avec Csmith (et C-Reduce pour réduire le code posant problème au strict minimum). Certains outils du projet LLVM ont pu être utilisés, puisque Visual C++ peut en exploiter les parties avant, comme Opt-fuzz, qui génère des expressions arithmétiques à optimiser.

Un exemple

Ces nouvelles optimisations peuvent avoir un effet assez radical sur certains bouts de code. Par exemple, pour un test de parité :

int test(int a) {
    return a % 2 != 0 ? 4 : 2;
}

Les précédentes versions du compilateur produisaient un code qui prenait entre cinq et dix cycles en x86, selon que tout le processeur est exploité (prédiction du branchement parfaite) ou non :

?test@@YAHH@Z PROC
    and   ecx, -2147483647
    jge   SHORT $LN3@test
    dec   ecx
    or    ecx, -2
    inc   ecx
$LN3@test:
    test  ecx, ecx
    mov   eax, 2
    mov   edx, 4
    cmovne eax, edx
    ret   0

Sauf que… Dans le test a % 2 == 0, le signe de a n’a aucune espèce d’importance, seul un bit est important : le modulo peut être remplacé par une opération logique, c’est-à-dire a & 1 == 0. Or, la comparaison implique un branchement dans le code, forcément lent sur les architectures x86 modernes : pour s’en débarrasser, la structure bool(a) ? C1 : C2 peut être remplacée par C2 + a*(C1-C2), c’est-à-dire exclusivement des calculs. Par conséquent, le nouveau code assembleur est le suivant :

?test@@YAHH@Z PROC
    and   ecx, 1
    lea   eax, DWORD PTR [rcx*2+2]
    ret   0

Celui-ci prend, à tous les coups, deux cycles d’horloge : par rapport à cinq à dix cycles, le gain est important, tant en rapidité qu’en taille de l’exécutable.

D’autres mécanismes effectuent une analyse statique du code, en précalculant autant de bits que possible dans les variables. Par exemple, lors d’une conversion vers un type plus grand, une série de bits est forcément à zéro, peu importe la valeur d’entrée. Ensuite, cette information peut être adaptée en fonction des opérations effectuées, ce qui peut guider le reste du processus.

int test(unsigned char a) {
    short b = a;    // b: 00000000________, a: ________
    b <<= 4;        // b: 0000________0000
    b |= 3;         // b: 0000________0011
    return b != 0;  // -> return true  
}

Impact sur la taille du code généré

L’impact de ces modifications sur le code généré n’est pas facile à établir : certaines optimisations diminuent forcément la quantité de code, le compilateur sera alors plus enclin à recopier in extenso le code de petites fonctions pour éviter le surcoût dû à tout appel de fonction (qui n’est négligeable que pour des fonctions plus grandes) — ce qui conduit à l’augmentation de la taille du code. Il n’empêche, les résultats sont intéressants : sur tout Windows, c’est-à-dire plus d’un gigaoctet, les gains sont de 438 Ko par rapport à l’optimiseur précédent (0,3 %) ; sur SQL Server, 46 Ko sur 64 Mo (0,8 %) ; sur Chakra, le nouveau moteur JavaScript, 10 Ko sur 6 Mo (1,7 %).

En analysant plus en détail l’impact au niveau des instructions, les plus lentes sont largement évitées (branchements, multiplications, divisions), remplacées par des opérations plus rapides (comme des déplacements conditionnels). Les temps de compilation ont été impacté de diverses manières : une augmentation de 1,7 % pour Chrome ou une diminution de 2,6 % pour le noyau Windows.

Et alors ?

Les travaux sur l’optimiseur viennent seulement d’être annoncés : l’architecture choisie permettra aux développeurs d’ajouter des optimisations supplémentaires rapidement (et certaines sont déjà en cours de planification). Cet optimiseur devrait arriver dès Visual C++ 2015 Update 3, mais le travail continuera sur cet aspect du compilateur, afin de le rendre compétitif par rapport à ses concurrents, voire de les dépasser. Il est d’ores et déjà possible de le tester.

Source : Introducing a new, advanced Visual C++ code optimizer.
L’image a été créée par l’auteur et est soumise au droit d’auteur.

Malaise dans la communauté Qt par rapport à l’édition commerciale

À ses débuts en 1991, Qt était un projet exclusivement commercial, avant de voir ses sources disponibles en 1995 sous une licence presque libre (la redistribution des sources modifiées n’était pas autorisée). La situation n’a posé de problème qu’en 1998, quand KDE est devenu un environnement de bureau majeur : la licence alors adoptée était la QPL, libre mais incompatible avec la GPL. En même temps, les développeurs de KDE ont obtenu que, si plus aucune version libre de Qt ne sortait en un an, la dernière tomberait automatiquement sous une licence très permissive, de type BSD — un accord toujours valable. L’histoire de Qt l’a alors porté vers la GPL, puis plus récemment vers la LGPL et, dernièrement, une mise à jour vers la dernière version de ces licences.

En d’autres termes, Qt a depuis longtemps baigné dans le logiciel libre, en acceptant les contributions de l’extérieur. Depuis cinq ans, cette organisation s’est même formalisée autour du Qt Project : tout le développement a lieu en public, toute personne externe peut prendre part au développement et même à la gouvernance du projet.

Digia a lancé un programme d’unification de l’offre Qt, en rapprochant les éditions libres et commerciales de Qt. Ce mouvement a notamment libéré bon nombre de fonctionnalités commerciales de Qt. Un autre impact a été la fusion des sites Web : qt.io est censé présenter les deux éditions. C’est actuellement la pierre d’achoppement : la partie libre est de moins en moins présente sur le site officiel, en présentant plus Qt pour les utilisateurs que pour les potentiels contributeurs.

Les griefs ne s’arrêtent pas à ce manque de visibilité : le site met en avant les éditions commerciales, en reléguant le côté libre de côté. Pire encore, quand les aspects libres se présentent, le site n’hésite pas à pointer du doigt les possibles problèmes légaux avec les licences libres… même si ces soucis ne pourraient concerner qu’une très faible minorité des utilisateurs.

Source : [Development] Qt-Project misrepresented on qt.io.

Sortie de PyQt 5.6

Riverbank a publié la dernière version de sa couche de liaison Qt pour Python, PyQt, en version 5.6. L’amélioration principale est une pleine compatibilité avec Qt 5.6. De plus, la distribution se fait maintenant préférentiellement par wheels, sur toutes les plateformes (les installateurs sous la forme d’EXE ne seront plus disponibles pour Windows après cette version).

Plus en détail, le module Qt WebEngine Core a été ajouté pour donner un accès plus direct au moteur Chromium de Qt WebEngine, avec une API de plus bas niveau. Quelques fonctions manquantes par rapport à Qt ont été ajoutées : qt_set_sequence_auto_mnemonic() dans Qt GUI, MouseLock dans QWebEnginePage.Feature, WA_DontShowOnScreen.

Plus intéressant pour les utilisateurs d’environnements de développement intégrés, des fichiers PEP 484 sont maintenant générés. Ils intègrent une indication sur les types attendus par les fonctions lors de leur appel, ce qui permet de détecter bon nombre d’erreurs avant même d’exécuter son application.

Source : PyQt v5.6 Released

Sortie de GCC 6.1 : C++14 activé par défaut, OpenMP 4.5

GCC vient de sortir sa version majeure annuelle, numérotée 6.1. Elle cumule les développements d’une année entière, avec des évolutions dans tous les domaines : côté C++, le compilateur se positionnera sur la norme C++14 par défaut, au lieu de C++98 auparavant, quelques fonctionnalités de C++17 ont été implémentées ; pour le domaine HPC, OpenMP 4.5 est complètement implémenté, les calculs peuvent être déportés sur des coprocesseurs Intel Xeon Phi « Knights Landing » et sur du matériel AMD par HSAIL ; l’implémentation de OpenACC 2.0a a été améliorée, avec une possible déportation sur du matériel NVIDIA par PTX. Au niveau matériel, les prochains processeurs d’AMD, basés sur l’architecture Zen, sont déjà pris en charge ; les plateformes ARM ont été le théâtre de bon nombre d’améliorations ; l’architecture PowerPC a reçu la compatibilité avec POWER9, la prochaine itération des processeurs d’IBM.

Côté C++

La précédente version majeure de GCC, numérotée 5.1, apportait les dernières touches à l’implémentation de C++14, en apportant des fonctionnalités comme la désallocation d’une partie d’un tableau, des constexpr plus généraux, des fonctions anonymes génériques.

Cette nouvelle version de GCC s’arme déjà pour C++17, avec par exemple, la définition d’attributs sur les énumérateurs ou encore des expressions utilisant l’opérateur fold (aussi nommé reduce ou autre, selon les modes) :

// Cette fonction somme tous ses arguments.
template<typename... Args>
  bool f(Args... args) {
    return (true + ... + args);
  }

Plus de détails dans la documentation.

Une nouvelle optimisation en C++ casse du code existant

Une nouvelle optimisation fait parler d’elle : la propagation de valeurs considère désormais que le pointeur this en C++ (qui pointe vers l’objet courant) est toujours initialisé (sa valeur n’est jamais nullptr). Ce point particulier n’a jamais été précisé dans une norme, les compilateurs sont donc libres quant à son interprétation — même si Qt 5 ou Chromium exploitaient l’implémentation précédente. Ce cas peut arriver pour des structures, comme un arbre binaire :

struct Node {
  Node * left;
  Node * right;
};

Pour traverser cet arbre en C, la manière la plus naturelle d’écrire l’algorithme est récursive. Pour traiter le cas d’une branche absente, la fonction commence par vérifier que le pointeur passé en argument est bien valide :

void in_order(Node* n) {
  if (! n) return;
  in_order(n->left);
  in_order(n->right);
}

En C++, la syntaxe est plus plaisante avec une fonction membre. Dans ce cas, l’argument de la fonction est passé de manière implicite, à travers le pointeur this :

void in_order() {
  if (this == nullptr) return;
  left->in_order();
  right->in_order();
}

Cependant, avec cette optimisation (permise par le standard C++), le premier test sera toujours faux, puisque, par hypothèse, this est toujours un pointeur valide… et ce code plantera lamentablement à l’arrivée d’une feuille. Heureusement, cette optimisation peut être désactivée avec un simple paramètre lors de la compilation (-fno-delete-null-pointer-checks) et l’absence de tel code peut aussi être vérifiée (-fsanitize=undefined).

Bien évidemment, une meilleure manière d’écrire le code vérifie directement chacun des deux pointeurs contenus dans la structure avant de continuer la récursion — ce qui évite en passant les problèmes potentiels avec cette optimisation :

void in_order() {
  if (left)   left->in_order();
  if (right) right->in_order();
}

Sources : GCC 6.1 Released, Why does the enhanced GCC 6 optimizer break practical C++ code?, GCC 6 Release Series: Changes, New Features, and Fixes, C++ Standards Support in GCC.
Merci à Winjerome pour ses conseils à la rédaction.

PySide 2 : de retour sous l’ombrelle du Qt Project

Qt est un framework C++ principalement connu pour la création d’interfaces graphiques, c’est notamment ce qui lui a valu bon nombres de couches d’accès depuis d’autres langages, principalement Python. Il en existe deux : PyQt et PySide. Historiquement, PyQt est arrivé en premier, mais sous licence GPL ou commerciale — ce qui ne convient pas à bon nombre de projets, la famille de licences GPL étant prévue pour empoisonner tout le code qui l’utilise (copyleft). Nokia a donc lancé le développement de PySide, qui est disponible sous une licence bien plus permissive : la LGPL.

Cependant, dès 2011, les développeurs avaient des doutes sur la viabilité de PySide : Nokia venait d’arrêter de les financer. Le projet n’a plus pu avancer à un bon rythme les années d’après, même en rejoignant l’infrastructure du Qt Project. En 2015, il a été déclaré officiellement abandonné. Au niveau technique, PySide n’a jamais pu être porté tel quel vers Qt 5, il s’est limité à Qt 4, à cause notamment de la nouvelle architecture modulaire.

Peu après l’annonce de mort cérébrale, un développeur indépendant a repris le travail vers un PySide 2. Le projet revit petit à petit.

Depuis lors, la Qt Company a vu son intérêt grandir dans le projet et s’apprête à y consacrer plusieurs développeurs à temps plein, ainsi que d’investir dans l’infrastructure nécessaire, de telle sorte que PySide devienne une partie intégrante des nouvelles versions de Qt. L’intérêt principal est de fournir une couche de liaison Python sous une licence libre — la LGPL —, en accord avec les derniers changements à ce sujet dans Qt. Évidemment, l’objectif est aussi de fournir PySide sous une licence commerciale, ce qui nécessite l’accord des développeurs existants de PySide.

Pour la technique, l’avenir de PySide passera probablement par une grande réécriture de son code. En effet, une bonne partie utilise Shiboken, un générateur de code qui doit analyser une bonne partie de la syntaxe C++ du code de Qt, un exercice qui deviendra de plus en plus difficile avec Qt 5.7 et l’exploitation plus importante de C++11. Une possibilité serait d’exploiter Clang, plus particulièrement sa partie d’analyse syntaxique et sémantique du code C++.

Source : Bringing pyside back to Qt Project.

Sortie de Qt 5.7 Beta

Pas loin d’un mois et demi après la première préversion, Qt 5.7 Beta pointe le bout de son nez. En quelques mots, elle apporte bon nombre de nouveaux modules, exploite C++11 dans le code de Qt et dans son API, tout en proposant une unification au niveau des fonctionnalités entre les versions libre et commerciale.

Qt existe dans sa forme actuelle uniquement grâce à C++, tant dans ses fondations (parfois décriées) que dans sa performance à l’exécution. Le langage évolue, Qt le suit pour profiter des dernières fonctionnalités — avec un certain délai, pour ne pas abandonner en route ceux qui ne peuvent pas mettre à jour leur compilateur (notamment en gardant une version avec un support à long terme). Ainsi, dès Qt 5.7, la compatibilité avec C++98 est abandonnée, laissant place à un minimum de C++11. Des fonctionnalités comme le mot clé auto ou les fonctions anonymes trouvent maintenant place dans le code de Qt et dans son API.

Au niveau des modules, certains préversions technologiques atteignent leur maturité : Qt Quick Controls 2 et Qt 3D (pour ce dernier, après des années de développement !). De nouvelles préversions font également leur apparition : Qt Wayland Compositor, Qt SCXML, Qt SerialBus et Qt Gamepad.

Les changements de licence ont déjà fait couler pas mal d’encre. En résumé, la plupart du code de Qt sera disponible sous licence LGPLv3 ou GPLv2, les derniers modules libérés seront sous licence LGPLv3 ou GPLv3, Qt Creator et d’autres outils sous GPLv3 uniquement — ou, comme toujours, sous licence commerciale. Malgré la complexification de l’offre qui donnera du fil à retordre aux services juridiques, ces licences donnent suffisamment de garanties à Digia pour libérer plus de fonctionnalités dans l’édition libre de Qt.

Cette fois, contrairement à la précédente préversion, cette version est livrée avec des binaires prêts pour les tests. Elle est aussi intégrée aux installateurs de Qt Creator 4.0 RC.

Source : Qt 5.7 Beta Released.

Sortie de Qt Creator 4.0 RC 1

Selon ses développeurs, la version finale de Qt Creator 4.0 ne tardera plus : la RC 1, sortie aujourd’hui, s’occupe de corriger un bon nombre de défauts détectés depuis la sortie de Beta, il y a à peu près un mois.

Les principaux changements depuis la dernière préversion concernent l’interface, avec un thème plat lustré : il est maintenant le thème par défaut de Qt Creator, les utilisateurs n’ayant jamais changé de thème le verront par défaut lors de la mise à jour. L’ancien thème est bien sûr toujours disponible, dans le menu Outils, Options, Environnement, Interface (option Classique).

Les binaires de cette nouvelle préversion sont disponibles sur la page des téléchargements de Qt.

Source : Qt Creator 4.0 RC1 released.