Estimer efficacement la vitesse à laquelle une boucle s'exécute

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour,

Je suis actuellement en train de bosser sur un programme de rendu de fractal. Je prévois quelques fonctionnalités assez complexes et l'une d'entre elle est d'avoir un indicateur en temps réel de la vitesse à laquelle la boucle principale s'exécute et l'afficher toutes les secondes ou tous les dixièmes de seconde.

La solution la plus simple est d'appeler une fonction type time()1 à chaque itération et de faire les calculs nécessaires à partir de là. Le problème avec cette approche est que l'appel à time() va générer un appel système qui risque d'avoir un coût non négligeable comparé à celui de l'exécution du code à l'intérieur de la boucle. Les performances étant un des points les plus critiques de mon programme.

Une autre solution serait de faire l'appel à time() toute les x itérations, sauf que ce x n'est pas connu à l'avance et risque fort de varier durant l'exécution du programme.

Une autre solution à laquelle j'ai pensé est d'avoir un compteur incrémenté à chaque itération et d'avoir un thread séparé pour calculer la vitesse d'exécution toutes les x millisecondes. Sauf que l'itérateur doit alors être thread-safe, ce qui risque là aussi d'impacter les performances, que ce soit à cause de l'utilisation de verrou ou simplement à cause de la synchronisation des caches du processeur.

La dernière solution qui me semble faisable est d'avoir un système similaire à ma deuxième solution, mais avec une estimation dynamique du nombre d'itérations à effectuer avant d'appeler time() pour avoir un impact négligeable sur les performances tout en ayant une estimation correcte de la vitesse d'exécution du code.

Sachant que le problème me semble quelque chose de potentiellement "courant", je suppose qu'il doit déjà y avoir une librairie qui fait ça beaucoup mieux que ce que je pourrais faire, mais je n'ai rien trouvé (en tout cas, rien avec une recherche Google et rien dans Boost), donc je me demande si mon approche est correcte.

Est-ce ça vous semble sensé?


  1. oui, je sais qu'il y a des objets dédiés en C++, c'était juste pour l'exemple. 

+0 -0

J'ai trouvé ça sur cplusplus

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// high_resolution_clock example
#include <iostream>
#include <ctime>
#include <ratio>
#include <chrono>

int main ()
{
  using namespace std::chrono;

  high_resolution_clock::time_point t1 = high_resolution_clock::now();

  std::cout << "printing out 1000 stars...\n";
  for (int i=0; i<1000; ++i) std::cout << "*";
  std::cout << std::endl;

  high_resolution_clock::time_point t2 = high_resolution_clock::now();

  duration<double> time_span = duration_cast<duration<double>>(t2 - t1);

  std::cout << "It took me " << time_span.count() << " seconds.";
  std::cout << std::endl;

  return 0;
}

Édité par d3m0t3p

conseil: le thé est meilleur avec un zeste de citron

+0 -2

Cette réponse a aidé l'auteur du sujet

Un point qu'il faut bien comprendre : L'informatique c'est quantique : mesurer va changer la valeur, il faut juste perturber le moins possible.

Toutes tes options me paraissent possibles. - Le première en wrappant ta fonction avec ce que montre d3m0t3p - Je vois pas en quoi la seconde te pose un soucis. Faire une moyenne sur 50 ou 100 appels se fait bien. - Pour la 3eme Avec un simple atomic<int>donné à une tâche asynchrone, le surcout de com entre thread devrait être minimal.

Sinon, benchmark par google (même si c'est plus orienté unittest), et une vidéo légèrement off-topic sur le sujet

Édité par Davidbrcz

+3 -0

Cette réponse a aidé l'auteur du sujet

Pour accéder au atomic_int, utilise le mode d'accès relaxé, comme on ne l'utilise pas pour faire de la synchronisation, il n'y aura pas de problème à faire ça et ça évitera des flush de cache.

First : Always RTFM - "Tout devrait être rendu aussi simple que possible, mais pas plus." A.Einstein

+1 -0
Auteur du sujet

Le problème de la deuxième solution, c'est que je peux très bien avoir un moment où la boucle tourne à 10 itérations secondes et un autre où c'est 1 million (ça restera cependant assez cohérent sur une courte période de temps). Donc en fixant le nombre d'itération pour chaque calcul, je risque fort de me retrouver à avoir un moment où les données sont mise à jour pas assez souvent et un autre où j'impacte les performances.

Par contre, l'idée d'utiliser atomic correspond bien à ce qu'il me faut. Non seulement, gérer l'affichage et le temps dans un thread séparé me permet d'avoir un fonctionnement simple, mais c'est peut-être la solution qui impacte le moins les performances.

Merci à vous :)

+0 -0
Auteur du sujet

La grosse majorité des profileurs ralentissent énormément le code et permettent après l'exécution d'avoir des informations sur l'exécution du code.

Mon but est très différent puisque je souhaite avoir au sein de programme un moyen de connaître la vitesse d'exécution actuelle et ce en impactant les performances au minimum.

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte