2016-05-17 1 views
6

Inspired by SQLite, Je suis en train d'utiliser l'outil "cachegrind" de valgrind pour effectuer des tests de performances reproductibles. Les nombres qu'il produit sont beaucoup plus stables que toute autre méthode de chronométrage que j'ai trouvée, mais ils ne sont pas déterministes. À titre d'exemple, voici un programme simple C:Pourquoi le cachegrind n'est-il pas complètement déterministe?

int main() { 
    volatile int x; 
    while (x < 1000000) { 
    x++; 
    } 
} 

Si je le compiler et l'exécuter sous cachegrind, je reçois les résultats suivants:

$ gcc -O2 x.c -o x 
$ valgrind --tool=cachegrind ./x 
==11949== Cachegrind, a cache and branch-prediction profiler 
==11949== Copyright (C) 2002-2015, and GNU GPL'd, by Nicholas Nethercote et al. 
==11949== Using Valgrind-3.11.0.SVN and LibVEX; rerun with -h for copyright info 
==11949== Command: ./x 
==11949== 
--11949-- warning: L3 cache found, using its data for the LL simulation. 
==11949== 
==11949== I refs:  11,158,333 
==11949== I1 misses:   3,565 
==11949== LLi misses:   2,611 
==11949== I1 miss rate:  0.03% 
==11949== LLi miss rate:  0.02% 
==11949== 
==11949== D refs:  4,116,700 (3,552,970 rd + 563,730 wr) 
==11949== D1 misses:  21,119 ( 19,041 rd + 2,078 wr) 
==11949== LLd misses:   7,487 ( 6,148 rd + 1,339 wr) 
==11949== D1 miss rate:  0.5% (  0.5%  +  0.4% ) 
==11949== LLd miss rate:  0.2% (  0.2%  +  0.2% ) 
==11949== 
==11949== LL refs:   24,684 ( 22,606 rd + 2,078 wr) 
==11949== LL misses:   10,098 ( 8,759 rd + 1,339 wr) 
==11949== LL miss rate:   0.1% (  0.1%  +  0.2% ) 
$ valgrind --tool=cachegrind ./x 
==11982== Cachegrind, a cache and branch-prediction profiler 
==11982== Copyright (C) 2002-2015, and GNU GPL'd, by Nicholas Nethercote et al. 
==11982== Using Valgrind-3.11.0.SVN and LibVEX; rerun with -h for copyright info 
==11982== Command: ./x 
==11982== 
--11982-- warning: L3 cache found, using its data for the LL simulation. 
==11982== 
==11982== I refs:  11,159,225 
==11982== I1 misses:   3,611 
==11982== LLi misses:   2,611 
==11982== I1 miss rate:  0.03% 
==11982== LLi miss rate:  0.02% 
==11982== 
==11982== D refs:  4,117,029 (3,553,176 rd + 563,853 wr) 
==11982== D1 misses:  21,174 ( 19,090 rd + 2,084 wr) 
==11982== LLd misses:   7,496 ( 6,154 rd + 1,342 wr) 
==11982== D1 miss rate:  0.5% (  0.5%  +  0.4% ) 
==11982== LLd miss rate:  0.2% (  0.2%  +  0.2% ) 
==11982== 
==11982== LL refs:   24,785 ( 22,701 rd + 2,084 wr) 
==11982== LL misses:   10,107 ( 8,765 rd + 1,342 wr) 
==11982== LL miss rate:   0.1% (  0.1%  +  0.2% ) 
$ 

Dans ce cas, « je refs » diffère par seulement 0,008% entre les deux courses mais je me demande encore pourquoi ils sont différents. Dans les programmes plus complexes (dizaines de millisecondes), ils peuvent varier de plus en plus. Y a-t-il un moyen de rendre les passages complètement reproductibles?

+0

Utilisez un processeur moins sophistiqué qui ne fait pas, par exemple, de prédiction de branchement. –

+1

Si je comprends bien, valgrind simule son propre CPU et ne fait pas de prédiction de branche à moins que vous ne passiez --branch-sim = yes. Même ainsi, pourquoi la prédiction de branchement ne peut-elle pas être déterministe lors de la simulation d'une CPU? –

Répondre

5

A la fin de a topic in gmane.comp.debugging.valgrind, Nicholas Nethercote (un developpeur Mozilla travaille dans l'équipe de développement Valgrind) indique que des variations mineures sont communes à l'aide Cachegrind (et je peux en déduire qu'ils ne conduisent pas à des problèmes majeurs).

Cachegrind’s manual mentionne que le programme est très sensible. Par exemple, sous Linux, la randomisation de l'espace d'adressage (utilisée pour améliorer la sécurité) peut être la source du non-déterminisme.

Une autre chose à noter est que les résultats sont très sensibles. La modification de la taille de l'exécutable en cours de profil ou des tailles de des bibliothèques partagées qu'il utilise, ou même de la longueur de leur fichier , peut perturber les résultats. Les variations seront faibles, mais n'attendez pas des résultats parfaitement reproductibles si votre programme change du tout.

Les distributions GNU/Linux plus récentes effectuent la randomisation de l'espace adressable, en , où des exécutions identiques du même programme ont leurs bibliothèques partagées chargées à différents endroits, par mesure de sécurité. Cela aussi perturbe les résultats.

Bien que ces facteurs signifient que vous ne devez pas croire que les résultats sont très précis, ils doivent être assez proches pour être utiles.