1 /*
2  * This software was written by Jim Fougeron jfoug AT cox dot net
3  * in 2009. No copyright is claimed, and the software is hereby
4  * placed in the public domain. In case this attempt to disclaim
5  * copyright and place the software in the public domain is deemed
6  * null and void, then the software is Copyright (c) 2009 Jim Fougeron
7  * and it is hereby released to the general public under the following
8  * terms:
9  *
10  * This software may be modified, redistributed, and used for any
11  * purpose, in source and binary forms, with or without modification.
12  *
13  * Portable hi-res timer.  Was a nice C++ class.
14  * Downgraded to C for project john
15  */
16 
17 #include <stdio.h>
18 
19 #include "timer.h"
20 
21 double sm_HRTicksPerSec = 0.0;  // HR Ticks per second
22 int sm_fGotHRTicksPerSec = 0;   // Set if we have got the above
23 double sm_hrPrecision = 0.0;
24 double sm_cPrecision = 0.0;
25 
sTimer_Init(sTimer * t)26 void sTimer_Init(sTimer *t)
27 {
28 	t->m_fRunning = 0;
29 	t->m_cStartTime = 0;
30 	t->m_cEndTime = 0;
31 	t->m_dAccumSeconds = 0;
32 	HRZERO(t->m_hrStartTime);
33 	HRZERO(t->m_hrEndTime);
34 	if (!sm_fGotHRTicksPerSec) {
35 		// What's the lowest digit set non-zero in a clock() call
36 		// That's a fair indication what the precision is likely to be.
37 		// Note - this isn't actually used
38 		int i;
39 		sm_fGotHRTicksPerSec = 1;
40 		sm_cPrecision = 0;
41 		for (i = 0; i < 10; ++i) {
42 			clock_t heuristicTimeTest = clock();
43 			if (heuristicTimeTest % 10) {
44 				sm_cPrecision = 1.0 / CLOCKS_PER_SEC;
45 				break;
46 			}
47 			else if (heuristicTimeTest % 100) {
48 				if (sm_cPrecision == 0 ||
49 				        sm_cPrecision > 10.0 / CLOCKS_PER_SEC)
50 					sm_cPrecision = 10.0 / CLOCKS_PER_SEC;
51 			}
52 			else if (heuristicTimeTest % 1000) {
53 				if (sm_cPrecision == 0 ||
54 				        sm_cPrecision > 100.0 / CLOCKS_PER_SEC)
55 					sm_cPrecision = 100.0 / CLOCKS_PER_SEC;
56 			}
57 			else if (heuristicTimeTest % 10000) {
58 				if (sm_cPrecision == 0 ||
59 				        sm_cPrecision > 1000.0 / CLOCKS_PER_SEC)
60 					sm_cPrecision =
61 					    1000.0 / CLOCKS_PER_SEC;
62 			}
63 			else {
64 				if (sm_cPrecision == 0 ||
65 				        sm_cPrecision > 10000.0 / CLOCKS_PER_SEC)
66 					sm_cPrecision =
67 					    10000.0 / CLOCKS_PER_SEC;
68 			}
69 		}
70 
71 		// Find the claimed resolution of the high res timer
72 		// Then find the most likely real rate by waiting for it to change.
73 		// Note - I've frequently seen missed beats, and therefore a
74 		// 0.000001 reality gets reported as a 0.000002.
75 		// Note - this also isn't actually used, all that matters is
76 		// whether HRTicksPerSec has a non-zero value or not.
77 		HRGETTICKS_PER_SEC(sm_HRTicksPerSec);
78 
79 		if (sm_HRTicksPerSec != 0.0) {
80 			hr_timer start, end;
81 			HRSETCURRENT(start);
82 			do {
83 				HRSETCURRENT(end);
84 			} while (HRGETTICKS(end) == HRGETTICKS(start));
85 
86 			sm_hrPrecision =
87 			    (HRGETTICKS(end) -
88 			     HRGETTICKS(start)) / sm_HRTicksPerSec;
89 		}
90 	}
91 }
92 
93 
sTimer_Stop(sTimer * t)94 void sTimer_Stop(sTimer *t)
95 {
96 	if (t->m_fRunning) {
97 		if (sm_HRTicksPerSec != 0.0) {
98 			HRSETCURRENT(t->m_hrEndTime);
99 		}
100 		else {
101 			t->m_cEndTime = clock();
102 		}
103 	}
104 	else
105 		HRZERO(t->m_hrEndTime);
106 	t->m_fRunning = 0;
107 }
108 
sTimer_Start(sTimer * t,int bClear)109 void sTimer_Start(sTimer *t, int bClear)
110 {
111 	if (bClear)
112 		sTimer_ClearTime(t);
113 	if (sm_HRTicksPerSec != 0.0) {
114 		HRSETCURRENT(t->m_hrStartTime);
115 	}
116 	else {
117 		t->m_cStartTime = clock();
118 	}
119 	t->m_fRunning = 1;
120 }
121 
sTimer_ClearTime(sTimer * t)122 void sTimer_ClearTime(sTimer *t)
123 {
124 	t->m_dAccumSeconds = 0;
125 	HRZERO(t->m_hrStartTime);
126 	HRZERO(t->m_hrEndTime);
127 	t->m_fRunning = 0;
128 }
129 
sTimer_GetSecs(sTimer * t)130 double sTimer_GetSecs(sTimer *t)
131 {
132 	double retval;
133 	if (t->m_fRunning) {
134 		if (sm_HRTicksPerSec != 0.0) {
135 			HRSETCURRENT(t->m_hrEndTime);
136 		}
137 		else {
138 			t->m_cEndTime = clock();
139 		}
140 	}
141 	if (sm_HRTicksPerSec == 0.0) {
142 		// This is process time
143 		double d = (t->m_cEndTime - t->m_cStartTime) * 1.0;
144 		if (d > 0)
145 			retval = d / CLOCKS_PER_SEC;
146 		else
147 			retval = 0;
148 	}
149 	else {
150 		// This is wall-clock time
151 		double d =
152 		    (HRGETTICKS(t->m_hrEndTime) -
153 		     HRGETTICKS(t->m_hrStartTime));
154 		retval = 0;
155 		if (d > 0)
156 			retval = d / sm_HRTicksPerSec;
157 		else
158 			retval = 0;
159 	}
160 	return retval + t->m_dAccumSeconds;
161 }
162