Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
mpu.cpp
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/***********************************************************************************************
20 *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
21 ***********************************************************************************************
22 * *
23 * Project Name : Command & Conquer *
24 * *
25 * $Archive:: /Commando/Code/wwlib/mpu.cpp $*
26 * *
27 * $Author:: Denzil_l $*
28 * *
29 * $Modtime:: 8/23/01 5:07p $*
30 * *
31 * $Revision:: 4 $*
32 * *
33 *---------------------------------------------------------------------------------------------*
34 * Functions: *
35 * Get_CPU_Rate -- Fetch the rate of CPU ticks per second. *
36 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
37
38#include "always.h"
39#include "win.h"
40#include "mpu.h"
41#include "math.h"
42#include <assert.h>
43
44typedef union {
45 LARGE_INTEGER LargeInt;
46 struct QuadPart {
47 unsigned long LowPart;
48 unsigned long HighPart;
49 } QuadPart;
50} QuadValue;
51
52
53/***********************************************************************************************
54 * Get_CPU_Rate -- Fetch the rate of CPU ticks per second. *
55 * *
56 * This routine will query the CPU to determine how many clock per second it is. *
57 * *
58 * INPUT: high -- Reference to the location that will be filled with the upper 32 bits *
59 * of the result. *
60 * *
61 * OUTPUT: Returns with the lower 32 bits of the result. *
62 * *
63 * WARNINGS: none *
64 * *
65 * HISTORY: *
66 * 05/20/1997 JLB : Created. *
67 *=============================================================================================*/
68unsigned long Get_CPU_Rate(unsigned long & high)
69{
70 union {
71 LARGE_INTEGER LargeInt;
72 struct {
73 unsigned long LowPart;
74 unsigned long HighPart;
75 } QuadPart;
76 } value;
77
78 if (QueryPerformanceFrequency(&value.LargeInt)) {
79 high = value.QuadPart.HighPart;
80 return(value.QuadPart.LowPart);
81 }
82 high = 0;
83 return(0);
84}
85
86
87unsigned long Get_CPU_Clock(unsigned long & high)
88{
89 int h;
90 int l;
91 __asm {
92 _emit 0Fh
93 _emit 31h
94 mov [h],edx
95 mov [l],eax
96 }
97 high = h;
98 return(l);
99}
100
101
102
103
104/*
105**
106** Cut and paste job from an intel example.
107**
108**
109**
110**
111**
112**
113*/
114
115#define ASM_RDTSC _asm _emit 0x0f _asm _emit 0x31
116
117// Max # of samplings to allow before giving up and returning current average.
118#define MAX_TRIES 20
119#define ROUND_THRESHOLD 6
120
121// # of MHz to allow samplings to deviate from average of samplings.
122#define TOLERANCE 1
123
124static unsigned long TSC_Low;
125static unsigned long TSC_High;
126
127void RDTSC(void)
128{
129 _asm
130 {
131 ASM_RDTSC;
132 mov TSC_Low, eax
133 mov TSC_High, edx
134 }
135}
136
137
139{
140 LARGE_INTEGER t0,t1;
141 DWORD freq=0; // Most current freq. calc.
142 DWORD freq2=0; // 2nd most current freq. calc.
143 DWORD freq3=0; // 3rd most current freq. calc.
144 DWORD total; // Sum of previous three freq. calc.
145 int tries=0; // Number of times a calculation has been
146 // made on this call
147 DWORD total_cycles=0, cycles; // Clock cycles elapsed during test
148 DWORD stamp0, stamp1; // Time Stamp for beginning and end of test
149 DWORD total_ticks=0, ticks; // Microseconds elapsed during test
150// DWORD current = 0; // Elapsed time during loop
151 LARGE_INTEGER count_freq; // Hi-Res Performance Counter frequency
152
153
154 if ( !QueryPerformanceFrequency(&count_freq) ) return(0);
155
156
157 HANDLE process = GetCurrentProcess();
158 DWORD processPri = GetPriorityClass(process);
159 SetPriorityClass(process, REALTIME_PRIORITY_CLASS);
160
161 HANDLE thread = GetCurrentThread();
162 int threadPri = GetThreadPriority(thread);
163 SetThreadPriority(thread, THREAD_PRIORITY_TIME_CRITICAL);
164
165 /*
166 ** On processors supporting the TSC opcode, compare elapsed time on the
167 ** High-Resolution Counter with elapsed cycles on the Time Stamp Counter.
168 */
169
170 do {
171 /*
172 ** This do loop runs up to 20 times or until the average of the previous
173 ** three calculated frequencies is within 1 MHz of each of the individual
174 ** calculated frequencies. This resampling increases the accuracy of the
175 ** results since outside factors could affect this calculation.
176 */
177
178 tries++; // Increment number of times sampled
179 // on this call to cpuspeed
180
181 freq3 = freq2; // Shift frequencies back to make
182 freq2 = freq; // room for new frequency measurement
183
184 /*
185 ** Get high-resolution performance counter time
186 */
187 QueryPerformanceCounter(&t0);
188
189 t1.LowPart = t0.LowPart; // Set Initial time
190 t1.HighPart = t0.HighPart;
191
192 /*
193 ** Loop until 50 ticks have passed since last read of hi-res counter.
194 ** This accounts for overhead later.
195 */
196 while ( (DWORD)t1.LowPart - (DWORD)t0.LowPart<50) {
197 QueryPerformanceCounter(&t1);
198 }
199
200 ASM_RDTSC;
201 _asm mov stamp0, EAX
202
203 t0.LowPart = t1.LowPart; // Reset Initial Time
204 t0.HighPart = t1.HighPart;
205
206 /*
207 ** Loop until 1000 ticks have passed since last read of hi-res counter.
208 ** This allows for elapsed time for sampling.
209 */
210 while ( (DWORD)t1.LowPart - (DWORD)t0.LowPart < 1000 ) {
211 QueryPerformanceCounter(&t1);
212 }
213
214 ASM_RDTSC;
215 _asm mov stamp1, EAX
216
217
218 cycles = stamp1 - stamp0; // # of cycles passed between reads
219
220 double bigticks = (double)((DWORD)t1.LowPart - (DWORD)t0.LowPart);
221 assert((bigticks * 100000.0) > bigticks);
222 bigticks = bigticks * 100000.0; // Convert ticks to hundred
223 // thousandths of a tick
224 ticks = (DWORD)(bigticks / (double)(count_freq.LowPart / 10));
225 // Hundred Thousandths of a
226 // Ticks / ( 10 ticks/second )
227 // = microseconds (us)
228 total_ticks += ticks;
229 total_cycles += cycles;
230 if ( (ticks % count_freq.LowPart) > (count_freq.LowPart/2) ) ticks++; // Round up if necessary
231
232 freq = cycles/ticks; // MHz = cycles / us
233
234 if ( cycles%ticks > ticks/2 ) freq++; // Round up if necessary
235
236 total = ( freq + freq2 + freq3 ); // Total last three frequency calcs
237
238 } while ( (tries < 3 ) || (tries < 20) && ((abs(3 * freq -total) > 3*TOLERANCE )|| (abs(3 * freq2-total) > 3*TOLERANCE )|| (abs(3 * freq3-total) > 3*TOLERANCE )));
239
240 SetThreadPriority(thread, threadPri);
241 SetPriorityClass(process, processPri);
242
243 /*
244 ** Try one more significant digit.
245 */
246 freq3 = ( total_cycles * 10 ) / total_ticks;
247 freq2 = ( total_cycles * 100 ) / total_ticks;
248
249 if ( freq2 - (freq3 * 10) >= ROUND_THRESHOLD ) freq3++;
250
251 int norm_freq = total_cycles / total_ticks;
252
253 freq = norm_freq * 10;
254 if ( (freq3 - freq) >= ROUND_THRESHOLD ) norm_freq++;
255
256 return (norm_freq);
257
258}
259
260
void const char * value
unsigned long DWORD
Definition bittype.h:57
#define ASM_RDTSC
#define TOLERANCE
Definition mpu.cpp:122
unsigned long Get_CPU_Clock(unsigned long &high)
Definition mpu.cpp:87
int Get_RDTSC_CPU_Speed(void)
Definition mpu.cpp:138
unsigned long Get_CPU_Rate(unsigned long &high)
Definition mpu.cpp:68
#define ROUND_THRESHOLD
Definition mpu.cpp:119
void RDTSC(void)
Definition mpu.cpp:127
unsigned long LowPart
Definition mpu.cpp:47
unsigned long HighPart
Definition mpu.cpp:48
LARGE_INTEGER LargeInt
Definition mpu.cpp:45