From 5d40417d7d5a816f8725d94b303863e0c19908a6 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 16 Dec 2009 06:53:53 +0000 Subject: [PATCH] Added SDL_GetCPUCount() to see how many cores are available. --- configure.in | 2 +- include/SDL_config.h.in | 1 + include/SDL_config_iphoneos.h | 1 + include/SDL_config_macosx.h | 1 + include/SDL_cpuinfo.h | 5 + src/cpuinfo/SDL_cpuinfo.c | 345 ++++++++++++++--------------- src/thread/SDL_systhread.h | 1 + test/automated/platform/platform.c | 1 + test/testplatform.c | 1 + 9 files changed, 175 insertions(+), 183 deletions(-) diff --git a/configure.in b/configure.in index 88693eb02..4cc6b7158 100644 --- a/configure.in +++ b/configure.in @@ -207,7 +207,7 @@ if test x$enable_libc = xyes; then AC_DEFINE(HAVE_MPROTECT) ]), ) - AC_CHECK_FUNCS(malloc calloc realloc free getenv putenv unsetenv qsort abs bcopy memset memcpy memmove strlen strlcpy strlcat strdup _strrev _strupr _strlwr strchr strrchr strstr itoa _ltoa _uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp sscanf snprintf vsnprintf sigaction setjmp nanosleep) + AC_CHECK_FUNCS(malloc calloc realloc free getenv putenv unsetenv qsort abs bcopy memset memcpy memmove strlen strlcpy strlcat strdup _strrev _strupr _strlwr strchr strrchr strstr itoa _ltoa _uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp sscanf snprintf vsnprintf sigaction setjmp nanosleep sysctlbyname) AC_CHECK_LIB(m, pow, [LIBS="$LIBS -lm"; EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lm"]) AC_CHECK_FUNCS(ceil copysign cos cosf fabs floor log pow scalbn sin sinf sqrt) diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index bbad229b8..c4b8a3cfd 100644 --- a/include/SDL_config.h.in +++ b/include/SDL_config.h.in @@ -150,6 +150,7 @@ #undef HAVE_SIGACTION #undef HAVE_SETJMP #undef HAVE_NANOSLEEP +#undef HAVE_SYSCTLBYNAME #undef HAVE_CLOCK_GETTIME #undef HAVE_GETPAGESIZE #undef HAVE_MPROTECT diff --git a/include/SDL_config_iphoneos.h b/include/SDL_config_iphoneos.h index 7b300872a..1be963a49 100644 --- a/include/SDL_config_iphoneos.h +++ b/include/SDL_config_iphoneos.h @@ -106,6 +106,7 @@ typedef unsigned long uintptr_t; #define HAVE_SIGACTION 1 #define HAVE_SETJMP 1 #define HAVE_NANOSLEEP 1 +#define HAVE_SYSCTLBYNAME 1 /* enable iPhone version of Core Audio driver */ #define SDL_AUDIO_DRIVER_COREAUDIOIPHONE 1 diff --git a/include/SDL_config_macosx.h b/include/SDL_config_macosx.h index 120246b3b..984c4e945 100644 --- a/include/SDL_config_macosx.h +++ b/include/SDL_config_macosx.h @@ -105,6 +105,7 @@ #define HAVE_SIGACTION 1 #define HAVE_SETJMP 1 #define HAVE_NANOSLEEP 1 +#define HAVE_SYSCTLBYNAME 1 /* Enable various audio drivers */ #define SDL_AUDIO_DRIVER_COREAUDIO 1 diff --git a/include/SDL_cpuinfo.h b/include/SDL_cpuinfo.h index 545462b84..3e9122fbb 100644 --- a/include/SDL_cpuinfo.h +++ b/include/SDL_cpuinfo.h @@ -39,6 +39,11 @@ extern "C" { /* *INDENT-ON* */ #endif +/** + * This function returns the number of CPU cores available. + */ +extern DECLSPEC int SDLCALL SDL_GetCPUCount(void); + /** * This function returns true if the CPU has the RDTSC instruction. */ diff --git a/src/cpuinfo/SDL_cpuinfo.c b/src/cpuinfo/SDL_cpuinfo.c index 0abfb43fd..27d1da562 100644 --- a/src/cpuinfo/SDL_cpuinfo.c +++ b/src/cpuinfo/SDL_cpuinfo.c @@ -25,6 +25,10 @@ #include "SDL_cpuinfo.h" +#ifdef HAVE_SYSCTLBYNAME +#include +#include +#endif #if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__)) #include /* For AltiVec check */ #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP @@ -32,14 +36,14 @@ #include #endif -#define CPU_HAS_RDTSC 0x00000001 -#define CPU_HAS_MMX 0x00000002 -#define CPU_HAS_MMXEXT 0x00000004 -#define CPU_HAS_3DNOW 0x00000010 +#define CPU_HAS_RDTSC 0x00000001 +#define CPU_HAS_MMX 0x00000002 +#define CPU_HAS_MMXEXT 0x00000004 +#define CPU_HAS_3DNOW 0x00000010 #define CPU_HAS_3DNOWEXT 0x00000020 -#define CPU_HAS_SSE 0x00000040 -#define CPU_HAS_SSE2 0x00000080 -#define CPU_HAS_ALTIVEC 0x00000100 +#define CPU_HAS_SSE 0x00000040 +#define CPU_HAS_SSE2 0x00000080 +#define CPU_HAS_ALTIVEC 0x00000100 #if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ /* This is the brute force way of detecting instruction sets... @@ -59,7 +63,7 @@ CPU_haveCPUID(void) int has_CPUID = 0; /* *INDENT-OFF* */ #if defined(__GNUC__) && defined(i386) - __asm__ ( + __asm__ ( " pushfl # Get original EFLAGS \n" " popl %%eax \n" " movl %%eax,%%ecx \n" @@ -72,14 +76,14 @@ CPU_haveCPUID(void) " jz 1f # Processor=80486 \n" " movl $1,%0 # We have CPUID support \n" "1: \n" - : "=m" (has_CPUID) - : - : "%eax", "%ecx" - ); + : "=m" (has_CPUID) + : + : "%eax", "%ecx" + ); #elif defined(__GNUC__) && defined(__x86_64__) /* Technically, if this is being compiled under __x86_64__ then it has CPUid by definition. But it's nice to be able to prove it. :) */ - __asm__ ( + __asm__ ( " pushfq # Get original EFLAGS \n" " popq %%rax \n" " movq %%rax,%%rcx \n" @@ -92,12 +96,12 @@ CPUid by definition. But it's nice to be able to prove it. :) */ " jz 1f # Processor=80486 \n" " movl $1,%0 # We have CPUID support \n" "1: \n" - : "=m" (has_CPUID) - : - : "%rax", "%rcx" - ); + : "=m" (has_CPUID) + : + : "%rax", "%rcx" + ); #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) - __asm { + __asm { pushfd ; Get original EFLAGS pop eax mov ecx, eax @@ -110,24 +114,24 @@ CPUid by definition. But it's nice to be able to prove it. :) */ jz done ; Processor=80486 mov has_CPUID,1 ; We have CPUID support done: - } + } #elif defined(__sun) && defined(__i386) - __asm ( + __asm ( " pushfl \n" -" popl %eax \n" -" movl %eax,%ecx \n" -" xorl $0x200000,%eax \n" -" pushl %eax \n" -" popfl \n" -" pushfl \n" -" popl %eax \n" -" xorl %ecx,%eax \n" -" jz 1f \n" -" movl $1,-8(%ebp) \n" +" popl %eax \n" +" movl %eax,%ecx \n" +" xorl $0x200000,%eax \n" +" pushl %eax \n" +" popfl \n" +" pushfl \n" +" popl %eax \n" +" xorl %ecx,%eax \n" +" jz 1f \n" +" movl $1,-8(%ebp) \n" "1: \n" - ); + ); #elif defined(__sun) && defined(__amd64) - __asm ( + __asm ( " pushfq \n" " popq %rax \n" " movq %rax,%rcx \n" @@ -140,92 +144,42 @@ CPUid by definition. But it's nice to be able to prove it. :) */ " jz 1f \n" " movl $1,-8(%rbp) \n" "1: \n" - ); + ); #endif /* *INDENT-ON* */ return has_CPUID; } +#if defined(__GNUC__) && (defined(i386) || defined(__x86_64__)) +#define cpuid(func, ax, bx, cx, dx) \ + __asm__ __volatile__ ("cpuid": \ + "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func)) +#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) +#define cpuid(func, ax, bx, cx, dx) \ + asm { \ + mov eax, func \ + cpuid + mov ax, eax \ + mov bx, ebx \ + mov cx, ecx \ + mov dx, edx \ + } +#else +#define cpuid(func, ax, bx, cx, dx) \ + ax = bx = cx = dx = 0 +#endif + static __inline__ int CPU_getCPUIDFeatures(void) { int features = 0; -/* *INDENT-OFF* */ -#if defined(__GNUC__) && defined(i386) - __asm__ ( -" xorl %%eax,%%eax # Set up for CPUID instruction \n" -" pushl %%ebx \n" -" cpuid # Get and save vendor ID \n" -" popl %%ebx \n" -" cmpl $1,%%eax # Make sure 1 is valid input for CPUID\n" -" jl 1f # We dont have the CPUID instruction\n" -" xorl %%eax,%%eax \n" -" incl %%eax \n" -" pushl %%ebx \n" -" cpuid # Get family/model/stepping/features\n" -" popl %%ebx \n" -" movl %%edx,%0 \n" -"1: \n" - : "=m" (features) - : - : "%eax", "%ecx", "%edx" - ); -#elif defined(__GNUC__) && defined(__x86_64__) - __asm__ ( -" xorl %%eax,%%eax # Set up for CPUID instruction \n" -" pushq %%rbx \n" -" cpuid # Get and save vendor ID \n" -" popq %%rbx \n" -" cmpl $1,%%eax # Make sure 1 is valid input for CPUID\n" -" jl 1f # We dont have the CPUID instruction\n" -" xorl %%eax,%%eax \n" -" incl %%eax \n" -" pushq %%rbx \n" -" cpuid # Get family/model/stepping/features\n" -" popq %%rbx \n" -" movl %%edx,%0 \n" -"1: \n" - : "=m" (features) - : - : "%rax", "%rcx", "%rdx" - ); -#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) - __asm { - xor eax, eax ; Set up for CPUID instruction - push ebx - cpuid ; Get and save vendor ID - pop ebx - cmp eax, 1 ; Make sure 1 is valid input for CPUID - jl done ; We dont have the CPUID instruction - xor eax, eax - inc eax - push ebx - cpuid ; Get family/model/stepping/features - pop ebx - mov features, edx -done: - } -#elif defined(__sun) && (defined(__i386) || defined(__amd64)) - __asm( -" xorl %eax,%eax \n" -" pushl %ebx \n" -" cpuid \n" -" popl %ebx \n" -" cmpl $1,%eax \n" -" jl 1f \n" -" xorl %eax,%eax \n" -" incl %eax \n" -" pushl %ebx \n" -" cpuid \n" -" popl %ebx \n" -#ifdef __i386 -" movl %edx,-8(%ebp) \n" -#else -" movl %edx,-8(%rbp) \n" -#endif -"1: \n" -#endif -/* *INDENT-ON* */ + int ax, bx, cx, dx; + + cpuid(0, ax, bx, cx, dx); + if (ax >= 1) { + cpuid(1, ax, bx, cx, dx); + features = dx; + } return features; } @@ -233,79 +187,13 @@ static __inline__ int CPU_getCPUIDFeaturesExt(void) { int features = 0; -/* *INDENT-OFF* */ -#if defined(__GNUC__) && defined(i386) - __asm__ ( -" movl $0x80000000,%%eax # Query for extended functions \n" -" pushl %%ebx \n" -" cpuid # Get extended function limit \n" -" popl %%ebx \n" -" cmpl $0x80000001,%%eax \n" -" jl 1f # Nope, we dont have function 800000001h\n" -" movl $0x80000001,%%eax # Setup extended function 800000001h\n" -" pushl %%ebx \n" -" cpuid # and get the information \n" -" popl %%ebx \n" -" movl %%edx,%0 \n" -"1: \n" - : "=m" (features) - : - : "%eax", "%ecx", "%edx" - ); -#elif defined(__GNUC__) && defined (__x86_64__) - __asm__ ( -" movl $0x80000000,%%eax # Query for extended functions \n" -" pushq %%rbx \n" -" cpuid # Get extended function limit \n" -" popq %%rbx \n" -" cmpl $0x80000001,%%eax \n" -" jl 1f # Nope, we dont have function 800000001h\n" -" movl $0x80000001,%%eax # Setup extended function 800000001h\n" -" pushq %%rbx \n" -" cpuid # and get the information \n" -" popq %%rbx \n" -" movl %%edx,%0 \n" -"1: \n" - : "=m" (features) - : - : "%rax", "%rcx", "%rdx" - ); -#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) - __asm { - mov eax,80000000h ; Query for extended functions - push ebx - cpuid ; Get extended function limit - pop ebx - cmp eax,80000001h - jl done ; Nope, we dont have function 800000001h - mov eax,80000001h ; Setup extended function 800000001h - push ebx - cpuid ; and get the information - pop ebx - mov features,edx -done: - } -#elif defined(__sun) && ( defined(__i386) || defined(__amd64) ) - __asm ( -" movl $0x80000000,%eax \n" -" pushl %ebx \n" -" cpuid \n" -" popl %ebx \n" -" cmpl $0x80000001,%eax \n" -" jl 1f \n" -" movl $0x80000001,%eax \n" -" pushl %ebx \n" -" cpuid \n" -" popl %ebx \n" -#ifdef __i386 -" movl %edx,-8(%ebp) \n" -#else -" movl %edx,-8(%rbp) \n" -#endif -"1: \n" - ); -#endif -/* *INDENT-ON* */ + int ax, bx, cx, dx; + + cpuid(0x80000000, ax, bx, cx, dx); + if (ax >= 0x80000001) { + cpuid(0x80000001, ax, bx, cx, dx); + features = dx; + } return features; } @@ -395,6 +283,97 @@ CPU_haveAltiVec(void) return altivec; } +static int SDL_CPUCount = 0; + +int +SDL_GetCPUCount() +{ + if (!SDL_CPUCount) { +#ifdef HAVE_SYSCTLBYNAME + size_t size = sizeof(SDL_CPUCount); + sysctlbyname("hw.ncpu", &SDL_CPUCount, &size, NULL, 0); +#endif + /* There has to be at least 1, right? :) */ + if (!SDL_CPUCount) { + SDL_CPUCount = 1; + } + } + return SDL_CPUCount; +} + +/* Oh, such a sweet sweet trick, just not very useful. :) */ +const char * +SDL_GetCPUType() +{ + static char SDL_CPUType[48]; + + if (!SDL_CPUType[0]) { + int i = 0; + int ax, bx, cx, dx; + + if (CPU_haveCPUID()) { + cpuid(0x80000000, ax, bx, cx, dx); + if (ax >= 0x80000004) { + cpuid(0x80000002, ax, bx, cx, dx); + SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8; + SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8; + SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8; + SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8; + SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8; + SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8; + SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8; + SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8; + SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8; + SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8; + SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8; + SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8; + SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8; + SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8; + SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8; + SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8; + cpuid(0x80000003, ax, bx, cx, dx); + SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8; + SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8; + SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8; + SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8; + SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8; + SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8; + SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8; + SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8; + SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8; + SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8; + SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8; + SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8; + SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8; + SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8; + SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8; + SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8; + cpuid(0x80000004, ax, bx, cx, dx); + SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8; + SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8; + SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8; + SDL_CPUType[i++] = (char)(ax & 0xff); ax >>= 8; + SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8; + SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8; + SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8; + SDL_CPUType[i++] = (char)(bx & 0xff); bx >>= 8; + SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8; + SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8; + SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8; + SDL_CPUType[i++] = (char)(cx & 0xff); cx >>= 8; + SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8; + SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8; + SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8; + SDL_CPUType[i++] = (char)(dx & 0xff); dx >>= 8; + } + } + if (!SDL_CPUType[0]) { + SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType)); + } + } + return SDL_CPUType; +} + static Uint32 SDL_CPUFeatures = 0xFFFFFFFF; static Uint32 @@ -509,6 +488,8 @@ SDL_HasAltiVec(void) int main() { + printf("CPU count: %d\n", SDL_GetCPUCount()); + printf("CPU name: %s\n", SDL_GetCPUType()); printf("RDTSC: %d\n", SDL_HasRDTSC()); printf("MMX: %d\n", SDL_HasMMX()); printf("MMXExt: %d\n", SDL_HasMMXExt()); diff --git a/src/thread/SDL_systhread.h b/src/thread/SDL_systhread.h index d1d1a6586..f2803dd2d 100644 --- a/src/thread/SDL_systhread.h +++ b/src/thread/SDL_systhread.h @@ -49,4 +49,5 @@ extern void SDL_SYS_SetupThread(void); extern void SDL_SYS_WaitThread(SDL_Thread * thread); #endif /* _SDL_systhread_h */ + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/test/automated/platform/platform.c b/test/automated/platform/platform.c index a41562b79..57c04ce89 100644 --- a/test/automated/platform/platform.c +++ b/test/automated/platform/platform.c @@ -155,6 +155,7 @@ int test_platform (void) "big" #endif ); + SDL_ATprintVerbose( 1, "CPU count: %d\n", SDL_GetCPUCount()); SDL_ATprintVerbose( 1, "Available extensions:\n" ); SDL_ATprintVerbose( 1, " RDTSC %s\n", SDL_HasRDTSC()? "detected" : "not detected" ); SDL_ATprintVerbose( 1, " MMX %s\n", SDL_HasMMX()? "detected" : "not detected" ); diff --git a/test/testplatform.c b/test/testplatform.c index 83cf36d61..89fe2c686 100644 --- a/test/testplatform.c +++ b/test/testplatform.c @@ -134,6 +134,7 @@ int TestCPUInfo(SDL_bool verbose) { if (verbose) { + printf("CPU count: %d\n", SDL_GetCPUCount()); printf("RDTSC %s\n", SDL_HasRDTSC()? "detected" : "not detected"); printf("MMX %s\n", SDL_HasMMX()? "detected" : "not detected"); printf("MMX Ext %s\n", SDL_HasMMXExt()? "detected" : "not detected");