2.6.2
by Mario Limonciello
Update to 1.0rc2 |
1 |
/* small utility to extract CPU information
|
2 |
Used by configure to set CPU optimization levels on some operating
|
|
3 |
systems where /proc/cpuinfo is non-existent or unreliable. */
|
|
4 |
||
5 |
#include <stdio.h> |
|
6 |
#include <sys/time.h> |
|
7 |
#include <stdlib.h> |
|
8 |
#include <string.h> |
|
9 |
#include <unistd.h> |
|
10 |
||
11 |
#if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION <= 3) && (__MINGW32_MINOR_VERSION < 10)
|
|
12 |
#include <sys/timeb.h> |
|
13 |
void gettimeofday(struct timeval* t,void* timezone) { |
|
14 |
struct timeb timebuffer; |
|
15 |
ftime( &timebuffer ); |
|
16 |
t->tv_sec=timebuffer.time; |
|
17 |
t->tv_usec=1000*timebuffer.millitm; |
|
18 |
}
|
|
19 |
#endif
|
|
20 |
#ifdef __MINGW32__
|
|
21 |
#define MISSING_USLEEP
|
|
22 |
#include <windows.h> |
|
23 |
#define sleep(t) Sleep(1000*t);
|
|
24 |
#endif
|
|
25 |
||
26 |
#ifdef __BEOS__
|
|
27 |
#define usleep(t) snooze(t)
|
|
28 |
#endif
|
|
29 |
||
30 |
#ifdef M_UNIX
|
|
31 |
typedef long long int64_t; |
|
32 |
#define MISSING_USLEEP
|
|
33 |
#else
|
|
34 |
#include <inttypes.h> |
|
35 |
#endif
|
|
36 |
||
37 |
#define CPUID_FEATURE_DEF(bit, desc, description) \
|
|
38 |
{ bit, desc }
|
|
39 |
||
40 |
typedef struct cpuid_regs { |
|
41 |
unsigned int eax; |
|
42 |
unsigned int ebx; |
|
43 |
unsigned int ecx; |
|
44 |
unsigned int edx; |
|
45 |
} cpuid_regs_t; |
|
46 |
||
47 |
static cpuid_regs_t |
|
48 |
cpuid(int func) { |
|
49 |
cpuid_regs_t regs; |
|
50 |
#define CPUID ".byte 0x0f, 0xa2; "
|
|
51 |
#ifdef __x86_64__
|
|
52 |
asm("mov %%rbx, %%rsi\n\t" |
|
53 |
#else
|
|
54 |
asm("mov %%ebx, %%esi\n\t" |
|
55 |
#endif
|
|
56 |
CPUID"\n\t" |
|
57 |
#ifdef __x86_64__
|
|
58 |
"xchg %%rsi, %%rbx\n\t" |
|
59 |
#else
|
|
60 |
"xchg %%esi, %%ebx\n\t" |
|
61 |
#endif
|
|
62 |
: "=a" (regs.eax), "=S" (regs.ebx), "=c" (regs.ecx), "=d" (regs.edx) |
|
63 |
: "0" (func)); |
|
64 |
return regs; |
|
65 |
}
|
|
66 |
||
67 |
||
68 |
static int64_t |
|
69 |
rdtsc(void) |
|
70 |
{
|
|
71 |
uint64_t i; |
|
72 |
#define RDTSC ".byte 0x0f, 0x31; "
|
|
73 |
asm volatile (RDTSC : "=A"(i) : ); |
|
74 |
return i; |
|
75 |
}
|
|
76 |
||
77 |
static const char* |
|
78 |
brandname(int i) |
|
79 |
{
|
|
80 |
const static char* brandmap[] = { |
|
81 |
NULL, |
|
82 |
"Intel(R) Celeron(R) processor", |
|
83 |
"Intel(R) Pentium(R) III processor", |
|
84 |
"Intel(R) Pentium(R) III Xeon(tm) processor", |
|
85 |
"Intel(R) Pentium(R) III processor", |
|
86 |
NULL, |
|
87 |
"Mobile Intel(R) Pentium(R) III processor-M", |
|
88 |
"Mobile Intel(R) Celeron(R) processor"
|
|
89 |
};
|
|
90 |
||
91 |
if (i >= sizeof(brandmap)) |
|
92 |
return NULL; |
|
93 |
else
|
|
94 |
return brandmap[i]; |
|
95 |
}
|
|
96 |
||
97 |
static void |
|
98 |
store32(char *d, unsigned int v) |
|
99 |
{
|
|
100 |
d[0] = v & 0xff; |
|
101 |
d[1] = (v >> 8) & 0xff; |
|
102 |
d[2] = (v >> 16) & 0xff; |
|
103 |
d[3] = (v >> 24) & 0xff; |
|
104 |
}
|
|
105 |
||
106 |
||
107 |
int
|
|
108 |
main(int argc, char **argv) |
|
109 |
{
|
|
110 |
cpuid_regs_t regs, regs_ext; |
|
111 |
char idstr[13]; |
|
112 |
unsigned max_cpuid; |
|
113 |
unsigned max_ext_cpuid; |
|
114 |
unsigned int amd_flags; |
|
115 |
unsigned int amd_flags2; |
|
116 |
const char *model_name = NULL; |
|
117 |
int i; |
|
118 |
char processor_name[49]; |
|
119 |
||
120 |
regs = cpuid(0); |
|
121 |
max_cpuid = regs.eax; |
|
122 |
/* printf("%d CPUID function codes\n", max_cpuid+1); */
|
|
123 |
||
124 |
store32(idstr+0, regs.ebx); |
|
125 |
store32(idstr+4, regs.edx); |
|
126 |
store32(idstr+8, regs.ecx); |
|
127 |
idstr[12] = 0; |
|
128 |
printf("vendor_id\t: %s\n", idstr); |
|
129 |
||
130 |
regs_ext = cpuid((1<<31) + 0); |
|
131 |
max_ext_cpuid = regs_ext.eax; |
|
132 |
if (max_ext_cpuid >= (1<<31) + 1) { |
|
133 |
regs_ext = cpuid((1<<31) + 1); |
|
134 |
amd_flags = regs_ext.edx; |
|
135 |
amd_flags2 = regs_ext.ecx; |
|
136 |
||
137 |
if (max_ext_cpuid >= (1<<31) + 4) { |
|
138 |
for (i = 2; i <= 4; i++) { |
|
139 |
regs_ext = cpuid((1<<31) + i); |
|
140 |
store32(processor_name + (i-2)*16, regs_ext.eax); |
|
141 |
store32(processor_name + (i-2)*16 + 4, regs_ext.ebx); |
|
142 |
store32(processor_name + (i-2)*16 + 8, regs_ext.ecx); |
|
143 |
store32(processor_name + (i-2)*16 + 12, regs_ext.edx); |
|
144 |
}
|
|
145 |
processor_name[48] = 0; |
|
146 |
model_name = processor_name; |
|
147 |
while (*model_name == ' ') { |
|
148 |
model_name++; |
|
149 |
}
|
|
150 |
}
|
|
151 |
} else { |
|
152 |
amd_flags = 0; |
|
153 |
amd_flags2 = 0; |
|
154 |
}
|
|
155 |
||
156 |
if (max_cpuid >= 1) { |
|
157 |
static struct { |
|
158 |
int bit; |
|
159 |
char *desc; |
|
160 |
} cap[] = { |
|
161 |
CPUID_FEATURE_DEF(0, "fpu", "Floating-point unit on-chip"), |
|
162 |
CPUID_FEATURE_DEF(1, "vme", "Virtual Mode Enhancements"), |
|
163 |
CPUID_FEATURE_DEF(2, "de", "Debugging Extension"), |
|
164 |
CPUID_FEATURE_DEF(3, "pse", "Page Size Extension"), |
|
165 |
CPUID_FEATURE_DEF(4, "tsc", "Time Stamp Counter"), |
|
166 |
CPUID_FEATURE_DEF(5, "msr", "Pentium Processor MSR"), |
|
167 |
CPUID_FEATURE_DEF(6, "pae", "Physical Address Extension"), |
|
168 |
CPUID_FEATURE_DEF(7, "mce", "Machine Check Exception"), |
|
169 |
CPUID_FEATURE_DEF(8, "cx8", "CMPXCHG8B Instruction Supported"), |
|
170 |
CPUID_FEATURE_DEF(9, "apic", "On-chip APIC Hardware Enabled"), |
|
171 |
CPUID_FEATURE_DEF(11, "sep", "SYSENTER and SYSEXIT"), |
|
172 |
CPUID_FEATURE_DEF(12, "mtrr", "Memory Type Range Registers"), |
|
173 |
CPUID_FEATURE_DEF(13, "pge", "PTE Global Bit"), |
|
174 |
CPUID_FEATURE_DEF(14, "mca", "Machine Check Architecture"), |
|
175 |
CPUID_FEATURE_DEF(15, "cmov", "Conditional Move/Compare Instruction"), |
|
176 |
CPUID_FEATURE_DEF(16, "pat", "Page Attribute Table"), |
|
177 |
CPUID_FEATURE_DEF(17, "pse36", "Page Size Extension 36-bit"), |
|
178 |
CPUID_FEATURE_DEF(18, "pn", "Processor Serial Number"), |
|
179 |
CPUID_FEATURE_DEF(19, "clflush", "CFLUSH instruction"), |
|
180 |
CPUID_FEATURE_DEF(21, "dts", "Debug Store"), |
|
181 |
CPUID_FEATURE_DEF(22, "acpi", "Thermal Monitor and Clock Ctrl"), |
|
182 |
CPUID_FEATURE_DEF(23, "mmx", "MMX Technology"), |
|
183 |
CPUID_FEATURE_DEF(24, "fxsr", "FXSAVE/FXRSTOR"), |
|
184 |
CPUID_FEATURE_DEF(25, "sse", "SSE Extensions"), |
|
185 |
CPUID_FEATURE_DEF(26, "sse2", "SSE2 Extensions"), |
|
186 |
CPUID_FEATURE_DEF(27, "ss", "Self Snoop"), |
|
187 |
CPUID_FEATURE_DEF(28, "ht", "Multi-threading"), |
|
188 |
CPUID_FEATURE_DEF(29, "tm", "Therm. Monitor"), |
|
189 |
CPUID_FEATURE_DEF(30, "ia64", "IA-64 Processor"), |
|
190 |
CPUID_FEATURE_DEF(31, "pbe", "Pend. Brk. EN."), |
|
191 |
{ -1 } |
|
192 |
};
|
|
193 |
static struct { |
|
194 |
int bit; |
|
195 |
char *desc; |
|
196 |
} cap2[] = { |
|
197 |
CPUID_FEATURE_DEF(0, "pni", "SSE3 Extensions"), |
|
198 |
CPUID_FEATURE_DEF(3, "monitor", "MONITOR/MWAIT"), |
|
199 |
CPUID_FEATURE_DEF(4, "ds_cpl", "CPL Qualified Debug Store"), |
|
200 |
CPUID_FEATURE_DEF(5, "vmx", "Virtual Machine Extensions"), |
|
201 |
CPUID_FEATURE_DEF(6, "smx", "Safer Mode Extensions"), |
|
202 |
CPUID_FEATURE_DEF(7, "est", "Enhanced Intel SpeedStep Technology"), |
|
203 |
CPUID_FEATURE_DEF(8, "tm2", "Thermal Monitor 2"), |
|
204 |
CPUID_FEATURE_DEF(9, "ssse3", "Supplemental SSE3"), |
|
205 |
CPUID_FEATURE_DEF(10, "cid", "L1 Context ID"), |
|
206 |
CPUID_FEATURE_DEF(13, "cx16", "CMPXCHG16B Available"), |
|
207 |
CPUID_FEATURE_DEF(14, "xtpr", "xTPR Disable"), |
|
208 |
CPUID_FEATURE_DEF(15, "pdcm", "Perf/Debug Capability MSR"), |
|
209 |
CPUID_FEATURE_DEF(18, "dca", "Direct Cache Access"), |
|
210 |
CPUID_FEATURE_DEF(19, "sse41", "SSE4.1 Extensions"), |
|
211 |
CPUID_FEATURE_DEF(20, "sse42", "SSE4.2 Extensions"), |
|
212 |
CPUID_FEATURE_DEF(23, "popcnt", "Pop Count Instruction"), |
|
213 |
{ -1 } |
|
214 |
};
|
|
215 |
static struct { |
|
216 |
int bit; |
|
217 |
char *desc; |
|
218 |
} cap_amd[] = { |
|
219 |
CPUID_FEATURE_DEF(11, "syscall", "SYSCALL and SYSRET"), |
|
220 |
CPUID_FEATURE_DEF(19, "mp", "MP Capable"), |
|
221 |
CPUID_FEATURE_DEF(20, "nx", "No-Execute Page Protection"), |
|
222 |
CPUID_FEATURE_DEF(22, "mmxext", "MMX Technology (AMD Extensions)"), |
|
223 |
CPUID_FEATURE_DEF(25, "fxsr_opt", "Fast FXSAVE/FXRSTOR"), |
|
224 |
CPUID_FEATURE_DEF(26, "pdpe1gb", "PDP Entry for 1GiB Page"), |
|
225 |
CPUID_FEATURE_DEF(27, "rdtscp", "RDTSCP Instruction"), |
|
226 |
CPUID_FEATURE_DEF(29, "lm", "Long Mode Capable"), |
|
227 |
CPUID_FEATURE_DEF(30, "3dnowext", "3DNow! Extensions"), |
|
228 |
CPUID_FEATURE_DEF(31, "3dnow", "3DNow!"), |
|
229 |
{ -1 } |
|
230 |
};
|
|
231 |
static struct { |
|
232 |
int bit; |
|
233 |
char *desc; |
|
234 |
} cap_amd2[] = { |
|
235 |
CPUID_FEATURE_DEF(0, "lahf_lm", "LAHF/SAHF Supported in 64-bit Mode"), |
|
236 |
CPUID_FEATURE_DEF(1, "cmp_legacy", "Chip Multi-Core"), |
|
237 |
CPUID_FEATURE_DEF(2, "svm", "Secure Virtual Machine"), |
|
238 |
CPUID_FEATURE_DEF(3, "extapic", "Extended APIC Space"), |
|
239 |
CPUID_FEATURE_DEF(4, "cr8legacy", "CR8 Available in Legacy Mode"), |
|
240 |
CPUID_FEATURE_DEF(5, "abm", "Advanced Bit Manipulation"), |
|
241 |
CPUID_FEATURE_DEF(6, "sse4a", "SSE4A Extensions"), |
|
242 |
CPUID_FEATURE_DEF(7, "misalignsse", "Misaligned SSE Mode"), |
|
243 |
CPUID_FEATURE_DEF(8, "3dnowprefetch", "3DNow! Prefetch/PrefetchW"), |
|
244 |
CPUID_FEATURE_DEF(9, "osvw", "OS Visible Workaround"), |
|
245 |
CPUID_FEATURE_DEF(10, "ibs", "Instruction Based Sampling"), |
|
246 |
{ -1 } |
|
247 |
};
|
|
248 |
unsigned int family, model, stepping; |
|
249 |
||
250 |
regs = cpuid(1); |
|
251 |
family = (regs.eax >> 8) & 0xf; |
|
252 |
model = (regs.eax >> 4) & 0xf; |
|
253 |
stepping = regs.eax & 0xf; |
|
254 |
||
255 |
if (family == 0xf) |
|
256 |
family += (regs.eax >> 20) & 0xff; |
|
257 |
if (family == 0xf || family == 6) |
|
258 |
model += ((regs.eax >> 16) & 0xf) << 4; |
|
259 |
||
260 |
printf("cpu family\t: %d\n" |
|
261 |
"model\t\t: %d\n" |
|
262 |
"stepping\t: %d\n" , |
|
263 |
family, |
|
264 |
model, |
|
265 |
stepping); |
|
266 |
||
267 |
if (strstr(idstr, "Intel") && !model_name) { |
|
268 |
if (family == 6 && model == 0xb && stepping == 1) |
|
269 |
model_name = "Intel (R) Celeron (R) processor"; |
|
270 |
else
|
|
271 |
model_name = brandname(regs.ebx & 0xf); |
|
272 |
}
|
|
273 |
||
274 |
printf("flags\t\t:"); |
|
275 |
for (i = 0; cap[i].bit >= 0; i++) { |
|
276 |
if (regs.edx & (1 << cap[i].bit)) { |
|
277 |
printf(" %s", cap[i].desc); |
|
278 |
}
|
|
279 |
}
|
|
280 |
for (i = 0; cap2[i].bit >= 0; i++) { |
|
281 |
if (regs.ecx & (1 << cap2[i].bit)) { |
|
282 |
printf(" %s", cap2[i].desc); |
|
283 |
}
|
|
284 |
}
|
|
285 |
/* k6_mtrr is supported by some AMD K6-2/K6-III CPUs but
|
|
286 |
it is not indicated by a CPUID feature bit, so we
|
|
287 |
have to check the family, model and stepping instead. */
|
|
288 |
if (strstr(idstr, "AMD") && |
|
289 |
family == 5 && |
|
290 |
(model >= 9 || model == 8 && stepping >= 8)) |
|
291 |
printf(" %s", "k6_mtrr"); |
|
292 |
/* similar for cyrix_arr. */
|
|
293 |
if (strstr(idstr, "Cyrix") && |
|
294 |
(family == 5 && model < 4 || family == 6)) |
|
295 |
printf(" %s", "cyrix_arr"); |
|
296 |
/* as well as centaur_mcr. */
|
|
297 |
if (strstr(idstr, "Centaur") && |
|
298 |
family == 5) |
|
299 |
printf(" %s", "centaur_mcr"); |
|
300 |
||
301 |
for (i = 0; cap_amd[i].bit >= 0; i++) { |
|
302 |
if (amd_flags & (1 << cap_amd[i].bit)) { |
|
303 |
printf(" %s", cap_amd[i].desc); |
|
304 |
}
|
|
305 |
}
|
|
306 |
for (i = 0; cap_amd2[i].bit >= 0; i++) { |
|
307 |
if (amd_flags2 & (1 << cap_amd2[i].bit)) { |
|
308 |
printf(" %s", cap_amd2[i].desc); |
|
309 |
}
|
|
310 |
}
|
|
311 |
printf("\n"); |
|
312 |
||
313 |
if (regs.edx & (1 << 4)) { |
|
314 |
int64_t tsc_start, tsc_end; |
|
315 |
struct timeval tv_start, tv_end; |
|
316 |
int usec_delay; |
|
317 |
||
318 |
tsc_start = rdtsc(); |
|
319 |
gettimeofday(&tv_start, NULL); |
|
320 |
#ifdef MISSING_USLEEP
|
|
321 |
sleep(1); |
|
322 |
#else
|
|
323 |
usleep(100000); |
|
324 |
#endif
|
|
325 |
tsc_end = rdtsc(); |
|
326 |
gettimeofday(&tv_end, NULL); |
|
327 |
||
328 |
usec_delay = 1000000 * (tv_end.tv_sec - tv_start.tv_sec) |
|
329 |
+ (tv_end.tv_usec - tv_start.tv_usec); |
|
330 |
||
331 |
printf("cpu MHz\t\t: %.3f\n", |
|
332 |
(double)(tsc_end-tsc_start) / usec_delay); |
|
333 |
}
|
|
334 |
}
|
|
335 |
||
336 |
printf("model name\t: "); |
|
337 |
if (model_name) |
|
338 |
printf("%s\n", model_name); |
|
339 |
else
|
|
340 |
printf("Unknown %s CPU\n", idstr); |
|
341 |
}
|