/* ============================================================================== This file is part of the JUCE library - "Jules' Utility Class Extensions" Copyright 2004-7 by Raw Material Software ltd. ------------------------------------------------------------------------------ JUCE can be redistributed and/or modified under the terms of the GNU General Public License, as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with JUCE; if not, visit www.gnu.org/licenses or write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ------------------------------------------------------------------------------ If you'd like to release a closed-source product which uses JUCE, commercial licenses are also available: visit www.rawmaterialsoftware.com/juce for more information. ============================================================================== */ #include "linuxincludes.h" #include "../../../src/juce_core/basics/juce_StandardHeader.h" #include #include #ifndef CPU_ISSET #undef SUPPORT_AFFINITIES #endif BEGIN_JUCE_NAMESPACE #include "../../../src/juce_core/io/files/juce_File.h" #include "../../../src/juce_core/basics/juce_SystemStats.h" #include "../../../src/juce_core/threads/juce_Process.h" #include "../../../src/juce_appframework/events/juce_Timer.h" #include "../../../src/juce_core/misc/juce_PlatformUtilities.h" static struct _LogicalCpuInfo { bool htSupported; bool htAvailable; int numPackages; int numLogicalPerPackage; uint32 physicalAffinityMask; } logicalCpuInfo; //============================================================================== static juce_noinline unsigned int getCPUIDWord (int* familyModel, int* extFeatures) throw() { unsigned int cpu = 0; unsigned int ext = 0; unsigned int family = 0; unsigned int dummy = 0; #if JUCE_64BIT __asm__ ("cpuid" : "=a" (family), "=b" (ext), "=c" (dummy), "=d" (cpu) : "a" (1)); #else __asm__ ("push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx" : "=a" (family), "=D" (ext), "=c" (dummy), "=d" (cpu) : "a" (1)); #endif if (familyModel != 0) *familyModel = family; if (extFeatures != 0) *extFeatures = ext; return cpu; } void juce_initLogicalCpuInfo() throw() { int familyModelWord, extFeaturesWord; int featuresWord = getCPUIDWord (&familyModelWord, &extFeaturesWord); logicalCpuInfo.htSupported = false; logicalCpuInfo.htAvailable = false; logicalCpuInfo.numLogicalPerPackage = 1; logicalCpuInfo.numPackages = 0; logicalCpuInfo.physicalAffinityMask = 0; #if SUPPORT_AFFINITIES cpu_set_t processAffinity; /* N.B. If this line causes a compile error, then you've probably not got the latest version of glibc installed. If you don't want to update your copy of glibc and don't care about cpu affinities, then you can just disable all this stuff by removing the SUPPORT_AFFINITIES macro from the linuxincludes.h file. */ if (sched_getaffinity (getpid(), sizeof (cpu_set_t), &processAffinity) != sizeof (cpu_set_t)) { return; } // Checks: CPUID supported, model >= Pentium 4, Hyperthreading bit set, logical CPUs per package > 1 if (featuresWord == 0 || ((familyModelWord >> 8) & 0xf) < 15 || (featuresWord & (1 << 28)) == 0 || ((extFeaturesWord >> 16) & 0xff) < 2) { for (int i = 0; i < 64; ++i) if (CPU_ISSET (i, &processAffinity)) logicalCpuInfo.physicalAffinityMask |= (1 << i); return; } logicalCpuInfo.htSupported = true; logicalCpuInfo.numLogicalPerPackage = (extFeaturesWord >> 16) & 0xff; cpu_set_t affinityMask; cpu_set_t physAff; CPU_ZERO (&physAff); unsigned char i = 1; unsigned char physIdMask = 0xFF; unsigned char physIdShift = 0; //unsigned char apicId, logId, physId; while (i < logicalCpuInfo.numLogicalPerPackage) { i *= 2; physIdMask <<= 1; physIdShift++; } CPU_SET (0, &affinityMask); logicalCpuInfo.numPackages = 0; //xxx revisit this at some point.. /* while ((affinityMask != 0) && (affinityMask <= processAffinity)) { int ret; if (! sched_setaffinity (getpid(), sizeof (cpu_set_t), &affinityMask)) { sched_yield(); // schedule onto correct CPU featuresWord = getCPUIDWord(&familyModelWord, &extFeaturesWord); apicId = (unsigned char)(extFeaturesWord >> 24); logId = (unsigned char)(apicId & ~physIdMask); physId = (unsigned char)(apicId >> physIdShift); if (logId != 0) logicalCpuInfo.htAvailable = true; if ((((int)logId) % logicalCpuInfo.numLogicalPerPackage) == 0) { // This is a physical CPU physAff |= affinityMask; logicalCpuInfo.numPackages++; } } affinityMask = affinityMask << 1; } sched_setaffinity (getpid(), sizeof(unsigned long), &processAffinity); */ logicalCpuInfo.physicalAffinityMask = 0; for (int i = 0; i < 64; ++i) if (CPU_ISSET (i, &physAff)) logicalCpuInfo.physicalAffinityMask |= (1 << i); #endif } //============================================================================== void Logger::outputDebugString (const String& text) throw() { fprintf (stdout, text.toUTF8()); fprintf (stdout, "\n"); } void Logger::outputDebugPrintf (const tchar* format, ...) throw() { String text; va_list args; va_start (args, format); text.vprintf(format, args); outputDebugString(text); } SystemStats::OperatingSystemType SystemStats::getOperatingSystemType() throw() { return Linux; } const String SystemStats::getOperatingSystemName() throw() { return T("Linux"); } static const String getCpuInfo (const char* key, bool lastOne = false) throw() { String info; char buf [256]; FILE* f = fopen ("/proc/cpuinfo", "r"); while (f != 0 && fgets (buf, sizeof(buf), f)) { if (strncmp (buf, key, strlen (key)) == 0) { char* p = buf; while (*p && *p != '\n') ++p; if (*p != 0) *p = 0; p = buf; while (*p != 0 && *p != ':') ++p; if (*p != 0 && *(p + 1) != 0) info = p + 2; if (! lastOne) break; } } fclose (f); return info; } bool SystemStats::hasMMX() throw() { return getCpuInfo ("flags").contains (T("mmx")); } bool SystemStats::hasSSE() throw() { return getCpuInfo ("flags").contains (T("sse")); } bool SystemStats::hasSSE2() throw() { return getCpuInfo ("flags").contains (T("sse2")); } bool SystemStats::has3DNow() throw() { return getCpuInfo ("flags").contains (T("3dnow")); } const String SystemStats::getCpuVendor() throw() { return getCpuInfo ("vendor_id"); } int SystemStats::getCpuSpeedInMegaherz() throw() { const String speed (getCpuInfo ("cpu MHz")); return (int) (speed.getFloatValue() + 0.5f); } bool SystemStats::hasHyperThreading() throw() { return logicalCpuInfo.htAvailable; } int SystemStats::getMemorySizeInMegabytes() throw() { struct sysinfo sysi; if (sysinfo (&sysi) == 0) return (sysi.totalram * sysi.mem_unit / (1024 * 1024)); return 0; } uint32 juce_millisecondsSinceStartup() throw() { static unsigned int calibrate = 0; static bool calibrated = false; timeval t; unsigned int ret = 0; if (! gettimeofday (&t, 0)) { if (! calibrated) { struct sysinfo sysi; if (sysinfo (&sysi) == 0) // Safe to assume system was not brought up earlier than 1970! calibrate = t.tv_sec - sysi.uptime; calibrated = true; } ret = 1000 * (t.tv_sec - calibrate) + (t.tv_usec / 1000); } return ret; } double Time::getMillisecondCounterHiRes() throw() { return getHighResolutionTicks() * 0.001; } int64 Time::getHighResolutionTicks() throw() { timeval t; if (gettimeofday (&t, 0)) return 0; return ((int64) t.tv_sec * (int64) 1000000) + (int64) t.tv_usec; } int64 Time::getHighResolutionTicksPerSecond() throw() { // Microseconds return 1000000; } bool Time::setSystemTimeToThisTime() const throw() { timeval t; t.tv_sec = millisSinceEpoch % 1000000; t.tv_usec = millisSinceEpoch - t.tv_sec; return settimeofday (&t, NULL) ? false : true; } int SystemStats::getPageSize() throw() { static int systemPageSize = 0; if (systemPageSize == 0) systemPageSize = sysconf (_SC_PAGESIZE); return systemPageSize; } int SystemStats::getNumPhysicalCpus() throw() { if (logicalCpuInfo.numPackages) return logicalCpuInfo.numPackages; return getNumLogicalCpus(); } int SystemStats::getNumLogicalCpus() throw() { const int lastCpu = getCpuInfo ("processor", true).getIntValue(); return lastCpu + 1; } uint32 SystemStats::getPhysicalAffinityMask() throw() { #if SUPPORT_AFFINITIES return logicalCpuInfo.physicalAffinityMask; #else /* affinities aren't supported because either the appropriate header files weren't found, or the SUPPORT_AFFINITIES macro was turned off in linuxheaders.h */ jassertfalse return 0; #endif } //============================================================================== void SystemStats::initialiseStats() throw() { // Process starts off as root when running suid Process::lowerPrivilege(); String s (SystemStats::getJUCEVersion()); juce_initLogicalCpuInfo(); } void PlatformUtilities::fpuReset() { } END_JUCE_NAMESPACE