Bonjour,

Il y a des personnes qui critiquent la mesure de temps écoulé avec gettimeofday() et préfèrent utiliser clock_gettime() avec la raison que celle-ci est plus précise, mais à quel point ?
J'ai écrit le code ci-dessous pour faire des tests de comparaison.

Description du code :
> Changement de la police d'ordonnancement du processus (il faut avoir des droits 'root').
> récupérer la résolution temporelle du système.
> utiliser nanosleep() pour dormir une période(= résolution temporelle du système.) mesurée avec clock_gettime et gettimeofday()
> utiliser nanosleep() pour dormir une période(= résolution temporelle du système /2) mesurée avec clock_gettime et gettimeofday().

Analyse du résultat :
D'après le manpage nanosleep() est soumis à la résolution temporelle du système sauf pour le cas expectionnelle de petite temporisation ou la boucle est active, donc vous ne pourrez jamais dormir une période en deça de cette résolution (d'où le même résultat quand on divise par deux la période).

Mais en plus de cela il faut ajouter au temps du sommeil le temps pour redémarrer le processus ("sortir du sleep et continuer le code") qui est au plus égal à la résolution temporelle du système, ce qui explique que les temps mesurés sont toujours supérieurs à la milliseconde mais restent en deça de la milliseconde de plus .
Finalement la différence de mesure est très faible (0.3 % d'écart) et donc il est possible d'utiliser clock_gettime() comme gettimeofday() pour des mesures à la microsecondes.
Enfin, je n'ai pas constaté que le nanosleep était plus précis pour des petites temporisations. Si des personnes ont des idées là-dessus ?

Ci-dessous le code (des commentaires sont ajoutés pour une autre méthode de mesure) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <sched.h>
#include <errno.h>
#include <string.h>
 
 
// Linux : link with librt : gcc -O3 -Wall main.c -lrt
//  add a random arg to set SCHED_FIFO priority
 
/*
	TEST with :
	Env: 
		Linux sli-linux 2.6.13CIO-SLI-15-default #5 Thu Apr 5 11:29:06 CEST 2007 i686 i686 i386 GNU/Linux
	Processor :
		vendor_id       : GenuineIntel
		cpu family      : 15
		model           : 2
		model name      : Intel(R) Pentium(R) 4 CPU 2.00GHz
		stepping        : 4
		cpu MHz         : 1994.327
		cache size      : 512 KB
	gcc version 4.0.2 20050901 (prerelease) (SUSE Linux)
 
	RESULTS :
	sli@sli-linux:~/developpement/my_tests/test_clock_gettime> ./a.out
	No sheduling change
	resolution : 0 s 999848 nsec
	classic scheduling, nanosleep(0 s, 999848 nsec), clock_gettime interval : 0 s 1408000 nsec
	classic scheduling, nanosleep(0 s, 999848 nsec), gettimeofday interval : 0 s 1406 usec
	relative accuracy of gettimeofday() to clockgettime() : -0.142248 %
	classic scheduling, nanosleep(0 s, 499924 nsec), clock_gettime interval : 0 s 1515000 nsec
	classic scheduling, nanosleep(0 s, 499924 nsec), gettimeofday interval : 0 s 1515 usec
	relative accuracy of gettimeofday() to clockgettime() : 0.000000 %
	sli@sli-linux:~/developpement/my_tests/test_clock_gettime> sudo ./a.out r
	Password:
	setting scheduling to FIFO
	resolution : 0 s 999848 nsec
	classic scheduling, nanosleep(0 s, 999848 nsec), clock_gettime interval : 0 s 1168000 nsec
	classic scheduling, nanosleep(0 s, 999848 nsec), gettimeofday interval : 0 s 1166 usec
	relative accuracy of gettimeofday() to clockgettime() : -0.171527 %
	classic scheduling, nanosleep(0 s, 499924 nsec), clock_gettime interval : 0 s 1939000 nsec
	classic scheduling, nanosleep(0 s, 499924 nsec), gettimeofday interval : 0 s 1939 usec
	relative accuracy of gettimeofday() to clockgettime() : 0.000000 %
 
	CONCLUSION :
	Whatever scheduling is sleep() resolution time is system resolution time (here 1ms)
	The difference beetwenn clock_gettime() and gettimeofday() is negligible
	However clock_gettime() is compatible SUSv2, POSIX 1003.1-2001 (manpages), when gettimeofday() not ( SVr4, BSD 4.3), and for portability reason it is always better to use POSIX functions. For linux you will have to check the librt availability.
 
	TODO :
		Make two list of measures and compare mediums
		Check that with sched FIFO and <2ms tempo nanosleep() is more accurate.
*/
int main (int argc, char * argv[])
{
	clockid_t clk_id = CLOCK_REALTIME ;
	// resolution
	struct timespec res, tp_start, tp_end ;
	struct timeval tv_start, tv_end ;
	// nanosleep
	struct timespec req, rem, tick_adj ;
	// shed
	struct sched_param param ;
	int i ;
	float accuracy ;
 
	// Set RT priority ?
	if (argc > 1)
	{
		printf("setting scheduling to FIFO\n") ;
		if (sched_getparam(0, &param ) == -1)	
		{
			printf("error shed_get  : %s\n", strerror(errno)) ;
			return -1 ;
		}
		// manpage says priority must be >0 for fifo sched
		param.sched_priority = 1 ;
		if ( sched_setscheduler(0, SCHED_FIFO, &param) == -1)
		{
			printf("error shed_set  : %s\n", strerror(errno)) ;
                        return -1 ;
		}
	}
	else
	{
		printf("No sheduling change\n") ;
	}
 
	if ( clock_getres(clk_id, &res) == 0)
	{
		printf("resolution : %ld s %ld nsec\n", res.tv_sec, res.tv_nsec) ;
	}	
	else
	{
		printf("err getting resolution : %s\n", strerror(errno));
		return -1 ;
	}
 
	for (i = 1 ; i < 3 ; i++)
	{
		// manpage says : nanosleep sleep at least a time slice (i386=10ms), unless SCHED_FIFO/SCHED_RR for process (in this case 1us)
 
		// Now sleep a 'RT' time resolution / i to check nanosleep resolution in the Linux Classic Scheduling
	    req = res ;
		req.tv_sec /= i ;
		req.tv_nsec /= i ;
 
		// put a non-active sleep here to start on a tick.
		tick_adj.tv_sec = 0 ;
		tick_adj.tv_nsec = 20 * 1000000 ;
		nanosleep(&tick_adj, NULL) ;
 
		// We 'hope' that execution of clock_gettime+gettimeofday+nanosleep < tick duration
		clock_gettime(clk_id,&tp_start) ;
		gettimeofday(&tv_start, NULL) ;
		if(nanosleep(&req, &rem) == 0)
		{
			clock_gettime(clk_id,&tp_end) ;
			gettimeofday(&tv_end, NULL) ;
			printf("classic scheduling, nanosleep(%ld s, %ld nsec), clock_gettime interval : %ld s %ld nsec\n", 
				res.tv_sec / i, res.tv_nsec / i ,
				tp_end.tv_sec - tp_start.tv_sec, tp_end.tv_nsec - tp_start.tv_nsec) ;	
 
			printf("classic scheduling, nanosleep(%ld s, %ld nsec), gettimeofday interval : %ld s %ld usec\n",
					res.tv_sec /i , res.tv_nsec /i ,
					tv_end.tv_sec - tv_start.tv_sec, tv_end.tv_usec - tv_start.tv_usec) ;
 
			// printf relative accuracy (rounded to us) :
			accuracy = 1.0 - (float)((tp_end.tv_sec - tp_start.tv_sec)*1000000 + (tp_end.tv_nsec - tp_start.tv_nsec)/1000) / (float)( (tv_end.tv_sec - tv_start.tv_sec)*1000000 + tv_end.tv_usec - tv_start.tv_usec) ;		
			accuracy *= 100.0 ;
			printf("relative accuracy of gettimeofday() to clockgettime() : %f %% \n", accuracy) ;
		}
		else
		{
			printf("interrupted sleep, aborting : %s\n", strerror(errno)) ;
		}
	}	
 
	return 0 ;
}