The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

408 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #include "linuxincludes.h"
  24. #include "../../../src/juce_core/basics/juce_StandardHeader.h"
  25. #include <sys/sysinfo.h>
  26. #include <dlfcn.h>
  27. #ifndef CPU_ISSET
  28. #undef SUPPORT_AFFINITIES
  29. #endif
  30. BEGIN_JUCE_NAMESPACE
  31. #include "../../../src/juce_core/io/files/juce_File.h"
  32. #include "../../../src/juce_core/basics/juce_SystemStats.h"
  33. #include "../../../src/juce_core/threads/juce_Process.h"
  34. #include "../../../src/juce_appframework/events/juce_Timer.h"
  35. #include "../../../src/juce_core/misc/juce_PlatformUtilities.h"
  36. static struct _LogicalCpuInfo
  37. {
  38. bool htSupported;
  39. bool htAvailable;
  40. int numPackages;
  41. int numLogicalPerPackage;
  42. uint32 physicalAffinityMask;
  43. } logicalCpuInfo;
  44. //==============================================================================
  45. static juce_noinline unsigned int getCPUIDWord (int* familyModel, int* extFeatures) throw()
  46. {
  47. unsigned int cpu = 0;
  48. unsigned int ext = 0;
  49. unsigned int family = 0;
  50. unsigned int dummy = 0;
  51. #if JUCE_64BIT
  52. __asm__ ("cpuid"
  53. : "=a" (family), "=b" (ext), "=c" (dummy), "=d" (cpu) : "a" (1));
  54. #else
  55. __asm__ ("push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx"
  56. : "=a" (family), "=D" (ext), "=c" (dummy), "=d" (cpu) : "a" (1));
  57. #endif
  58. if (familyModel != 0)
  59. *familyModel = family;
  60. if (extFeatures != 0)
  61. *extFeatures = ext;
  62. return cpu;
  63. }
  64. void juce_initLogicalCpuInfo() throw()
  65. {
  66. int familyModelWord, extFeaturesWord;
  67. int featuresWord = getCPUIDWord (&familyModelWord, &extFeaturesWord);
  68. logicalCpuInfo.htSupported = false;
  69. logicalCpuInfo.htAvailable = false;
  70. logicalCpuInfo.numLogicalPerPackage = 1;
  71. logicalCpuInfo.numPackages = 0;
  72. logicalCpuInfo.physicalAffinityMask = 0;
  73. #if SUPPORT_AFFINITIES
  74. cpu_set_t processAffinity;
  75. /*
  76. N.B. If this line causes a compile error, then you've probably not got the latest
  77. version of glibc installed.
  78. If you don't want to update your copy of glibc and don't care about cpu affinities,
  79. then you can just disable all this stuff by removing the SUPPORT_AFFINITIES macro
  80. from the linuxincludes.h file.
  81. */
  82. if (sched_getaffinity (getpid(),
  83. sizeof (cpu_set_t),
  84. &processAffinity) != sizeof (cpu_set_t))
  85. {
  86. return;
  87. }
  88. // Checks: CPUID supported, model >= Pentium 4, Hyperthreading bit set, logical CPUs per package > 1
  89. if (featuresWord == 0
  90. || ((familyModelWord >> 8) & 0xf) < 15
  91. || (featuresWord & (1 << 28)) == 0
  92. || ((extFeaturesWord >> 16) & 0xff) < 2)
  93. {
  94. for (int i = 0; i < 64; ++i)
  95. if (CPU_ISSET (i, &processAffinity))
  96. logicalCpuInfo.physicalAffinityMask |= (1 << i);
  97. return;
  98. }
  99. logicalCpuInfo.htSupported = true;
  100. logicalCpuInfo.numLogicalPerPackage = (extFeaturesWord >> 16) & 0xff;
  101. cpu_set_t affinityMask;
  102. cpu_set_t physAff;
  103. CPU_ZERO (&physAff);
  104. unsigned char i = 1;
  105. unsigned char physIdMask = 0xFF;
  106. unsigned char physIdShift = 0;
  107. //unsigned char apicId, logId, physId;
  108. while (i < logicalCpuInfo.numLogicalPerPackage)
  109. {
  110. i *= 2;
  111. physIdMask <<= 1;
  112. physIdShift++;
  113. }
  114. CPU_SET (0, &affinityMask);
  115. logicalCpuInfo.numPackages = 0;
  116. //xxx revisit this at some point..
  117. /* while ((affinityMask != 0) && (affinityMask <= processAffinity))
  118. {
  119. int ret;
  120. if (! sched_setaffinity (getpid(), sizeof (cpu_set_t), &affinityMask))
  121. {
  122. sched_yield(); // schedule onto correct CPU
  123. featuresWord = getCPUIDWord(&familyModelWord, &extFeaturesWord);
  124. apicId = (unsigned char)(extFeaturesWord >> 24);
  125. logId = (unsigned char)(apicId & ~physIdMask);
  126. physId = (unsigned char)(apicId >> physIdShift);
  127. if (logId != 0)
  128. logicalCpuInfo.htAvailable = true;
  129. if ((((int)logId) % logicalCpuInfo.numLogicalPerPackage) == 0)
  130. {
  131. // This is a physical CPU
  132. physAff |= affinityMask;
  133. logicalCpuInfo.numPackages++;
  134. }
  135. }
  136. affinityMask = affinityMask << 1;
  137. }
  138. sched_setaffinity (getpid(), sizeof(unsigned long), &processAffinity);
  139. */
  140. logicalCpuInfo.physicalAffinityMask = 0;
  141. for (int i = 0; i < 64; ++i)
  142. if (CPU_ISSET (i, &physAff))
  143. logicalCpuInfo.physicalAffinityMask |= (1 << i);
  144. #endif
  145. }
  146. //==============================================================================
  147. void Logger::outputDebugString (const String& text) throw()
  148. {
  149. fprintf (stdout, text.toUTF8());
  150. fprintf (stdout, "\n");
  151. }
  152. void Logger::outputDebugPrintf (const tchar* format, ...) throw()
  153. {
  154. String text;
  155. va_list args;
  156. va_start (args, format);
  157. text.vprintf(format, args);
  158. outputDebugString(text);
  159. }
  160. SystemStats::OperatingSystemType SystemStats::getOperatingSystemType() throw()
  161. {
  162. return Linux;
  163. }
  164. const String SystemStats::getOperatingSystemName() throw()
  165. {
  166. return T("Linux");
  167. }
  168. static const String getCpuInfo (const char* key, bool lastOne = false) throw()
  169. {
  170. String info;
  171. char buf [256];
  172. FILE* f = fopen ("/proc/cpuinfo", "r");
  173. while (f != 0 && fgets (buf, sizeof(buf), f))
  174. {
  175. if (strncmp (buf, key, strlen (key)) == 0)
  176. {
  177. char* p = buf;
  178. while (*p && *p != '\n')
  179. ++p;
  180. if (*p != 0)
  181. *p = 0;
  182. p = buf;
  183. while (*p != 0 && *p != ':')
  184. ++p;
  185. if (*p != 0 && *(p + 1) != 0)
  186. info = p + 2;
  187. if (! lastOne)
  188. break;
  189. }
  190. }
  191. fclose (f);
  192. return info;
  193. }
  194. bool SystemStats::hasMMX() throw()
  195. {
  196. return getCpuInfo ("flags").contains (T("mmx"));
  197. }
  198. bool SystemStats::hasSSE() throw()
  199. {
  200. return getCpuInfo ("flags").contains (T("sse"));
  201. }
  202. bool SystemStats::hasSSE2() throw()
  203. {
  204. return getCpuInfo ("flags").contains (T("sse2"));
  205. }
  206. bool SystemStats::has3DNow() throw()
  207. {
  208. return getCpuInfo ("flags").contains (T("3dnow"));
  209. }
  210. const String SystemStats::getCpuVendor() throw()
  211. {
  212. return getCpuInfo ("vendor_id");
  213. }
  214. int SystemStats::getCpuSpeedInMegaherz() throw()
  215. {
  216. const String speed (getCpuInfo ("cpu MHz"));
  217. return (int) (speed.getFloatValue() + 0.5f);
  218. }
  219. bool SystemStats::hasHyperThreading() throw()
  220. {
  221. return logicalCpuInfo.htAvailable;
  222. }
  223. int SystemStats::getMemorySizeInMegabytes() throw()
  224. {
  225. struct sysinfo sysi;
  226. if (sysinfo (&sysi) == 0)
  227. return (sysi.totalram * sysi.mem_unit / (1024 * 1024));
  228. return 0;
  229. }
  230. uint32 juce_millisecondsSinceStartup() throw()
  231. {
  232. static unsigned int calibrate = 0;
  233. static bool calibrated = false;
  234. timeval t;
  235. unsigned int ret = 0;
  236. if (! gettimeofday (&t, 0))
  237. {
  238. if (! calibrated)
  239. {
  240. struct sysinfo sysi;
  241. if (sysinfo (&sysi) == 0)
  242. // Safe to assume system was not brought up earlier than 1970!
  243. calibrate = t.tv_sec - sysi.uptime;
  244. calibrated = true;
  245. }
  246. ret = 1000 * (t.tv_sec - calibrate) + (t.tv_usec / 1000);
  247. }
  248. return ret;
  249. }
  250. double Time::getMillisecondCounterHiRes() throw()
  251. {
  252. return getHighResolutionTicks() * (1.0 / 1000000.0);
  253. }
  254. int64 Time::getHighResolutionTicks() throw()
  255. {
  256. timeval t;
  257. if (gettimeofday (&t,NULL))
  258. return 0;
  259. return ((int64) t.tv_sec * (int64) 1000000) + (int64) t.tv_usec;
  260. }
  261. int64 Time::getHighResolutionTicksPerSecond() throw()
  262. {
  263. // Microseconds
  264. return 1000000;
  265. }
  266. bool Time::setSystemTimeToThisTime() const throw()
  267. {
  268. timeval t;
  269. t.tv_sec = millisSinceEpoch % 1000000;
  270. t.tv_usec = millisSinceEpoch - t.tv_sec;
  271. return settimeofday (&t, NULL) ? false : true;
  272. }
  273. int SystemStats::getPageSize() throw()
  274. {
  275. static int systemPageSize = 0;
  276. if (systemPageSize == 0)
  277. systemPageSize = sysconf (_SC_PAGESIZE);
  278. return systemPageSize;
  279. }
  280. int SystemStats::getNumPhysicalCpus() throw()
  281. {
  282. if (logicalCpuInfo.numPackages)
  283. return logicalCpuInfo.numPackages;
  284. return getNumLogicalCpus();
  285. }
  286. int SystemStats::getNumLogicalCpus() throw()
  287. {
  288. const int lastCpu = getCpuInfo ("processor", true).getIntValue();
  289. return lastCpu + 1;
  290. }
  291. uint32 SystemStats::getPhysicalAffinityMask() throw()
  292. {
  293. #if SUPPORT_AFFINITIES
  294. return logicalCpuInfo.physicalAffinityMask;
  295. #else
  296. /* affinities aren't supported because either the appropriate header files weren't found,
  297. or the SUPPORT_AFFINITIES macro was turned off in linuxheaders.h
  298. */
  299. jassertfalse
  300. return 0;
  301. #endif
  302. }
  303. //==============================================================================
  304. void SystemStats::initialiseStats() throw()
  305. {
  306. // Process starts off as root when running suid
  307. Process::lowerPrivilege();
  308. String s (SystemStats::getJUCEVersion());
  309. juce_initLogicalCpuInfo();
  310. }
  311. void PlatformUtilities::fpuReset()
  312. {
  313. }
  314. END_JUCE_NAMESPACE