comparison src/cpuinfo/SDL_cpuinfo.c @ 3579:3427271a2d75

Added SDL_GetCPUCount() to see how many cores are available.
author Sam Lantinga <slouken@libsdl.org>
date Wed, 16 Dec 2009 06:53:53 +0000
parents d94e331e85fa
children 951dd6a5d1a2
comparison
equal deleted inserted replaced
3578:0d1b16ee0bca 3579:3427271a2d75
23 23
24 /* CPU feature detection for SDL */ 24 /* CPU feature detection for SDL */
25 25
26 #include "SDL_cpuinfo.h" 26 #include "SDL_cpuinfo.h"
27 27
28 #ifdef HAVE_SYSCTLBYNAME
29 #include <sys/types.h>
30 #include <sys/sysctl.h>
31 #endif
28 #if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__)) 32 #if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))
29 #include <sys/sysctl.h> /* For AltiVec check */ 33 #include <sys/sysctl.h> /* For AltiVec check */
30 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP 34 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
31 #include <signal.h> 35 #include <signal.h>
32 #include <setjmp.h> 36 #include <setjmp.h>
33 #endif 37 #endif
34 38
35 #define CPU_HAS_RDTSC 0x00000001 39 #define CPU_HAS_RDTSC 0x00000001
36 #define CPU_HAS_MMX 0x00000002 40 #define CPU_HAS_MMX 0x00000002
37 #define CPU_HAS_MMXEXT 0x00000004 41 #define CPU_HAS_MMXEXT 0x00000004
38 #define CPU_HAS_3DNOW 0x00000010 42 #define CPU_HAS_3DNOW 0x00000010
39 #define CPU_HAS_3DNOWEXT 0x00000020 43 #define CPU_HAS_3DNOWEXT 0x00000020
40 #define CPU_HAS_SSE 0x00000040 44 #define CPU_HAS_SSE 0x00000040
41 #define CPU_HAS_SSE2 0x00000080 45 #define CPU_HAS_SSE2 0x00000080
42 #define CPU_HAS_ALTIVEC 0x00000100 46 #define CPU_HAS_ALTIVEC 0x00000100
43 47
44 #if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ 48 #if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__
45 /* This is the brute force way of detecting instruction sets... 49 /* This is the brute force way of detecting instruction sets...
46 the idea is borrowed from the libmpeg2 library - thanks! 50 the idea is borrowed from the libmpeg2 library - thanks!
47 */ 51 */
57 CPU_haveCPUID(void) 61 CPU_haveCPUID(void)
58 { 62 {
59 int has_CPUID = 0; 63 int has_CPUID = 0;
60 /* *INDENT-OFF* */ 64 /* *INDENT-OFF* */
61 #if defined(__GNUC__) && defined(i386) 65 #if defined(__GNUC__) && defined(i386)
62 __asm__ ( 66 __asm__ (
63 " pushfl # Get original EFLAGS \n" 67 " pushfl # Get original EFLAGS \n"
64 " popl %%eax \n" 68 " popl %%eax \n"
65 " movl %%eax,%%ecx \n" 69 " movl %%eax,%%ecx \n"
66 " xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n" 70 " xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
67 " pushl %%eax # Save new EFLAGS value on stack \n" 71 " pushl %%eax # Save new EFLAGS value on stack \n"
70 " popl %%eax # Store new EFLAGS in EAX \n" 74 " popl %%eax # Store new EFLAGS in EAX \n"
71 " xorl %%ecx,%%eax # Can not toggle ID bit, \n" 75 " xorl %%ecx,%%eax # Can not toggle ID bit, \n"
72 " jz 1f # Processor=80486 \n" 76 " jz 1f # Processor=80486 \n"
73 " movl $1,%0 # We have CPUID support \n" 77 " movl $1,%0 # We have CPUID support \n"
74 "1: \n" 78 "1: \n"
75 : "=m" (has_CPUID) 79 : "=m" (has_CPUID)
76 : 80 :
77 : "%eax", "%ecx" 81 : "%eax", "%ecx"
78 ); 82 );
79 #elif defined(__GNUC__) && defined(__x86_64__) 83 #elif defined(__GNUC__) && defined(__x86_64__)
80 /* Technically, if this is being compiled under __x86_64__ then it has 84 /* Technically, if this is being compiled under __x86_64__ then it has
81 CPUid by definition. But it's nice to be able to prove it. :) */ 85 CPUid by definition. But it's nice to be able to prove it. :) */
82 __asm__ ( 86 __asm__ (
83 " pushfq # Get original EFLAGS \n" 87 " pushfq # Get original EFLAGS \n"
84 " popq %%rax \n" 88 " popq %%rax \n"
85 " movq %%rax,%%rcx \n" 89 " movq %%rax,%%rcx \n"
86 " xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n" 90 " xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
87 " pushq %%rax # Save new EFLAGS value on stack \n" 91 " pushq %%rax # Save new EFLAGS value on stack \n"
90 " popq %%rax # Store new EFLAGS in EAX \n" 94 " popq %%rax # Store new EFLAGS in EAX \n"
91 " xorl %%ecx,%%eax # Can not toggle ID bit, \n" 95 " xorl %%ecx,%%eax # Can not toggle ID bit, \n"
92 " jz 1f # Processor=80486 \n" 96 " jz 1f # Processor=80486 \n"
93 " movl $1,%0 # We have CPUID support \n" 97 " movl $1,%0 # We have CPUID support \n"
94 "1: \n" 98 "1: \n"
95 : "=m" (has_CPUID) 99 : "=m" (has_CPUID)
96 : 100 :
97 : "%rax", "%rcx" 101 : "%rax", "%rcx"
98 ); 102 );
99 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) 103 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
100 __asm { 104 __asm {
101 pushfd ; Get original EFLAGS 105 pushfd ; Get original EFLAGS
102 pop eax 106 pop eax
103 mov ecx, eax 107 mov ecx, eax
104 xor eax, 200000h ; Flip ID bit in EFLAGS 108 xor eax, 200000h ; Flip ID bit in EFLAGS
105 push eax ; Save new EFLAGS value on stack 109 push eax ; Save new EFLAGS value on stack
108 pop eax ; Store new EFLAGS in EAX 112 pop eax ; Store new EFLAGS in EAX
109 xor eax, ecx ; Can not toggle ID bit, 113 xor eax, ecx ; Can not toggle ID bit,
110 jz done ; Processor=80486 114 jz done ; Processor=80486
111 mov has_CPUID,1 ; We have CPUID support 115 mov has_CPUID,1 ; We have CPUID support
112 done: 116 done:
113 } 117 }
114 #elif defined(__sun) && defined(__i386) 118 #elif defined(__sun) && defined(__i386)
115 __asm ( 119 __asm (
116 " pushfl \n" 120 " pushfl \n"
117 " popl %eax \n" 121 " popl %eax \n"
118 " movl %eax,%ecx \n" 122 " movl %eax,%ecx \n"
119 " xorl $0x200000,%eax \n" 123 " xorl $0x200000,%eax \n"
120 " pushl %eax \n" 124 " pushl %eax \n"
121 " popfl \n" 125 " popfl \n"
122 " pushfl \n" 126 " pushfl \n"
123 " popl %eax \n" 127 " popl %eax \n"
124 " xorl %ecx,%eax \n" 128 " xorl %ecx,%eax \n"
125 " jz 1f \n" 129 " jz 1f \n"
126 " movl $1,-8(%ebp) \n" 130 " movl $1,-8(%ebp) \n"
127 "1: \n" 131 "1: \n"
128 ); 132 );
129 #elif defined(__sun) && defined(__amd64) 133 #elif defined(__sun) && defined(__amd64)
130 __asm ( 134 __asm (
131 " pushfq \n" 135 " pushfq \n"
132 " popq %rax \n" 136 " popq %rax \n"
133 " movq %rax,%rcx \n" 137 " movq %rax,%rcx \n"
134 " xorl $0x200000,%eax \n" 138 " xorl $0x200000,%eax \n"
135 " pushq %rax \n" 139 " pushq %rax \n"
138 " popq %rax \n" 142 " popq %rax \n"
139 " xorl %ecx,%eax \n" 143 " xorl %ecx,%eax \n"
140 " jz 1f \n" 144 " jz 1f \n"
141 " movl $1,-8(%rbp) \n" 145 " movl $1,-8(%rbp) \n"
142 "1: \n" 146 "1: \n"
143 ); 147 );
144 #endif 148 #endif
145 /* *INDENT-ON* */ 149 /* *INDENT-ON* */
146 return has_CPUID; 150 return has_CPUID;
147 } 151 }
148 152
153 #if defined(__GNUC__) && (defined(i386) || defined(__x86_64__))
154 #define cpuid(func, ax, bx, cx, dx) \
155 __asm__ __volatile__ ("cpuid": \
156 "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func))
157 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
158 #define cpuid(func, ax, bx, cx, dx) \
159 asm { \
160 mov eax, func \
161 cpuid
162 mov ax, eax \
163 mov bx, ebx \
164 mov cx, ecx \
165 mov dx, edx \
166 }
167 #else
168 #define cpuid(func, ax, bx, cx, dx) \
169 ax = bx = cx = dx = 0
170 #endif
171
149 static __inline__ int 172 static __inline__ int
150 CPU_getCPUIDFeatures(void) 173 CPU_getCPUIDFeatures(void)
151 { 174 {
152 int features = 0; 175 int features = 0;
153 /* *INDENT-OFF* */ 176 int ax, bx, cx, dx;
154 #if defined(__GNUC__) && defined(i386) 177
155 __asm__ ( 178 cpuid(0, ax, bx, cx, dx);
156 " xorl %%eax,%%eax # Set up for CPUID instruction \n" 179 if (ax >= 1) {
157 " pushl %%ebx \n" 180 cpuid(1, ax, bx, cx, dx);
158 " cpuid # Get and save vendor ID \n" 181 features = dx;
159 " popl %%ebx \n" 182 }
160 " cmpl $1,%%eax # Make sure 1 is valid input for CPUID\n"
161 " jl 1f # We dont have the CPUID instruction\n"
162 " xorl %%eax,%%eax \n"
163 " incl %%eax \n"
164 " pushl %%ebx \n"
165 " cpuid # Get family/model/stepping/features\n"
166 " popl %%ebx \n"
167 " movl %%edx,%0 \n"
168 "1: \n"
169 : "=m" (features)
170 :
171 : "%eax", "%ecx", "%edx"
172 );
173 #elif defined(__GNUC__) && defined(__x86_64__)
174 __asm__ (
175 " xorl %%eax,%%eax # Set up for CPUID instruction \n"
176 " pushq %%rbx \n"
177 " cpuid # Get and save vendor ID \n"
178 " popq %%rbx \n"
179 " cmpl $1,%%eax # Make sure 1 is valid input for CPUID\n"
180 " jl 1f # We dont have the CPUID instruction\n"
181 " xorl %%eax,%%eax \n"
182 " incl %%eax \n"
183 " pushq %%rbx \n"
184 " cpuid # Get family/model/stepping/features\n"
185 " popq %%rbx \n"
186 " movl %%edx,%0 \n"
187 "1: \n"
188 : "=m" (features)
189 :
190 : "%rax", "%rcx", "%rdx"
191 );
192 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
193 __asm {
194 xor eax, eax ; Set up for CPUID instruction
195 push ebx
196 cpuid ; Get and save vendor ID
197 pop ebx
198 cmp eax, 1 ; Make sure 1 is valid input for CPUID
199 jl done ; We dont have the CPUID instruction
200 xor eax, eax
201 inc eax
202 push ebx
203 cpuid ; Get family/model/stepping/features
204 pop ebx
205 mov features, edx
206 done:
207 }
208 #elif defined(__sun) && (defined(__i386) || defined(__amd64))
209 __asm(
210 " xorl %eax,%eax \n"
211 " pushl %ebx \n"
212 " cpuid \n"
213 " popl %ebx \n"
214 " cmpl $1,%eax \n"
215 " jl 1f \n"
216 " xorl %eax,%eax \n"
217 " incl %eax \n"
218 " pushl %ebx \n"
219 " cpuid \n"
220 " popl %ebx \n"
221 #ifdef __i386
222 " movl %edx,-8(%ebp) \n"
223 #else
224 " movl %edx,-8(%rbp) \n"
225 #endif
226 "1: \n"
227 #endif
228 /* *INDENT-ON* */
229 return features; 183 return features;
230 } 184 }
231 185
232 static __inline__ int 186 static __inline__ int
233 CPU_getCPUIDFeaturesExt(void) 187 CPU_getCPUIDFeaturesExt(void)
234 { 188 {
235 int features = 0; 189 int features = 0;
236 /* *INDENT-OFF* */ 190 int ax, bx, cx, dx;
237 #if defined(__GNUC__) && defined(i386) 191
238 __asm__ ( 192 cpuid(0x80000000, ax, bx, cx, dx);
239 " movl $0x80000000,%%eax # Query for extended functions \n" 193 if (ax >= 0x80000001) {
240 " pushl %%ebx \n" 194 cpuid(0x80000001, ax, bx, cx, dx);
241 " cpuid # Get extended function limit \n" 195 features = dx;
242 " popl %%ebx \n" 196 }
243 " cmpl $0x80000001,%%eax \n"
244 " jl 1f # Nope, we dont have function 800000001h\n"
245 " movl $0x80000001,%%eax # Setup extended function 800000001h\n"
246 " pushl %%ebx \n"
247 " cpuid # and get the information \n"
248 " popl %%ebx \n"
249 " movl %%edx,%0 \n"
250 "1: \n"
251 : "=m" (features)
252 :
253 : "%eax", "%ecx", "%edx"
254 );
255 #elif defined(__GNUC__) && defined (__x86_64__)
256 __asm__ (
257 " movl $0x80000000,%%eax # Query for extended functions \n"
258 " pushq %%rbx \n"
259 " cpuid # Get extended function limit \n"
260 " popq %%rbx \n"
261 " cmpl $0x80000001,%%eax \n"
262 " jl 1f # Nope, we dont have function 800000001h\n"
263 " movl $0x80000001,%%eax # Setup extended function 800000001h\n"
264 " pushq %%rbx \n"
265 " cpuid # and get the information \n"
266 " popq %%rbx \n"
267 " movl %%edx,%0 \n"
268 "1: \n"
269 : "=m" (features)
270 :
271 : "%rax", "%rcx", "%rdx"
272 );
273 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
274 __asm {
275 mov eax,80000000h ; Query for extended functions
276 push ebx
277 cpuid ; Get extended function limit
278 pop ebx
279 cmp eax,80000001h
280 jl done ; Nope, we dont have function 800000001h
281 mov eax,80000001h ; Setup extended function 800000001h
282 push ebx
283 cpuid ; and get the information
284 pop ebx
285 mov features,edx
286 done:
287 }
288 #elif defined(__sun) && ( defined(__i386) || defined(__amd64) )
289 __asm (
290 " movl $0x80000000,%eax \n"
291 " pushl %ebx \n"
292 " cpuid \n"
293 " popl %ebx \n"
294 " cmpl $0x80000001,%eax \n"
295 " jl 1f \n"
296 " movl $0x80000001,%eax \n"
297 " pushl %ebx \n"
298 " cpuid \n"
299 " popl %ebx \n"
300 #ifdef __i386
301 " movl %edx,-8(%ebp) \n"
302 #else
303 " movl %edx,-8(%rbp) \n"
304 #endif
305 "1: \n"
306 );
307 #endif
308 /* *INDENT-ON* */
309 return features; 197 return features;
310 } 198 }
311 199
312 static __inline__ int 200 static __inline__ int
313 CPU_haveRDTSC(void) 201 CPU_haveRDTSC(void)
393 signal(SIGILL, handler); 281 signal(SIGILL, handler);
394 #endif 282 #endif
395 return altivec; 283 return altivec;
396 } 284 }
397 285
286 static int SDL_CPUCount = 0;
287
288 int
289 SDL_GetCPUCount()
290 {
291 if (!SDL_CPUCount) {
292 #ifdef HAVE_SYSCTLBYNAME
293 size_t size = sizeof(SDL_CPUCount);
294 sysctlbyname("hw.ncpu", &SDL_CPUCount, &size, NULL, 0);
295 #endif
296 /* There has to be at least 1, right? :) */
297 if (!SDL_CPUCount) {
298 SDL_CPUCount = 1;
299 }
300 }
301 return SDL_CPUCount;
302 }
303
304 /* Oh, such a sweet sweet trick, just not very useful. :) */
305 const char *
306 SDL_GetCPUType()
307 {
308 static char SDL_CPUType[48];
309
310 if (!SDL_CPUType[0]) {
311 int i = 0;
312 int ax, bx, cx, dx;
313
314 if (CPU_haveCPUID()) {
315 cpuid(0x80000000, ax, bx, cx, dx);
316 if (ax >= 0x80000004) {
317 cpuid(0x80000002, ax, bx, cx, dx);
318 SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8;
319 SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8;
320 SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8;
321 SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8;
322 SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8;
323 SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8;
324 SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8;
325 SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8;
326 SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8;
327 SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8;
328 SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8;
329 SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8;
330 SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8;
331 SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8;
332 SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8;
333 SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8;
334 cpuid(0x80000003, ax, bx, cx, dx);
335 SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8;
336 SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8;
337 SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8;
338 SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8;
339 SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8;
340 SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8;
341 SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8;
342 SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8;
343 SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8;
344 SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8;
345 SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8;
346 SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8;
347 SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8;
348 SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8;
349 SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8;
350 SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8;
351 cpuid(0x80000004, ax, bx, cx, dx);
352 SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8;
353 SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8;
354 SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8;
355 SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8;
356 SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8;
357 SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8;
358 SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8;
359 SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8;
360 SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8;
361 SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8;
362 SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8;
363 SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8;
364 SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8;
365 SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8;
366 SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8;
367 SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8;
368 }
369 }
370 if (!SDL_CPUType[0]) {
371 SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
372 }
373 }
374 return SDL_CPUType;
375 }
376
398 static Uint32 SDL_CPUFeatures = 0xFFFFFFFF; 377 static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
399 378
400 static Uint32 379 static Uint32
401 SDL_GetCPUFeatures(void) 380 SDL_GetCPUFeatures(void)
402 { 381 {
507 #include <stdio.h> 486 #include <stdio.h>
508 487
509 int 488 int
510 main() 489 main()
511 { 490 {
491 printf("CPU count: %d\n", SDL_GetCPUCount());
492 printf("CPU name: %s\n", SDL_GetCPUType());
512 printf("RDTSC: %d\n", SDL_HasRDTSC()); 493 printf("RDTSC: %d\n", SDL_HasRDTSC());
513 printf("MMX: %d\n", SDL_HasMMX()); 494 printf("MMX: %d\n", SDL_HasMMX());
514 printf("MMXExt: %d\n", SDL_HasMMXExt()); 495 printf("MMXExt: %d\n", SDL_HasMMXExt());
515 printf("3DNow: %d\n", SDL_Has3DNow()); 496 printf("3DNow: %d\n", SDL_Has3DNow());
516 printf("3DNowExt: %d\n", SDL_Has3DNowExt()); 497 printf("3DNowExt: %d\n", SDL_Has3DNowExt());