web-dev-qa-db-fra.com

Que dois-je utiliser pour remplacer gettimeofday () sous Windows?

J'écris une classe Socket portable qui prend en charge les délais d'attente pour l'envoi et la réception ... Pour implémenter ces délais, j'utilise select().... Mais, j'ai parfois besoin de savoir combien de temps j'ai été bloqué à l'intérieur de select() qui bien sûr sur Linux j'implémenterais en appelant gettimeofday() avant et après j'appelle select() puis en utilisant timersub() pour calculer la delta...

Étant donné que select() sous Windows accepte struct timeval pour son timeout, quelle méthode dois-je utiliser pour remplacer gettimeofday () sous Windows?

18
dicroce

J'ai fini par trouver cette page: gettimeofday () sur windows [edit: lien supprimé car il pointe désormais vers un site publicitaire]. Qui a une implémentation pratique et dandy de gettimeofday () sur Windows. Il utilise la méthode GetSystemTimeAsFileTime() pour obtenir une horloge précise.

Mise à jour : Voici un lien actif [edit: lien supprimé car il pointe maintenant vers un site publicitaire] qui pointe vers l'implémentation à laquelle l'OP a fait référence. Notez également qu'il y a une faute de frappe dans l'implémentation liée:

#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
  #define DELTA_Epoch_IN_MICROSECS  11644473600000000Ui64 // WRONG
#else
  #define DELTA_Epoch_IN_MICROSECS  11644473600000000ULL // WRONG
#endif

Il manque une valeur supplémentaire aux valeurs affichées 0 à la fin (ils ont supposé des microsecondes, pas le nombre d'intervalles de 100 nanosecondes). Cette faute de frappe a été trouvée via ce commentaire sur une page de projet de code Google. Les valeurs correctes à utiliser sont indiquées ci-dessous:

#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
  #define DELTA_Epoch_IN_MICROSECS  116444736000000000Ui64 // CORRECT
#else
  #define DELTA_Epoch_IN_MICROSECS  116444736000000000ULL // CORRECT
#endif

Implémentation PostgreSQL de gettimeofday pour Windows:

/*
 * gettimeofday.c
 *    Win32 gettimeofday() replacement
 *
 * src/port/gettimeofday.c
 *
 * Copyright (c) 2003 SRA, Inc.
 * Copyright (c) 2003 SKC, Inc.
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose, without fee, and without a
 * written agreement is hereby granted, provided that the above
 * copyright notice and this paragraph and the following two
 * paragraphs appear in all copies.
 *
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
 * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
 * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
 * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS
 * IS" BASIS, AND THE AUTHOR HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE,
 * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */

#include "c.h"

#include <sys/time.h>


/* FILETIME of Jan 1 1970 00:00:00. */
static const unsigned __int64 Epoch = ((unsigned __int64) 116444736000000000ULL);

/*
 * timezone information is stored outside the kernel so tzp isn't used anymore.
 *
 * Note: this function is not for Win32 high precision timing purpose. See
 * elapsed_time().
 */
int
gettimeofday(struct timeval * tp, struct timezone * tzp)
{
    FILETIME    file_time;
    SYSTEMTIME  system_time;
    ULARGE_INTEGER ularge;

    GetSystemTime(&system_time);
    SystemTimeToFileTime(&system_time, &file_time);
    ularge.LowPart = file_time.dwLowDateTime;
    ularge.HighPart = file_time.dwHighDateTime;

    tp->tv_sec = (long) ((ularge.QuadPart - Epoch) / 10000000L);
    tp->tv_usec = (long) (system_time.wMilliseconds * 1000);

    return 0;
}
20
dicroce

Que diriez-vous:

unsigned long start = GetTickCount();
// stuff that needs to be timed
unsigned long delta = GetTickCount() - start;

GetTickCount() n'est pas très précis, mais fonctionnera probablement bien. Si vous voyez beaucoup d'intervalles de 0, 16 ou 31 millisecondes, essayez de chronométrer sur des intervalles plus longs ou utilisez une fonction plus précise comme timeGetTime.

Ce que je fais habituellement, c'est ceci:

unsigned long deltastack;
int samples = 0;
float average;

unsigned long start = GetTickCount();
// stuff that needs to be timed
unsigned long delta = GetTickCount() - start;

deltastack += delta;
if (samples++ == 10)
{
   // total time divided by amount of samples
   average = (float)deltastack / 10.f;
   deltastack = 0;
   samples = 0;  
}
4
knight666

Dans votre cas, j'utiliserais la plateforme indépendante std :: clock

1
Shay Erlichmen

Vous pouvez consulter QueryPerformanceCounter et QueryPerformanceFrequency. Ce sont très haute résolution - jusqu'à un tick par dix cycles sur certains temporisateurs matériels.

1
Puppy