llsys.cpp 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226
  1. /**
  2. * @file llsys.cpp
  3. * @brief Impelementation of the basic system query functions.
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewergpl$
  6. *
  7. * Copyright (c) 2002-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include <sstream>
  33. #if LL_WINDOWS
  34. # if LL_NETBIOS
  35. # include "llwin32headers.h"
  36. # include <nb30.h> // For ADAPTER_STATUS
  37. # else
  38. # include "llwin32headerslean.h"
  39. # endif
  40. # include <iphlpapi.h>
  41. # include <psapi.h>
  42. # include <VersionHelpers.h>
  43. # include <mmsystem.h> // For timeBeginPeriod()
  44. # define _interlockedbittestandset _renamed_interlockedbittestandset
  45. # define _interlockedbittestandreset _renamed_interlockedbittestandreset
  46. # include <intrin.h>
  47. # undef _interlockedbittestandset
  48. # undef _interlockedbittestandreset
  49. # include <powerbase.h>
  50. #elif LL_DARWIN
  51. # include <unistd.h>
  52. # include <stdint.h>
  53. # include <errno.h>
  54. # include <sys/types.h>
  55. # include <sys/time.h>
  56. # include <sys/socket.h>
  57. # include <sys/ioctl.h>
  58. # include <sys/types.h>
  59. # include <sys/sysctl.h>
  60. # include <sys/utsname.h>
  61. # include <net/if.h>
  62. # include <net/if_types.h>
  63. # include <net/if_dl.h>
  64. # include <net/route.h>
  65. # include <ifaddrs.h>
  66. # include <CoreServices/CoreServices.h>
  67. # include <mach/task.h>
  68. # include <mach/mach_host.h>
  69. # include <mach/machine.h>
  70. // Disable warnings about Gestalt calls being deprecated until Apple gets on
  71. // the ball and provides an alternative
  72. # pragma clang diagnostic ignored "-Wdeprecated-declarations"
  73. #elif LL_LINUX
  74. # include <unistd.h>
  75. # include <fcntl.h>
  76. # include <errno.h>
  77. # include <sched.h> // For sched_setaffinity() & getcpu() when present
  78. # ifndef getcpu // ... else we need syscall():
  79. # include <sys/syscall.h>
  80. # endif
  81. # include <sys/utsname.h>
  82. # include <sys/types.h>
  83. # include <sys/time.h>
  84. # include <sys/stat.h>
  85. # include <sys/file.h>
  86. # include <sys/ioctl.h>
  87. # include <sys/socket.h>
  88. # include <net/if.h>
  89. # include <netinet/in.h>
  90. # include <linux/sockios.h>
  91. #endif
  92. #include "boost/thread.hpp"
  93. #include "linden_common.h"
  94. #include "llsys.h"
  95. #include "llmemory.h"
  96. #include "llsd.h"
  97. #include "llthread.h" // For *_main_thread()
  98. #include "lltimer.h"
  99. ///////////////////////////////////////////////////////////////////////////////
  100. // LLOSInfo class
  101. ///////////////////////////////////////////////////////////////////////////////
  102. #if LL_WINDOWS
  103. #ifndef DLLVERSIONINFO
  104. typedef struct _DllVersionInfo
  105. {
  106. DWORD cbSize;
  107. DWORD dwMajorVersion;
  108. DWORD dwMinorVersion;
  109. DWORD dwBuildNumber;
  110. DWORD dwPlatformID;
  111. } DLLVERSIONINFO;
  112. #endif
  113. #ifndef DLLGETVERSIONPROC
  114. typedef int (FAR WINAPI* DLLGETVERSIONPROC) (DLLVERSIONINFO*);
  115. #endif
  116. // When running under Wine, this function returns a pointer on the Wine version
  117. // number, or NULL otherwise. HB
  118. static const char* get_wine_version()
  119. {
  120. HMODULE h_dll_inst = GetModuleHandle(TEXT("ntdll.dll"));
  121. if (!h_dll_inst)
  122. {
  123. // Should never happen under Win7+...
  124. llwarns << "Could not load ntdll.dll; cannot determine if running under Wine."
  125. << llendl;
  126. return NULL;
  127. }
  128. typedef const char* (FAR WINAPI* DLLGETWINEVERPROC)();
  129. DLLGETWINEVERPROC wine_get_versionp =
  130. (DLLGETWINEVERPROC)GetProcAddress(h_dll_inst, "wine_get_version");
  131. if (!wine_get_versionp)
  132. {
  133. return NULL;
  134. }
  135. return (*wine_get_versionp)();
  136. }
  137. #endif // LL_WINDOWS
  138. LLOSInfo::LLOSInfo()
  139. {
  140. #if LL_WINDOWS
  141. S32 major = 0;
  142. S32 minor = 0;
  143. S32 build = 0;
  144. if (IsWindows10OrGreater())
  145. {
  146. major = 10;
  147. mOSStringSimple = "Windows 10 ";
  148. }
  149. else if (IsWindows8Point1OrGreater())
  150. {
  151. major = 6;
  152. minor = 3;
  153. if (IsWindowsServer())
  154. {
  155. mOSStringSimple = "Windows Server 2012 R2 ";
  156. }
  157. else
  158. {
  159. mOSStringSimple = "Windows 8.1 ";
  160. }
  161. }
  162. else if (IsWindows8OrGreater())
  163. {
  164. major = 6;
  165. minor = 2;
  166. if (IsWindowsServer())
  167. {
  168. mOSStringSimple = "Windows Server 2012 ";
  169. }
  170. else
  171. {
  172. mOSStringSimple = "Windows 8 ";
  173. }
  174. }
  175. else if (IsWindows7SP1OrGreater())
  176. {
  177. major = 6;
  178. minor = 1;
  179. if (IsWindowsServer())
  180. {
  181. mOSStringSimple = "Windows Server 2008 R2 SP1 ";
  182. }
  183. else
  184. {
  185. mOSStringSimple = "Windows 7 SP1 ";
  186. }
  187. }
  188. else if (IsWindows7OrGreater())
  189. {
  190. major = 6;
  191. minor = 1;
  192. if (IsWindowsServer())
  193. {
  194. mOSStringSimple = "Windows Server 2008 R2 ";
  195. }
  196. else
  197. {
  198. mOSStringSimple = "Windows 7 ";
  199. }
  200. }
  201. else if (IsWindowsVistaSP2OrGreater())
  202. {
  203. major = 6;
  204. if (IsWindowsServer())
  205. {
  206. mOSStringSimple = "Windows Server 2008 SP2 ";
  207. }
  208. else
  209. {
  210. mOSStringSimple = "Windows Vista SP2 ";
  211. }
  212. }
  213. else
  214. {
  215. mOSStringSimple = "Windows unsupported version ";
  216. }
  217. // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
  218. OSVERSIONINFOEX osvi;
  219. ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
  220. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  221. bool success = GetVersionEx((OSVERSIONINFO*)&osvi) != 0;
  222. if (!success)
  223. {
  224. // If OSVERSIONINFOEX does not work, try OSVERSIONINFO.
  225. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  226. success = GetVersionEx((OSVERSIONINFO*)&osvi) != 0;
  227. }
  228. if (success)
  229. {
  230. build = osvi.dwBuildNumber & 0xffff;
  231. if (major == 10 && build >= 22000)
  232. {
  233. major = 11;
  234. mOSStringSimple = "Windows 11 ";
  235. }
  236. }
  237. else
  238. {
  239. llwarns << "Could not get Windows build via GetVersionEx()."
  240. << llendl;
  241. }
  242. mInaccurateSleep = false;
  243. DWORD revision = 0;
  244. if (major >= 10)
  245. {
  246. // Windows 10 and later got an inaccurate Sleep() call by default...
  247. // Let's change the minimum resolution to 1ms. HB
  248. mInaccurateSleep = true;
  249. if (timeBeginPeriod(1) == TIMERR_NOCANDO)
  250. {
  251. llwarns << "Could not set the Sleep() resolution to 1ms."
  252. << llendl;
  253. }
  254. // For Windows 10+, get the update build revision from the registry
  255. HKEY key;
  256. if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  257. TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"),
  258. 0, KEY_READ, &key) == ERROR_SUCCESS)
  259. {
  260. DWORD cb_data(sizeof(DWORD));
  261. if (RegQueryValueExW(key, L"UBR", 0, NULL,
  262. reinterpret_cast<LPBYTE>(&revision),
  263. &cb_data) != ERROR_SUCCESS)
  264. {
  265. revision = 0;
  266. }
  267. }
  268. }
  269. if (revision)
  270. {
  271. mOSVersionString = llformat("%d.%d (build %d.%d)", major, minor, build,
  272. (S32)revision);
  273. }
  274. else
  275. {
  276. mOSVersionString = llformat("%d.%d (build %d)", major, minor, build);
  277. }
  278. mOSStringSimple += "64 bits ";
  279. mOSString = "Microsoft " + mOSStringSimple + "v" + mOSVersionString;
  280. // Check for Wine emulation (needed to work around bugs in Wine). HB
  281. const char* wine_ver = get_wine_version();
  282. mUnderWine = wine_ver != NULL;
  283. if (mUnderWine)
  284. {
  285. mWineVersionString.assign(wine_ver);
  286. mOSString += " (Wine v" + mWineVersionString + ")";
  287. }
  288. #elif LL_DARWIN
  289. // Initialize mOSStringSimple to something like:
  290. // "Mac OS X 10.6.7"
  291. {
  292. SInt32 major_version, minor_version, bugfix_version;
  293. OSErr r1 = Gestalt(gestaltSystemVersionMajor, &major_version);
  294. OSErr r2 = Gestalt(gestaltSystemVersionMinor, &minor_version);
  295. OSErr r3 = Gestalt(gestaltSystemVersionBugFix, &bugfix_version);
  296. if (r1 == noErr && r2 == noErr && r3 == noErr)
  297. {
  298. mOSVersionString = llformat("%d.%d.%d", major_version,
  299. minor_version, bugfix_version);
  300. std::string os_version = "Mac OS X " + mOSVersionString;
  301. // Put it in the OS string we are compiling
  302. mOSStringSimple.append(os_version);
  303. }
  304. else
  305. {
  306. mOSStringSimple.append("Unable to collect OS info");
  307. }
  308. }
  309. // Initialize mOSString to something like:
  310. // "Mac OS X 10.6.7 Darwin Kernel Version 10.7.0:
  311. // Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386"
  312. struct utsname un;
  313. if (uname(&un) != -1)
  314. {
  315. mOSString = mOSStringSimple;
  316. mOSString.append(" ");
  317. mOSString.append(un.sysname);
  318. mOSString.append(" ");
  319. mOSString.append(un.release);
  320. mOSString.append(" ");
  321. mOSString.append(un.version);
  322. mOSString.append(" ");
  323. mOSString.append(un.machine);
  324. }
  325. else
  326. {
  327. mOSString = mOSStringSimple;
  328. }
  329. #else // LL_LINUX
  330. mVersionMajor = mVersionMinor = 0;
  331. struct utsname un;
  332. if (uname(&un) != -1)
  333. {
  334. mOSString.assign(un.sysname);
  335. mOSString.append("-");
  336. mOSString.append(un.machine);
  337. // Note: un.release is the actual Linux version (including any string
  338. // identifying distribution-specific patched kernels), while un.version
  339. // is just "#<build number> SMP <build date>", which is irrelevant and
  340. // we do not care the least about... HB
  341. mOSVersionString.assign(un.release);
  342. mOSString += " v" + mOSVersionString;
  343. mOSStringSimple = mOSString;
  344. std::string version = mOSVersionString;
  345. size_t i = version.find('.');
  346. if (i != std::string::npos)
  347. {
  348. mVersionMajor = atoi(version.substr(0, i).c_str());
  349. version.erase(0, i + 1);
  350. i = version.find('.');
  351. if (i != std::string::npos)
  352. {
  353. mVersionMinor = atoi(version.substr(0, i).c_str());
  354. }
  355. }
  356. }
  357. else
  358. {
  359. mOSStringSimple = "Unable to collect OS info";
  360. mOSString = mOSStringSimple;
  361. }
  362. #endif
  363. }
  364. LLOSInfo::~LLOSInfo()
  365. {
  366. #if LL_WINDOWS
  367. if (mInaccurateSleep)
  368. {
  369. // On process exit, restore default by calling this to match the
  370. // timeBeginPeriod(1) above. HB
  371. timeEndPeriod(1);
  372. }
  373. #endif
  374. }
  375. //static
  376. S32 LLOSInfo::getNodeID(unsigned char* node_id)
  377. {
  378. static unsigned char sNodeID[8];
  379. static S32 result = -2;
  380. if (result == -2) // First call.
  381. {
  382. result = getOSNodeID(sNodeID);
  383. }
  384. if (result == 1)
  385. {
  386. memcpy(node_id, sNodeID, 6);
  387. }
  388. return result;
  389. }
  390. #if LL_LINUX
  391. //static
  392. S32 LLOSInfo::getOSNodeID(unsigned char* node_id)
  393. {
  394. int n, i;
  395. unsigned char* a;
  396. // BSD 4.4 defines the size of an ifreq to be the max of sizeof(ifreq)
  397. // and sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len. However, under earlier
  398. // systems, sa_len is not present, so the size is just sizeof(struct ifreq).
  399. #ifdef HAVE_SA_LEN
  400. # define ifreq_size(i) llmax(sizeof(struct ifreq),\
  401. sizeof((i).ifr_name) + (i).ifr_addr.sa_len)
  402. #else
  403. # define ifreq_size(i) sizeof(struct ifreq)
  404. #endif // HAVE_SA_LEN
  405. int sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
  406. if (sd < 0)
  407. {
  408. return -1;
  409. }
  410. char buf[1024];
  411. memset(buf, 0, sizeof(buf));
  412. struct ifreq ifr, *ifrp;
  413. struct ifconf ifc;
  414. ifc.ifc_len = sizeof(buf);
  415. ifc.ifc_buf = buf;
  416. if (ioctl (sd, SIOCGIFCONF, (char*)&ifc) < 0)
  417. {
  418. close(sd);
  419. return -1;
  420. }
  421. n = ifc.ifc_len;
  422. for (i = 0; i < n; i+= ifreq_size(*ifr))
  423. {
  424. ifrp = (struct ifreq*)((char*) ifc.ifc_buf + i);
  425. strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
  426. #ifdef SIOCGIFHWADDR
  427. if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
  428. continue;
  429. a = (unsigned char*)&ifr.ifr_hwaddr.sa_data;
  430. #else
  431. # ifdef SIOCGENADDR
  432. if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
  433. continue;
  434. a = (unsigned char*)ifr.ifr_enaddr;
  435. # else // We do not have a way of getting the hardware address
  436. close(sd);
  437. return 0;
  438. # endif // SIOCGENADDR
  439. #endif // SIOCGIFHWADDR
  440. if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
  441. {
  442. continue;
  443. }
  444. if (node_id)
  445. {
  446. memcpy(node_id, a, 6);
  447. close(sd);
  448. return 1;
  449. }
  450. }
  451. close(sd);
  452. return 0;
  453. }
  454. #elif LL_WINDOWS
  455. # if LL_NETBIOS
  456. typedef struct _ASTAT_
  457. {
  458. ADAPTER_STATUS adapt;
  459. NAME_BUFFER NameBuff [30];
  460. } ASTAT, * PASTAT;
  461. //static
  462. S32 LLOSInfo::getOSNodeID(unsigned char* node_id)
  463. {
  464. NCB Ncb;
  465. memset(&Ncb, 0, sizeof(Ncb));
  466. Ncb.ncb_command = NCBENUM;
  467. LANA_ENUM lenum;
  468. Ncb.ncb_buffer = (UCHAR*)&lenum;
  469. Ncb.ncb_length = sizeof(lenum);
  470. UCHAR ret_code = Netbios(&Ncb);
  471. S32 retval = 0;
  472. ASTAT Adapter;
  473. for (S32 i = 0; i < (S32)lenum.length; ++i)
  474. {
  475. memset(&Ncb, 0, sizeof(Ncb));
  476. Ncb.ncb_command = NCBRESET;
  477. Ncb.ncb_lana_num = lenum.lana[i];
  478. ret_code = Netbios(&Ncb);
  479. memset(&Ncb, 0, sizeof (Ncb));
  480. Ncb.ncb_command = NCBASTAT;
  481. Ncb.ncb_lana_num = lenum.lana[i];
  482. strcpy((char*)Ncb.ncb_callname, "* ");
  483. Ncb.ncb_buffer = (unsigned char*)&Adapter;
  484. Ncb.ncb_length = sizeof(Adapter);
  485. ret_code = Netbios(&Ncb);
  486. if (ret_code == 0)
  487. {
  488. memcpy(node_id, Adapter.adapt.adapter_address, 6);
  489. retval = 1;
  490. }
  491. }
  492. return retval;
  493. }
  494. # else // LL_NETBIOS
  495. //static
  496. S32 LLOSInfo::getOSNodeID(unsigned char* node_id)
  497. {
  498. static bool got_node_id = false;
  499. static unsigned char local_node_id[6];
  500. if (got_node_id)
  501. {
  502. memcpy(node_id, local_node_id, sizeof(local_node_id));
  503. return 1;
  504. }
  505. ULONG out_buf_len = 0U;
  506. ULONG family = AF_INET;
  507. ULONG flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS;
  508. GetAdaptersAddresses(AF_INET, flags, NULL, NULL, &out_buf_len);
  509. PIP_ADAPTER_ADDRESSES addrp =
  510. reinterpret_cast<PIP_ADAPTER_ADDRESSES>(malloc(out_buf_len));
  511. if (!addrp)
  512. {
  513. return 0;
  514. }
  515. DWORD dw_ret_val = 0;
  516. for (U32 i = 0; i < 3; ++i)
  517. {
  518. dw_ret_val = GetAdaptersAddresses(family, flags, NULL, addrp,
  519. &out_buf_len);
  520. if (dw_ret_val != ERROR_BUFFER_OVERFLOW)
  521. {
  522. break;
  523. }
  524. }
  525. S32 retval = 0;
  526. if (dw_ret_val == NO_ERROR)
  527. {
  528. PIP_ADAPTER_ADDRESSES curaddrp = addrp;
  529. do
  530. {
  531. if (curaddrp->FirstGatewayAddress &&
  532. curaddrp->OperStatus == IfOperStatusUp &&
  533. curaddrp->PhysicalAddressLength == 6 &&
  534. (curaddrp->ConnectionType == NET_IF_CONNECTION_DEDICATED &&
  535. (curaddrp->IfType == IF_TYPE_ETHERNET_CSMACD ||
  536. curaddrp->IfType == IF_TYPE_IEEE80211)))
  537. {
  538. for (U32 i = 0; i < 6; ++i)
  539. {
  540. node_id[i] = local_node_id[i] =
  541. curaddrp->PhysicalAddress[i];
  542. }
  543. retval = 1;
  544. got_node_id = true;
  545. break;
  546. }
  547. curaddrp = curaddrp->Next;
  548. }
  549. while (curaddrp);
  550. }
  551. free(addrp);
  552. return retval;
  553. }
  554. # endif // LL_NETBIOS
  555. #elif LL_DARWIN
  556. //static
  557. S32 LLOSInfo::getOSNodeID(unsigned char* node_id)
  558. {
  559. unsigned char* a = NULL;
  560. struct ifaddrs *ifap, *ifa;
  561. int rv;
  562. S32 result = 0;
  563. if ((rv = getifaddrs(&ifap)) == -1)
  564. {
  565. return -1;
  566. }
  567. if (ifap == NULL)
  568. {
  569. return -1;
  570. }
  571. for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
  572. {
  573. if (ifa->ifa_addr->sa_family == AF_LINK)
  574. {
  575. // This is a link-level address
  576. struct sockaddr_dl* lla = (struct sockaddr_dl*)ifa->ifa_addr;
  577. if (lla->sdl_type == IFT_ETHER)
  578. {
  579. // Use the first ethernet MAC in the list.
  580. // For some reason, the macro LLADDR() defined in net/if_dl.h
  581. // does not expand correctly. This is what it would do.
  582. a = (unsigned char*)&((lla)->sdl_data);
  583. a += (lla)->sdl_nlen;
  584. if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
  585. {
  586. continue;
  587. }
  588. if (node_id)
  589. {
  590. memcpy(node_id, a, 6);
  591. result = 1;
  592. }
  593. // We found one.
  594. break;
  595. }
  596. }
  597. }
  598. freeifaddrs(ifap);
  599. return result;
  600. }
  601. #endif
  602. ///////////////////////////////////////////////////////////////////////////////
  603. // LLProcessorInfo class, which used to be in a separate llprocessor.h/cpp
  604. // module, but is only consumed by LLCPUInfo, so I moved it here, where it
  605. // belongs. *TODO: maybe make it into an LLCPUInfo::Impl sub-class ? HB
  606. ///////////////////////////////////////////////////////////////////////////////
  607. class LLProcessorInfo final
  608. {
  609. friend class LLCPUInfo;
  610. protected: // Access limited to LLCPUInfo
  611. LOG_CLASS(LLProcessorInfo);
  612. LLProcessorInfo();
  613. F64 getCPUFrequency() const;
  614. bool hasSSE2() const;
  615. bool hasSSE3() const;
  616. bool hasSSE3S() const;
  617. bool hasSSE41() const;
  618. bool hasSSE42() const;
  619. bool hasSSE4a() const;
  620. U32 getPhysicalCores() const;
  621. U32 getVirtualCores() const;
  622. U32 getMaxChildThreads() const;
  623. std::string getCPUFamilyName() const;
  624. std::string getCPUBrandName() const;
  625. // This is virtual to support a different Linux format.
  626. virtual std::string getCPUFeatureDescription() const;
  627. protected:
  628. void setInfo(S32 info_type, const LLSD& value);
  629. LLSD getInfo(S32 info_type, const LLSD& default_val) const;
  630. void setConfig(S32 config_type, const LLSD& value);
  631. LLSD getConfig(S32 config_type, const LLSD& default_val) const;
  632. void setExtension(const std::string& name);
  633. bool hasExtension(const std::string& name) const;
  634. // Used to refresh the frequency of the core we are running onto, after
  635. // it was left enough time to reach its turbo frequency. Returns true when
  636. // it detected an increase of the frequency. HB
  637. #if LL_LINUX
  638. bool refreshAffectedCPUFrequency();
  639. #else
  640. LL_INLINE bool refreshAffectedCPUFrequency() { return false; }
  641. #endif
  642. private:
  643. void getCPUIDInfo();
  644. void setInfo(const std::string& name, const LLSD& value);
  645. LLSD getInfo(const std::string& name, const LLSD& defaultVal) const;
  646. void setConfig(const std::string& name, const LLSD& value);
  647. LLSD getConfig(const std::string& name, const LLSD& defaultVal) const;
  648. private:
  649. LLSD mProcessorInfo;
  650. };
  651. enum cpu_info
  652. {
  653. eBrandName = 0,
  654. eFrequency,
  655. eVendor,
  656. eStepping,
  657. eFamily,
  658. eExtendedFamily,
  659. eModel,
  660. eExtendedModel,
  661. eType,
  662. eBrandID,
  663. eFamilyName
  664. };
  665. const char* cpu_info_names[] =
  666. {
  667. "Processor Name",
  668. "Frequency",
  669. "Vendor",
  670. "Stepping",
  671. "Family",
  672. "Extended Family",
  673. "Model",
  674. "Extended Model",
  675. "Type",
  676. "Brand ID",
  677. "Family Name"
  678. };
  679. enum cpu_config
  680. {
  681. eMaxID,
  682. eMaxExtID,
  683. eCLFLUSHCacheLineSize,
  684. eAPICPhysicalID,
  685. eCacheLineSize,
  686. eL2Associativity,
  687. eCacheSizeK,
  688. eFeatureBits,
  689. eExtFeatureBits
  690. };
  691. const char* cpu_config_names[] =
  692. {
  693. "Max Supported CPUID level",
  694. "Max Supported Ext. CPUID level",
  695. "CLFLUSH cache line size",
  696. "APIC Physical ID",
  697. "Cache Line Size",
  698. "L2 Associativity",
  699. "Cache Size",
  700. "Feature Bits",
  701. "Ext. Feature Bits"
  702. };
  703. // *NOTE: Mani - this contains the elements we reference directly and
  704. // extensions beyond the first 32. The rest of the names are referenced by bit
  705. // mask returned from cpuid.
  706. enum cpu_features
  707. {
  708. eSSE2_Ext = 26,
  709. eSSE3_Features = 32,
  710. eMONTIOR_MWAIT = 33,
  711. eCPLDebugStore = 34,
  712. eThermalMonitor2 = 35,
  713. eSSE3S_Features = 37,
  714. eSSE4_1_Features = 38,
  715. eSSE4_2_Features = 39,
  716. eSSE4a_Features = 40,
  717. };
  718. const char* cpu_feature_names[] =
  719. {
  720. "x87 FPU On Chip",
  721. "Virtual-8086 Mode Enhancement",
  722. "Debugging Extensions",
  723. "Page Size Extensions",
  724. "Time Stamp Counter",
  725. "RDMSR and WRMSR Support",
  726. "Physical Address Extensions",
  727. "Machine Check Exception",
  728. "CMPXCHG8B Instruction",
  729. "APIC On Chip",
  730. "Unknown1",
  731. "SYSENTER and SYSEXIT",
  732. "Memory Type Range Registers",
  733. "PTE Global Bit",
  734. "Machine Check Architecture",
  735. "Conditional Move/Compare Instruction",
  736. "Page Attribute Table",
  737. "Page Size Extension",
  738. "Processor Serial Number",
  739. "CFLUSH Extension",
  740. "Unknown2",
  741. "Debug Store",
  742. "Thermal Monitor and Clock Ctrl",
  743. "MMX Technology",
  744. "FXSAVE/FXRSTOR",
  745. "SSE Extensions",
  746. "SSE2 Extensions",
  747. "Self Snoop",
  748. "Hyper-threading Technology",
  749. "Thermal Monitor",
  750. "Unknown4",
  751. "Pend. Brk. EN.", // 31 End of FeatureInfo bits
  752. "SSE3 New Instructions", // 32
  753. "MONITOR/MWAIT",
  754. "CPL Qualified Debug Store",
  755. "Thermal Monitor 2",
  756. "", // No more in use (was "Altivec")
  757. "SSE3S Instructions",
  758. "SSE4.1 Instructions",
  759. "SSE4.2 Instructions",
  760. "SSE4a Instructions",
  761. };
  762. #if SSE2NEON // ARM CPUs only
  763. static std::string arm_cpu_family_name(S32 implementer, S32 cpu_part)
  764. {
  765. std::string name;
  766. switch (implementer)
  767. {
  768. // Table from util-linux' lscpu utility
  769. case 0x41: name = "ARM "; break;
  770. case 0x42: name = "Broadcom "; break;
  771. case 0x43: name = "Cavium "; break;
  772. case 0x44: name = "DEC "; break;
  773. case 0x4e: name = "NVIDIA "; break;
  774. case 0x50: name = "APM "; break;
  775. case 0x51: name = "Qualcomm "; break;
  776. case 0x53: name = "Samsung "; break;
  777. case 0x56: name = "Marvell "; break;
  778. case 0x69: name = "Intel "; break;
  779. default: name = "Unknown implementer ";
  780. }
  781. // Table from https://en.wikipedia.org/wiki/Comparison_of_ARMv8-A_cores
  782. // We only care about 64 bits (ARM v8+) processors.
  783. switch (cpu_part)
  784. {
  785. case 0xd01: name += "Cortex-A32"; break;
  786. case 0xd02: name += "Cortex-A34"; break;
  787. case 0xd03: name += "Cortex-A53"; break;
  788. case 0xd04: name += "Cortex-A35"; break;
  789. case 0xd05: name += "Cortex-A55"; break;
  790. case 0xd06: name += "Cortex-A65"; break;
  791. case 0xd07: name += "Cortex-A57"; break;
  792. case 0xd08: name += "Cortex-A72"; break;
  793. case 0xd09: name += "Cortex-A73"; break;
  794. case 0xd0a: name += "Cortex-A75"; break;
  795. case 0xd0b: name += "Cortex-A76"; break;
  796. case 0xd0d: name += "Cortex-A77"; break;
  797. case 0xd41: name += "Cortex-A78"; break;
  798. case 0xd44: name += "Cortex-X1"; break;
  799. default: name += "unknown model";
  800. }
  801. return name;
  802. }
  803. #else
  804. static std::string intel_cpu_family_name(S32 cpu_part)
  805. {
  806. switch (cpu_part)
  807. {
  808. # if 0 // We do not support these (32 bits) CPUs
  809. case 0x03: return "Intel i386";
  810. case 0x04: return "Intel i486";
  811. case 0x05: return "Intel Pentium";
  812. # endif
  813. case 0x06: return "Intel Pentium Pro/Pentium 2/Pentium 3/Core";
  814. case 0x07: return "Intel Itanium (IA-64)";
  815. case 0x0F: return "Intel Pentium 4/Pentium D/Nocona";
  816. case 0x10: return "Intel Itanium 2 (IA-64)";
  817. }
  818. return llformat("Unknown Intel 0x%.2x family", cpu_part);
  819. }
  820. static std::string amd_cpu_family_name(S32 cpu_part)
  821. {
  822. switch (cpu_part)
  823. {
  824. # if 0 // We do not support these (32 bits) CPUs
  825. case 0x04: return "AMD 80486/5x86";
  826. case 0x05: return "AMD K5/K6";
  827. case 0x06: return "AMD K7";
  828. # endif
  829. case 0x0F: return "AMD K8/Hammer";
  830. case 0x10: return "AMD K10";
  831. case 0x11: return "AMD K8/K10 hybrid";
  832. case 0x12: return "AMD K10 Llano";
  833. case 0x14: return "AMD Bobcat";
  834. case 0x15: return "AMD Bulldozer/Piledriver/Steamroller/Excavator";
  835. case 0x16: return "AMD Jaguar";
  836. case 0x17: return "AMD Zen/Zen+/Zen2";
  837. case 0x18: return "AMD Hygon Dhyana";
  838. case 0x19: return "AMD Zen3/Zen3+/Zen4";
  839. case 0x1A: return "AMD Zen5";
  840. }
  841. return llformat("Unknown AMD 0x%.2x family", cpu_part);
  842. }
  843. #endif
  844. #if LL_LINUX
  845. static const char CPUINFO_FILE[] = "/proc/cpuinfo";
  846. static const char CPUFREQ_FILE[] =
  847. "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_cur_freq";
  848. static std::string get_cpu_family_name(const char* id, S32 cpu_part)
  849. {
  850. # if SSE2NEON
  851. std::stringstream s;
  852. s << std::hex << id;
  853. S32 cpu_id;
  854. s >> cpu_id;
  855. return arm_cpu_family_name(cpu_id, cpu_part);
  856. # else
  857. const char* intel_string = "GenuineIntel";
  858. const char* amd_string = "AuthenticAMD";
  859. if (!strncmp(id, intel_string, strlen(intel_string)))
  860. {
  861. return intel_cpu_family_name(cpu_part);
  862. }
  863. if (!strncmp(id, amd_string, strlen(amd_string)))
  864. {
  865. return amd_cpu_family_name(cpu_part);
  866. }
  867. # endif
  868. return llformat("Unknown CPU vendor: %s", id);
  869. }
  870. #else
  871. static std::string get_cpu_family_name(const char* cpu_vendor, S32 family,
  872. S32 ext_family)
  873. {
  874. const char* intel_string = "GenuineIntel";
  875. const char* amd_string = "AuthenticAMD";
  876. if (!strncmp(cpu_vendor, intel_string, strlen(intel_string)))
  877. {
  878. U32 cpu_part = family + ext_family;
  879. return intel_cpu_family_name(cpu_part);
  880. }
  881. if (!strncmp(cpu_vendor, amd_string, strlen(amd_string)))
  882. {
  883. U32 cpu_part = family == 0xF ? family + ext_family : family;
  884. return amd_cpu_family_name(cpu_part);
  885. }
  886. return llformat("Unknown CPU vendor: %s", cpu_vendor);
  887. }
  888. #endif
  889. #if LL_WINDOWS
  890. typedef struct _PROCESSOR_POWER_INFORMATION
  891. {
  892. ULONG Number;
  893. ULONG MaxMhz;
  894. ULONG CurrentMhz;
  895. ULONG MhzLimit;
  896. ULONG MaxIdleState;
  897. ULONG CurrentIdleState;
  898. } PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;
  899. // Normally, the return type should be NTSTATUS, but the latter is defined in
  900. // a header that conficts with the already included windows.h header (Windoze
  901. // sucks !)... Since it is just an enum, simply use an int for our typedef. HB
  902. typedef int (FAR WINAPI* CALLNTPOWERINFORMATION)(POWER_INFORMATION_LEVEL,
  903. PVOID, ULONG, PVOID, ULONG);
  904. // Returns the detected CPU core frequency in MHz for the core running the
  905. // viewer, or 0.0 in case of failure. 'method' is set to 0 in case of failure,
  906. // 1 when the detection was done via the system power service, or 2 when the
  907. // frequency was measured based on a TSC timing loop. Note: this function does
  908. // not work properly with modern CPUs and their turbo modes. Windows does not
  909. // expose any user-level API to determine their actual, running frequency, and
  910. // determining it by ourselves would mean running the viewer with admin
  911. // priviledges or using a custom (and signed) driver, in order to access the
  912. // MSRs; it would also mean implementing CPU model-specific MSR decoding... HB
  913. static F64 calculate_cpu_frequency(U32 cores, U32& method)
  914. {
  915. method = 0;
  916. F64 frequency = 0.0;
  917. // We set the process and thread priority to the highest available level
  918. // (realtime priority). Also we set the process affinity to the first
  919. // processor in the multiprocessor system.
  920. HANDLE processh = GetCurrentProcess();
  921. HANDLE threadh = GetCurrentThread();
  922. unsigned long prio_class = GetPriorityClass(processh);
  923. int thread_prio = GetThreadPriority(threadh);
  924. DWORD_PTR process_mask, system_mask;
  925. GetProcessAffinityMask(processh, &process_mask, &system_mask);
  926. SetPriorityClass(processh, REALTIME_PRIORITY_CLASS);
  927. SetThreadPriority(threadh, THREAD_PRIORITY_TIME_CRITICAL);
  928. DWORD_PTR new_mask = 1;
  929. SetProcessAffinityMask(processh, new_mask);
  930. if (cores)
  931. {
  932. // We first try to get the actual CPU frequency for the CPU core we are
  933. // running on via the system power service. Amusingly, this code always
  934. // works beautifully when running via Wine under Linux, but fails to
  935. // report the *actual* frequency in CurrentMhz under Windows with modern
  936. // CPUs (anything after the Core2 Quad, for Intel)... HB
  937. HINSTANCE h_dll = LoadLibraryW(L"powrprof.dll");
  938. if (h_dll)
  939. {
  940. CALLNTPOWERINFORMATION proc =
  941. (CALLNTPOWERINFORMATION)GetProcAddress(h_dll,
  942. "CallNtPowerInformation");
  943. if (proc)
  944. {
  945. int size = cores * sizeof(PROCESSOR_POWER_INFORMATION);
  946. LPBYTE bufferp = new BYTE[size];
  947. if ((*proc)(ProcessorInformation, NULL, 0, bufferp, size) == 0)
  948. {
  949. PPROCESSOR_POWER_INFORMATION ppi =
  950. (PPROCESSOR_POWER_INFORMATION)bufferp;
  951. frequency = F64(ppi->CurrentMhz);
  952. method = 1;
  953. }
  954. delete[] bufferp;
  955. }
  956. FreeLibrary(h_dll);
  957. }
  958. }
  959. // If the above failed, fall back to an unreliable method, involving
  960. // performance counters (based on the TSC), which is sadly (and just as
  961. // well as the system power service method) incapable of reporting turbo
  962. // frequencies on modern CPUs... HB
  963. if (frequency == 0.0)
  964. {
  965. // Check the frequency of the high resolution timer for the measure
  966. // process.
  967. LARGE_INTEGER wait;
  968. if (QueryPerformanceFrequency((LARGE_INTEGER*)&wait))
  969. {
  970. wait.QuadPart >>= 7; // 128ms for a 1ms resolution
  971. // Call a CPUID to ensure, that all other prior called functions
  972. // are completed now (serialization).
  973. int cpu_info[4] = { -1 };
  974. __cpuid(cpu_info, 0);
  975. LARGE_INTEGER start, current;
  976. QueryPerformanceCounter(&start);
  977. unsigned __int64 start_time = __rdtsc();
  978. do
  979. {
  980. QueryPerformanceCounter(&current);
  981. }
  982. while (current.QuadPart - start.QuadPart < wait.QuadPart);
  983. frequency = F64(((__rdtsc() - start_time) << 7) / 1000000UL);
  984. method = 2;
  985. }
  986. }
  987. // Now we can restore the default process and thread priorities
  988. SetProcessAffinityMask(processh, process_mask);
  989. SetThreadPriority(threadh, thread_prio);
  990. SetPriorityClass(processh, prio_class);
  991. return frequency;
  992. }
  993. #elif LL_DARWIN
  994. static int get_sysctl(const char* name)
  995. {
  996. int result = 0;
  997. size_t len = sizeof(int);
  998. int error = sysctlbyname(name, (void*)&result, &len, NULL, 0);
  999. return error == -1 ? 0 : result;
  1000. }
  1001. static uint64_t get_sysctl64(const char* name)
  1002. {
  1003. uint64_t value = 0;
  1004. size_t size = sizeof(value);
  1005. int result = sysctlbyname(name, (void*)&value, &size, NULL, 0);
  1006. if (result == 0)
  1007. {
  1008. if (size == sizeof(uint64_t))
  1009. {
  1010. // Nothing to do
  1011. }
  1012. else if (size == sizeof(uint32_t))
  1013. {
  1014. value = (uint64_t)((uint32_t*)&value);
  1015. }
  1016. else if (size == sizeof(uint16_t))
  1017. {
  1018. value = (uint64_t)((uint16_t*)&value);
  1019. }
  1020. else if (size == sizeof(uint8_t))
  1021. {
  1022. value = (uint64_t)((uint8_t*)&value);
  1023. }
  1024. else
  1025. {
  1026. llwarns << "Unknown type returned from sysctl !" << llendl;
  1027. }
  1028. }
  1029. return result == -1 ? 0 : value;
  1030. }
  1031. #endif
  1032. LLProcessorInfo::LLProcessorInfo()
  1033. {
  1034. mProcessorInfo["info"] = LLSD::emptyMap();
  1035. mProcessorInfo["config"] = LLSD::emptyMap();
  1036. mProcessorInfo["extension"] = LLSD::emptyMap();
  1037. getCPUIDInfo();
  1038. S32 threads = boost::thread::hardware_concurrency();
  1039. #if LL_WINDOWS
  1040. U32 vcores = threads;
  1041. #endif
  1042. mProcessorInfo["virtual_cores"] = threads;
  1043. S32 cores = boost::thread::physical_concurrency();
  1044. mProcessorInfo["physical_cores"] = cores;
  1045. if (!threads)
  1046. {
  1047. llwarns << "Could not determine hardware thread concurrency on this platform !"
  1048. << llendl;
  1049. threads = 4; // Use a sane default: 4 threads
  1050. }
  1051. else if (threads != cores && threads > 4)
  1052. {
  1053. // For multi-core CPUs with SMT and and more than 4 threads, reserve
  1054. // two threads to the main loop.
  1055. threads -= 2;
  1056. }
  1057. else if (threads > 1)
  1058. {
  1059. // For multi-core CPUs without SMT or with 4 threads or less, reserve
  1060. // one core or thread to the main loop.
  1061. --threads;
  1062. }
  1063. mProcessorInfo["max_child_threads"] = threads;
  1064. #if LL_WINDOWS
  1065. U32 method = 0;
  1066. setInfo(eFrequency, calculate_cpu_frequency(vcores, method));
  1067. if (method)
  1068. {
  1069. llinfos << "Got the CPU frequency via "
  1070. << (method == 1 ? "the system power service"
  1071. : "a TSC timing loop")
  1072. << " (this sadly does not account for turbo modes of modern CPUs)."
  1073. << llendl;
  1074. }
  1075. else
  1076. {
  1077. llwarns << "Failed to determine the CPU frequency." << llendl;
  1078. }
  1079. #elif LL_DARWIN
  1080. U64 frequency = get_sysctl64("hw.cpufrequency");
  1081. if (!frequency)
  1082. {
  1083. struct clockinfo clockrate;
  1084. size_t clockrate_len = sizeof(clockrate);
  1085. int error = sysctlbyname("kern.clockrate", (void*)&clockrate,
  1086. &clockrate_len, NULL, 0);
  1087. if (error)
  1088. {
  1089. llwarns << "Failed to determine the CPU frequency." << llendl;
  1090. }
  1091. else
  1092. {
  1093. frequency = get_sysctl64("hw.tbfrequency") * clockrate.hz;
  1094. }
  1095. }
  1096. setInfo(eFrequency, (F64)frequency / (F64)1000000);
  1097. #endif
  1098. }
  1099. F64 LLProcessorInfo::getCPUFrequency() const
  1100. {
  1101. return getInfo(eFrequency, 0).asReal();
  1102. }
  1103. bool LLProcessorInfo::hasSSE2() const
  1104. {
  1105. return hasExtension(cpu_feature_names[eSSE2_Ext]);
  1106. }
  1107. bool LLProcessorInfo::hasSSE3() const
  1108. {
  1109. return hasExtension(cpu_feature_names[eSSE3_Features]);
  1110. }
  1111. bool LLProcessorInfo::hasSSE3S() const
  1112. {
  1113. return hasExtension(cpu_feature_names[eSSE3S_Features]);
  1114. }
  1115. bool LLProcessorInfo::hasSSE41() const
  1116. {
  1117. return hasExtension(cpu_feature_names[eSSE4_1_Features]);
  1118. }
  1119. bool LLProcessorInfo::hasSSE42() const
  1120. {
  1121. return hasExtension(cpu_feature_names[eSSE4_2_Features]);
  1122. }
  1123. bool LLProcessorInfo::hasSSE4a() const
  1124. {
  1125. return hasExtension(cpu_feature_names[eSSE4a_Features]);
  1126. }
  1127. U32 LLProcessorInfo::getPhysicalCores() const
  1128. {
  1129. return U32(mProcessorInfo["physical_cores"].asInteger());
  1130. }
  1131. U32 LLProcessorInfo::getVirtualCores() const
  1132. {
  1133. return U32(mProcessorInfo["virtual_cores"].asInteger());
  1134. }
  1135. U32 LLProcessorInfo::getMaxChildThreads() const
  1136. {
  1137. return U32(mProcessorInfo["max_child_threads"].asInteger());
  1138. }
  1139. std::string LLProcessorInfo::getCPUFamilyName() const
  1140. {
  1141. return getInfo(eFamilyName, "Unset family").asString();
  1142. }
  1143. std::string LLProcessorInfo::getCPUBrandName() const
  1144. {
  1145. return getInfo(eBrandName, "Unset brand").asString();
  1146. }
  1147. void LLProcessorInfo::setInfo(S32 info_type, const LLSD& value)
  1148. {
  1149. setInfo(cpu_info_names[info_type], value);
  1150. }
  1151. LLSD LLProcessorInfo::getInfo(S32 info_type, const LLSD& defaultVal) const
  1152. {
  1153. return getInfo(cpu_info_names[info_type], defaultVal);
  1154. }
  1155. void LLProcessorInfo::setConfig(S32 config_type, const LLSD& value)
  1156. {
  1157. setConfig(cpu_config_names[config_type], value);
  1158. }
  1159. LLSD LLProcessorInfo::getConfig(S32 config_type, const LLSD& defaultVal) const
  1160. {
  1161. return getConfig(cpu_config_names[config_type], defaultVal);
  1162. }
  1163. void LLProcessorInfo::setExtension(const std::string& name)
  1164. {
  1165. mProcessorInfo["extension"][name] = "true";
  1166. }
  1167. bool LLProcessorInfo::hasExtension(const std::string& name) const
  1168. {
  1169. return mProcessorInfo["extension"].has(name);
  1170. }
  1171. void LLProcessorInfo::setInfo(const std::string& name, const LLSD& value)
  1172. {
  1173. mProcessorInfo["info"][name] = value;
  1174. }
  1175. LLSD LLProcessorInfo::getInfo(const std::string& name,
  1176. const LLSD& default_val) const
  1177. {
  1178. if (mProcessorInfo["info"].has(name))
  1179. {
  1180. return mProcessorInfo["info"][name];
  1181. }
  1182. return default_val;
  1183. }
  1184. void LLProcessorInfo::setConfig(const std::string& name, const LLSD& value)
  1185. {
  1186. mProcessorInfo["config"][name] = value;
  1187. }
  1188. LLSD LLProcessorInfo::getConfig(const std::string& name,
  1189. const LLSD& default_val) const
  1190. {
  1191. LLSD r = mProcessorInfo["config"].get(name);
  1192. return r.isDefined() ? r : default_val;
  1193. }
  1194. #if LL_LINUX
  1195. std::string LLProcessorInfo::getCPUFeatureDescription() const
  1196. {
  1197. std::ostringstream s;
  1198. // *NOTE:Mani - This is for linux only.
  1199. LLFILE* cpuinfo = LLFile::open(CPUINFO_FILE, "rb");
  1200. if (cpuinfo)
  1201. {
  1202. constexpr size_t BUFFER_LEN = 32768;
  1203. char line[BUFFER_LEN];
  1204. memset(line, 0, BUFFER_LEN);
  1205. while(fgets(line, BUFFER_LEN, cpuinfo))
  1206. {
  1207. line[strlen(line) - 1] = ' ';
  1208. s << line;
  1209. s << std::endl;
  1210. }
  1211. LLFile::close(cpuinfo);
  1212. s << std::endl;
  1213. }
  1214. else
  1215. {
  1216. s << "Unable to collect processor information" << std::endl;
  1217. }
  1218. return s.str();
  1219. }
  1220. #else
  1221. std::string LLProcessorInfo::getCPUFeatureDescription() const
  1222. {
  1223. std::ostringstream out;
  1224. out << std::endl << std::endl;
  1225. out << "// CPU General Information" << std::endl;
  1226. out << "//////////////////////////" << std::endl;
  1227. out << "Processor Name: " << getCPUBrandName() << std::endl;
  1228. out << "Frequency: " << getCPUFrequency() << " MHz"
  1229. << std::endl;
  1230. out << "Vendor: "
  1231. << getInfo(eVendor, "Unset vendor").asString()
  1232. << std::endl;
  1233. out << "Family: " << getCPUFamilyName() << " ("
  1234. << getInfo(eFamily, 0) << ")" << std::endl;
  1235. out << "Extended family: " << getInfo(eExtendedFamily, 0).asInteger()
  1236. << std::endl;
  1237. out << "Model: " << getInfo(eModel, 0).asInteger() << std::endl;
  1238. out << "Extended model: " << getInfo(eExtendedModel, 0).asInteger()
  1239. << std::endl;
  1240. out << "Type: " << getInfo(eType, 0).asInteger() << std::endl;
  1241. out << "Brand ID: " << getInfo(eBrandID, 0).asInteger()
  1242. << std::endl;
  1243. out << std::endl;
  1244. out << "// CPU Configuration" << std::endl;
  1245. out << "//////////////////////////" << std::endl;
  1246. // Iterate through the dictionary of configuration options.
  1247. LLSD configs = mProcessorInfo["config"];
  1248. for (LLSD::map_const_iterator cfgItr = configs.beginMap();
  1249. cfgItr != configs.endMap(); ++cfgItr)
  1250. {
  1251. out << cfgItr->first << " = " << cfgItr->second.asInteger()
  1252. << std::endl;
  1253. }
  1254. out << std::endl;
  1255. out << "// CPU Extensions" << std::endl;
  1256. out << "//////////////////////////" << std::endl;
  1257. for (LLSD::map_const_iterator
  1258. itr = mProcessorInfo["extension"].beginMap();
  1259. itr != mProcessorInfo["extension"].endMap(); ++itr)
  1260. {
  1261. out << " " << itr->first << std::endl;
  1262. }
  1263. return out.str();
  1264. }
  1265. #endif // LL_LINUX
  1266. #if LL_LINUX
  1267. static std::map<std::string, std::string> sCPUInfo;
  1268. static S32 get_affected_cpu_info()
  1269. {
  1270. // By default (-1), no info on the CPU/core we are running onto.
  1271. S32 result = -1;
  1272. unsigned int cpu = 0;
  1273. # if defined(getcpu) // glibc v2.29+
  1274. if (getcpu(&cpu, NULL) == 0)
  1275. {
  1276. result = (S32)cpu;
  1277. }
  1278. # elif defined(SYS_getcpu) // Linux after v2.6.20
  1279. if (syscall(SYS_getcpu, &cpu, NULL, NULL) != -1)
  1280. {
  1281. result = (S32)cpu;
  1282. }
  1283. # endif
  1284. std::string next_cpu = llformat("%d", cpu + 1);
  1285. LLFILE* cpuinfo_fp = LLFile::open(CPUINFO_FILE, "rb");
  1286. if (!cpuinfo_fp)
  1287. {
  1288. return -2; // Code for no CPUINFO_FILE file !
  1289. }
  1290. sCPUInfo.clear();
  1291. bool has_freq = false;
  1292. constexpr size_t BUFFER_LEN = 32768;
  1293. char line[BUFFER_LEN];
  1294. memset(line, 0, BUFFER_LEN);
  1295. while (fgets(line, BUFFER_LEN, cpuinfo_fp))
  1296. {
  1297. // /proc/cpuinfo on Linux looks like:
  1298. // name\t*: value\n
  1299. char* tabspot = strchr(line, '\t');
  1300. if (!tabspot) continue;
  1301. char* colspot = strchr(tabspot, ':');
  1302. if (!colspot) continue;
  1303. char* spacespot = strchr(colspot, ' ');
  1304. if (!spacespot) continue;
  1305. char* nlspot = strchr(line, '\n');
  1306. if (!nlspot)
  1307. {
  1308. // Fallback to terminating NUL
  1309. nlspot = line + strlen(line);
  1310. }
  1311. std::string linename(line, tabspot);
  1312. std::string llinename(linename);
  1313. LLStringUtil::toLower(llinename);
  1314. std::string lineval(spacespot + 1, nlspot);
  1315. if (llinename == "processor" && lineval == next_cpu)
  1316. {
  1317. break;
  1318. }
  1319. sCPUInfo[llinename] = lineval;
  1320. if (!has_freq && llinename == "cpu mhz")
  1321. {
  1322. has_freq = true;
  1323. }
  1324. }
  1325. LLFile::close(cpuinfo_fp);
  1326. if (!has_freq)
  1327. {
  1328. // Try cpufreq instead...
  1329. llifstream s(llformat(CPUFREQ_FILE, cpu).c_str());
  1330. if (s.is_open())
  1331. {
  1332. S32 freq;
  1333. s >> freq;
  1334. sCPUInfo["cpu mhz"] = llformat("%.2f", F32(freq) * 0.001f);
  1335. }
  1336. }
  1337. return result;
  1338. }
  1339. void LLProcessorInfo::getCPUIDInfo()
  1340. {
  1341. S32 cpu = get_affected_cpu_info();
  1342. if (cpu == -2)
  1343. {
  1344. llwarns << "Could not get any CPU information: " << CPUINFO_FILE
  1345. << " file not found !" << llendl;
  1346. return;
  1347. }
  1348. if (cpu >= 0)
  1349. {
  1350. llinfos << "Running on CPU/core #" << cpu << llendl;
  1351. }
  1352. else
  1353. {
  1354. llwarns << "Could not determine on which CPU/core we are running."
  1355. << llendl;
  1356. cpu = 0; // Use the info for the first core...
  1357. }
  1358. F64 mhz = 0.0;
  1359. if (LLStringUtil::convertToF64(sCPUInfo["cpu mhz"], mhz) &&
  1360. mhz > 200.0 && mhz < 10000.0)
  1361. {
  1362. setInfo(eFrequency, mhz);
  1363. }
  1364. #define LLPI_SET_INFO_STRING(llpi_id, cpuinfo_id) \
  1365. if (!sCPUInfo[cpuinfo_id].empty()) \
  1366. { setInfo(llpi_id, sCPUInfo[cpuinfo_id]);}
  1367. #define LLPI_SET_INFO_INT(llpi_id, cpuinfo_id) \
  1368. {\
  1369. S32 result; \
  1370. if (!sCPUInfo[cpuinfo_id].empty() \
  1371. && LLStringUtil::convertToS32(sCPUInfo[cpuinfo_id], result)) \
  1372. { setInfo(llpi_id, result);} \
  1373. }
  1374. LLPI_SET_INFO_STRING(eBrandName, "model name");
  1375. LLPI_SET_INFO_STRING(eVendor, "vendor_id");
  1376. LLPI_SET_INFO_INT(eStepping, "stepping");
  1377. LLPI_SET_INFO_INT(eModel, "model");
  1378. S32 family = 0;
  1379. # if SSE2NEON
  1380. // No "vendor_id" in /proc/cpuinfo for ARM: use "cpu implementer"
  1381. // instead. HB
  1382. const std::string& id = sCPUInfo["cpu implementer"];
  1383. // No "cpu family" in /proc/cpuinfo for ARM: use "cpu part" instead to
  1384. // identify the CPU model. HB
  1385. if (!sCPUInfo["cpu part"].empty())
  1386. {
  1387. std::stringstream s;
  1388. s << std::hex << sCPUInfo["cpu part"];
  1389. s >> family;
  1390. setInfo(eFamily, family);
  1391. }
  1392. #else
  1393. const std::string& id = sCPUInfo["vendor_id"];
  1394. if (!sCPUInfo["cpu family"].empty() &&
  1395. LLStringUtil::convertToS32(sCPUInfo["cpu family"], family))
  1396. {
  1397. setInfo(eFamily, family);
  1398. }
  1399. #endif
  1400. std::string cpu_family = get_cpu_family_name(id.c_str(), family);
  1401. setInfo(eFamilyName, cpu_family);
  1402. #if SSE2NEON
  1403. // There is no "model name" in /proc/cpuinfo for ARM: use the family name
  1404. // we just got, instead... HB
  1405. setInfo(eBrandName, cpu_family);
  1406. #endif
  1407. // Read extensions
  1408. std::string flags = " " + sCPUInfo["flags"] + " ";
  1409. LLStringUtil::toLower(flags);
  1410. # if SSE2NEON // Force SSE2 flag on if we got Neon-translated SSE2... HB
  1411. setExtension(cpu_feature_names[eSSE2_Ext]);
  1412. # else
  1413. if (flags.find(" sse2 ") != std::string::npos)
  1414. {
  1415. setExtension(cpu_feature_names[eSSE2_Ext]);
  1416. }
  1417. if (flags.find(" pni ") != std::string::npos)
  1418. {
  1419. setExtension(cpu_feature_names[eSSE3_Features]);
  1420. }
  1421. if (flags.find(" ssse3 ") != std::string::npos)
  1422. {
  1423. setExtension(cpu_feature_names[eSSE3S_Features]);
  1424. }
  1425. if (flags.find(" sse4_1 ") != std::string::npos)
  1426. {
  1427. setExtension(cpu_feature_names[eSSE4_1_Features]);
  1428. }
  1429. if (flags.find(" sse4_2 ") != std::string::npos)
  1430. {
  1431. setExtension(cpu_feature_names[eSSE4_2_Features]);
  1432. }
  1433. if (flags.find(" sse4a ") != std::string::npos)
  1434. {
  1435. setExtension(cpu_feature_names[eSSE4a_Features]);
  1436. }
  1437. # endif
  1438. }
  1439. bool LLProcessorInfo::refreshAffectedCPUFrequency()
  1440. {
  1441. S32 cpu = get_affected_cpu_info();
  1442. if (cpu >= 0)
  1443. {
  1444. // Do not account for this little a change in frequency (in MHz). HB
  1445. constexpr F64 CPU_FREQ_JITTER = 16.0;
  1446. F64 mhz;
  1447. if (LLStringUtil::convertToF64(sCPUInfo["cpu mhz"], mhz) &&
  1448. mhz > 200.0 && mhz < 10000.0 &&
  1449. mhz > getCPUFrequency() + CPU_FREQ_JITTER)
  1450. {
  1451. setInfo(eFrequency, mhz);
  1452. llinfos << "Detected increased CPU/core frequency: " << mhz
  1453. << "MHz" << llendl;
  1454. return true;
  1455. }
  1456. }
  1457. return false;
  1458. }
  1459. #elif LL_DARWIN
  1460. void LLProcessorInfo::getCPUIDInfo()
  1461. {
  1462. size_t len = 0;
  1463. char cpu_brand_string[0x40];
  1464. len = sizeof(cpu_brand_string);
  1465. memset(cpu_brand_string, 0, len);
  1466. sysctlbyname("machdep.cpu.brand_string",
  1467. (void*)cpu_brand_string, &len, NULL, 0);
  1468. cpu_brand_string[0x3f] = 0;
  1469. setInfo(eBrandName, cpu_brand_string);
  1470. char cpu_vendor[0x20];
  1471. len = sizeof(cpu_vendor);
  1472. memset(cpu_vendor, 0, len);
  1473. sysctlbyname("machdep.cpu.vendor", (void*)cpu_vendor, &len, NULL, 0);
  1474. cpu_vendor[0x1f] = 0;
  1475. setInfo(eVendor, cpu_vendor);
  1476. setInfo(eStepping, get_sysctl("machdep.cpu.stepping"));
  1477. setInfo(eModel, get_sysctl("machdep.cpu.model"));
  1478. int family = get_sysctl("machdep.cpu.family");
  1479. int ext_family = get_sysctl("machdep.cpu.extfamily");
  1480. setInfo(eFamily, family);
  1481. setInfo(eExtendedFamily, ext_family);
  1482. setInfo(eFamilyName, get_cpu_family_name(cpu_vendor, family, ext_family));
  1483. setInfo(eExtendedModel, get_sysctl("machdep.cpu.extmodel"));
  1484. setInfo(eBrandID, get_sysctl("machdep.cpu.brand"));
  1485. setInfo(eType, 0); // ? where to find this?
  1486. setConfig(eCacheLineSize, get_sysctl("machdep.cpu.cache.linesize"));
  1487. setConfig(eL2Associativity,
  1488. get_sysctl("machdep.cpu.cache.L2_associativity"));
  1489. setConfig(eCacheSizeK, get_sysctl("machdep.cpu.cache.size"));
  1490. uint64_t feature_info = get_sysctl64("machdep.cpu.feature_bits");
  1491. S32* feature_infos = (S32*)(&feature_info);
  1492. setConfig(eFeatureBits, feature_infos[0]);
  1493. char cpu_features[1024];
  1494. len = sizeof(cpu_features);
  1495. memset((void*)cpu_features, 0, len);
  1496. sysctlbyname("machdep.cpu.features", (void*)cpu_features, &len, NULL, 0);
  1497. std::string cpu_features_str(cpu_features);
  1498. cpu_features_str = " " + cpu_features_str + " ";
  1499. if (cpu_features_str.find(" SSE3 ") != std::string::npos)
  1500. {
  1501. setExtension(cpu_feature_names[eSSE3_Features]);
  1502. }
  1503. if (cpu_features_str.find(" SSE3 ") != std::string::npos)
  1504. {
  1505. setExtension(cpu_feature_names[eSSE3_Features]);
  1506. }
  1507. if (cpu_features_str.find(" SSSE3 ") != std::string::npos)
  1508. {
  1509. setExtension(cpu_feature_names[eSSE3S_Features]);
  1510. }
  1511. if (cpu_features_str.find(" SSE4.1 ") != std::string::npos)
  1512. {
  1513. setExtension(cpu_feature_names[eSSE4_1_Features]);
  1514. }
  1515. if (cpu_features_str.find(" SSE4.2 ") != std::string::npos)
  1516. {
  1517. setExtension(cpu_feature_names[eSSE4_2_Features]);
  1518. }
  1519. if (cpu_features_str.find(" SSE4A ") != std::string::npos)
  1520. {
  1521. setExtension(cpu_feature_names[eSSE4a_Features]);
  1522. }
  1523. for (unsigned int index = 0, bit = 1; index < eSSE3_Features;
  1524. ++index, bit <<= 1)
  1525. {
  1526. if (feature_info & bit)
  1527. {
  1528. setExtension(cpu_feature_names[index]);
  1529. }
  1530. }
  1531. uint64_t ext_feature_info = get_sysctl64("machdep.cpu.extfeature_bits");
  1532. S32 *ext_feature_infos = (S32*)(&ext_feature_info);
  1533. setConfig(eExtFeatureBits, ext_feature_infos[0]);
  1534. }
  1535. #elif LL_WINDOWS
  1536. void LLProcessorInfo::getCPUIDInfo()
  1537. {
  1538. // http://msdn.microsoft.com/en-us/library/hskdteyh(VS.80).aspx
  1539. // __cpuid with an InfoType argument of 0 returns the number of
  1540. // valid Ids in cpu_info[0] and the CPU identification string in
  1541. // the other three array elements. The CPU identification string is
  1542. // not in linear order. The code below arranges the information
  1543. // in a human readable form.
  1544. int cpu_info[4] = { -1 };
  1545. __cpuid(cpu_info, 0);
  1546. unsigned int ids = (unsigned int)cpu_info[0];
  1547. setConfig(eMaxID, (S32)ids);
  1548. char cpu_vendor[0x20];
  1549. memset(cpu_vendor, 0, sizeof(cpu_vendor));
  1550. *((int*)cpu_vendor) = cpu_info[1];
  1551. *((int*)(cpu_vendor + 4)) = cpu_info[3];
  1552. *((int*)(cpu_vendor + 8)) = cpu_info[2];
  1553. setInfo(eVendor, cpu_vendor);
  1554. bool is_amd = !strncmp(cpu_vendor, "AuthenticAMD", 12);
  1555. // Get the information associated with each valid Id
  1556. for (unsigned int i = 0; i <= ids; ++i)
  1557. {
  1558. __cpuid(cpu_info, i);
  1559. // Interpret CPU feature information.
  1560. if (i == 1)
  1561. {
  1562. setInfo(eStepping, cpu_info[0] & 0xf);
  1563. setInfo(eModel, (cpu_info[0] >> 4) & 0xf);
  1564. int family = (cpu_info[0] >> 8) & 0xf;
  1565. setInfo(eFamily, family);
  1566. setInfo(eType, (cpu_info[0] >> 12) & 0x3);
  1567. setInfo(eExtendedModel, (cpu_info[0] >> 16) & 0xf);
  1568. int ext_family = (cpu_info[0] >> 20) & 0xff;
  1569. setInfo(eExtendedFamily, ext_family);
  1570. setInfo(eBrandID, cpu_info[1] & 0xff);
  1571. setInfo(eFamilyName,
  1572. get_cpu_family_name(cpu_vendor, family, ext_family));
  1573. setConfig(eCLFLUSHCacheLineSize,
  1574. ((cpu_info[1] >> 8) & 0xff) * 8);
  1575. setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff);
  1576. if (cpu_info[2] & 0x1)
  1577. {
  1578. setExtension(cpu_feature_names[eSSE3_Features]);
  1579. }
  1580. if (cpu_info[2] & 0x8)
  1581. {
  1582. // Intel specific SSE3 suplements
  1583. setExtension(cpu_feature_names[eMONTIOR_MWAIT]);
  1584. }
  1585. if (cpu_info[2] & 0x10)
  1586. {
  1587. setExtension(cpu_feature_names[eCPLDebugStore]);
  1588. }
  1589. if (cpu_info[2] & 0x100)
  1590. {
  1591. setExtension(cpu_feature_names[eThermalMonitor2]);
  1592. }
  1593. if (cpu_info[2] & 0x200)
  1594. {
  1595. setExtension(cpu_feature_names[eSSE3S_Features]);
  1596. }
  1597. if (cpu_info[2] & 0x80000)
  1598. {
  1599. setExtension(cpu_feature_names[eSSE4_1_Features]);
  1600. }
  1601. if (cpu_info[2] & 0x100000)
  1602. {
  1603. setExtension(cpu_feature_names[eSSE4_2_Features]);
  1604. }
  1605. unsigned int feature_info = (unsigned int) cpu_info[3];
  1606. for (unsigned int index = 0, bit = 1; index < eSSE3_Features;
  1607. ++index, bit <<= 1)
  1608. {
  1609. if (feature_info & bit)
  1610. {
  1611. setExtension(cpu_feature_names[index]);
  1612. }
  1613. }
  1614. }
  1615. }
  1616. // Calling __cpuid with 0x80000000 as the InfoType argument gets the number
  1617. // of valid extended IDs.
  1618. __cpuid(cpu_info, 0x80000000);
  1619. unsigned int ext_ids = cpu_info[0];
  1620. setConfig(eMaxExtID, 0);
  1621. char cpu_brand_string[0x40];
  1622. memset(cpu_brand_string, 0, sizeof(cpu_brand_string));
  1623. // Get the information associated with each extended ID.
  1624. for (unsigned int i = 0x80000000; i <= ext_ids; ++i)
  1625. {
  1626. __cpuid(cpu_info, i);
  1627. // Interpret CPU brand string and cache information.
  1628. if (i == 0x80000001)
  1629. {
  1630. if (is_amd)
  1631. {
  1632. setExtension(cpu_feature_names[eSSE4a_Features]);
  1633. }
  1634. }
  1635. else if (i == 0x80000002)
  1636. {
  1637. memcpy(cpu_brand_string, cpu_info, sizeof(cpu_info));
  1638. }
  1639. else if (i == 0x80000003)
  1640. {
  1641. memcpy(cpu_brand_string + 16, cpu_info, sizeof(cpu_info));
  1642. }
  1643. else if (i == 0x80000004)
  1644. {
  1645. memcpy(cpu_brand_string + 32, cpu_info, sizeof(cpu_info));
  1646. setInfo(eBrandName, cpu_brand_string);
  1647. }
  1648. else if (i == 0x80000006)
  1649. {
  1650. setConfig(eCacheLineSize, cpu_info[2] & 0xff);
  1651. setConfig(eL2Associativity, (cpu_info[2] >> 12) & 0xf);
  1652. setConfig(eCacheSizeK, (cpu_info[2] >> 16) & 0xffff);
  1653. }
  1654. }
  1655. }
  1656. #endif // LL_WINDOWS
  1657. ///////////////////////////////////////////////////////////////////////////////
  1658. // LLCPUInfo class
  1659. ///////////////////////////////////////////////////////////////////////////////
  1660. // Static members
  1661. U32 LLCPUInfo::sMainThreadAffinityMask = 0;
  1662. bool LLCPUInfo::sMainThreadAffinitySet = false;
  1663. LLCPUInfo::LLCPUInfo()
  1664. : mImpl(new LLProcessorInfo)
  1665. {
  1666. mHasSSE2 = mImpl->hasSSE2();
  1667. mHasSSE3 = mImpl->hasSSE3();
  1668. mHasSSE3S = mImpl->hasSSE3S();
  1669. mHasSSE41 = mImpl->hasSSE41();
  1670. mHasSSE42 = mImpl->hasSSE42();
  1671. mHasSSE4a = mImpl->hasSSE4a();
  1672. mCPUMHz = mImpl->getCPUFrequency();
  1673. mFamily = mImpl->getCPUFamilyName();
  1674. mCPUString = mImpl->getCPUBrandName();
  1675. mPhysicalCores = mImpl->getPhysicalCores();
  1676. mVirtualCores = mImpl->getVirtualCores();
  1677. mMaxChildThreads = mImpl->getMaxChildThreads();
  1678. }
  1679. LLCPUInfo::~LLCPUInfo()
  1680. {
  1681. delete mImpl;
  1682. mImpl = NULL;
  1683. }
  1684. S32 LLCPUInfo::affectedCoreFreqDelta()
  1685. {
  1686. if (mImpl->refreshAffectedCPUFrequency())
  1687. {
  1688. F64 old_freq = mCPUMHz;
  1689. mCPUMHz = mImpl->getCPUFrequency();
  1690. return (S32)(mCPUMHz - old_freq);
  1691. }
  1692. return 0;
  1693. }
  1694. std::string LLCPUInfo::getCPUString(bool update_freq)
  1695. {
  1696. // If requested (i.e. we are not in a hurry), check (and possibly update)
  1697. // the affected CPU/core frequency stat for when where we want a more
  1698. // accurate/current figure (e.g. in the About floater). HB
  1699. if (update_freq)
  1700. {
  1701. affectedCoreFreqDelta();
  1702. }
  1703. // *NOTE: cpu speed is often way wrong, do a sanity check
  1704. if (mCPUMHz <= 200 || mCPUMHz >= 10000)
  1705. {
  1706. return mCPUString;
  1707. }
  1708. return mCPUString + llformat(" (%d MHz)", (S32)mCPUMHz);
  1709. }
  1710. LLSD LLCPUInfo::getSSEVersions() const
  1711. {
  1712. LLSD sse_versions;
  1713. #if SSE2NEON
  1714. // Let's report Neon for AMR64 builds... HB
  1715. sse_versions.append("Neon");
  1716. #else
  1717. if (mHasSSE2)
  1718. {
  1719. // All x86_64 CPUs got SSE1... and SSE2...
  1720. // *TODO: eliminate the SSE2 test ? HB
  1721. sse_versions.append("1");
  1722. sse_versions.append("2");
  1723. }
  1724. if (mHasSSE3)
  1725. {
  1726. sse_versions.append("3");
  1727. }
  1728. if (mHasSSE3S)
  1729. {
  1730. sse_versions.append("3S");
  1731. }
  1732. if (mHasSSE41)
  1733. {
  1734. sse_versions.append("4.1");
  1735. }
  1736. if (mHasSSE42)
  1737. {
  1738. sse_versions.append("4.2");
  1739. }
  1740. if (mHasSSE4a)
  1741. {
  1742. sse_versions.append("4a");
  1743. }
  1744. #endif
  1745. return sse_versions;
  1746. }
  1747. std::string LLCPUInfo::getInfo() const
  1748. {
  1749. std::ostringstream s;
  1750. if (mImpl)
  1751. {
  1752. // Gather machine information.
  1753. s << mImpl->getCPUFeatureDescription();
  1754. // These are interesting as they reflect our internal view of the
  1755. // CPU's attributes regardless of platform
  1756. s << "->mHasSSE2: " << (U32)mHasSSE2 << std::endl;
  1757. s << "->mHasSSE3: " << (U32)mHasSSE3 << std::endl;
  1758. s << "->mHasSSE3S: " << (U32)mHasSSE3S << std::endl;
  1759. s << "->mHasSSE41: " << (U32)mHasSSE41 << std::endl;
  1760. s << "->mHasSSE42: " << (U32)mHasSSE42 << std::endl;
  1761. s << "->mHasSSE4a: " << (U32)mHasSSE4a << std::endl;
  1762. s << "->mCPUMHz: " << mCPUMHz << std::endl;
  1763. s << "->mCPUString: " << mCPUString << std::endl;
  1764. }
  1765. return s.str();
  1766. }
  1767. //static
  1768. void LLCPUInfo::setMainThreadCPUAffinifty(U32 cpu_mask)
  1769. {
  1770. assert_main_thread(); // Must be called from the main thread only !
  1771. #if LL_LINUX || LL_WINDOWS
  1772. sMainThreadAffinitySet = true;
  1773. if (!cpu_mask)
  1774. {
  1775. return;
  1776. }
  1777. U32 vcpus = boost::thread::hardware_concurrency();
  1778. U32 cores = boost::thread::physical_concurrency();
  1779. if (vcpus < 4 || cores < 4)
  1780. {
  1781. llinfos << "Too few CPU cores to set an affinity. Skipping." << llendl;
  1782. return;
  1783. }
  1784. U32 reserved_vcpus = 0;
  1785. # if LL_LINUX
  1786. cpu_set_t cpuset;
  1787. CPU_ZERO(&cpuset);
  1788. for (int i = 0, last = llmin((int)CPU_SETSIZE, 32); i < last; ++i)
  1789. {
  1790. if (cpu_mask & (1 << i))
  1791. {
  1792. CPU_SET(i, &cpuset);
  1793. ++reserved_vcpus;
  1794. }
  1795. }
  1796. # else // LL_WINDOWS
  1797. // The mask is just a 64 bits value.
  1798. DWORD_PTR cpuset = 0;
  1799. for (int i = 0, last = sizeof(DWORD_PTR) * 8; i < last; ++i)
  1800. {
  1801. if (cpu_mask & (1 << i))
  1802. {
  1803. cpuset |= (1 << i);
  1804. ++reserved_vcpus;
  1805. }
  1806. }
  1807. # endif
  1808. if (!reserved_vcpus) // This should not happen (CPU_SETSIZE > 32)...
  1809. {
  1810. llwarns << "Request to reserve cores not part of available cores. Skipping."
  1811. << llendl;
  1812. return;
  1813. }
  1814. if (reserved_vcpus + 2 > vcpus)
  1815. {
  1816. llwarns << "Request to reserve too many cores (" << reserved_vcpus
  1817. << ") for the main thread; only " << vcpus
  1818. << " cores are available on this system. Skipping." << llendl;
  1819. return;
  1820. }
  1821. # if LL_LINUX
  1822. if (sched_setaffinity(0, sizeof(cpuset), &cpuset))
  1823. # else // LL_WINDOWS
  1824. if (!SetThreadAffinityMask(GetCurrentThread(), cpuset))
  1825. # endif
  1826. {
  1827. llwarns << "Failed to set CPU affinity for the main thread." << llendl;
  1828. return;
  1829. }
  1830. // Success ! Remember our mask so to set a complementary one on each new
  1831. // child thread.
  1832. sMainThreadAffinityMask = cpu_mask;
  1833. #endif // LL_LINUX || LL_WINDOWS
  1834. }
  1835. //static
  1836. S32 LLCPUInfo::setThreadCPUAffinity(const char* name)
  1837. {
  1838. #if LL_LINUX || LL_WINDOWS
  1839. if (!sMainThreadAffinitySet)
  1840. {
  1841. // Cannot set a child thread affinity before the main thread one is set
  1842. if (name)
  1843. {
  1844. llwarns << "Cannot yet set CPU affinity for thread: " << name
  1845. << llendl;
  1846. }
  1847. return -1;
  1848. }
  1849. // This is a no-operation if no affinity setting is used, or when called
  1850. // from the main thread. Report a "success" in both cases.
  1851. if (!sMainThreadAffinityMask || is_main_thread())
  1852. {
  1853. return 1;
  1854. }
  1855. # if LL_LINUX
  1856. cpu_set_t cpuset;
  1857. CPU_ZERO(&cpuset);
  1858. for (U32 i = 0; i < (U32)CPU_SETSIZE; ++i)
  1859. {
  1860. if (i >= 32 || !(sMainThreadAffinityMask & (1 << i)))
  1861. {
  1862. CPU_SET((int)i, &cpuset);
  1863. }
  1864. }
  1865. if (sched_setaffinity(0, sizeof(cpuset), &cpuset))
  1866. # else // LL_WINDOWS
  1867. DWORD_PTR cpuset = 0;
  1868. for (U32 i = 0; i < (U32)(sizeof(cpuset) * 8); ++i)
  1869. {
  1870. if (i >= 32 || !(sMainThreadAffinityMask & (1 << i)))
  1871. {
  1872. cpuset |= (1 << i);
  1873. }
  1874. }
  1875. if (!SetThreadAffinityMask(GetCurrentThread(), cpuset))
  1876. # endif
  1877. {
  1878. if (name)
  1879. {
  1880. llwarns << "Failed to set CPU affinity for thread: " << name
  1881. << llendl;
  1882. }
  1883. return 0;
  1884. }
  1885. #endif // LL_LINUX || LL_WINDOWS
  1886. return 1;
  1887. }
  1888. // Forward declaration (the function is moved at the end on purpose, so that we
  1889. // can disable the compiler optimizations for it, and for it only). HB
  1890. static F64 benchmark(U32 upper_limit);
  1891. // Returns the speed factor for the running CPU core compared with a reference
  1892. // CPU (Core i7-9700K @ 5.0GHz). HB
  1893. F32 LLCPUInfo::benchmarkFactor()
  1894. {
  1895. // Reference values for benchmark(), as measured on a 9700K @ 5GHz (fixed,
  1896. // locked frequency on all cores) under Linux (compiled with gcc, clang)
  1897. // and Windows (compiled with MSVC). HB
  1898. constexpr U32 BENCH_REF_LIMIT = 10000000;
  1899. #if LL_CLANG
  1900. constexpr F32 BENCH_REF_9700K_5GHZ = 33.8f; // In ms
  1901. #elif LL_GNUC
  1902. constexpr F32 BENCH_REF_9700K_5GHZ = 29.8f; // In ms
  1903. #else // LL_MSVC
  1904. constexpr F32 BENCH_REF_9700K_5GHZ = 31.f; // In ms
  1905. #endif
  1906. // Let's average several benchmarks for a total duration of 500ms to 1s.
  1907. constexpr F64 MAX_DURATION = 500.0; // In ms.
  1908. // Let's not check the CPU/core frequency too frequently...
  1909. constexpr F64 DELAY_BETWEEN_FREQ_CHECKS = 100.0; // In ms.
  1910. F64 total = 0.0;
  1911. F64 last_freq_check = 0.0;
  1912. F64 duration = 0.0;
  1913. S32 iterations = 0;
  1914. do
  1915. {
  1916. F64 sample = benchmark(BENCH_REF_LIMIT);
  1917. total += sample;
  1918. if (total - last_freq_check >= DELAY_BETWEEN_FREQ_CHECKS)
  1919. {
  1920. last_freq_check = total;
  1921. if (affectedCoreFreqDelta() > 0 && total <= MAX_DURATION)
  1922. {
  1923. // Reject former results, since the CPU/core was not yet
  1924. // in turbo mode... HB
  1925. duration = 0.0;
  1926. iterations = 0;
  1927. continue;
  1928. }
  1929. }
  1930. // Update the stats
  1931. duration += sample;
  1932. ++iterations;
  1933. }
  1934. while (total <= MAX_DURATION);
  1935. F32 result = F32(duration / F64(iterations));
  1936. llinfos << "Time taken to find all prime numbers below " << BENCH_REF_LIMIT
  1937. << ": " << result << "ms";
  1938. if (iterations > 1)
  1939. {
  1940. llcont << " (averaged on " << iterations << " runs)";
  1941. }
  1942. llcont << "." << llendl;
  1943. F32 factor = BENCH_REF_9700K_5GHZ / result;
  1944. llinfos << "CPU single-core performance factor relative to a 9700K @ 5GHz: "
  1945. << factor << llendl;
  1946. return factor;
  1947. }
  1948. // Try and make the benchmark code performances insensitive to user-selected
  1949. // compiler optimizations, and *mostly* compiler-agnostic...
  1950. #if LL_CLANG
  1951. # pragma clang optimize off
  1952. #elif LL_GNUC
  1953. # pragma GCC optimize("O0")
  1954. #elif LL_MSVC
  1955. # pragma optimize("", off)
  1956. #endif
  1957. // This is a simple (non-vectorized) benchmark based on the well known sieve of
  1958. // Eratosthenes algorithm to find prime numbers. The algorithm itself is not
  1959. // optimized for primes-finding efficiency (aside from searching primes beyond
  1960. // 2 only among odd numbers). Its main advantage is that it benches only
  1961. // genuine CPU operations and not some standard C/C++ library function
  1962. // implementation. I tried to prevent some 'stealth' optimizations (i.e.
  1963. // optimizations done even at -O0) by some compilers via (minor) manual
  1964. // optimization of the code, e.g. by using intermediate variables for reusable
  1965. // results and replacing integer divisions and multiplications with bit
  1966. // shifting. Note however that the various compilers (or even the various
  1967. // compiler versions of a same compiler) generate a different code anyway, but
  1968. // all in all, and with optimizations off, they seem to perform almost equally
  1969. // with this implementation of the algorithm (see the BENCH_REF_9700K_5GHZ
  1970. // constexpr above for the measured figures). HB
  1971. static F64 benchmark(U32 upper_limit)
  1972. {
  1973. if (upper_limit < 4)
  1974. {
  1975. return 0.0;
  1976. }
  1977. // Number of odd numbers between 3 and upper_limit;
  1978. U32 odds = upper_limit / 2 - 1;
  1979. // Avoids possible differences in compiler code generation (e.g. it could
  1980. // be placed in a 64 bits register, or be converted (extended to 64 bits)
  1981. // at each loop from upper_limit for the comparison with j)...
  1982. U64 ul_64 = upper_limit;
  1983. // An array of booleans (using a 'char' type instead of 'bool', to avoid
  1984. // any potential optimization by compilers, such as using an integer type
  1985. // when it is faster to access a 16 or 32 bits integer than a byte (char)
  1986. // to represent a bool type on a specific CPU architecture); at the end of
  1987. // the sieving process, an element will be true (non-zero) when its index
  1988. // finally does not correspond to a prime number.
  1989. char* non_prime_odds = new char[odds];
  1990. memset((void*)non_prime_odds, 0, odds * sizeof(char));
  1991. // Initialize and start the timer now (i.e. do not benchmark the C/C++
  1992. // libraries implementations of new() and memset()).
  1993. LLTimer timer;
  1994. timer.start();
  1995. // Check all odd numbers (2 * i + 3) between 3 and upper_limit
  1996. for (U32 i = 0; i < odds; ++i)
  1997. {
  1998. if (!non_prime_odds[i])
  1999. {
  2000. U32 number = (i << 1) + 3;
  2001. U32 k = number << 1;
  2002. for (U64 j = k + number; j <= ul_64; j += k)
  2003. {
  2004. non_prime_odds[(j >> 1) - 1] = 1;
  2005. }
  2006. }
  2007. }
  2008. // End of timed benchmark
  2009. F64 time = timer.getElapsedTimeF64() * 1000.0; // Convert in ms
  2010. delete[] non_prime_odds;
  2011. return time;
  2012. }