====== Partie 2 : Mesurer le temps passé par une fonction ====== [[in204:tds:sujets:td12_2023|TD12]] ===== Références===== [[https://en.cppreference.com/w/cpp/chrono/high_resolution_clock|std::chrono::high_resolution_clock]] [[https://en.cppreference.com/w/cpp/utility/pair/make_pair|str::make_pair(...)]] [[https://en.cppreference.com/w/cpp/utility/pair/pair|str::pair]] ====== Partie n°1 ====== Nous souhaitons mesurer le temps de calcul d'une fonction. Pour ce faire, nous souhaitons créer une fonction : - qui va prendre en argument la fonction que nous souhaitons exécuter, - les arguments que nous devons passer à cette fonction, - qui va lancer un chronomètre, - qui va lancer la fonction - qui va récupérer le résultat de la fonction, - qui va estimer le temps passé par le temps de la fonction, - qui va retourner à la fois le résultat de la fonction mais aussi le temps passé par la fonction. ===== Question n°1 ===== Pour simplifier la conception, écrivez dans un premier la fonction qui appelle la fonction factorielle qui suit: et qui va exécuter cette fonction int factorial(int n) { return n == 0 ? 1 : (n * factorial(n - 1)); } La fonction aura le squelette suivant: std::pair estimate_factorial_time(int n) { // Code pour lancer le chronomètre int result = factorial(n); // Code pour calculer le temps écoulé // Retourner la paire contenant le résultat et le temps passé. } Ceci est assez simple à réaliser en utilisant les fonctions ''std::chrono::high_resolution_clock::now()'' et ''std::make_pair()''. std::pair estimate_factorial_time(int n) { auto starting_time = std::chrono::high_resolution_clock::now(); auto result = factorial(n); auto elasped_time = std::chrono::high_resolution_clock::now() - starting_time; return std::make_pair(elasped_time, result); } ===== Question n°2 ===== Transformer la fonction précédente estimate_time pour qu'elle prenne en argument une fonction arbitraire qui prend un argument et retourne un résultat qui ne sera pas obligatoirement un résultat de type ''long double''. Il faudra penser à utiliser un modèle (template) de fonctions. Il suffit de modifier la fonction antérieure comme un fonction qui prend deux paramètres de types: - le type correspondant à la fonction, - le type correspondant au paramètre de la fonction. Et le tour est joué. Ceci donne le code suivant : template auto estimate_function_time(Function function, T argument) { auto starting_time = std::chrono::high_resolution_clock::now(); auto result = function(argument); auto elasped_time = std::chrono::high_resolution_clock::now() - starting_time; return std::make_pair(elasped_time, result); } ===== Question n°3 ===== Nous souhaitons désormais pouvoir prendre une fonction pouvant prendre plusieurs arguments comme la fonction puissance. template numericalT power_by_int(numericalT x, int y) { numericalT result = (numericalT)1.0; while (y-- > 0) result *= x; return result; } Modifier le code de la fonction pour pouvoir prendre une telle fonction comme paramètre. __**Remarque**__: il faut penser à utiliser les **packs de paramètres** que nous avons vu dans la première partie du TD. Dans le cas présent, comme nous avons aucun, un ou plusieurs paramètres, chacun des paramètres pouvant avoir un type différent. Dans ce cas, nous pouvons remplacer le paramêtre ''T'' de la fonction ''estimate_function_time'' précédenter par un argument correspondant à un pack de paramètres ''...Args''. Et c'est tout ! template auto estimate_function_time(Function function, Args... arguments) { auto starting_time = std::chrono::high_resolution_clock::now(); auto result = function(arguments...); auto elasped_time = std::chrono::high_resolution_clock::now() - starting_time; return std::make_pair(elasped_time, result); } Estimer le temps nécesaire pour calculer par exemple : 1.0002 ^ 10000000. Le code suivant va permettre d'estimer le temps passé à calculer le résultat : auto pw = estimate_function_time(power_by_int, 1.0002, 1000000); std::cout << "Computing 1.02^1000000=" << pw.second << " in " << pw_10000000.first.count() << " ticks.\n"; ==== Question n°5 ==== Créer une fonction nouvelle qui va appeller la fonction ''estimate_function_time'' pour calculer ''x'' fois le temps nécessaire pour calculer la fonction et qui retourn le temps moyen pour effectuer un "run" de la fonction. Cette fonction aura l'entête suivante : template long long mean_function_time(int number_of_runs, Function function, Args... arguments) { ... } Il suffit de lancer ''number_of_runs'' fois un appel à ''estimate_function_time'' pour la fonction et les arguments. Ceci donne le code suivant : template long long mean_function_time(int number_of_runs, Function function, Args... arguments) { long long duration = 0L; int remaining_runs = number_of_runs; while (remaining_runs-- > 0) duration += estimate_function_time(function, arguments...).first.count(); return duration / (long long)number_of_runs; } ====== Navigation ====== Partie 1: [[.part1|Manipuler un nombre variable de paramètres]]\\ Partie 3: [[.part3|Exécution à la compilation]]