• # Méthode de mesure.

    Posté par . En réponse au journal Quand Pythran fait tourner du Python plus vite que du C++, c'est que.... Évalué à 10.

    Hum,

    Je suis d'accord avec toi, quelque chose ne va pas.

    J'ai regardé rapidement le code C++ (enfin, l'un des deux fichiers). Il n'y a qu'une seule mesure de faite, ce qui ne veut du coup strictement rien dire. Il faudrait exécuter le même code plusieurs fois, dans plusieurs types de conditions différentes pour pouvoir réellement mesurer. En gros, là, le code fait quelque chose de ce genre :

    // Fonctions à utiliser ...
    int 
    main(void)
    {
     double start = get_clock();
     /* trucs compliqués qui prennent un peu de temps */
     double stop = get_clock();
     cout << "Time: " << stop-start << endl;
     return 0;
    }

    Alors qu'en pratique, il faudrait garantir 2-3 trucs :

    1. Il faut garantir que le code s'exécutera toujours sur le même cœur (utilisation de sched_setaffinity etc.), pour éviter que l'ordonnanceur ne migre le programme d'un cœur à un autre (peu probable, mais ça arrive...)
    2. Il faut effectuer plusieurs mesures, en utilisant des facteurs de répétition à différents endroits.
    3. Comme tu le disais, la façon dont un code est exprimé va plus ou moins aider le compilateur. Dans beaucoup de cas, faire du code simple aide énormément le compilateur.

    Donc au lieu du code précédent, il faudrait un truc plutôt dans ce genre :

    /* Fonctions à déclarer/définir ... */
    void compute(void *arg)
    {
     utiliser_sched_setaffinity_ici();
     return 0;
    }
    int 
    main(void)
    {
     std::queue<double> timings;
     for (int i = 0; i < META_REPETS; ++i) { 
     flush_caches();
     double start = get_clock();
     for (int i = 0; i < NB_REPETS; ++i) {
     /* calculs faits ici */
     }
     double stop = get_clock();
     timings.push_back(stop-start);
     }
     do_clever_stats_with(timings); // moyenne, écart-type, tout ça
     return 0;
    }

    Dans ce code, on pourra ensuite faire varier META_REPETS et NB_REPETS pour vérifier les comportements/temps d'exécution si les caches de données sont chauffés ou pas, etc.

    Sinon, j'ai regardé un peu plus le code, et certaines boucles sont écrites « en Fortran », c'est-à-dire qu'elles sont écrites comme si les tableaux n-dimensionnels étaient stockés en « column major ». Par exemple [ici(https://github.com/jesusfv/Comparison-Programming-Languages-Economics/blob/master/RBC_CPP.cpp), lignes 93-97. Bon dans ce cas ce n'est pas très grave (c'est une boucle exécutée une fois seulement), mais ça la fout mal quand même.

    Sinon le reste du code me semble largement optimisable, et il faudrait voir comment triturer un peu tout ça. J'ai l'impression que certaines boucles sont séparées parce qu'il était plus facile de raisonner ainsi plutôt que parce que c'est nécessaire, que d'autres devraient au contraire être fissionnées car ne favorisant pas trop la localité, etc.