• [^] # Re: y'a trop peu d'infos pour t'aider.

    Posté par . En réponse au journal Performances des processeurs Intel et optimisation. Évalué à 8.

    Tu as tort. Utiliser rdtsc est parfaitement logique surtout si ton bench prend peu de temps (après tout, les risques de modification de fréquence sont bien moindres). Ça n'empêche pas qu'il faut une certain stabilité. Généralement lorsque je fais des micro-benchmarks, j'utilise un truc du genre:

    for ( outer = 0; outer < MAX_OUTER; ++outer) {
     FLUSH_CACHES();
    #if OBSERVE_IN_CACHE_BEHAVIOR
     run_kernel(); // warm up caches 
    #endif
     uint64_t exec_time = read_rdtsc();
     for (inner = 0; inner < MAX_INNER; ++inner) {
     run_kernel();
     }
     exec_times[outer] = (double) (read_rdtsc() - exec_time) / MAX_INNER;
    }
    /* ... */
    /* exec_times[] contient un « histogramme » des différentes exécutions */
    REMOVE_OUTLIERS(exec_times,MAX_OUTER); // supprime les temps les plus courts et les plus longs en fonction de lubies statistiques
    COMPUTE_MEAN(exec_times, MAX_OUTER); // arithmétique, harmonique, etc., en fonction des besoins
    
    

    Note que MAX_INNER/MAX_OUTER peuvent être extrêmement petits dans le cas de microbenchmarks, surtout si l'environnement de benchmarking permet de fixer un thread sur un cœur donné : on évite les variations dues à l'ordonnanceur qui est moins con qu'avant, mais qui va quand même réordonnancer certains threads pour les remettre sur le même cœur juste après… mais avec des caches et TLB qui ont eu droit à des entrées évincées.

    Maintenant ce que j'appelle « micro-benchmarks », ce sont vraiment de minuscules benchs, où je teste un sous-système de mon micro-processeur. Genre je veux tester la latence réelle de mon cache L3 partagé : je vais faire tourner 4 threads en parallèle sur mon core i7, un par cœur. Ensuite je vais m'assurer que chaque thread copie un mot de 64 bits dans un registre, puis copie le (i×ばつk)è mot dans le même registre à l'itération suivante, etc. J'ai besoin de faire i×ばつk car les prefetchers des archis x86 ont tendance à rapatrier la ligne de cache adjacente lors d'un défaut de cache. Du coup il faut précharger au moins tous les 16 mots. L'autre problème étant que, au moins pour les micro-archis Intel, il existe un « stride préfetcher » (« préchargeur de distance » ? je ne sais pas comment traduire). Il détecte tout seul comme un grand si la distance entre deux mots mémoire est fixe. Si c'est le cas, il va précharger les mots mémoire suivants sans qu'on lui demande quoi que ce soit (dans la limite d'une page mémoire, donc pas au-delà de 4096 octets). Du coup il faut faire son sioux, et précharger un mot aléatoire dans la ligne de cache « suivante ».

    Soupir

    Désolé pour le HS complet. J'ai pas pu m'empêcher. :)