• [^] # Re: Temps d'exécution sans optimisation ?

    Posté par . En réponse au journal Pythran chatouille Cython. Évalué à 5.

    Tu pars du principe que le programmeur est meilleur que la machine pour optimiser et donc qu'il est plus efficace de partir d'un langage bas niveau qui donne toute la latitude pour piloter le calcul.

    Ça dépend de quel type d'optimisation on discute (voir plus bas). Dans le cas normal je suis d'accord avec toi, le compilateur est souvent meilleur que toi. Lorsqu'on parle de gens qui cherchent à optimiser une boucle après avoir observé que c'est celle-ci prend beaucoup de temps à s'exécuter, alors c'est un cas différent : tu as déjà compilé avec -O3, possiblement en promettant à ton compilo que les pointeurs ne pointent pas sur des zones qui se recouvrent1

    Les langages fonctionnelles sont très efficaces pour cela. Les notions de fonctions pures, de typage fort (avec ou sans inférence), d'évaluation paresseuse, les map (qui sont une forme de SIMD)

    (c'est moi qui graisse) Si le concept est similaire (une seule instruction appliquée à un jeu de données vs. une seule fonction appliquée à une liste d'éléments), les implications en termes de génération de code n'ont strictement rien à voir.

    Quand il s'agit de vectorisation, les compilateurs (y compris Intel) sont quand même pas complètement au point. Ils font souvent de la « vectorisation partielle », dans le sens où ils utilisent correctement les registres SSE/AVX (avec le bon type d'instructions du coup), mais où ils ne savent pas s'ils ont le droit de correctement charger les données 128 ou 256 bits à la fois, et donc utilisent ces registres principalement pour charger des données 64 bits dans des registres qui font le double ou le quadruple en capacité. Depuis peu, GCC fait de l'auto-vectorisation partielle (qui me semble légèrement moins au point que celle d'Intel), mais dans tous les cas, à moins d'avoir des garanties en béton sur les pointeurs, sur le code, etc., la vectorisation complète (càd : qui utilise pleinement les registres vectoriels des machines x86/x64) est rarement achevée. C'est pour ça qu'on continue d'utiliser les intrinsics à la main dans beaucoup de codes à partir du moment où on se dit que ça va pas assez vite. Après, il existe des outils pour déterminer si ça vaut le coup de se prendre la tête à vectoriser, en regardant le rapport entre le nombre d'instructions arithmétiques et le nombre de mouvements mémoire : un code peut être vectorisable sans pour autant faire gagner en performance, car le processeur passe son temps à attendre que la mémoire lui fournisse les prochains éléments à traiter.

    D'ailleurs, c'est tellement reconnu que le dernier standard en date pour OpenMP (qui est le langage de programmation parallèle le plus populaire dans la communauté du calcul intensif) fournit une clause (le mot-clef « simd ») pour dire au compilateur que le code est vectorisable (donc en gros le programmeur prend la responsabilité d'avoir vérifié que l'agencement des données permet effectivement de vectoriser le code, mais au moins il n'a plus à utiliser les intrinsics — enfin, on espère).


    1. En C/C++, ça s'exprime avec restrict dans la signature des fonctions, ou au niveau du compilateur tu peux le spécifier « par fichier » avec un flag de type -fno-alias chez Intel ou -fstrict-aliasing chez GCC je crois — et il semblerait qu'au moins avec gcc ce soit activé à partir de -O2.