Fonctions de minutage dans R [fermé]

36
  1. Je voudrais mesurer le temps qu'il faut pour répéter l'exécution d'une fonction. Est-ce replicate()que l'utilisation de boucles for est équivalente? Par exemple:

    system.time(replicate(1000, f()));
    system.time(for(i in 1:1000){f()});

    Quelle est la méthode préférée?

  2. En sortie de system.time(), sys+userle temps CPU réel pour exécuter le programme est-il? Une elapsedbonne mesure de la performance temporelle du programme?

Tim
la source
3
Pour mémoire, étant donné que je suis clairement trop tard pour changer le cours de cette question: c'est le type de problème qui, à mon avis, convient le mieux à StackOverflow.
Matt Parker
2
@ Matt je conviens que les questions sur la manière dont un programme convient bien à SO. Je conviens également qu'une interprétation littérale de cette question (telle que reprise par plusieurs des réponses) la placerait hors sujet ici sur CV. Il semble néanmoins y avoir un intérêt statistique à concevoir une expérience de chronométrage et à analyser les résultats d’une telle expérience.
whuber

Réponses:

19

Pour une synchronisation efficace des programmes, surtout lorsque vous souhaitez comparer des solutions alternatives, vous avez besoin d’un contrôle! Un bon moyen est de mettre la procédure que vous chronométrez dans une fonction. Appelez la fonction dans une boucle de synchronisation. Ecrivez une procédure stub, essentiellement en supprimant tout le code de votre fonction et en en revenant (en laissant tous les arguments). Mettez le talon dans votre boucle de synchronisation et re-temps. Ceci mesure tous les frais généraux associés au timing. Soustrayez le temps intermédiaire du temps de procédure pour obtenir le net: il doit s'agir d'une mesure précise du temps réel nécessaire.

Comme la plupart des systèmes peuvent de nos jours être interrompus de manière péremptoire, il est important de procéder à plusieurs exécutions pour vérifier la variabilité. Au lieu de faire une longue série de secondes, effectuez courses d'environ secondes chacune. Cela aide de faire cela dans une double boucle tout en un. Non seulement cela est plus facile à gérer, mais cela introduit un peu de corrélation négative dans chaque série temporelle, ce qui améliore les estimations.NmN/m

En utilisant ces principes de base de la conception expérimentale, vous contrôlez essentiellement toute différence liée à la manière dont vous déployez le code (par exemple, la différence entre une boucle for et une réplication ()). Cela fait disparaître votre problème.

whuber
la source
25

En ce qui concerne vos deux points:

  1. C'est stylistique. J'aime comme replicate()c'est fonctionnel.
  2. J'ai tendance à me concentrer sur elapsedle troisième chiffre.

Ce que je fais souvent c'est

N <- someNumber
mean(replicate( N, system.time( f(...) )[3], trimmed=0.05) )

pour obtenir une moyenne ajustée de 90% de N répétitions d'appels f().

(Edité, avec un merci à Hadley d'avoir attrapé un thinko.)

Dirk Eddelbuettel
la source
2
Tu ne veux pas dire mean(replicate(N, system.time(f(...))[3]), trim = 0.05)?
Hadley
2
Si l'appel f () est long, c'est bon. Cependant, si l'appel f () est court, alors tout temps système supplémentaire de la minuterie de l'appelant augmentera probablement la mesure d'erreur. Avec un seul appel à system.time () après plusieurs répétitions de f (), il est possible de diviser l'erreur en un appel jusqu'à obtenir une valeur infinitésimale (et le retour est plus rapide).
John
@ John: Merci, mais je ne comprends pas tout à fait ce que vous avez dit. Je me demande toujours lequel est le meilleur, en répétant f () à l'intérieur ou à l'extérieur de system.time ()?
Tim
Chaque appel à la commande system.time () a un temps variable d’appel qui provoque une certaine quantité d’erreur de mesure. Ceci est une petite quantité. Mais que se passe-t-il si f () est un appel très bref? Ensuite, cette erreur peut être confondue avec le temps nécessaire pour appeler f (). Ainsi, lorsque vous appelez f () 1 à 5 fois dans un même appel system.time (), l’erreur est divisée en fragments 1e5. Lorsque vous appelez system.time () pour chaque f (), son impact peut être significatif si le temps imparti à f () est réduit. Bien sûr, si tout ce dont vous avez besoin, c'est du timing relatif, peu importe.
John
Oh, et la deuxième partie est qu'il serait plus rapide d'appeler une seule fois system.call ().
John
10

Vous pouvez également chronométrer avec les pas de temps renvoyés par Sys.time; ceci mesure bien sûr le temps passé sur le mur, donc le temps de calcul en temps réel. Exemple de code:

Sys.time()->start;
replicate(N,doMeasuredComputation());
print(Sys.time()-start);

la source
3

En ce qui concerne la métrique de synchronisation à utiliser, je ne peux rien ajouter aux autres intervenants.

En ce qui concerne la fonction à utiliser, j'aime bien utiliser le? Benchmark du paquetage rbenchmark .

Tal Galili
la source
1

Ils font des choses différentes. Chronométrez ce que vous souhaitez faire. replicate () renvoie un vecteur de résultats de chaque exécution de la fonction. La boucle for ne fonctionne pas. Par conséquent, ce ne sont pas des déclarations équivalentes.

De plus, déterminez le nombre de façons dont vous voulez que quelque chose soit fait. Ensuite, vous pouvez trouver la méthode la plus efficace.

John
la source
mod-tip: postez la deuxième partie en tant que commentaire sur la réponse de Dirk.