Visual Studio en 64 bits ?

Visual Studio est l’environnement de développement intégré proposé par Microsoft. Il gère une pléiade de langages, historiquement des langages natifs comme C++, mais aussi toute la pile .Net avec C#, VB.Net et d’autres, y compris pour le Web. Il est souvent cité en référence comme environnement de développement. À l’origine payant, les éditions Express sont apparues en 2005 ; nettement moins limitées, les éditions Community sont beaucoup plus récentes.

Cependant, l’environnement est aussi connu pour ne pas toujours être extrêmement réactif, notamment dans le cas de projets de grande ampleur ou avec des extensions. Suite à un tweet de Gunnar Skogsholm, le débat sur une version 64 bits de Visual Studio est relancé : ainsi, l’environnement ne serait plus limité à quatre gigaoctets de mémoire vive, il pourrait exploiter toute la mémoire des machines actuelles, ce qui pourrait aider en performance. D’ailleurs, une série d’environnements de développement y sont déjà passés, comme Eclipse ou Android Studio — ces deux-là ayant la particularité d’être écrits en Java et de dépendre d’une JVM, les efforts de portage en 64 bits sont donc très limités.

Des raisons techniques

Rico Mariani, un ancien développeur de Visual Studio, maintenant passé dans l’équipe de Microsoft Edge (le nouveau navigateur de Microsoft), indique cependant que passer au 64 bits n’apportera pas grand-chose à l’EDI, cela risque même plus probablement de lui causer d’autres problèmes de performance. En effet, du côté technique, ces 64 bits correspondent à la taille d’une adresse en mémoire (ce qui permet d’indexer beaucoup plus de mémoire vive qu’en 32 bits) ; cette transition doublerait donc la taille de tous les pointeurs, ce qui a des impacts sur l’alignement en mémoire des structures de données, sur la densité des données stockées et donc la localité.

De manière générale, le code sera plus lourd, l’application occupera plus de place en mémoire en 64 bits plutôt qu’en 32 bits (dans un facteur qui dépend fortement de l’application considérée). Par conséquent, les caches du processeur seront moins bien utilisés, puisqu’il n’ont pas soudainement augmenté en taille ; les registres disponibles seront certes plus grands et plus nombreux, mais ce facteur n’a de réel impact que sur le code effectuant des traitements lourds (comme du calcul scientifique ou de l’analyse de données) plutôt que des interfaces graphiques. Cette migration en 64 bits ne se justifie donc que s’il est nécessaire d’utiliser plus de mémoire que la partie accessible en 32 bits.

Une autre justification est moins attendue : en 64 bits, une fuite de mémoire ne fera pas planter l’application rapidement, puisqu’elle pourra consommer toute la mémoire de l’ordinateur, le ralentir à l’extrême et le rendre complètement inutilisable. Ce genre de justification est encore plus valable pour un navigateur qui autorise des extensions.

Utiliser plus de mémoire est une erreur de conception, pour Rico Mariani

D’ailleurs, même si cette mémoire supplémentaire était utile, il y a d’autres options pour rester en 32 bits, notamment une représentation plus efficace des données en mémoire. Pour gagner en performance, cette solution est bien évidemment meilleure que d’exploiter plus de mémoire. L’idée est donc de prévoir son code pour que seule une partie de la mémoire requise doive résider en mémoire vive, c’est-à-dire stocker la plupart des données dans un fichier et s’assurer d’en avoir besoin très peu souvent.

En effet, pour qu’une application puisse se mettre à grande échelle, ce genre de techniques est souvent requis. Pour un client, l’approche est très positive : il est possible de faire bien plus avec moins de ressources. Par exemple, en 1989, même avec 640 ko de mémoire vive, il restait possible d’exploiter sans problème de performance une base de données de 24 Mo, simplement en gardant un cache de 12 ko de données intéressantes pour accélérer les opérations de recherche et de lecture. À l’heure d’aujourd’hui, les échelles monteraient plutôt à quelques téraoctets de données au moins à traiter, mais le principe reste d’application. Le conseil de Rico Mariani est de considérer les données comme une base de données relationnelle (SQL), puis de la charger par tranches en mémoire, au lieu d’exploiter des représentations plus naturelles pour un programmeur à base de pointeurs.

Cette migration n’est de toute façon pas encore utile

Ces considérations techniques éloignent le débat des points réellement importants pour une application : être agréable à utiliser. Utiliser telle ou telle technologie n’a aucun impact sur ce critère premier ; en réalité, utiliser aussi peu de technologies différentes est probablement une bonne chose. De même, utiliser plus de mémoire n’a pas d’impact direct sur l’utilisabilité : moins de mémoire pour la même expérience devrait être l’objectif. En d’autres termes, une migration en 64 bits n’a pas de sens pour l’utilisateur de Visual Studio.

De plus, elle coûte en temps de développement, qui pourrait être investi dans d’autres fonctionnalités. Notamment, les formats de fichiers binaires utilisent régulièrement des pointeurs, ce qui empêche une migration aisée entre 32 et 64 bits. Cette même évolution a longtemps été retardée par Firefox par manque de compatibilité avec un grand nombre de dépendances externes en 64 bits : il est difficile de ne pas effectuer une migration complète, c’est-à-dire seulement les quelques parties qui en bénéficieraient.

Depuis 2008, Visual Studio permet la création d’extensions chargées en dehors du processus principal de l’EDI, c’est-à-dire dans un processus séparé, avec un espace mémoire séparé. Ces extensions peuvent être réalisées de diverses manières : par exemple, le cœur de Visual Studio est assez léger, beaucoup de fonctionnalités sont proposées en extensions (comme les solutions), dont un nombre grandissant est écrit en C#, avec une exécution dans une machine virtuelle. Il est aussi possible de compiler ces extensions en 64 bits si nécessaire… et le fait est que très peu d’extensions le font, parce que ce changement ne leur est pas utile. Par contre, Resharper C++, une extension de JetBrains pour Visual Studio, à l’origine du retour de cette controverse, ne profite pas de cette possibilités et a des difficultés à gérer de grandes quantités de code.

Et Rico Mariani de conclure en disant qu’avoir un système d’exploitation 64 bits est extrêmement utile — ce qui n’est pas le cas de la majorité des applications.

Sources : Revisiting 64-bit-ness in Visual Studio and elsewhere, 64-bit Visual Studio — the « pro 64″ argument, Visual Studio: Why is there no 64 bit version? (yet).

Calendrier 2016 pour Scala : la version 2.12 en vue

Scala est un langage de programmation pour la JVM, c’est-à-dire qu’il exploite l’écosystème Java, mais avec une syntaxe et des concepts radicalement différents de ceux de Java, tout en maintenant une forte compatibilité (tout code Java peut être appelé depuis Scala et vice-versa). Scala est donc un langage orienté objet, mais fonctionnel depuis sa conception (contrairement aux extensions fonctionnelles de Java 8) ; il possède également un système de typage fort. De manière générale, il tend à être concis tout en éliminant les défauts du langage Java — sa conception a débuté en 2001 à l’EPFL, dans le laboratoire de méthodes de programmation (LAMP).

La série actuelle, numérotée 2.11, sera la dernière à être compatible avec Java 6, avec des versions régulièrement mises à disposition. Les développeurs peaufinent énormément cette version, car la suivante est l’objet de grands travaux, avec notamment l’élimination de la compatibilité avec Java 6 et 7. La dernière version devrait être la 2.11.9, au troisième trimestre de 2016, c’est-à-dire deux ans après la première version de Scala 2.11.

Le futur s’annonce de plus en plus excitant : pour tirer le meilleur parti de Java 8, le compilateur encodera d’une manière très différente les traits et fonctions anonymes, beaucoup plus proche du comportement actuel de Java 8. Ainsi, l’interopérabilité sera beaucoup plus facile avec Java, avec la possibilité d’écrire des fonctions anonymes en Java pour les utiliser avec une bibliothèque Scala et vice-versa — ceci, sans changement du code Scala. Du côté technique, cet encodage utilisera les pointeurs sur méthodes (instances de la classe MethodHandle), comme Java 8, ce qui devrait diminuer les temps de compilation et la taille des binaires générés, même si le gain de performance n’est pas clair.

De manière plus générale, le compilateur a droit à une cure de jouvence, basé sur les derniers travaux côté EPFL de Miguel Garcia (partiellement intégrés dans Scala 2.11) : de manière générale, seule l’analyse syntaxique du code Scala est gardée par rapport aux versions précédentes, le reste a été fondamentalement retravaillé pour augmenter la performance (la compilation est de quinze pour cent plus rapide qu’avec Scala 2.10, sur tout le processus) et la taille des binaires générés.

La syntaxe du langage n’évolue pas entre Scala 2.11 et 2.12, toutes ces améliorations se font sous le capot. Actuellement, la préversion 2.12 M3 est disponible depuis début octobre ; elle est déclarée suffisamment stable pour que les développeurs de bibliothèques commencent à tester et à distribuer des versions compilées de leurs bibliothèques. La prochaine, numérotée 2.12 M4, est prévue fin janvier 2016, avec la première version admissible 2.12 RC1 fin mai 2016. La version finale n’est pas encore planifiée, mais ne devrait pas tarder, à moins que des défauts majeurs soient trouvés.

Les versions suivantes devraient reprendre le train des améliorations dans la syntaxe et la bibliothèque standard, avec un compilateur bien plus facile à maintenir et à faire évoluer. Rien n’est encore véritablement planifié, mais les améliorations imaginées comportent :

  • une simplification des collections (par exemple, de leur hiérarchie), par défaut immuables, avec un déplacement de fonctionnalités en dehors de la bibliothèque standard, notamment pour faciliter l’optimisation ;
  • des collections parallèles avec des améliorations de performance, obtenues par la fusion d’opérations et un ordonnancement ;
  • l’intégration de la réflexion et des macros à la Lisp comme fonctionnalités pleinement supportées (certaines sont actuellement expérimentales) ;
  • une syntaxe simplifiée et unifiée, pour se rapprocher des principes fondateurs du langage : un ensemble réduit de fonctionnalités orthogonales faciles à assembler (comme Lisp) ; la syntaxe XML pourrait ainsi disparaître, tout comme les fonctionnalités qui mènent régulièrement à des comportements inexplicables pour les débutants.

Source : 2016 Scala Release Schedule update, Scala 2.12 Roadmap.

Sortie de Julia 0.4

À peine un mois après la sortie de sa RC 1, plus d’un an après sa dernière version mineure (0.3 en août 2014), la version finale de Julia 0.4 est sortie. Ce langage de programmation assez récent est principalement prévu pour le calcul scientifique. Similaire à MATLAB au niveau de la syntaxe, il est de très haut niveau et dynamique, tout en atteignant une performance comparable aux langages statiques comme C ou Fortran.

Pour les utilisateurs, les nouveautés principales de cette version mineure concernent la performance : la compilation incrémentale des paquets, ce qui réduit fortement le temps de chargement des plus lourds d’entre eux ; le ramasse-miette est passé à une implémentation par générations, ce qui améliore la performance dans les cas les plus fréquents par rapport à l’implémentation traçante précédente ; des canaux de communication entre tâches plus rapides. Les types des tuples ont complètement changé, passant de (A,B) à Tuple{A,B}, ce qui est plus cohérent ; de plus, cette refactorisation autorise la graphie field::NTuple{N,T} pour désigner des tuples de N éléments d’un même type.

Les développeurs de paquets se réjouiront de la finalisation d’autres fonctionnalités, comme la surcharge des appels de fonction (y compris les constructeurs) pour n’importe quel objet (et pas seulement la fonction elle-même) ; en particulier, il devient possible de définir des constructeurs pour des types abstraits. Les fonctions générées donnent un contrôle bien plus grand sur la spécialisation des fonctions lors de la compilation : ces fonctions retournent un code en fonction du type des paramètres (et non une valeur en fonction des valeurs des paramètres pour les fonctions traditionnelles).

De manière générale, Julia 0.4 a aussi été l’occasion d’améliorer la performance (réduction des vérifications effectuées lors de l’adressage tout en garantissant le même niveau de sécurité) et la flexibilité des tableaux à plusieurs dimensions, des vues sur ces tableaux (SubArray) et de l’itération (avec par exemple la fonction eachindex() pour itérer sur tous les éléments d’un tableau, peu importe le nombre de dimensions, en garantissant une performance optimale) ; les changements implémentés sont listés dans un métaticket. Plus de changements sont prévus pour Julia 0.5, détaillés dans le métaticket Arraypocalypse.

La communauté Julia a aussi gagné en maturité depuis l’instant de mise à disposition de la version 0.3. Notamment, une série de paquets ont atteint une belle maturité : JuliaOpt pour l’optimisation ; JuliaStats pour les statistiques et l’apprentissage automatique ; JuliaGPU pour l’accès au GPU ; IJulia, une interface en feuilles de calcul basée sur IPython ; Images.jl pour le traitement d’images ; Gadfly et Winston pour les graphiques ; Juno comme environnement de développement.

Source : Julia 0.4 Release Announcement.

Merci à Claude Leloup pour ses corrections.

Sortie de Julia 0.4 RC1

Julia est un langage de programmation assez récent prévu pour le calcul scientifique (sa première version est sortie en 2009). Similaire à MATLAB au niveau de la syntaxe, il est de très haut niveau et dynamique, mais sa conception même lui permet d’atteindre une performance comparable aux langages statiques comme C ou Fortran, par l’utilisation de la compilation juste à temps (JIT). Selon les tests de performance publiés sur le site officiel, il peut être plus rapide que le C ou jusque deux fois plus lent — son principal concurrent, MATLAB, pouvant être plusieurs milliers de fois plus lent. Pour y arriver, l’interpréteur n’utilise pas la programmation orientée objet, mais un concept dérivé : la fonction à appeler est déterminé en fonction du type des arguments (multiple dispatch) ; au besoin, il peut aussi directement appeler du code C ou Fortran, directement depuis la bibliothèque standard (des modules externes permettent de faire la même chose pour C++ et Python).

En tant que langage spécifiquement prévu pour le calcul scientifique, un bon nombre de bibliothèques sont d’ores et déjà disponibles dans le domaine pour former une bibliothèque standard plus que conséquente, principalement pour l’algèbre linéaire, la génération de nombres aléatoires et le traitement du signal. Notamment, toutes les fonctions de BLAS existent, mais sont également intégrées dans la syntaxe du langage (* pour la multiplication matricielle, \ pour la résolution de systèmes linéaires, ⋅ pour le produit scalaire, × pour le produit vectoriel, etc.). Ces opérateurs utilisent les symboles habituels dans la littérature (de même, tout caractère Unicode peut être utilisé comme nom de variable).

Contrairement à bon nombre de langages, le parallélisme est pris en charge directement dans la syntaxe du langage. Par exemple, pour mener un grand nombre d’expériences de pile ou face sur des grappes de calcul, le code est extrêmement simple :

nheads = @parallel (+) for i=1:100000000
  int(randbool())
end

Parmi les fonctionnalités très attendues de cette nouvelle version 0.4 RC1, la précompilation évite de compiler les modules importés à chaque exécution d’un script : ils sont convertis en code binaire une fois pour toutes, ce qui améliore fortement les temps de chargement (dans certains cas, d’une dizaine de secondes à moins d’une). De plus, cette fonctionnalité ne réduit pas la performance du code à l’exécution : le même moteur de compilation est utilisé (LLVM), il est seulement moins souvent appelé.

La documentation des modules pour la version 0.3 se faisait par le module Docile.jl et est maintenant intégrée directement au niveau du langage. Le texte écrit en Markdown et est accessible depuis l’invite de commande. Cette fonctionnalité est incrémentale, de telle sorte que, si un fichier est modifié, seules les méthodes ayant subi des changements seront recompilées.

Un autre point fort du langage est la métaprogrammation, avec des macros très similaire à l’esprit de LISP : ces macros peuvent prendre du code en argument, représenté comme une structure de données (arbre syntaxique abstrait), manipulable à l’envi, afin de générer du code à l’exécution. Ces fonctionnalités sont très pratiques pour développer des langages dédiés (comme JuMP pour la programmation mathématique), intégrés directement dans le code Julia. À ce sujet, cette version 0.4 utilise la métaprogrammation pour définir des fonctions générées : son implémentation travaille uniquement sur le type des variables, la valeur retournée étant l’expression à évaluer lors de l’appel effectif de cette fonction sur des valeurs données — sans que le code qui appelle cette fonction soit conscient de ces détails.

La version finale de Julia 0.4 est attendue assez rapidement, une fois les derniers défauts corrigés. Les nouvelles fonctionnalités seront ajoutées dans la branche Julia 0.5, qui pourrait également apporter quelques changements qui casseront la compatibilité avec le code existant. Une nouveauté attendue sera la gestion du débogage interactif (actuellement implémenté dans un module externe, qui nécessite d’instrumenter le code : Debug.jl).

Source : Julia v0.4.0 Release Notes.