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