web-dev-qa-db-fra.com

Mesurer le temps d'exécution d'une fonction en C ++

Je veux savoir combien de temps une certaine fonction prend dans mon programme C++ pour s'exécuter sur Linux. Ensuite, je veux faire une comparaison de vitesse. J'ai vu plusieurs fois fonctionner mais j'ai fini avec cela de boost. Chrono:

process_user_cpu_clock, captures user-CPU time spent by the current process

Maintenant, je ne sais pas si j'utilise la fonction ci-dessus. Est-ce que je n'aurai que le temps que le processeur consacrera à cette fonction?

Deuxièmement, je n'ai trouvé aucun exemple d'utilisation de la fonction ci-dessus. Quelqu'un peut-il m'aider s'il vous plaît comment utiliser la fonction ci-dessus?

P.S: À l’heure actuelle, j’utilise std::chrono::system_clock::now() pour obtenir le temps en secondes, mais cela me donne des résultats différents en raison de la charge de processeur différente à chaque fois.

101
Xara

C'est une méthode très facile à utiliser en C++ 11. Vous devez utiliser std::chrono::high_resolution_clock à partir de <chrono> en-tête.

Utilisez-le comme suit:

#include <iostream>
#include <chrono>

void function()
{
    long long number = 0;

    for( long long i = 0; i != 2000000; ++i )
    {
       number += 5;
    }
}

int main()
{
    auto t1 = std::chrono::high_resolution_clock::now();
    function();
    auto t2 = std::chrono::high_resolution_clock::now();

    auto duration = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count();

    std::cout << duration;
    return 0;
}

Cela permettra de mesurer la durée de la fonction.

NOTE: Vous n'obtiendrez pas toujours le même timing pour une fonction. Cela est dû au fait que le processeur de votre machine peut être moins ou davantage utilisé par d'autres processus en cours d'exécution sur votre ordinateur, tout comme votre esprit peut être plus ou moins concentré lorsque vous résolvez un exercice mathématique. Dans l’esprit humain, nous pouvons nous souvenir de la solution d’un problème mathématique, mais pour un ordinateur, le même processus sera toujours quelque chose de nouveau; ainsi, comme je l'ai dit, vous n'obtiendrez pas toujours le même résultat!

201
Victor

Voici une fonction qui mesurera le temps d'exécution de toute fonction passée en argument:

#include <chrono>
#include <utility>

typedef std::chrono::high_resolution_clock::time_point TimeVar;

#define duration(a) std::chrono::duration_cast<std::chrono::nanoseconds>(a).count()
#define timeNow() std::chrono::high_resolution_clock::now()

template<typename F, typename... Args>
double funcTime(F func, Args&&... args){
    TimeVar t1=timeNow();
    func(std::forward<Args>(args)...);
    return duration(timeNow()-t1);
}

Exemple d'utilisation:

#include <iostream>
#include <algorithm>

typedef std::string String;

//first test function doing something
int countCharInString(String s, char delim){
    int count=0;
    String::size_type pos = s.find_first_of(delim);
    while ((pos = s.find_first_of(delim, pos)) != String::npos){
        count++;pos++;
    }
    return count;
}

//second test function doing the same thing in different way
int countWithAlgorithm(String s, char delim){
    return std::count(s.begin(),s.end(),delim);
}


int main(){
    std::cout<<"norm: "<<funcTime(countCharInString,"precision=10",'=')<<"\n";
    std::cout<<"algo: "<<funcTime(countWithAlgorithm,"precision=10",'=');
    return 0;
}

Sortie:

norm: 15555
algo: 2976
12
Jahid

programme simple pour trouver le temps d’exécution d’une fonction.

#include <iostream>
#include <ctime> // time_t
#include <cstdio>

void function()
{
     for(long int i=0;i<1000000000;i++)
     {
        // do nothing
     }
}

int main()
{

time_t begin,end; // time_t is a datatype to store time values.

time (&begin); // note time before execution
function();
time (&end); // note time after execution

double difference = difftime (end,begin);
printf ("time taken for function() %.2lf seconds.\n", difference );

return 0;
}
8
Abdullah Farweez

Dans le livre de Scott Meyers, j'ai trouvé un exemple d'expression lambda générique universelle qui peut être utilisée pour mesurer le temps d'exécution d'une fonction. (C++ 14)

auto timeFuncInvocation = 
    [](auto&& func, auto&&... params) {
        // get time before function invocation
        const auto& start = high_resolution_clock::now();
        // function invocation using perfect forwarding
        std::forward<decltype(func)>(func)(std::forward<decltype(params)>(params)...);
        // get time after function invocation
        const auto& stop = high_resolution_clock::now();
        return stop - start;
     };

Le problème est que vous ne mesurez qu'une seule exécution, les résultats peuvent donc être très différents. Pour obtenir un résultat fiable, vous devez mesurer un grand nombre d'exécutions. Selon la conférence Andrei Alexandrescu lors de la conférence code :: dive 2015 - Writing Fast Code I:

Temps mesuré: tm = t + tq + tn + à

où:

tm - temps mesuré (observé)

t - le temps d'intérêt réel

tq - temps ajouté par le bruit de quantification

tn - temps ajouté par diverses sources de bruit

temps supplémentaire (mesure, mise en boucle, fonctions d'appel)

Selon ce qu'il a dit plus tard dans la conférence, vous devriez prendre comme résultat un minimum de ce grand nombre d'exécutions. Je vous encourage à regarder la conférence dans laquelle il explique pourquoi.

En outre, il existe une très bonne bibliothèque de Google - https://github.com/google/benchmark . Cette bibliothèque est très simple à utiliser et puissante. Vous pouvez consulter certaines conférences de Chandler Carruth sur youtube où il utilise cette bibliothèque dans la pratique. Par exemple, CppCon 2017: Chandler Carruth “Going Nowhere Faster”;

Exemple d'utilisation:

#include <iostream>
#include <chrono>
#include <vector>
auto timeFuncInvocation = 
    [](auto&& func, auto&&... params) {
        // get time before function invocation
        const auto& start = high_resolution_clock::now();
        // function invocation using perfect forwarding
        for(auto i = 0; i < 100000/*largeNumber*/; ++i) {
            std::forward<decltype(func)>(func)(std::forward<decltype(params)>(params)...);
        }
        // get time after function invocation
        const auto& stop = high_resolution_clock::now();
        return (stop - start)/100000/*largeNumber*/;
     };

void f(std::vector<int>& vec) {
    vec.Push_back(1);
}

void f2(std::vector<int>& vec) {
    vec.emplace_back(1);
}
int main()
{
    std::vector<int> vec;
    std::vector<int> vec2;
    std::cout << timeFuncInvocation(f, vec).count() << std::endl;
    std::cout << timeFuncInvocation(f2, vec2).count() << std::endl;
    std::vector<int> vec3;
    vec3.reserve(100000);
    std::vector<int> vec4;
    vec4.reserve(100000);
    std::cout << timeFuncInvocation(f, vec3).count() << std::endl;
    std::cout << timeFuncInvocation(f2, vec4).count() << std::endl;
    return 0;
}

EDIT: Bien sûr, vous devez toujours vous rappeler que votre compilateur peut optimiser ou non quelque chose. Des outils tels que perf peuvent être utiles dans de tels cas.

4

Moyen facile pour les anciens C++ ou C:

#include <time.h> // includes clock_t and CLOCKS_PER_SEC

int main() {

    clock_t start, end;

    start = clock();
    // ...code to measure...
    end = clock();

    double duration_sec = double(end-start)/CLOCKS_PER_SEC;
    return 0;
}

La précision de la cadence en secondes est 1.0/CLOCKS_PER_SEC

3
v.chaplin
  • C'est une méthode très facile à utiliser en C++ 11.
  • Nous pouvons utiliser std :: chrono :: high_resolution_clock à partir de l'en-tête
  • Nous pouvons écrire une méthode pour imprimer le temps d'exécution de la méthode sous une forme très lisible.

Par exemple, pour trouver tous les nombres premiers compris entre 1 et 100 millions, il faut environ 1 minute et 40 secondes. Donc, le temps d'exécution est imprimé comme:

Execution Time: 1 Minutes, 40 Seconds, 715 MicroSeconds, 715000 NanoSeconds

Le code est ici:

#include <iostream>
#include <chrono>

using namespace std;
using namespace std::chrono;

typedef high_resolution_clock Clock;
typedef Clock::time_point ClockTime;

void findPrime(long n, string file);
void printExecutionTime(ClockTime start_time, ClockTime end_time);

int main()
{
    long n = long(1E+8);  // N = 100 million

    ClockTime start_time = Clock::now();

    // Write all the prime numbers from 1 to N to the file "prime.txt"
    findPrime(n, "C:\\prime.txt"); 

    ClockTime end_time = Clock::now();

    printExecutionTime(start_time, end_time);
}

void printExecutionTime(ClockTime start_time, ClockTime end_time)
{
    auto execution_time_ns = duration_cast<nanoseconds>(end_time - start_time).count();
    auto execution_time_ms = duration_cast<microseconds>(end_time - start_time).count();
    auto execution_time_sec = duration_cast<seconds>(end_time - start_time).count();
    auto execution_time_min = duration_cast<minutes>(end_time - start_time).count();
    auto execution_time_hour = duration_cast<hours>(end_time - start_time).count();

    cout << "\nExecution Time: ";
    if(execution_time_hour > 0)
    cout << "" << execution_time_hour << " Hours, ";
    if(execution_time_min > 0)
    cout << "" << execution_time_min % 60 << " Minutes, ";
    if(execution_time_sec > 0)
    cout << "" << execution_time_sec % 60 << " Seconds, ";
    if(execution_time_ms > 0)
    cout << "" << execution_time_ms % long(1E+3) << " MicroSeconds, ";
    if(execution_time_ns > 0)
    cout << "" << execution_time_ns % long(1E+6) << " NanoSeconds, ";
}
1
Pratik Patil

Voici un excellent modèle de classe contenant uniquement des en-têtes pour mesurer le temps écoulé d'une fonction ou d'un bloc de code:

#ifndef EXECUTION_TIMER_H
#define EXECUTION_TIMER_H

template<class Resolution = std::chrono::milliseconds>
class ExecutionTimer {
public:
    using Clock = std::conditional_t<std::chrono::high_resolution_clock::is_steady,
                                     std::chrono::high_resolution_clock,
                                     std::chrono::steady_clock>;
private:
    const Clock::time_point mStart = Clock::now();

public:
    ExecutionTimer() = default;
    ~ExecutionTimer() {
        const auto end = Clock::now();
        std::ostringstream strStream;
        strStream << "Destructor Elapsed: "
                  << std::chrono::duration_cast<Resolution>( end - mStart ).count()
                  << std::endl;
        std::cout << strStream.str() << std::endl;
    }    

    inline void stop() {
        const auto end = Clock::now();
        std::ostringstream strStream;
        strStream << "Stop Elapsed: "
                  << std::chrono::duration_cast<Resolution>(end - mStart).count()
                  << std::endl;
        std::cout << strStream.str() << std::endl;
    }

}; // ExecutionTimer

#endif // EXECUTION_TIMER_H

En voici quelques utilisations:

int main() {
    { // empty scope to display ExecutionTimer's destructor's message
         // displayed in milliseconds
         ExecutionTimer<std::chrono::milliseconds> timer;

         // function or code block here

         timer.stop();

    } 

    { // same as above
        ExecutionTimer<std::chrono::microseconds> timer;

        // code block here...

        timer.stop();
    }

    {  // same as above
       ExecutionTimer<std::chrono::nanoseconds> timer;

       // code block here...

       timer.stop();

    }

    {  // same as above
       ExecutionTimer<std::chrono::seconds> timer;

       // code block here...

       timer.stop();

    }              

    return 0;
}

Comme la classe est un modèle, nous pouvons facilement spécifier comment nous voulons que notre temps soit mesuré et affiché. Il s'agit d'un modèle de classe utilitaire très pratique pour effectuer le balisage et très facile à utiliser.

0
Francis Cugler

Je recommande d'utiliser steady_clock qui est monotone, contrairement à high_resolution_clock.

#include <iostream>
#include <chrono>

using namespace std;

unsigned int stopwatch()
{
    static auto start_time = chrono::steady_clock::now();

    auto end_time = chrono::steady_clock::now();
    auto delta    = chrono::duration_cast<chrono::microseconds>(end_time - start_time);

    start_time = end_time;

    return delta.count();
}

int main() {
  stopwatch(); //Start stopwatch
  std::cout << "Hello World!\n";
  cout << stopwatch() << endl; //Time to execute last line
  for (int i=0; i<1000000; i++)
      string s = "ASDFAD";
  cout << stopwatch() << endl; //Time to execute for loop
}

Sortie:

Hello World!
62
163514
0
Gillespie