Journal pythran: python -> c++

Posté par (page perso) . Licence CC by-sa
30
8
juil.
2012

La lecture quotidienne des journaux m'avertit qu'il y a de nombreux pythonistes dans le coin, alors…

Dans ma pratique régulière du Python (et n'oubliez pas : manger 5 langages par jour pour être bien en forme !), je prends un grand plaisir à coder des algos à base de liste / ensembles / dictionnaires le tout dans une petite sauce fonctionnelle. C'est loin d'être la seule façon de programmer en Python mais c'est comme ça que je fais.

Bien sûr, tout ceci ne s’exécute pas ultra rapidement, mais c'est généralement le cadet de mes soucis. Sauf quand ça le devient.

Dans ce cas que peut-on faire ?

Biblio rapide

  • utiliser l'API C de Python directement. C'est pas ultra sorcier, un peu de glue et on a le plaisir de faire du C derrière.
  • boost::python est assez sympa aussi, moins de glue, et on a le plaisir de faire du C++.
  • ctypes est tout ce qu'il y a de plus standard, et permet d'appeler des bibliothèques externes depuis son code python. Un bon choix si on a déjà le code C/C++ sous la main. Il parait que cffi est du même acabit mais je n'ai pas testé.
  • shedskin en voilà un outil qu'il est bien, puisqu'il prend un module python implicitement typé statiquement, et nous transforme ça en module natif. Avec des speedup pas dégueux du tout
  • pymothoa plus jeune et qui nous crache du bytecode llvm. Par contre, le typage est explicite et ça … berk et le dialecte supporté est un peu faiblard
  • copperhead qui a plutôt un statut de recherche mais qui propose de porter nos bébés serpents sur GPU, rien que ça. Comme tout à un prix le sous langage utilisé est très orienté (curieux !) data paralellism.

Toi, toi, toi, tu ressembles à celle

Alors voilà, j'ai joué avec les uns et les autres, goûté à tout (très bon pour le teint) et pour mettre à profit les trois années de thèse passée, je me suis fondu d'un nouveau membre pour cette belle famille, pythran. Le reste du journal parle de ce magnifique projet.

kezaco

Un convertisseur automatique d'un sous ensemble de python (sans classe ni introspection) vers du c++

Ça va vite ?

(bah oui faut bien motiver les troupes)

Dans les bons jours, on va 30 fois plus vite que du CPython, et 1.5 fous plus vite que du shedskin. Pas regardé pour les autres encore. Dans les mauvais deux-trois fois plus lent à cause du coût de conversion listes python -> tableaux natifs (on laisse de côté les tableaux numpy pour le moment)

Comment ça marche

Bien (ahah).

En gros l'idée c'est d'exploiter à fond les fonctionnalités du dernier standard C++ pour déporter la complexité du compilo sur le compilo C++, qui a une propriété terriblement géniale : quelqu'un d'autre l'a déjà écrit. Par exemple pour typer le p'tit bout de code suivant

a=[1,2,3.]
for i in xrange(a):
    print i

On va essayer de générer du code de ce genre là

std::vector< decltype( 1 + 2 + 3.) > a = { 1, 2, 3. };
for(auto i: xrange(a))
    print(i);

Alors la première partie, c'est d'écrire un runtime C++ qui va nous fournir tous les builtins python : ceux là. À grands renforts de template et de foncteurs, on s'en sort pas trop mal. Merci les variadic template pour implémenter des jolis map, reduce et autre zip.

Ensuite faut gérer le polymorphisme. Pour les fonctions, la p'tite astuce c'est de toutes les déclarer comme template, par exemple

def mul(self, other): return self*other

deviendra

template<class T0, class T1>
auto mul(T0 const& self, T1 const& other) -> decltype(self*other) {
    return self * other;
}

En poussant l'idée à l'extrême, on peut transformer un module complet en un gros pâté de fonctions template dont chacune des variables locale a un type calculé à coup de decltpe à partir de ceux des paramètres formels. La classe !

Ça a l'air cool, je veux essayer

Fastoche, après avoir suivi les instructions cachées sur le site web, tu pourras t'essayer à un joli
shell
pythran -E mon_module.py

Qui ne marchera que si tu as fourni au bousin une ligne du genre

#pythran export foo(int)
#pythran export foo(complex)

pour lui dire que parmi toutes tes zolies fonctions, tu veux en exporter deux, avec les signatures idoines.

Je passe sur pleins d'autres aspects rigolos, et je vous invite à tester la bête, ce qui devrait vite l'épuiser et montrer ses limites, une belle occasion de l'améliorer !

  • # say moche...

    Posté par (page perso) . Évalué à 8.

    … de faire comme s'il n'y avait pas une fonctionnalité de prévisualisation…

    • utiliser l'(API C)[http://docs.python.org/c-api] de Python directement. C'est pas ultra sorcier, un peu de glue et on a le plaisir de faire du C derrière
    • (boost::python)[www.boost.org/libs/python/doc/] est assez sympa aussi, moins de glue, et on a le plaisir de faire du C++
    • (ctypes)[docs.python.org/library/ctypes.html] est tout ce qu'il y a de plus standard, et permet d'appeler des bibliothèques externes depuis son code python. Un bon choix si on a déjà le code C/C++ sous la main. Il parait que (cffi)[https://bitbucket.org/cffi/cffi] est du même acabit mais je n'ai pas testé.
    • (shedskin)[http://shed-skin.blogspot.fr/]: en voilà un outil qu'il est bien, puisqu'il prend un module python implicitement typé statiquement, et nous transforme ça en module natif. Avec des speedup pas dégueux du tout
    • (pymothoa)[http://code.google.com/p/pymothoa/]: plus jeune et qui nous crache du bytecode llvm. Par contre le typage est explicite et ça … berk et le dialecte supporté est un peu faiblard
    • (copperhead)[http://copperhead.github.com/]: qui a plutôt un statut de recherche mais qui propose de porter nos bébés serpents sur GPU, rien que ça. Comme tout à un prix le sous langage utilisé est très orienté (curieux!) data paralellism

    aurait pu être :

    • utiliser l'API C de Python directement. C'est pas ultra sorcier, un peu de glue et on a le plaisir de faire du C derrière
    • boost::python est assez sympa aussi, moins de glue, et on a le plaisir de faire du C++
    • ctypes est tout ce qu'il y a de plus standard, et permet d'appeler des bibliothèques externes depuis son code python. Un bon choix si on a déjà le code C/C++ sous la main. Il parait que (cffi)[https://bitbucket.org/cffi/cffi] est du même acabit mais je n'ai pas testé.
    • shedskin: en voilà un outil qu'il est bien, puisqu'il prend un module python implicitement typé statiquement, et nous transforme ça en module natif. Avec des speedup pas dégueux du tout
    • pymothoa: plus jeune et qui nous crache du bytecode llvm. Par contre le typage est explicite et ça … berk et le dialecte supporté est un peu faiblard
    • copperhead: qui a plutôt un statut de recherche mais qui propose de porter nos bébés serpents sur GPU, rien que ça. Comme tout à un prix le sous langage utilisé est très orienté (curieux!) data paralellism
  • # cython

    Posté par . Évalué à 7.

    Il manque dans ta liste le plus important : cython. Il permet d'intégrer du C/C++ dans du Python et inversement. Il peut aussi convertir du code Python en code C, soit sans rien faire et tu gagnes un peu, soit en en spécifiant les types et tu gagnes beaucoup (x10 au minimum, plus de 100x sur calcul numérique). Il a d'autres fonctionnalités que je vous laisse voir sur le site.

    cython est un projet très actif (ex : master suit à quelques jours les changements de la branche de dev CPython) et comprends parfaitement la syntaxe CPython du la version 2.5 à la 3.3dev(le but est d'être 100% compatible pour la 1.0).

    Le support de PyPy est encours et Stephan Benhel (le dev principal) est lui très actif. Bref, que du bon.

    • [^] # Re: cython

      Posté par (page perso) . Évalué à 3.

      By Jove
      Bien sûr Cython devrait être dans le haut de la liste. Et puis le côté incrémental est vraiment chouette :-)

  • # Pypy

    Posté par . Évalué à 4.

    Pypy est souvent bluffant au niveau des performances. C'est le premier à essayer à essayer vu qu'il n'y a rien à changer au code.

    • [^] # Re: Pypy

      Posté par (page perso) . Évalué à 3.

      Je le pense aussi.

      A lire les derniers blogs, je pense que PyPy devrait mouliner ton code pour l'optimiser à mort. Et le gros avantage par rapport à ton projet:
      1. il est déjà écrit
      2. il support l'ensemble complet de Python

      • [^] # Re: Pypy

        Posté par (page perso) . Évalué à 6.

        merci pour les remarques, constructives à défaut d'être encourageantes ;-)

        Par acquit de conscience, j'ai lancé un petit bench (un quicksort dont le code cython est donné et dont le code python est identique aux cdef prêts.

        J'ai fait mouliné ça sur des tableaux de flottants numpy.array (sauf pour shedskin qui supporte pas) de taille 10000, à l'aide du module timeit et en prenant la médiane sur 11 runs. Tout ce qui peut être compilé est compilé en -O2.

        python: 11.802s
        pypy: 0.120s
        shedskin: 0.096
        pythran: 0.092
        cython: 0.060

        le classement est au final assez représentatif de ce que l'on pouvait attendre: plus on met d'effort / de contraintes plus on obtient de perfs. 0 efforts pour pypy et de sacré bonnes perfs, pas mal d'annotations avec cython et de très bonnes perfs.

        /me va rejouer le même jeu sur un matrix multiply pour voir.

  • # Nuitka

    Posté par (page perso) . Évalué à 5.

    Sur #python-dev, on m'a parlé de cette conférence à EuroPython 2012 :
    https://ep2012.europython.eu/conference/talks/nuitka-the-python-compiler

    Et hop, un autre compilateur Python => C++, mais qui gère les classes et tout le bazar.

    • [^] # Re: Nuitka

      Posté par (page perso) . Évalué à 3.

      Merci!
      Je viens de tester la version dans debian sid pour les deux exemples précédents et c'est pas GG

      quicksort: 8.64s
      matmul:2.06s

      Et en regardant le code généré, c'est assez proche d'un cython sans annotations de types…

      il n'y a pas de repas gratuits !

Suivre le flux des commentaires

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