• [^] # Re: Interessant

    Posté par (site web personnel) . En réponse à la dépêche Beagle 0.2 : le "Desktop Search" gagne en stabilité. Évalué à 6.

    Non, le compilateur de .NET ne compile pas du code natif,
    C'est quoi le compilateur .NET ?
    Dans ces environnements il y a 2 types de compilateurs :
    - les compilateurs qui visent la machine virtuelles (C# --> MSIL ou Java -->bytecode)
    - les compilateurs qui visent le code natif (MSIL --> x86 ou bytecode --> x86)

    GCC fonctionne à peu prêt pareil : il a un frontend et un backend avec un langage intermédiaire propre à GCC. les frontend (ceux qui manipulent du C, du C++ ou jesaispasquoi) produise du code intermédiaire (ce sont des frontend), puis le backend s'occupe d'effectuer la compilation en code natif suivant la machine cible (x86 ou autre).

    Comme tu peux le constater sur le papier, c'est exactement le même fonctionnement. D'ailleur c'est pas pour rien que GCC est capable de compiler du Java, techniquement les 2 phases de compilations sont similaires dans leurs objectifs.

    Au final le code qui s'exécute EST du code machine x86 (ou autre) quelque soit la technique :
    - Pour le compilateur GCC, le code produit est par défaut systématiquement du code machine. Il est cependant possible de lui demander le code intermédiaire.

    Pour les environnement Java et .NET, la dernière étape de compilation (code intermédiaire --> code natif) est effectuée par défaut au dernier moment (Just-In-Time), au prix d'un chargement plus long mais d'une plus grande souplesse de déploiement, voir des optimisations supplémentaires : en effet, le runtime connaît exactement la configuration sur laquelle il tourne, il est alors capable d'effectuer des optimisations spécifiques, là où avec un compilateur "classique" comme GCC tu aurais été obligé de générer toute une série de binaire avec toutes les combinaisons d'optimisations possible, ou, plus généralement, t'aurais pondu un binaire optimisé de manière "générique".
    Maintenant, de la même manière qu'il est possible de modifier le comportement par défaut de GCC pour qu'il génère son code intermédiaire, il est possible de modifier le comportement par défaut de Java ou .NET/Mono pour qu'il compile directement en natif, bref pour qu'un binaire x86 arrive à la sortie.
    Tu sembles en douter, ben fait le test :
    Java :
    utilises GCJ, c'est son comportement par défaut
    Mono :
    mono -aot monprog.exe (AOT pour Ahead-Of-Time)
    Avec .NET :
    ngen monprog.exe

    Le code généré est-il (attention, je parle du code produit par le compilateur dynamique de Mono ou de .net) aussi performant "algorithmiquement" qu'un code C (donc issu de gcc, avec toutes les optimisation qu'il a jugé nécessaire de faire, quand tu lui donnes un -O2) ?
    Faut bien voir que même algorithmiquement identiques, des programmes écrits dans des langages différents ne peuvent être optimisés de la même façon, bien souvent à cause de la sémantique du langage. Le C est pas forcement le meilleur dans le domaine, puisque bien souvent il autorise tout et n'importe quoi, ne laissant pas vraiment de liberté au compilateur pour spécialiser un morceau de code.
    Ensuite un compilateur comme GCC peut très bien te pondre du code super-optimisé sur telle plateforme (x86) et super mal optimisé sur une autre plateforme (PPC) (je dis n'importe quoi c'est pour l'exemple).
    Il peut aussi y avoir de grosses différences entre les compilateurs, le compilo d'intel est par exemple beaucoup plus performant que le compilo GCC.

    Donc voilà comme tu peux le constater, c'est vraiment difficile de comparer. Mais techniquement, les problèmes d'optimisations sont les mêmes en C ou C#/Java. Ce qui va ralentir ton code, une fois de plus ce n'est pas le fait qu'il y est un code intermédiaire, mais le fait qu'il est des services associés : sercices de reflexion, de gestion de types, d'isolation et plus généralement de sécurité. Ces services fournissent de nombreuses fonctionnalités aux développeurs et peuvent avoir un coup en terme de performance.
    Ces services assurent une qualité de code supplémentaire non négligeable.
    Mais que va faire un "bon" programmeur C/C++ ? Il va chercher à acquérir les mêmes types de services (réflexion, gestion mémoire, etc.). Comment va-t-il faire ? Il va utiliser des outils pour (GC, etc.) ou alors il va réinventer la roue, avec de forte chances que le tout soit moins bien optimisé et avec autant de bugs potentiels. Quand à certains services, il ne pourra peut être même pas les "émuler", comme tous ceux liés à la sécurité.

    L'intérêt de plateformes comme Java ou .NET c'est de proposer ces services "en standard", avec une implémentation largement testée et éprouvée.

    Maintenant que certains préfèrent encore se passer de ces services et gagner quelques malheureux % de temps d'exécution au risque de passer un temps fou à réinventer la roue avec des bugs potentiels supplémentaires, ca les regardent, ca peut être parfois justifier (bas niveau), mais d'une manière générale ca l'est rarement. Ou si pour le "fun".

    Il faut également bien voir que les plateformes comme Java ou .NET proposent une grande quantité de classes en standards, celle-ci sont bien souvent optimisés et/ou font appels à du code natif quand c'est nécessaire.

    'aimerais trouvé un dump (assembleur x86) d'un traitement matématique écrit en C#, compilé en MSIL puis compilé en langage machine par Mono, puis par .NET (sous Windows). Pour voir si le code est aussi optimisé (dans ce cas précis) ...
    Si tu veux prendre un exemple "mathématique", j'ai envie de te répondre : plutôt que de passer 3 plombes en C à débugguer un segmentation fault ou autre fuite mémoire, moi je préfères affiner mon algorithme en Java en réduisant sa complexité. Ca c'est autrement plus efficace ;)

    Enfin si tu veux vraiment trouver un dump, ben utilise les méthodes que je t'ai expliqué au dessus (gcj, mono -aot et ngen) pour avoir une image native :) Mais bon visiblement t'y crois pas à ce fameux code natif avant exécution :)