8
votes

Comment puis-je tester les performances d'une fonction C?

Y a-t-il de bonnes façons de savoir comment une fonction fonctionne dans C? Je voudrais, par exemple, comparez ma propre fonction à une fonction de bibliothèque.


0 commentaires

11 Réponses :


3
votes

Stockez le temps de l'heure avant de saisir la fonction. Stockez hors du temps du système après votre retour de la fonction. Soustrayez la différence et comparez les deux implémentations.


1 commentaires

Et bien sûr, en boucle assez de fois que vous n'avez pas la différence de zéro.



0
votes
  • Stockage horodatage avant entrer la fonction

  • Store Timestamp après la fonction de sortie

  • comparer horodatage

    Assurez-vous que d'utiliser un échantillon significatif à mesure que la résolution temporelle peut varier vos résultats. Cela est particulièrement vrai pour les fonctions de courte durée. Utilisez des minuteries haute résolution (la résolution de microsecondes est disponible sur la plupart des plates-formes).


0 commentaires

3
votes

exécutez-le plusieurs millions de fois (chacun) et mesurez le temps nécessaire.
Celui qui termine plus vite est le meilleur performant.

GPROF peut aider :) p>

Voici le résultat de GPROF lorsque j'exécute un programme de mien pendant 10 secondes (noms de fonction modifiés) p>

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
 60.29      8.68     8.68 115471546     0.00     0.00  workalot
 39.22     14.32     5.64       46   122.70   311.32  work_b
  0.49     14.39     0.07                             inlined
  0.07     14.40     0.01       46     0.22     0.22  work_c
  0.00     14.40     0.00      460     0.00     0.00  find_minimum
  0.00     14.40     0.00      460     0.00     0.00  feedback
  0.00     14.40     0.00       46     0.00     0.00  work_a


5 commentaires

Je serais d'accord avec ce généralement . Cependant, la première itération est susceptible d'être beaucoup plus lente que le reste, en raison de problèmes de mise en cache. Si la routine n'est généralement faite qu'une fois, plutôt que dans une boucle serrée, cela vous donnera une image asymétrique. OTOH, si la routine n'est faite qu'une seule fois, vous ne devez pas gaspiller de temps précieux pour essayer de profiler ou d'l'optimiser non plus.


Merci PMG, je vais vérifier GProf. J'ai remarqué que je l'avais même installé par défaut.


T.e.d. fait quelques excellents points. Le cache de la CPU et la mise en cache du système d'exploitation amélioreront considérablement les performances de votre fonction sur toutes les premières itérations, ce qui vous permettra une performance moyenne, ce que vous obtenez si la fonction est exécutée seule ou entre autres fonctions suffisamment charnues pour remplacer la Contenu du cache de la CPU. Mais c'est probablement la meilleure technique de profilage simple, et vous donnera toujours une figure de performance bonne / acceptable / terrible.


Si vous mélangez les appels, vous aurez tendance à éviter l'effet T.E.D. remarqué. D'autre part, la mise en cache affectera toutes les fonctions et l'effet pourrait même sortir.


Oui, mais ne fonctionnerait pas avec de nombreux appels ultérieurs, ce sont ceux où la performance est la plus importante. Comparer une boucle serrée avec une fonction d'appel dans chaque itération, à un seul appel. La performance d'un seul appel est moins susceptible d'importer la façon dont je le vois.



14
votes

Vous avez besoin de minuteries haute résolution.

sur Linux, GeTimeOdday () < / a> est un choix décent, il vous donne une résolution microseconde. Sous Windows, QueryPerformEcanceCounter () est typique. Assurez-vous que vous exécutez votre fonction plusieurs fois, pour obtenir des lectures stables.

échantillon rapide, pour Linux: xxx

Vous seriez bien sûr ajuster le compte ( 100 000) pour correspondre aux performances de la fonction. Il convient de mieux si la fonction prend vraiment un certain temps à exécuter, sinon la boucle et / ou la fonction d'appel de fonction pourrait dominer.


2 commentaires

Merci pour la pointe et l'exemple. Je gère Mac OS ici si GetTimeOdday () est disponible ici aussi.


Cela fonctionne bien si la fonction dépend uniquement de la mémoire et de la CPU et ne change pas les états (c'est-à-dire qui fonctionne à chaque fois). Si votre fonction a accès au fichier, vous pouvez être dupe de la cache de système de fichiers.



1
votes

Checkout HighRestimer pour une minuterie haute performance.

Vous trouverez probablement stocker le temps avant / après n'est pas assez précis et entraînera probablement 0 à moins que vous n'ayez une fonction de fonctionnement plus longue.


0 commentaires

1
votes

Vérifiez RDTSC mais il est préférable de le faire ci-dessous.

0 - Dormeur de sommeil ou de rendement du système d'appel de sorte que lorsqu'il retourne, vous avez une nouvelle ligne de TimesLice

1 - RDTSC

2 - Appelez votre fonction

3 - RDTSC

Si votre fonction est longue, vous devez utiliser une sorte d'outil de profilage comme GProf (il est très facile à utiliser) et l'application VTune d'Intel (que je n'ai pas utilisée depuis longtemps). Après avoir vu la réponse de l'art, j'ai changé d'avis de GProf en Callgrind. Je n'ai utilisé que l'outil Memcheck de Valgrind dans le passé et c'était un outil magnifique. Je n'ai pas utilisé Callgrind avant, mais je suis sûr qu'il est meilleur que GProf ...


1 commentaires

Cela intéressant, je ne savais pas qu'il y avait des instructions de montage pour cela. Peut-être avoir à essayer aussi de voir comment cela fonctionne.



4
votes

la source ouverte Callgrind profileur (pour Linux) est un moyen vraiment génial de mesurer performance. Couplé avec KcachetRind, vous obtenez de très grandes visualisations de votre temps.

Callgrind fait partie de Valgrind.

  • Art

0 commentaires

0
votes

Comme l'approche la plus simple et portable, vous pouvez utiliser le temps de fonction standard (), qui renvoie le nombre actuel de secondes depuis l'époque.

#include <time.h>

time_t starttime, endtime;

starttime = time(NULL);
for (i = 0; i < 1000000; i++)
{
    testfunc();
}
endtime = time(NULL);

printf("Time in seconds is %d\n", (int)(endtime-starttime));


0 commentaires

3
votes

Fred, je remarque que vous avez dit dans un commentaire que vous êtes sur OS X. Le meilleur moyen d'obtenir des horaires très précis des fonctions à petite échelle sur OS X est avec le mach_absoute_time () code> une fonction. Vous pouvez l'utiliser comme suit:

#include <mach/mach_time.h>
#include <sys/sysctl.h>
#include <stdint.h>

double ticksToNanoseconds(double ticks) {
    static double nanosecondsPerTick = 0.0;
    // The first time the function is called
    // ask the system how to convert mach
    // time units to nanoseconds
    if (0.0 == nanosecondsPerTick) {
        mach_timebase_info_data_t timebase;
        // to be completely pedantic, check the return code of this call:
        mach_timebase_info(&timebase);
        nanosecondsPerTick = (double)timebase.numer / timebase.denom;
    }
    return ticks * nanosecondsPerTick;
}

double nanosecondsToCycles(double nanoseconds) {
    static double cyclesPerNanosecond = 0.0;
    // The first time the function is called
    // ask the system what the CPU frequency is
    if (0.0 == cyclesPerNanosecond) {
        uint64_t freq;
        size_t freqSize = sizeof(freq);
        // Again, check the return code for correctness =)
        sysctlbyname("hw.cpufrequency", &freq, &freqSize, NULL, 0L );
        cyclesPerNanosecond = (double)freq * 1e-9;
    }
    return nanoseconds * cyclesPerNanosecond;
}


2 commentaires

Merci Stephen, Excelent! Je vais essayer cela.


Si vous frappez des problèmes, faites le moi savoir; J'ai tapé tout cela de la mémoire, alors j'ai peut-être fait une erreur quelque part =)



3
votes

Toutes ces autres réponses utilisent une variante de GetTimeOdday () pour le timing. Ceci est assez brut puisque vous devez généralement exécuter le noyau plusieurs fois pour obtenir des résultats reproductibles. La mise dans une boucle serrée change l'état des deux caches de code et de données afin que ces résultats ne soient donc pas révélés de la performance réelle.

Une bien meilleure alternative consiste à utiliser le compteur de cycle de la CPU. Sur X86, vous pouvez le faire avec l'instruction rdtsc . Cela vient de x264 < / a>: xxx

Pour plus d'informations sur le profilage à l'aide de divers compteurs de matériel, voir Papi . Simulateurs (comme Callgrind et des profilers basés sur des interruptions ( oprofile ) sont utiles.


0 commentaires

5
votes

Bonjour, je vais vous donner un exemple et l'expliquera: xxx

sortie: Temps de processeur utilisé par programme: 4.94066E-324 sec.

Time.h:

déclare clock_t qui est un arithmétique (vous pouvez faire des mathématiques sur cette valeur comme je le fais dans l'exemple). fondamentalement mettre n'importe quel code où le commentaire est.

Clocks_per_sec est une macro déclarée à temps.h, utilisez-la comme dénominateur pour convertir la valeur en secondes.

Il est essentiel de lancer à long terme pour deux raisons:

  1. Nous ne savons pas quel type clock_t est réellement, mais nous voulons l'imprimer (quelle conversion mettez-vous dans Printf?).
  2. Long Double est un type très précis qui peut représenter de très petites valeurs.

0 commentaires