The _SC_PHYS_PAGES method of calculating RAM works on Linux.
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
21 #include "SDL_config.h"
23 /* CPU feature detection for SDL */
25 #include "SDL_cpuinfo.h"
30 #ifdef HAVE_SYSCTLBYNAME
31 #include <sys/types.h>
32 #include <sys/sysctl.h>
34 #if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))
35 #include <sys/sysctl.h> /* For AltiVec check */
36 #elif defined(__OpenBSD__) && defined(__powerpc__)
37 #include <sys/param.h>
38 #include <sys/sysctl.h> /* For AltiVec check */
39 #include <machine/cpu.h>
40 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
45 #include "../core/windows/SDL_windows.h"
48 #define CPU_HAS_RDTSC 0x00000001
49 #define CPU_HAS_ALTIVEC 0x00000002
50 #define CPU_HAS_MMX 0x00000004
51 #define CPU_HAS_3DNOW 0x00000008
52 #define CPU_HAS_SSE 0x00000010
53 #define CPU_HAS_SSE2 0x00000020
54 #define CPU_HAS_SSE3 0x00000040
55 #define CPU_HAS_SSE41 0x00000100
56 #define CPU_HAS_SSE42 0x00000200
58 #if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ && !__OpenBSD__
59 /* This is the brute force way of detecting instruction sets...
60 the idea is borrowed from the libmpeg2 library - thanks!
62 static jmp_buf jmpbuf;
64 illegal_instruction(int sig)
68 #endif /* HAVE_SETJMP */
75 #if defined(__GNUC__) && defined(i386)
77 " pushfl # Get original EFLAGS \n"
79 " movl %%eax,%%ecx \n"
80 " xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
81 " pushl %%eax # Save new EFLAGS value on stack \n"
82 " popfl # Replace current EFLAGS value \n"
83 " pushfl # Get new EFLAGS \n"
84 " popl %%eax # Store new EFLAGS in EAX \n"
85 " xorl %%ecx,%%eax # Can not toggle ID bit, \n"
86 " jz 1f # Processor=80486 \n"
87 " movl $1,%0 # We have CPUID support \n"
93 #elif defined(__GNUC__) && defined(__x86_64__)
94 /* Technically, if this is being compiled under __x86_64__ then it has
95 CPUid by definition. But it's nice to be able to prove it. :) */
97 " pushfq # Get original EFLAGS \n"
99 " movq %%rax,%%rcx \n"
100 " xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
101 " pushq %%rax # Save new EFLAGS value on stack \n"
102 " popfq # Replace current EFLAGS value \n"
103 " pushfq # Get new EFLAGS \n"
104 " popq %%rax # Store new EFLAGS in EAX \n"
105 " xorl %%ecx,%%eax # Can not toggle ID bit, \n"
106 " jz 1f # Processor=80486 \n"
107 " movl $1,%0 # We have CPUID support \n"
113 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
115 pushfd ; Get original EFLAGS
118 xor eax, 200000h ; Flip ID bit in EFLAGS
119 push eax ; Save new EFLAGS value on stack
120 popfd ; Replace current EFLAGS value
121 pushfd ; Get new EFLAGS
122 pop eax ; Store new EFLAGS in EAX
123 xor eax, ecx ; Can not toggle ID bit,
124 jz done ; Processor=80486
125 mov has_CPUID,1 ; We have CPUID support
128 #elif defined(__sun) && defined(__i386)
133 " xorl $0x200000,%eax \n"
140 " movl $1,-8(%ebp) \n"
143 #elif defined(__sun) && defined(__amd64)
148 " xorl $0x200000,%eax \n"
155 " movl $1,-8(%rbp) \n"
163 #if defined(__GNUC__) && defined(i386)
164 #define cpuid(func, a, b, c, d) \
165 __asm__ __volatile__ ( \
168 " movl %%ebx, %%esi \n" \
170 "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
171 #elif defined(__GNUC__) && defined(__x86_64__)
172 #define cpuid(func, a, b, c, d) \
173 __asm__ __volatile__ ( \
176 " movq %%rbx, %%rsi \n" \
178 "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
179 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
180 #define cpuid(func, a, b, c, d) \
182 __asm mov eax, func \
190 #define cpuid(func, a, b, c, d) \
194 static __inline__ int
195 CPU_getCPUIDFeatures(void)
200 cpuid(0, a, b, c, d);
202 cpuid(1, a, b, c, d);
208 static __inline__ int
211 if (CPU_haveCPUID()) {
212 return (CPU_getCPUIDFeatures() & 0x00000010);
217 static __inline__ int
218 CPU_haveAltiVec(void)
220 volatile int altivec = 0;
221 #if (defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))) || (defined(__OpenBSD__) && defined(__powerpc__))
223 int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
225 int selectors[2] = { CTL_HW, HW_VECTORUNIT };
227 int hasVectorUnit = 0;
228 size_t length = sizeof(hasVectorUnit);
229 int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
231 altivec = (hasVectorUnit != 0);
232 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
233 void (*handler) (int sig);
234 handler = signal(SIGILL, illegal_instruction);
235 if (setjmp(jmpbuf) == 0) {
236 asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0"::"r" (-1));
239 signal(SIGILL, handler);
244 static __inline__ int
247 if (CPU_haveCPUID()) {
248 return (CPU_getCPUIDFeatures() & 0x00800000);
253 static __inline__ int
256 if (CPU_haveCPUID()) {
259 cpuid(0x80000000, a, b, c, d);
260 if (a >= 0x80000001) {
261 cpuid(0x80000001, a, b, c, d);
262 return (d & 0x80000000);
268 static __inline__ int
271 if (CPU_haveCPUID()) {
272 return (CPU_getCPUIDFeatures() & 0x02000000);
277 static __inline__ int
280 if (CPU_haveCPUID()) {
281 return (CPU_getCPUIDFeatures() & 0x04000000);
286 static __inline__ int
289 if (CPU_haveCPUID()) {
292 cpuid(0, a, b, c, d);
294 cpuid(1, a, b, c, d);
295 return (c & 0x00000001);
301 static __inline__ int
304 if (CPU_haveCPUID()) {
307 cpuid(1, a, b, c, d);
309 cpuid(1, a, b, c, d);
310 return (c & 0x00080000);
316 static __inline__ int
319 if (CPU_haveCPUID()) {
322 cpuid(1, a, b, c, d);
324 cpuid(1, a, b, c, d);
325 return (c & 0x00100000);
331 static int SDL_CPUCount = 0;
334 SDL_GetCPUCount(void)
337 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
338 if (SDL_CPUCount <= 0) {
339 SDL_CPUCount = (int)sysconf(_SC_NPROCESSORS_ONLN);
342 #ifdef HAVE_SYSCTLBYNAME
343 if (SDL_CPUCount <= 0) {
344 size_t size = sizeof(SDL_CPUCount);
345 sysctlbyname("hw.ncpu", &SDL_CPUCount, &size, NULL, 0);
349 if (SDL_CPUCount <= 0) {
351 GetSystemInfo(&info);
352 SDL_CPUCount = info.dwNumberOfProcessors;
355 /* There has to be at least 1, right? :) */
356 if (SDL_CPUCount <= 0) {
363 /* Oh, such a sweet sweet trick, just not very useful. :) */
367 static char SDL_CPUType[13];
369 if (!SDL_CPUType[0]) {
373 if (CPU_haveCPUID()) {
374 cpuid(0x00000000, a, b, c, d);
375 SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
376 SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
377 SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
378 SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
379 SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
380 SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
381 SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
382 SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
383 SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
384 SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
385 SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
386 SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
388 if (!SDL_CPUType[0]) {
389 SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
396 #ifdef TEST_MAIN /* !!! FIXME: only used for test at the moment. */
400 static char SDL_CPUName[48];
402 if (!SDL_CPUName[0]) {
406 if (CPU_haveCPUID()) {
407 cpuid(0x80000000, a, b, c, d);
408 if (a >= 0x80000004) {
409 cpuid(0x80000002, a, b, c, d);
410 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
411 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
412 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
413 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
414 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
415 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
416 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
417 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
418 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
419 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
420 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
421 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
422 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
423 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
424 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
425 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
426 cpuid(0x80000003, a, b, c, d);
427 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
428 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
429 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
430 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
431 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
432 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
433 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
434 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
435 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
436 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
437 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
438 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
439 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
440 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
441 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
442 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
443 cpuid(0x80000004, a, b, c, d);
444 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
445 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
446 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
447 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
448 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
449 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
450 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
451 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
452 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
453 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
454 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
455 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
456 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
457 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
458 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
459 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
462 if (!SDL_CPUName[0]) {
463 SDL_strlcpy(SDL_CPUName, "Unknown", sizeof(SDL_CPUName));
471 SDL_GetCPUCacheLineSize(void)
473 const char *cpuType = SDL_GetCPUType();
475 if (SDL_strcmp(cpuType, "GenuineIntel") == 0) {
478 cpuid(0x00000001, a, b, c, d);
479 return (((b >> 8) & 0xff) * 8);
480 } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) {
483 cpuid(0x80000005, a, b, c, d);
486 /* Just make a guess here... */
487 return SDL_CACHELINE_SIZE;
491 static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
494 SDL_GetCPUFeatures(void)
496 if (SDL_CPUFeatures == 0xFFFFFFFF) {
498 if (CPU_haveRDTSC()) {
499 SDL_CPUFeatures |= CPU_HAS_RDTSC;
501 if (CPU_haveAltiVec()) {
502 SDL_CPUFeatures |= CPU_HAS_ALTIVEC;
505 SDL_CPUFeatures |= CPU_HAS_MMX;
507 if (CPU_have3DNow()) {
508 SDL_CPUFeatures |= CPU_HAS_3DNOW;
511 SDL_CPUFeatures |= CPU_HAS_SSE;
513 if (CPU_haveSSE2()) {
514 SDL_CPUFeatures |= CPU_HAS_SSE2;
516 if (CPU_haveSSE3()) {
517 SDL_CPUFeatures |= CPU_HAS_SSE3;
519 if (CPU_haveSSE41()) {
520 SDL_CPUFeatures |= CPU_HAS_SSE41;
522 if (CPU_haveSSE42()) {
523 SDL_CPUFeatures |= CPU_HAS_SSE42;
526 return SDL_CPUFeatures;
532 if (SDL_GetCPUFeatures() & CPU_HAS_RDTSC) {
541 if (SDL_GetCPUFeatures() & CPU_HAS_ALTIVEC) {
550 if (SDL_GetCPUFeatures() & CPU_HAS_MMX) {
559 if (SDL_GetCPUFeatures() & CPU_HAS_3DNOW) {
568 if (SDL_GetCPUFeatures() & CPU_HAS_SSE) {
577 if (SDL_GetCPUFeatures() & CPU_HAS_SSE2) {
586 if (SDL_GetCPUFeatures() & CPU_HAS_SSE3) {
595 if (SDL_GetCPUFeatures() & CPU_HAS_SSE41) {
604 if (SDL_GetCPUFeatures() & CPU_HAS_SSE42) {
610 static int SDL_SystemRAM = 0;
613 SDL_GetSystemRAM(void)
615 if (!SDL_SystemRAM) {
616 #if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
617 if (SDL_SystemRAM <= 0) {
618 SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024*1024));
621 #ifdef HAVE_SYSCTLBYNAME
622 if (SDL_SystemRAM <= 0) {
623 int mib[2] = {CTL_HW, HW_MEMSIZE};
625 size_t len = sizeof(memsize);
627 if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) {
628 SDL_SystemRAM = (int)(memsize / (1024*1024));
633 if (SDL_SystemRAM <= 0) {
635 if (GlobalMemoryStatusEx(&stat)) {
636 SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
641 return SDL_SystemRAM;
652 printf("CPU count: %d\n", SDL_GetCPUCount());
653 printf("CPU type: %s\n", SDL_GetCPUType());
654 printf("CPU name: %s\n", SDL_GetCPUName());
655 printf("CacheLine size: %d\n", SDL_GetCPUCacheLineSize());
656 printf("RDTSC: %d\n", SDL_HasRDTSC());
657 printf("Altivec: %d\n", SDL_HasAltiVec());
658 printf("MMX: %d\n", SDL_HasMMX());
659 printf("3DNow: %d\n", SDL_Has3DNow());
660 printf("SSE: %d\n", SDL_HasSSE());
661 printf("SSE2: %d\n", SDL_HasSSE2());
662 printf("SSE3: %d\n", SDL_HasSSE3());
663 printf("SSE4.1: %d\n", SDL_HasSSE41());
664 printf("SSE4.2: %d\n", SDL_HasSSE42());
665 printf("RAM: %d MB\n", SDL_GetSystemRAM());
669 #endif /* TEST_MAIN */
671 /* vi: set ts=4 sw=4 expandtab: */