diff options
author | Dessie Linden <dessie@lindenlab.com> | 2010-06-11 11:51:59 -0700 |
---|---|---|
committer | Dessie Linden <dessie@lindenlab.com> | 2010-06-11 11:51:59 -0700 |
commit | a21b7b330b65eebff050eb6c036745cac1578232 (patch) | |
tree | f1d39777dc34fe5807f5b4a8bfdb4aadcb79ea62 /indra/llcommon | |
parent | 8ea4802251cbfb4fcf112f597f4a4ff1ab0d3f1f (diff) | |
parent | 571c2bc5e5190cae7324dd235f9c44db9823327a (diff) |
Merged from viewer-release
Diffstat (limited to 'indra/llcommon')
-rw-r--r-- | indra/llcommon/CMakeLists.txt | 4 | ||||
-rw-r--r-- | indra/llcommon/llapp.cpp | 188 | ||||
-rw-r--r-- | indra/llcommon/llapp.h | 25 | ||||
-rw-r--r-- | indra/llcommon/llfasttimer_class.cpp | 2 | ||||
-rw-r--r-- | indra/llcommon/llprocessor.cpp | 2810 | ||||
-rw-r--r-- | indra/llcommon/llprocessor.h | 169 | ||||
-rw-r--r-- | indra/llcommon/llsys.cpp | 98 | ||||
-rw-r--r-- | indra/llcommon/llversionserver.h | 6 | ||||
-rw-r--r-- | indra/llcommon/llversionviewer.h | 4 | ||||
-rw-r--r-- | indra/llcommon/tests/llprocessor_test.cpp | 67 |
10 files changed, 977 insertions, 2396 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 3c689930b8..2a036df06e 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -9,6 +9,7 @@ include(Linking) include(Boost) include(Pth) include(LLSharedLibs) +include(GoogleBreakpad) include(GooglePerfTools) include(Copy3rdPartyLibs) @@ -232,7 +233,6 @@ set(llcommon_HEADER_FILES metaclasst.h metaproperty.h metapropertyt.h - processor.h reflective.h reflectivet.h roles_constants.h @@ -259,6 +259,7 @@ endif(LLCOMMON_LINK_SHARED) target_link_libraries( llcommon + ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES} ${APRUTIL_LIBRARIES} ${APR_LIBRARIES} ${EXPAT_LIBRARIES} @@ -290,6 +291,7 @@ if (LL_TESTS) LL_ADD_INTEGRATION_TEST(llframetimer "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llinstancetracker "" "${test_libs}") LL_ADD_INTEGRATION_TEST(lllazy "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llprocessor "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llrand "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llsdserialize "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llstring "" "${test_libs}") diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index 6b2d1b7c20..eedec0b24e 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -30,6 +30,8 @@ * $/LicenseInfo$ */ +#include <cstdlib> + #include "linden_common.h" #include "llapp.h" @@ -41,8 +43,11 @@ #include "lllivefile.h" #include "llmemory.h" #include "llstl.h" // for DeletePointer() +#include "llstring.h" #include "lleventtimer.h" +#include "google_breakpad/exception_handler.h" + // // Signal handling // @@ -51,11 +56,22 @@ #if LL_WINDOWS LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop); BOOL ConsoleCtrlHandler(DWORD fdwCtrlType); +bool windows_post_minidump_callback(const wchar_t* dump_path, + const wchar_t* minidump_id, + void* context, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, + bool succeeded); #else # include <signal.h> # include <unistd.h> // for fork() void setup_signals(); void default_unix_signal_handler(int signum, siginfo_t *info, void *); + +// Called by breakpad exception handler after the minidump has been generated. +bool unix_post_minidump_callback(const char *dump_dir, + const char *minidump_id, + void *context, bool succeeded); # if LL_DARWIN /* OSX doesn't support SIGRT* */ S32 LL_SMACKDOWN_SIGNAL = SIGUSR1; @@ -81,7 +97,6 @@ BOOL LLApp::sLogInSignal = FALSE; // static LLApp::EAppStatus LLApp::sStatus = LLApp::APP_STATUS_STOPPED; // Keeps track of application status LLAppErrorHandler LLApp::sErrorHandler = NULL; -LLAppErrorHandler LLApp::sSyncErrorHandler = NULL; BOOL LLApp::sErrorThreadRunning = FALSE; #if !LL_WINDOWS LLApp::child_map LLApp::sChildMap; @@ -123,7 +138,12 @@ void LLApp::commonCtor() // Set the application to this instance. sApplication = this; - + + mExceptionHandler = 0; + + // initialize the buffer to write the minidump filename to + // (this is used to avoid allocating memory in the crash handler) + memset(minidump_path, 0, MAX_MINDUMP_PATH_LENGTH); } LLApp::LLApp(LLErrorThread *error_thread) : @@ -152,6 +172,8 @@ LLApp::~LLApp() delete mThreadErrorp; mThreadErrorp = NULL; } + + if(mExceptionHandler != 0) delete mExceptionHandler; LLCommon::cleanupClass(); } @@ -262,19 +284,18 @@ void LLApp::setupErrorHandling() // occasionally checks to see if the app is in an error state, and sees if it needs to be run. #if LL_WINDOWS - // Windows doesn't have the same signal handling mechanisms as UNIX, thus APR doesn't provide - // a signal handling thread implementation. - // What we do is install an unhandled exception handler, which will try to do the right thing - // in the case of an error (generate a minidump) - - // Disable this until the viewer gets ported so server crashes can be JIT debugged. - //LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; - //prev_filter = SetUnhandledExceptionFilter(default_windows_exception_handler); - // This sets a callback to handle w32 signals to the console window. // The viewer shouldn't be affected, sicne its a windowed app. SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE); + // Install the Google Breakpad crash handler for Windows + if(mExceptionHandler == 0) + { + llwarns << "adding breakpad exception handler" << llendl; + mExceptionHandler = new google_breakpad::ExceptionHandler( + L"C:\\Temp\\", 0, windows_post_minidump_callback, 0, google_breakpad::ExceptionHandler::HANDLER_ALL); + } + #else // // Start up signal handling. @@ -282,9 +303,14 @@ void LLApp::setupErrorHandling() // There are two different classes of signals. Synchronous signals are delivered to a specific // thread, asynchronous signals can be delivered to any thread (in theory) // - setup_signals(); - + + // Add google breakpad exception handler configured for Darwin/Linux. + if(mExceptionHandler == 0) + { + std::string dumpPath = "/tmp/"; + mExceptionHandler = new google_breakpad::ExceptionHandler(dumpPath, 0, &unix_post_minidump_callback, 0, true); + } #endif startErrorThread(); @@ -310,21 +336,6 @@ void LLApp::setErrorHandler(LLAppErrorHandler handler) LLApp::sErrorHandler = handler; } - -void LLApp::setSyncErrorHandler(LLAppErrorHandler handler) -{ - LLApp::sSyncErrorHandler = handler; -} - -// static -void LLApp::runSyncErrorHandler() -{ - if (LLApp::sSyncErrorHandler) - { - LLApp::sSyncErrorHandler(); - } -} - // static void LLApp::runErrorHandler() { @@ -337,7 +348,6 @@ void LLApp::runErrorHandler() LLApp::setStopped(); } - // static void LLApp::setStatus(EAppStatus status) { @@ -348,15 +358,27 @@ void LLApp::setStatus(EAppStatus status) // static void LLApp::setError() { - if (!isError()) - { - // perform any needed synchronous error-handling - runSyncErrorHandler(); - // set app status to ERROR so that the LLErrorThread notices - setStatus(APP_STATUS_ERROR); - } + // set app status to ERROR so that the LLErrorThread notices + setStatus(APP_STATUS_ERROR); } +void LLApp::setMiniDumpDir(const std::string &path) +{ + llassert(mExceptionHandler); +#ifdef LL_WINDOWS + wchar_t buffer[MAX_MINDUMP_PATH_LENGTH]; + mbstowcs(buffer, path.c_str(), MAX_MINDUMP_PATH_LENGTH); + mExceptionHandler->set_dump_path(std::wstring(buffer)); +#else + mExceptionHandler->set_dump_path(path); +#endif +} + +void LLApp::writeMiniDump() +{ + llassert(mExceptionHandler); + mExceptionHandler->WriteMinidump(); +} // static void LLApp::setQuitting() @@ -587,6 +609,7 @@ void setup_signals() // Asynchronous signals that result in core sigaction(SIGQUIT, &act, NULL); + } void clear_signals() @@ -765,4 +788,97 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) } } +bool unix_post_minidump_callback(const char *dump_dir, + const char *minidump_id, + void *context, bool succeeded) +{ + // Copy minidump file path into fixed buffer in the app instance to avoid + // heap allocations in a crash handler. + + // path format: <dump_dir>/<minidump_id>.dmp + int dirPathLength = strlen(dump_dir); + int idLength = strlen(minidump_id); + + // The path must not be truncated. + llassert((dirPathLength + idLength + 5) <= LLApp::MAX_MINDUMP_PATH_LENGTH); + + char * path = LLApp::instance()->getMiniDumpFilename(); + S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH; + strncpy(path, dump_dir, remaining); + remaining -= dirPathLength; + path += dirPathLength; + if (remaining > 0 && dirPathLength > 0 && path[-1] != '/') + { + *path++ = '/'; + --remaining; + } + if (remaining > 0) + { + strncpy(path, minidump_id, remaining); + remaining -= idLength; + path += idLength; + strncpy(path, ".dmp", remaining); + } + + llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl; + LLApp::runErrorHandler(); + return true; +} #endif // !WINDOWS + +#ifdef LL_WINDOWS +bool windows_post_minidump_callback(const wchar_t* dump_path, + const wchar_t* minidump_id, + void* context, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, + bool succeeded) +{ + char * path = LLApp::instance()->getMiniDumpFilename(); + S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH; + size_t bytesUsed; + + bytesUsed = wcstombs(path, dump_path, static_cast<size_t>(remaining)); + remaining -= bytesUsed; + path += bytesUsed; + if(remaining > 0 && bytesUsed > 0 && path[-1] != '\\') + { + *path++ = '\\'; + --remaining; + } + if(remaining > 0) + { + bytesUsed = wcstombs(path, minidump_id, static_cast<size_t>(remaining)); + remaining -= bytesUsed; + path += bytesUsed; + } + if(remaining > 0) + { + strncpy(path, ".dmp", remaining); + } + + llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl; + // *NOTE:Mani - this code is stolen from LLApp, where its never actually used. + //OSMessageBox("Attach Debugger Now", "Error", OSMB_OK); + // *TODO: Translate the signals/exceptions into cross-platform stuff + // Windows implementation + llinfos << "Entering Windows Exception Handler..." << llendl; + + if (LLApp::isError()) + { + llwarns << "Got another fatal signal while in the error handler, die now!" << llendl; + } + + // Flag status to error, so thread_error starts its work + LLApp::setError(); + + // Block in the exception handler until the app has stopped + // This is pretty sketchy, but appears to work just fine + while (!LLApp::isStopped()) + { + ms_sleep(10); + } + + return true; +} +#endif diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index e5b8edf9c3..fef05a7939 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -66,6 +66,10 @@ public: }; #endif +namespace google_breakpad { + class ExceptionHandler; // See exception_handler.h +} + class LL_COMMON_API LLApp : public LLOptionInterface { friend class LLErrorThread; @@ -227,8 +231,20 @@ public: void setupErrorHandling(); void setErrorHandler(LLAppErrorHandler handler); - void setSyncErrorHandler(LLAppErrorHandler handler); + static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred. //@} + + // the maximum length of the minidump filename returned by getMiniDumpFilename() + static const U32 MAX_MINDUMP_PATH_LENGTH = 256; + + // change the directory where Breakpad minidump files are written to + void setMiniDumpDir(const std::string &path); + + // Return the Google Breakpad minidump filename after a crash. + char *getMiniDumpFilename() { return minidump_path; } + + // Write out a Google Breakpad minidump file. + void writeMiniDump(); #if !LL_WINDOWS // @@ -286,15 +302,14 @@ protected: private: void startErrorThread(); - static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred. - static void runSyncErrorHandler(); // run IMMEDIATELY when we get an error, ran in the context of the faulting thread. + // Contains the filename of the minidump file after a crash. + char minidump_path[MAX_MINDUMP_PATH_LENGTH]; // *NOTE: On Windows, we need a routine to reset the structured // exception handler when some evil driver has taken it over for // their own purposes typedef int(*signal_handler_func)(int signum); static LLAppErrorHandler sErrorHandler; - static LLAppErrorHandler sSyncErrorHandler; // Default application threads LLErrorThread* mThreadErrorp; // Waits for app to go to status ERROR, then runs the error callback @@ -315,6 +330,8 @@ private: private: // the static application instance if it was created. static LLApp* sApplication; + + google_breakpad::ExceptionHandler * mExceptionHandler; #if !LL_WINDOWS diff --git a/indra/llcommon/llfasttimer_class.cpp b/indra/llcommon/llfasttimer_class.cpp index f39a4e6619..20727dd76e 100644 --- a/indra/llcommon/llfasttimer_class.cpp +++ b/indra/llcommon/llfasttimer_class.cpp @@ -238,7 +238,7 @@ U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer #else // windows or x86-mac or x86-linux or x86-solaris U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer { - static U64 sCPUClockFrequency = U64(CProcessor().GetCPUFrequency(50)); + static U64 sCPUClockFrequency = U64(LLProcessorInfo().getCPUFrequency()); // we drop the low-order byte in our timers, so report a lower frequency return sCPUClockFrequency >> 8; diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index f6ab55a6b5..d3ba215751 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -30,139 +30,389 @@ * $/LicenseInfo$ */ -// Filename: Processor.cpp -// ======================= -// Author: Benjamin Jurke -// File history: 27.02.2002 - File created. Support for Intel and AMD processors -// 05.03.2002 - Fixed the CPUID bug: On Pre-Pentium CPUs the CPUID -// command is not available -// - The CProcessor::WriteInfoTextFile function do not -// longer use Win32 file functions (-> os independend) -// - Optional include of the windows.h header which is -// still need for CProcessor::GetCPUFrequency. -// 06.03.2002 - My birthday (18th :-)) -// - Replaced the '\r\n' line endings in function -// CProcessor::CPUInfoToText by '\n' -// - Replaced unsigned __int64 by signed __int64 for -// solving some compiler conversion problems -// - Fixed a bug at family=6, model=6 (Celeron -> P2) -////////////////////////////////////////////////////////////////////////////////// - #include "linden_common.h" +#include "llprocessor.h" -#include "processor.h" +#include "llerror.h" -#include <memory> +//#include <memory> #if LL_WINDOWS # define WIN32_LEAN_AND_MEAN # include <winsock2.h> # include <windows.h> +# define _interlockedbittestandset _renamed_interlockedbittestandset +# define _interlockedbittestandreset _renamed_interlockedbittestandreset +# include <intrin.h> +# undef _interlockedbittestandset +# undef _interlockedbittestandreset #endif -#if LL_LINUX -#include "llsys.h" -#endif // LL_LINUX +#include "llsd.h" + +#if LL_MSVC && _M_X64 +# define LL_X86_64 1 +# define LL_X86 1 +#elif LL_MSVC && _M_IX86 +# define LL_X86 1 +#elif LL_GNUC && ( defined(__amd64__) || defined(__x86_64__) ) +# define LL_X86_64 1 +# define LL_X86 1 +#elif LL_GNUC && ( defined(__i386__) ) +# define LL_X86 1 +#elif LL_GNUC && ( defined(__powerpc__) || defined(__ppc__) ) +# define LL_PPC 1 +#endif + +class LLProcessorInfoImpl; // foward declaration for the mImpl; + +namespace +{ + enum cpu_info + { + eBrandName = 0, + eFrequency, + eVendor, + eStepping, + eFamily, + eExtendedFamily, + eModel, + eExtendedModel, + eType, + eBrandID, + eFamilyName + }; + + + const char* cpu_info_names[] = + { + "Processor Name", + "Frequency", + "Vendor", + "Stepping", + "Family", + "Extended Family", + "Model", + "Extended Model", + "Type", + "Brand ID", + "Family Name" + }; + + enum cpu_config + { + eMaxID, + eMaxExtID, + eCLFLUSHCacheLineSize, + eAPICPhysicalID, + eCacheLineSize, + eL2Associativity, + eCacheSizeK, + eFeatureBits, + eExtFeatureBits + }; + + const char* cpu_config_names[] = + { + "Max Supported CPUID level", + "Max Supported Ext. CPUID level", + "CLFLUSH cache line size", + "APIC Physical ID", + "Cache Line Size", + "L2 Associativity", + "Cache Size", + "Feature Bits", + "Ext. Feature Bits" + }; -#if !LL_DARWIN && !LL_SOLARIS -#ifdef PROCESSOR_FREQUENCY_MEASURE_AVAILABLE -// We need the QueryPerformanceCounter and Sleep functions -#define FORCEINLINE __forceinline -#else -#define FORCEINLINE -#endif + // *NOTE:Mani - this contains the elements we reference directly and extensions beyond the first 32. + // The rest of the names are referenced by bit maks returned from cpuid. + enum cpu_features + { + eSSE_Ext=25, + eSSE2_Ext=26, + + eSSE3_Features=32, + eMONTIOR_MWAIT=33, + eCPLDebugStore=34, + eThermalMonitor2=35, + eAltivec=36 + }; -// Some macros we often need -//////////////////////////// -#define CheckBit(var, bit) ((var & (1 << bit)) ? true : false) + const char* cpu_feature_names[] = + { + "x87 FPU On Chip", + "Virtual-8086 Mode Enhancement", + "Debugging Extensions", + "Page Size Extensions", + "Time Stamp Counter", + "RDMSR and WRMSR Support", + "Physical Address Extensions", + "Machine Check Exception", + "CMPXCHG8B Instruction", + "APIC On Chip", + "Unknown1", + "SYSENTER and SYSEXIT", + "Memory Type Range Registers", + "PTE Global Bit", + "Machine Check Architecture", + "Conditional Move/Compare Instruction", + "Page Attribute Table", + "Page Size Extension", + "Processor Serial Number", + "CFLUSH Extension", + "Unknown2", + "Debug Store", + "Thermal Monitor and Clock Ctrl", + "MMX Technology", + "FXSAVE/FXRSTOR", + "SSE Extensions", + "SSE2 Extensions", + "Self Snoop", + "Hyper-threading Technology", + "Thermal Monitor", + "Unknown4", + "Pend. Brk. EN.", // 31 End of FeatureInfo bits + + "SSE3 New Instructions", // 32 + "MONITOR/MWAIT", + "CPL Qualified Debug Store", + "Thermal Monitor 2", + + "Altivec" + }; + + std::string intel_CPUFamilyName(int composed_family) + { + switch(composed_family) + { + case 3: return "Intel i386"; + case 4: return "Intel i486"; + case 5: return "Intel Pentium"; + case 6: return "Intel Pentium Pro/2/3, Core"; + case 7: return "Intel Itanium (IA-64)"; + case 0xF: return "Intel Pentium 4"; + case 0x10: return "Intel Itanium 2 (IA-64)"; + } + return "Unknown"; + } + + std::string amd_CPUFamilyName(int composed_family) + { + switch(composed_family) + { + case 4: return "AMD 80486/5x86"; + case 5: return "AMD K5/K6"; + case 6: return "AMD K7"; + case 0xF: return "AMD K8"; + case 0x10: return "AMD K8L"; + } + return "Unknown"; + } + + std::string compute_CPUFamilyName(const char* cpu_vendor, int composed_family) + { + const char* intel_string = "GenuineIntel"; + const char* amd_string = "AuthenticAMD"; + if(!strncmp(cpu_vendor, intel_string, strlen(intel_string))) + { + return intel_CPUFamilyName(composed_family); + } + else if(!strncmp(cpu_vendor, amd_string, strlen(amd_string))) + { + return amd_CPUFamilyName(composed_family); + } + return "Unknown"; + } + + std::string compute_CPUFamilyName(const char* cpu_vendor, int family, int ext_family) + { + const char* intel_string = "GenuineIntel"; + const char* amd_string = "AuthenticAMD"; + if(!strncmp(cpu_vendor, intel_string, strlen(intel_string))) + { + U32 composed_family = family + ext_family; + return intel_CPUFamilyName(composed_family); + } + else if(!strncmp(cpu_vendor, amd_string, strlen(amd_string))) + { + U32 composed_family = (family == 0xF) + ? family + ext_family + : family; + return amd_CPUFamilyName(composed_family); + } + return "Unknown"; + } + +} // end unnamed namespace + +// The base class for implementations. +// Each platform should override this class. +class LLProcessorInfoImpl +{ +public: + LLProcessorInfoImpl() + { + mProcessorInfo["info"] = LLSD::emptyMap(); + mProcessorInfo["config"] = LLSD::emptyMap(); + mProcessorInfo["extension"] = LLSD::emptyMap(); + } + virtual ~LLProcessorInfoImpl() {} + + F64 getCPUFrequency() const + { + return getInfo(eFrequency, 0).asReal(); + } + + bool hasSSE() const + { + return hasExtension(cpu_feature_names[eSSE_Ext]); + } + + bool hasSSE2() const + { + return hasExtension(cpu_feature_names[eSSE2_Ext]); + } + + bool hasAltivec() const + { + return hasExtension("Altivec"); + } + + std::string getCPUFamilyName() const { return getInfo(eFamilyName, "Unknown").asString(); } + std::string getCPUBrandName() const { return getInfo(eBrandName, "Unknown").asString(); } + + // This is virtual to support a different linux format. + // *NOTE:Mani - I didn't want to screw up server use of this data... + virtual std::string getCPUFeatureDescription() const + { + std::ostringstream out; + out << std::endl << std::endl; + out << "// CPU General Information" << std::endl; + out << "//////////////////////////" << std::endl; + out << "Processor Name: " << getCPUBrandName() << std::endl; + out << "Frequency: " << getCPUFrequency() << " MHz" << std::endl; + out << "Vendor: " << getInfo(eVendor, "Unknown").asString() << std::endl; + out << "Family: " << getCPUFamilyName() << " (" << getInfo(eFamily, 0) << ")" << std::endl; + out << "Extended family: " << getInfo(eExtendedFamily, 0) << std::endl; + out << "Model: " << getInfo(eModel, 0) << std::endl; + out << "Extended model: " << getInfo(eExtendedModel, 0) << std::endl; + out << "Type: " << getInfo(eType, 0) << std::endl; + out << "Brand ID: " << getInfo(eBrandID, 0) << std::endl; + out << std::endl; + out << "// CPU Configuration" << std::endl; + out << "//////////////////////////" << std::endl; + + // Iterate through the dictionary of configuration options. + LLSD configs = mProcessorInfo["config"]; + for(LLSD::map_const_iterator cfgItr = configs.beginMap(); cfgItr != configs.endMap(); ++cfgItr) + { + out << cfgItr->first << " = " << cfgItr->second << std::endl; + } + out << std::endl; + + out << "// CPU Extensions" << std::endl; + out << "//////////////////////////" << std::endl; + + for(LLSD::map_const_iterator itr = mProcessorInfo["extension"].beginMap(); itr != mProcessorInfo["extension"].endMap(); ++itr) + { + out << " " << itr->first << std::endl; + } + return out.str(); + } + +protected: + void setInfo(cpu_info info_type, const LLSD& value) + { + setInfo(cpu_info_names[info_type], value); + } + LLSD getInfo(cpu_info info_type, const LLSD& defaultVal) const + { + return getInfo(cpu_info_names[info_type], defaultVal); + } + + void setConfig(cpu_config config_type, const LLSD& value) + { + setConfig(cpu_config_names[config_type], value); + } + LLSD getConfig(cpu_config config_type, const LLSD& defaultVal) const + { + return getConfig(cpu_config_names[config_type], defaultVal); + } + + void setExtension(const std::string& name) { mProcessorInfo["extension"][name] = "true"; } + bool hasExtension(const std::string& name) const + { + return mProcessorInfo["extension"].has(name); + } + +private: + void setInfo(const std::string& name, const LLSD& value) { mProcessorInfo["info"][name]=value; } + LLSD getInfo(const std::string& name, const LLSD& defaultVal) const + { + if(mProcessorInfo["info"].has(name)) + { + return mProcessorInfo["info"][name]; + } + return defaultVal; + } + void setConfig(const std::string& name, const LLSD& value) { mProcessorInfo["config"][name]=value; } + LLSD getConfig(const std::string& name, const LLSD& defaultVal) const + { + LLSD r = mProcessorInfo["config"].get(name); + return r.isDefined() ? r : defaultVal; + } + +private: + + LLSD mProcessorInfo; +}; + + +#ifdef LL_MSVC +// LL_MSVC and not LLWINDOWS because some of the following code +// uses the MSVC compiler intrinsics __cpuid() and __rdtsc(). -#ifdef PROCESSOR_FREQUENCY_MEASURE_AVAILABLE // Delays for the specified amount of milliseconds -static void _Delay(unsigned int ms) +static void _Delay(unsigned int ms) { - LARGE_INTEGER freq, c1, c2; - __int64 x; + LARGE_INTEGER freq, c1, c2; + __int64 x; - // Get High-Res Timer frequency + // Get High-Res Timer frequency if (!QueryPerformanceFrequency(&freq)) return; - + // Convert ms to High-Res Timer value x = freq.QuadPart/1000*ms; - // Get first snapshot of High-Res Timer value + // Get first snapshot of High-Res Timer value QueryPerformanceCounter(&c1); do { - // Get second snapshot - QueryPerformanceCounter(&c2); + // Get second snapshot + QueryPerformanceCounter(&c2); }while(c2.QuadPart-c1.QuadPart < x); // Loop while (second-first < x) } -#endif - -// CProcessor::CProcessor -// ====================== -// Class constructor: -///////////////////////// -CProcessor::CProcessor() -{ - uqwFrequency = 0; - strCPUName[0] = 0; - memset(&CPUInfo, 0, sizeof(CPUInfo)); -} -// unsigned __int64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs) -// ========================================================================= -// Function to measure the current CPU frequency -//////////////////////////////////////////////////////////////////////////// -F64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs) +static F64 calculate_cpu_frequency(U32 measure_msecs) { -#if LL_LINUX - // use the shinier LLCPUInfo interface - return 1000000.0F * gSysCPU.getMHz(); -#endif - -#ifndef PROCESSOR_FREQUENCY_MEASURE_AVAILABLE - return 0; -#else - // If there are invalid measure time parameters, zero msecs for example, - // we've to exit the function - if (uiMeasureMSecs < 1) + if(measure_msecs == 0) { - // If theres already a measured frequency available, we return it - if (uqwFrequency > 0) - return uqwFrequency; - else - return 0; - } - - // Now we check if the CPUID command is available - if (!CheckCPUIDPresence()) return 0; - - // First we get the CPUID standard level 0x00000001 - unsigned long reg; - __asm - { - mov eax, 1 - cpuid - mov reg, edx } - // Then we check, if the RDTSC (Real Date Time Stamp Counter) is available. - // This function is necessary for our measure process. - if (!(reg & (1 << 4))) - return 0; - // After that we declare some vars and check the frequency of the high // resolution timer for the measure process. - // If there's no high-res timer, we exit. - __int64 starttime, endtime, timedif, freq, start, end, dif; + // If there"s no high-res timer, we exit. + unsigned __int64 starttime, endtime, timedif, freq, start, end, dif; if (!QueryPerformanceFrequency((LARGE_INTEGER *) &freq)) + { return 0; + } // Now we can init the measure process. We set the process and thread priority // to the highest available level (Realtime priority). Also we focus the @@ -178,35 +428,27 @@ F64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs) SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); SetProcessAffinityMask(hProcess, dwNewMask); - // Now we call a CPUID to ensure, that all other prior called functions are - // completed now (serialization) - __asm cpuid + //// Now we call a CPUID to ensure, that all other prior called functions are + //// completed now (serialization) + //__asm cpuid + int cpu_info[4] = {-1}; + __cpuid(cpu_info, 0); // We ask the high-res timer for the start time QueryPerformanceCounter((LARGE_INTEGER *) &starttime); // Then we get the current cpu clock and store it - __asm - { - rdtsc - mov dword ptr [start+4], edx - mov dword ptr [start], eax - } + start = __rdtsc(); // Now we wart for some msecs - _Delay(uiMeasureMSecs); -// Sleep(uiMeasureMSecs); + _Delay(measure_msecs); + // Sleep(uiMeasureMSecs); // We ask for the end time QueryPerformanceCounter((LARGE_INTEGER *) &endtime); // And also for the end cpu clock - __asm - { - rdtsc - mov dword ptr [end+4], edx - mov dword ptr [end], eax - } + end = __rdtsc(); // Now we can restore the default process and thread priorities SetProcessAffinityMask(hProcess, dwProcessMask); @@ -219,2075 +461,433 @@ F64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs) // And finally the frequency is the clock difference divided by the time // difference. - uqwFrequency = (F64)dif / (((F64)timedif) / freq); + F64 frequency = (F64)dif / (((F64)timedif) / freq); // At last we just return the frequency that is also stored in the call - // member var uqwFrequency - return uqwFrequency; -#endif + // member var uqwFrequency - converted to MHz + return frequency / (F64)1000000; } -// bool CProcessor::AnalyzeIntelProcessor() -// ======================================== -// Private class function for analyzing an Intel processor -////////////////////////////////////////////////////////// -bool CProcessor::AnalyzeIntelProcessor() +// Windows implementation +class LLProcessorInfoWindowsImpl : public LLProcessorInfoImpl { -#if LL_WINDOWS - unsigned long eaxreg, ebxreg, edxreg; - - // First we check if the CPUID command is available - if (!CheckCPUIDPresence()) - return false; - - // Now we get the CPUID standard level 0x00000001 - __asm +public: + LLProcessorInfoWindowsImpl() { - mov eax, 1 - cpuid - mov eaxreg, eax - mov ebxreg, ebx - mov edxreg, edx + getCPUIDInfo(); + setInfo(eFrequency, calculate_cpu_frequency(50)); } - - // Then get the cpu model, family, type, stepping and brand id by masking - // the eax and ebx register - CPUInfo.uiStepping = eaxreg & 0xF; - CPUInfo.uiModel = (eaxreg >> 4) & 0xF; - CPUInfo.uiFamily = (eaxreg >> 8) & 0xF; - CPUInfo.uiType = (eaxreg >> 12) & 0x3; - CPUInfo.uiBrandID = ebxreg & 0xF; - - static const char* INTEL_BRAND[] = - { - /* 0x00 */ "", - /* 0x01 */ "0.18 micron Intel Celeron", - /* 0x02 */ "0.18 micron Intel Pentium III", - /* 0x03 */ "0.13 micron Intel Celeron", - /* 0x04 */ "0.13 micron Intel Pentium III", - /* 0x05 */ "", - /* 0x06 */ "0.13 micron Intel Pentium III Mobile", - /* 0x07 */ "0.13 micron Intel Celeron Mobile", - /* 0x08 */ "0.18 micron Intel Pentium 4", - /* 0x09 */ "0.13 micron Intel Pentium 4", - /* 0x0A */ "0.13 micron Intel Celeron", - /* 0x0B */ "0.13 micron Intel Pentium 4 Xeon", - /* 0x0C */ "Intel Xeon MP", - /* 0x0D */ "", - /* 0x0E */ "0.18 micron Intel Pentium 4 Xeon", - /* 0x0F */ "Mobile Intel Celeron", - /* 0x10 */ "", - /* 0x11 */ "Mobile Genuine Intel", - /* 0x12 */ "Intel Celeron M", - /* 0x13 */ "Mobile Intel Celeron", - /* 0x14 */ "Intel Celeron", - /* 0x15 */ "Mobile Genuine Intel", - /* 0x16 */ "Intel Pentium M", - /* 0x17 */ "Mobile Intel Celeron", - }; - // Only override the brand if we have it in the lookup table. We should - // already have a string here from GetCPUInfo(). JC - if ( CPUInfo.uiBrandID < LL_ARRAY_SIZE(INTEL_BRAND) ) +private: + void getCPUIDInfo() { - strncpy(CPUInfo.strBrandID, INTEL_BRAND[CPUInfo.uiBrandID], sizeof(CPUInfo.strBrandID)-1); - CPUInfo.strBrandID[sizeof(CPUInfo.strBrandID)-1]='\0'; + // http://msdn.microsoft.com/en-us/library/hskdteyh(VS.80).aspx + + // __cpuid with an InfoType argument of 0 returns the number of + // valid Ids in cpu_info[0] and the CPU identification string in + // the other three array elements. The CPU identification string is + // not in linear order. The code below arranges the information + // in a human readable form. + int cpu_info[4] = {-1}; + __cpuid(cpu_info, 0); + unsigned int ids = (unsigned int)cpu_info[0]; + setConfig(eMaxID, (S32)ids); + + char cpu_vendor[0x20]; + memset(cpu_vendor, 0, sizeof(cpu_vendor)); + *((int*)cpu_vendor) = cpu_info[1]; + *((int*)(cpu_vendor+4)) = cpu_info[3]; + *((int*)(cpu_vendor+8)) = cpu_info[2]; + setInfo(eVendor, cpu_vendor); - if (CPUInfo.uiBrandID == 3 && CPUInfo.uiModel == 6) + // Get the information associated with each valid Id + for(unsigned int i=0; i<=ids; ++i) { - strcpy(CPUInfo.strBrandID, "0.18 micron Intel Pentium III Xeon"); - } - } + __cpuid(cpu_info, i); - // Then we translate the cpu family - switch (CPUInfo.uiFamily) - { - case 3: // Family = 3: i386 (80386) processor family - strcpy(CPUInfo.strFamily, "Intel i386"); /* Flawfinder: ignore */ - break; - case 4: // Family = 4: i486 (80486) processor family - strcpy(CPUInfo.strFamily, "Intel i486"); /* Flawfinder: ignore */ - break; - case 5: // Family = 5: Pentium (80586) processor family - strcpy(CPUInfo.strFamily, "Intel Pentium"); /* Flawfinder: ignore */ - break; - case 6: // Family = 6: Pentium Pro (80686) processor family - strcpy(CPUInfo.strFamily, "Intel Pentium Pro/2/3, Core"); /* Flawfinder: ignore */ - break; - case 15: // Family = 15: Extended family specific - // Masking the extended family - CPUInfo.uiExtendedFamily = (eaxreg >> 20) & 0xFF; - switch (CPUInfo.uiExtendedFamily) - { - case 0: // Family = 15, Ext. Family = 0: Pentium 4 (80786 ??) processor family - strcpy(CPUInfo.strFamily, "Intel Pentium 4"); /* Flawfinder: ignore */ - break; - case 1: // Family = 15, Ext. Family = 1: McKinley (64-bit) processor family - strcpy(CPUInfo.strFamily, "Intel McKinley (IA-64)"); /* Flawfinder: ignore */ - break; - default: // Sure is sure - strcpy(CPUInfo.strFamily, "Unknown Intel Pentium 4+"); /* Flawfinder: ignore */ - break; - } - break; - default: // Failsave - strcpy(CPUInfo.strFamily, "Unknown"); /* Flawfinder: ignore */ - break; - } - - // Now we come to the big deal, the exact model name - switch (CPUInfo.uiFamily) - { - case 3: // i386 (80386) processor family - strcpy(CPUInfo.strModel, "Unknown Intel i386"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel i386", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - break; - case 4: // i486 (80486) processor family - switch (CPUInfo.uiModel) - { - case 0: // Model = 0: i486 DX-25/33 processor model - strcpy(CPUInfo.strModel, "Intel i486 DX-25/33"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel i486 DX-25/33", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - break; - case 1: // Model = 1: i486 DX-50 processor model - strcpy(CPUInfo.strModel, "Intel i486 DX-50"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel i486 DX-50", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - break; - case 2: // Model = 2: i486 SX processor model - strcpy(CPUInfo.strModel, "Intel i486 SX"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel i486 SX", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - break; - case 3: // Model = 3: i486 DX2 (with i487 numeric coprocessor) processor model - strcpy(CPUInfo.strModel, "Intel i486 487/DX2"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel i486 DX2 with i487 numeric coprocessor", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - break; - case 4: // Model = 4: i486 SL processor model (never heard ?!?) - strcpy(CPUInfo.strModel, "Intel i486 SL"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel i486 SL", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - break; - case 5: // Model = 5: i486 SX2 processor model - strcpy(CPUInfo.strModel, "Intel i486 SX2"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel i486 SX2", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - break; - case 7: // Model = 7: i486 write-back enhanced DX2 processor model - strcpy(CPUInfo.strModel, "Intel i486 write-back enhanced DX2"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel i486 write-back enhanced DX2", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - break; - case 8: // Model = 8: i486 DX4 processor model - strcpy(CPUInfo.strModel, "Intel i486 DX4"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel i486 DX4", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - break; - case 9: // Model = 9: i486 write-back enhanced DX4 processor model - strcpy(CPUInfo.strModel, "Intel i486 write-back enhanced DX4"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel i486 DX4", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - break; - default: // ... - strcpy(CPUInfo.strModel, "Unknown Intel i486"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel i486 (Unknown model)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - break; - } - break; - case 5: // Pentium (80586) processor family - switch (CPUInfo.uiModel) - { - case 0: // Model = 0: Pentium (P5 A-Step) processor model - strcpy(CPUInfo.strModel, "Intel Pentium (P5 A-Step)"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel Pentium (P5 A-Step core)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - break; // Famous for the DIV bug, as far as I know - case 1: // Model = 1: Pentium 60/66 processor model - strcpy(CPUInfo.strModel, "Intel Pentium 60/66 (P5)"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel Pentium 60/66 (P5 core)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - break; - case 2: // Model = 2: Pentium 75-200 (P54C) processor model - strcpy(CPUInfo.strModel, "Intel Pentium 75-200 (P54C)"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel Pentium 75-200 (P54C core)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - break; - case 3: // Model = 3: Pentium overdrive for 486 systems processor model - strcpy(CPUInfo.strModel, "Intel Pentium for 486 system (P24T Overdrive)"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel Pentium for 486 (P24T overdrive core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - case 4: // Model = 4: Pentium MMX processor model - strcpy(CPUInfo.strModel, "Intel Pentium MMX (P55C)"); /*Flawfinder: ignore*/ - strncat(strCPUName, "Intel Pentium MMX (P55C core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - case 7: // Model = 7: Pentium processor model (don't know difference to Model=2) - strcpy(CPUInfo.strModel, "Intel Pentium (P54C)"); /*Flawfinder: ignore*/ - strncat(strCPUName, "Intel Pentium (P54C core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - case 8: // Model = 8: Pentium MMX (0.25 micron) processor model - strcpy(CPUInfo.strModel, "Intel Pentium MMX (P55C), 0.25 micron"); /*Flawfinder: ignore*/ - strncat(strCPUName, "Intel Pentium MMX (P55C core), 0.25 micron", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - default: // ... - strcpy(CPUInfo.strModel, "Unknown Intel Pentium"); /*Flawfinder: ignore*/ - strncat(strCPUName, "Intel Pentium (Unknown P5-model)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - } - break; - case 6: // Pentium Pro (80686) processor family - switch (CPUInfo.uiModel) - { - case 0: // Model = 0: Pentium Pro (P6 A-Step) processor model - strcpy(CPUInfo.strModel, "Intel Pentium Pro (P6 A-Step)"); /*Flawfinder: ignore*/ - strncat(strCPUName, "Intel Pentium Pro (P6 A-Step core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - case 1: // Model = 1: Pentium Pro - strcpy(CPUInfo.strModel, "Intel Pentium Pro (P6)"); /*Flawfinder: ignore*/ - strncat(strCPUName, "Intel Pentium Pro (P6 core)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - case 3: // Model = 3: Pentium II (66 MHz FSB, I think) processor model - strcpy(CPUInfo.strModel, "Intel Pentium II Model 3, 0.28 micron"); /*Flawfinder: ignore*/ - strncat(strCPUName, "Intel Pentium II (Model 3 core, 0.28 micron process)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - case 5: // Model = 5: Pentium II/Xeon/Celeron (0.25 micron) processor model - strcpy(CPUInfo.strModel, "Intel Pentium II Model 5/Xeon/Celeron, 0.25 micron"); /*Flawfinder: ignore*/ - strncat(strCPUName, "Intel Pentium II/Xeon/Celeron (Model 5 core, 0.25 micron process)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - case 6: // Model = 6: Pentium II with internal L2 cache - strcpy(CPUInfo.strModel, "Intel Pentium II - internal L2 cache"); /*Flawfinder: ignore*/ - strncat(strCPUName, "Intel Pentium II with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - case 7: // Model = 7: Pentium III/Xeon (extern L2 cache) processor model - strcpy(CPUInfo.strModel, "Intel Pentium III/Pentium III Xeon - external L2 cache, 0.25 micron"); /*Flawfinder: ignore*/ - strncat(strCPUName, "Intel Pentium III/Pentium III Xeon (0.25 micron process) with external L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - case 8: // Model = 8: Pentium III/Xeon/Celeron (256 KB on-die L2 cache) processor model - strcpy(CPUInfo.strModel, "Intel Pentium III/Celeron/Pentium III Xeon - internal L2 cache, 0.18 micron"); /*Flawfinder: ignore*/ - // We want to know it exactly: - switch (CPUInfo.uiBrandID) - { - case 1: // Model = 8, Brand id = 1: Celeron (on-die L2 cache) processor model - strncat(strCPUName, "Intel Celeron (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - case 2: // Model = 8, Brand id = 2: Pentium III (on-die L2 cache) processor model (my current cpu :-)) - strncat(strCPUName, "Intel Pentium III (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - case 3: // Model = 8, Brand id = 3: Pentium III Xeon (on-die L2 cache) processor model - strncat(strCPUName, "Intel Pentium III Xeon (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - default: // ... - strncat(strCPUName, "Intel Pentium III core (unknown model, 0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - } - break; - case 9: // Model = 9: Intel Pentium M processor, Intel Celeron M processor, model 9 - strcpy(CPUInfo.strModel, "Intel Pentium M Series Processor"); /*Flawfinder: ignore*/ - strncat(strCPUName, "Intel Pentium M Series Processor", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - case 0xA: // Model = 0xA: Pentium III/Xeon/Celeron (1 or 2 MB on-die L2 cache) processor model - strcpy(CPUInfo.strModel, "Intel Pentium III/Celeron/Pentium III Xeon - internal L2 cache, 0.18 micron"); /*Flawfinder: ignore*/ - // Exact detection: - switch (CPUInfo.uiBrandID) - { - case 1: // Model = 0xA, Brand id = 1: Celeron (1 or 2 MB on-die L2 cache (does it exist??)) processor model - strncat(strCPUName, "Intel Celeron (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - case 2: // Model = 0xA, Brand id = 2: Pentium III (1 or 2 MB on-die L2 cache (never seen...)) processor model - strncat(strCPUName, "Intel Pentium III (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - case 3: // Model = 0xA, Brand id = 3: Pentium III Xeon (1 or 2 MB on-die L2 cache) processor model - strncat(strCPUName, "Intel Pentium III Xeon (0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - default: // Getting bored of this............ - strncat(strCPUName, "Intel Pentium III core (unknown model, 0.18 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - } - break; - case 0xB: // Model = 0xB: Pentium III/Xeon/Celeron (Tualatin core, on-die cache) processor model - strcpy(CPUInfo.strModel, "Intel Pentium III/Celeron/Pentium III Xeon - internal L2 cache, 0.13 micron"); /*Flawfinder: ignore*/ - // Omniscient: ;-) - switch (CPUInfo.uiBrandID) - { - case 3: // Model = 0xB, Brand id = 3: Celeron (Tualatin core) processor model - strncat(strCPUName, "Intel Celeron (Tualatin core, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - case 4: // Model = 0xB, Brand id = 4: Pentium III (Tualatin core) processor model - strncat(strCPUName, "Intel Pentium III (Tualatin core, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - case 7: // Model = 0xB, Brand id = 7: Celeron mobile (Tualatin core) processor model - strncat(strCPUName, "Intel Celeron mobile (Tualatin core, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - default: // *bored* - strncat(strCPUName, "Intel Pentium III Tualatin core (unknown model, 0.13 micron process) with internal L2 cache", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - } - break; - case 0xD: // Model = 0xD: Intel Pentium M processor, Intel Celeron M processor, model D - strcpy(CPUInfo.strModel, "Intel Pentium M Series Processor"); /*Flawfinder: ignore*/ - strncat(strCPUName, "Intel Pentium M Series Processor", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - case 0xE: // Model = 0xE: Intel Core Duo processor, Intel Core Solo processor, model E - strcpy(CPUInfo.strModel, "Intel Core Series Processor"); /*Flawfinder: ignore*/ - strncat(strCPUName, "Intel Core Series Processor", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - case 0xF: // Model = 0xF: Intel Core 2 Duo processor, model F - strcpy(CPUInfo.strModel, "Intel Core 2 Series Processor"); /*Flawfinder: ignore*/ - strncat(strCPUName, "Intel Core 2 Series Processor", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - default: // *more bored* - strcpy(CPUInfo.strModel, "Unknown Intel Pentium Pro/2/3, Core"); /*Flawfinder: ignore*/ - strncat(strCPUName, "Intel Pentium Pro/2/3, Core (Unknown model)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - break; - } - break; - case 15: // Extended processor family - // Masking the extended model - CPUInfo.uiExtendedModel = (eaxreg >> 16) & 0xFF; - switch (CPUInfo.uiModel) + // Interpret CPU feature information. + if (i == 1) { - case 0: // Model = 0: Pentium 4 Willamette (A-Step) core - if ((CPUInfo.uiBrandID) == 8) // Brand id = 8: P4 Willamette - { - strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette (A-Step)"); /*Flawfinder: ignore*/ - strncat(strCPUName, "Intel Pentium 4 Willamette (A-Step)", sizeof(strCPUName)-(strlen(strCPUName)-1)); /*Flawfinder: ignore*/ - } - else // else Xeon - { - strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette Xeon (A-Step)"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel Pentium 4 Willamette Xeon (A-Step)", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */ - } - break; - case 1: // Model = 1: Pentium 4 Willamette core - if ((CPUInfo.uiBrandID) == 8) // Brand id = 8: P4 Willamette + setInfo(eStepping, cpu_info[0] & 0xf); + setInfo(eModel, (cpu_info[0] >> 4) & 0xf); + int family = (cpu_info[0] >> 8) & 0xf; + setInfo(eFamily, family); + setInfo(eType, (cpu_info[0] >> 12) & 0x3); + setInfo(eExtendedModel, (cpu_info[0] >> 16) & 0xf); + int ext_family = (cpu_info[0] >> 20) & 0xff; + setInfo(eExtendedFamily, ext_family); + setInfo(eBrandID, cpu_info[1] & 0xff); + + setInfo(eFamilyName, compute_CPUFamilyName(cpu_vendor, family, ext_family)); + + setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8); + setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff); + + if(cpu_info[2] & 0x1) + { + setExtension(cpu_feature_names[eSSE3_Features]); + } + + if(cpu_info[2] & 0x8) + { + setExtension(cpu_feature_names[eMONTIOR_MWAIT]); + } + + if(cpu_info[2] & 0x10) + { + setExtension(cpu_feature_names[eCPLDebugStore]); + } + + if(cpu_info[2] & 0x100) + { + setExtension(cpu_feature_names[eThermalMonitor2]); + } + + unsigned int feature_info = (unsigned int) cpu_info[3]; + for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1) + { + if(feature_info & bit) { - strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel Pentium 4 Willamette", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */ + setExtension(cpu_feature_names[index]); } - else // else Xeon - { - strcpy(CPUInfo.strModel, "Intel Pentium 4 Willamette Xeon"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel Pentium 4 Willamette Xeon", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */ - } - break; - case 2: // Model = 2: Pentium 4 Northwood core - if (((CPUInfo.uiBrandID) == 9) || ((CPUInfo.uiBrandID) == 0xA)) // P4 Willamette - { - strcpy(CPUInfo.strModel, "Intel Pentium 4 Northwood"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel Pentium 4 Northwood", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */ - } - else // Xeon - { - strcpy(CPUInfo.strModel, "Intel Pentium 4 Northwood Xeon"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel Pentium 4 Northwood Xeon", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */ - } - break; - default: // Silly stupid never used failsave option - strcpy(CPUInfo.strModel, "Unknown Intel Pentium 4"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel Pentium 4 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */ - break; + } } - break; - default: // *grmpf* - strcpy(CPUInfo.strModel, "Unknown Intel model"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */ - break; - } - - // After the long processor model block we now come to the processors serial - // number. - // First of all we check if the processor supports the serial number - if (CPUInfo.MaxSupportedLevel >= 3) - { - // If it supports the serial number CPUID level 0x00000003 we read the data - unsigned long sig1, sig2, sig3; - __asm - { - mov eax, 1 - cpuid - mov sig1, eax - mov eax, 3 - cpuid - mov sig2, ecx - mov sig3, edx } - // Then we convert the data to a readable string - snprintf( /* Flawfinder: ignore */ - CPUInfo.strProcessorSerial, - sizeof(CPUInfo.strProcessorSerial), - "%04lX-%04lX-%04lX-%04lX-%04lX-%04lX", - sig1 >> 16, - sig1 & 0xFFFF, - sig3 >> 16, - sig3 & 0xFFFF, - sig2 >> 16, sig2 & 0xFFFF); - } - else - { - // If there's no serial number support we just put "No serial number" - snprintf( /* Flawfinder: ignore */ - CPUInfo.strProcessorSerial, - sizeof(CPUInfo.strProcessorSerial), - "No Processor Serial Number"); - } - - // Now we get the standard processor extensions - GetStandardProcessorExtensions(); - // And finally the processor configuration (caches, TLBs, ...) and translate - // the data to readable strings - GetStandardProcessorConfiguration(); - TranslateProcessorConfiguration(); + // Calling __cpuid with 0x80000000 as the InfoType argument + // gets the number of valid extended IDs. + __cpuid(cpu_info, 0x80000000); + unsigned int ext_ids = cpu_info[0]; + setConfig(eMaxExtID, 0); - // At last... - return true; -#else - return FALSE; -#endif -} + char cpu_brand_string[0x40]; + memset(cpu_brand_string, 0, sizeof(cpu_brand_string)); -// bool CProcessor::AnalyzeAMDProcessor() -// ====================================== -// Private class function for analyzing an AMD processor -//////////////////////////////////////////////////////// -bool CProcessor::AnalyzeAMDProcessor() -{ -#if LL_WINDOWS - unsigned long eaxreg, ebxreg, ecxreg, edxreg; - - // First of all we check if the CPUID command is available - if (!CheckCPUIDPresence()) - return 0; - - // Now we get the CPUID standard level 0x00000001 - __asm - { - mov eax, 1 - cpuid - mov eaxreg, eax - mov ebxreg, ebx - mov edxreg, edx - } - - // Then we mask the model, family, stepping and type (AMD does not support brand id) - CPUInfo.uiStepping = eaxreg & 0xF; - CPUInfo.uiModel = (eaxreg >> 4) & 0xF; - CPUInfo.uiFamily = (eaxreg >> 8) & 0xF; - CPUInfo.uiType = (eaxreg >> 12) & 0x3; - - // Now we check if the processor supports the brand id string extended CPUID level - if (CPUInfo.MaxSupportedExtendedLevel >= 0x80000004) - { - // If it supports the extended CPUID level 0x80000004 we read the data - char tmp[52]; /* Flawfinder: ignore */ - memset(tmp, 0, sizeof(tmp)); - __asm + // Get the information associated with each extended ID. + for(unsigned int i=0x80000000; i<=ext_ids; ++i) { - mov eax, 0x80000002 - cpuid - mov dword ptr [tmp], eax - mov dword ptr [tmp+4], ebx - mov dword ptr [tmp+8], ecx - mov dword ptr [tmp+12], edx - mov eax, 0x80000003 - cpuid - mov dword ptr [tmp+16], eax - mov dword ptr [tmp+20], ebx - mov dword ptr [tmp+24], ecx - mov dword ptr [tmp+28], edx - mov eax, 0x80000004 - cpuid - mov dword ptr [tmp+32], eax - mov dword ptr [tmp+36], ebx - mov dword ptr [tmp+40], ecx - mov dword ptr [tmp+44], edx - } - // And copy it to the brand id string - strncpy(CPUInfo.strBrandID, tmp,sizeof(CPUInfo.strBrandID)-1); - CPUInfo.strBrandID[sizeof(CPUInfo.strBrandID)-1]='\0'; - } - else - { - // Or just tell there is no brand id string support - strcpy(CPUInfo.strBrandID, ""); /* Flawfinder: ignore */ - } - - // After that we translate the processor family - switch(CPUInfo.uiFamily) - { - case 4: // Family = 4: 486 (80486) or 5x86 (80486) processor family - switch (CPUInfo.uiModel) + __cpuid(cpu_info, i); + + // Interpret CPU brand string and cache information. + if (i == 0x80000002) + memcpy(cpu_brand_string, cpu_info, sizeof(cpu_info)); + else if (i == 0x80000003) + memcpy(cpu_brand_string + 16, cpu_info, sizeof(cpu_info)); + else if (i == 0x80000004) { - case 3: // Thanks to AMD for this nice form of family - case 7: // detection.... *grmpf* - case 8: - case 9: - strcpy(CPUInfo.strFamily, "AMD 80486"); /* Flawfinder: ignore */ - break; - case 0xE: - case 0xF: - strcpy(CPUInfo.strFamily, "AMD 5x86"); /* Flawfinder: ignore */ - break; - default: - strcpy(CPUInfo.strFamily, "Unknown family"); /* Flawfinder: ignore */ - break; + memcpy(cpu_brand_string + 32, cpu_info, sizeof(cpu_info)); + setInfo(eBrandName, cpu_brand_string); } - break; - case 5: // Family = 5: K5 or K6 processor family - switch (CPUInfo.uiModel) + else if (i == 0x80000006) { - case 0: - case 1: - case 2: - case 3: - strcpy(CPUInfo.strFamily, "AMD K5"); /* Flawfinder: ignore */ - break; - case 6: - case 7: - case 8: - case 9: - strcpy(CPUInfo.strFamily, "AMD K6"); /* Flawfinder: ignore */ - break; - default: - strcpy(CPUInfo.strFamily, "Unknown family"); /* Flawfinder: ignore */ - break; + setConfig(eCacheLineSize, cpu_info[2] & 0xff); + setConfig(eL2Associativity, (cpu_info[2] >> 12) & 0xf); + setConfig(eCacheSizeK, (cpu_info[2] >> 16) & 0xffff); } - break; - case 6: // Family = 6: K7 (Athlon, ...) processor family - strcpy(CPUInfo.strFamily, "AMD K7"); /* Flawfinder: ignore */ - break; - default: // For security - strcpy(CPUInfo.strFamily, "Unknown family"); /* Flawfinder: ignore */ - break; + } } +}; - // After the family detection we come to the specific processor model - // detection - switch (CPUInfo.uiFamily) - { - case 4: // Family = 4: 486 (80486) or 5x85 (80486) processor family - switch (CPUInfo.uiModel) - { - case 3: // Model = 3: 80486 DX2 - strcpy(CPUInfo.strModel, "AMD 80486 DX2"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD 80486 DX2", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - case 7: // Model = 7: 80486 write-back enhanced DX2 - strcpy(CPUInfo.strModel, "AMD 80486 write-back enhanced DX2"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD 80486 write-back enhanced DX2", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - case 8: // Model = 8: 80486 DX4 - strcpy(CPUInfo.strModel, "AMD 80486 DX4"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD 80486 DX4", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - case 9: // Model = 9: 80486 write-back enhanced DX4 - strcpy(CPUInfo.strModel, "AMD 80486 write-back enhanced DX4"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD 80486 write-back enhanced DX4", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - case 0xE: // Model = 0xE: 5x86 - strcpy(CPUInfo.strModel, "AMD 5x86"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD 5x86", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - case 0xF: // Model = 0xF: 5x86 write-back enhanced (oh my god.....) - strcpy(CPUInfo.strModel, "AMD 5x86 write-back enhanced"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD 5x86 write-back enhanced", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - default: // ... - strcpy(CPUInfo.strModel, "Unknown AMD 80486 or 5x86 model"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD 80486 or 5x86 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - } - break; - case 5: // Family = 5: K5 / K6 processor family - switch (CPUInfo.uiModel) - { - case 0: // Model = 0: K5 SSA 5 (Pentium Rating *ggg* 75, 90 and 100 MHz) - strcpy(CPUInfo.strModel, "AMD K5 SSA5 (PR75, PR90, PR100)"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD K5 SSA5 (PR75, PR90, PR100)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - case 1: // Model = 1: K5 5k86 (PR 120 and 133 MHz) - strcpy(CPUInfo.strModel, "AMD K5 5k86 (PR120, PR133)"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD K5 5k86 (PR120, PR133)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - case 2: // Model = 2: K5 5k86 (PR 166 MHz) - strcpy(CPUInfo.strModel, "AMD K5 5k86 (PR166)"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD K5 5k86 (PR166)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - case 3: // Model = 3: K5 5k86 (PR 200 MHz) - strcpy(CPUInfo.strModel, "AMD K5 5k86 (PR200)"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD K5 5k86 (PR200)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - case 6: // Model = 6: K6 - strcpy(CPUInfo.strModel, "AMD K6 (0.30 micron)"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD K6 (0.30 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - case 7: // Model = 7: K6 (0.25 micron) - strcpy(CPUInfo.strModel, "AMD K6 (0.25 micron)"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD K6 (0.25 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - case 8: // Model = 8: K6-2 - strcpy(CPUInfo.strModel, "AMD K6-2"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD K6-2", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - case 9: // Model = 9: K6-III - strcpy(CPUInfo.strModel, "AMD K6-III"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD K6-III", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - case 0xD: // Model = 0xD: K6-2+ / K6-III+ - strcpy(CPUInfo.strModel, "AMD K6-2+ or K6-III+ (0.18 micron)"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD K6-2+ or K6-III+ (0.18 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - default: // ... - strcpy(CPUInfo.strModel, "Unknown AMD K5 or K6 model"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD K5 or K6 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - } - break; - case 6: // Family = 6: K7 processor family (AMDs first good processors) - switch (CPUInfo.uiModel) +#elif LL_DARWIN + +#include <mach/machine.h> +#include <sys/sysctl.h> + +class LLProcessorInfoDarwinImpl : public LLProcessorInfoImpl +{ +public: + LLProcessorInfoDarwinImpl() + { + getCPUIDInfo(); + uint64_t frequency = getSysctlInt64("hw.cpufrequency"); + setInfo(eFrequency, (F64)frequency / (F64)1000000); + } + + virtual ~LLProcessorInfoDarwinImpl() {} + +private: + int getSysctlInt(const char* name) + { + int result = 0; + size_t len = sizeof(int); + int error = sysctlbyname(name, (void*)&result, &len, NULL, 0); + return error == -1 ? 0 : result; + } + + uint64_t getSysctlInt64(const char* name) + { + uint64_t value = 0; + size_t size = sizeof(value); + int result = sysctlbyname(name, (void*)&value, &size, NULL, 0); + if ( result == 0 ) + { + if ( size == sizeof( uint64_t ) ) + ; + else if ( size == sizeof( uint32_t ) ) + value = (uint64_t)(( uint32_t *)&value); + else if ( size == sizeof( uint16_t ) ) + value = (uint64_t)(( uint16_t *)&value); + else if ( size == sizeof( uint8_t ) ) + value = (uint64_t)(( uint8_t *)&value); + else { - case 1: // Athlon - strcpy(CPUInfo.strModel, "AMD Athlon (0.25 micron)"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD Athlon (0.25 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - case 2: // Athlon (0.18 micron) - strcpy(CPUInfo.strModel, "AMD Athlon (0.18 micron)"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD Athlon (0.18 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - case 3: // Duron (Spitfire core) - strcpy(CPUInfo.strModel, "AMD Duron (Spitfire)"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD Duron (Spitfire core)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - case 4: // Athlon (Thunderbird core) - strcpy(CPUInfo.strModel, "AMD Athlon (Thunderbird)"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD Athlon (Thunderbird core)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - case 6: // Athlon MP / Mobile Athlon (Palomino core) - strcpy(CPUInfo.strModel, "AMD Athlon MP/Mobile Athlon (Palomino)"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD Athlon MP/Mobile Athlon (Palomino core)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - case 7: // Mobile Duron (Morgan core) - strcpy(CPUInfo.strModel, "AMD Mobile Duron (Morgan)"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD Mobile Duron (Morgan core)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - default: // ... - strcpy(CPUInfo.strModel, "Unknown AMD K7 model"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD K7 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; + LL_WARNS("Unknown type returned from sysctl!") << LL_ENDL; } - break; - default: // ... - strcpy(CPUInfo.strModel, "Unknown AMD model"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - } - - // Now we read the standard processor extension that are stored in the same - // way the Intel standard extensions are - GetStandardProcessorExtensions(); - - // Then we check if theres an extended CPUID level support - if (CPUInfo.MaxSupportedExtendedLevel >= 0x80000001) - { - // If we can access the extended CPUID level 0x80000001 we get the - // edx register - __asm - { - mov eax, 0x80000001 - cpuid - mov edxreg, edx } - - // Now we can mask some AMD specific cpu extensions - CPUInfo._Ext.EMMX_MultimediaExtensions = CheckBit(edxreg, 22); - CPUInfo._Ext.AA64_AMD64BitArchitecture = CheckBit(edxreg, 29); - CPUInfo._Ext._E3DNOW_InstructionExtensions = CheckBit(edxreg, 30); - CPUInfo._Ext._3DNOW_InstructionExtensions = CheckBit(edxreg, 31); - } - - // After that we check if the processor supports the ext. CPUID level - // 0x80000006 - if (CPUInfo.MaxSupportedExtendedLevel >= 0x80000006) + + return result == -1 ? 0 : value; + } + + void getCPUIDInfo() { - // If it's present, we read it out - __asm - { - mov eax, 0x80000005 - cpuid - mov eaxreg, eax - mov ebxreg, ebx - mov ecxreg, ecx - mov edxreg, edx - } + size_t len = 0; - // Then we mask the L1 Data TLB information - if ((ebxreg >> 16) && (eaxreg >> 16)) - { - CPUInfo._Data.bPresent = true; - strcpy(CPUInfo._Data.strPageSize, "4 KB / 2 MB / 4MB"); /*Flawfinder: ignore*/ - CPUInfo._Data.uiAssociativeWays = (eaxreg >> 24) & 0xFF; - CPUInfo._Data.uiEntries = (eaxreg >> 16) & 0xFF; - } - else if (eaxreg >> 16) - { - CPUInfo._Data.bPresent = true; - strcpy(CPUInfo._Data.strPageSize, "2 MB / 4MB"); /*Flawfinder: ignore*/ - CPUInfo._Data.uiAssociativeWays = (eaxreg >> 24) & 0xFF; - CPUInfo._Data.uiEntries = (eaxreg >> 16) & 0xFF; - } - else if (ebxreg >> 16) - { - CPUInfo._Data.bPresent = true; - strcpy(CPUInfo._Data.strPageSize, "4 KB"); /*Flawfinder: ignore*/ - CPUInfo._Data.uiAssociativeWays = (ebxreg >> 24) & 0xFF; - CPUInfo._Data.uiEntries = (ebxreg >> 16) & 0xFF; - } - if (CPUInfo._Data.uiAssociativeWays == 0xFF) - CPUInfo._Data.uiAssociativeWays = (unsigned int) -1; - - // Now the L1 Instruction/Code TLB information - if ((ebxreg & 0xFFFF) && (eaxreg & 0xFFFF)) - { - CPUInfo._Instruction.bPresent = true; - strcpy(CPUInfo._Instruction.strPageSize, "4 KB / 2 MB / 4MB"); /*Flawfinder: ignore*/ - CPUInfo._Instruction.uiAssociativeWays = (eaxreg >> 8) & 0xFF; - CPUInfo._Instruction.uiEntries = eaxreg & 0xFF; - } - else if (eaxreg & 0xFFFF) - { - CPUInfo._Instruction.bPresent = true; - strcpy(CPUInfo._Instruction.strPageSize, "2 MB / 4MB"); /*Flawfinder: ignore*/ - CPUInfo._Instruction.uiAssociativeWays = (eaxreg >> 8) & 0xFF; - CPUInfo._Instruction.uiEntries = eaxreg & 0xFF; - } - else if (ebxreg & 0xFFFF) - { - CPUInfo._Instruction.bPresent = true; - strcpy(CPUInfo._Instruction.strPageSize, "4 KB"); /*Flawfinder: ignore*/ - CPUInfo._Instruction.uiAssociativeWays = (ebxreg >> 8) & 0xFF; - CPUInfo._Instruction.uiEntries = ebxreg & 0xFF; - } - if (CPUInfo._Instruction.uiAssociativeWays == 0xFF) - CPUInfo._Instruction.uiAssociativeWays = (unsigned int) -1; + char cpu_brand_string[0x40]; + len = sizeof(cpu_brand_string); + memset(cpu_brand_string, 0, len); + sysctlbyname("machdep.cpu.brand_string", (void*)cpu_brand_string, &len, NULL, 0); + cpu_brand_string[0x3f] = 0; + setInfo(eBrandName, cpu_brand_string); - // Then we read the L1 data cache information - if ((ecxreg >> 24) > 0) - { - CPUInfo._L1.Data.bPresent = true; - snprintf(CPUInfo._L1.Data.strSize, sizeof(CPUInfo._L1.Data.strSize), "%d KB", ecxreg >> 24); /* Flawfinder: ignore */ - CPUInfo._L1.Data.uiAssociativeWays = (ecxreg >> 15) & 0xFF; - CPUInfo._L1.Data.uiLineSize = ecxreg & 0xFF; - } - // After that we read the L2 instruction/code cache information - if ((edxreg >> 24) > 0) - { - CPUInfo._L1.Instruction.bPresent = true; - snprintf(CPUInfo._L1.Instruction.strSize, sizeof(CPUInfo._L1.Instruction.strSize), "%d KB", edxreg >> 24); /* Flawfinder: ignore */ - CPUInfo._L1.Instruction.uiAssociativeWays = (edxreg >> 15) & 0xFF; - CPUInfo._L1.Instruction.uiLineSize = edxreg & 0xFF; - } - - // Note: I'm not absolutely sure that the L1 page size code (the - // 'if/else if/else if' structs above) really detects the real page - // size for the TLB. Somebody should check it.... - - // Now we read the ext. CPUID level 0x80000006 - __asm - { - mov eax, 0x80000006 - cpuid - mov eaxreg, eax - mov ebxreg, ebx - mov ecxreg, ecx - } + char cpu_vendor[0x20]; + len = sizeof(cpu_vendor); + memset(cpu_vendor, 0, len); + sysctlbyname("machdep.cpu.vendor", (void*)cpu_vendor, &len, NULL, 0); + cpu_vendor[0x1f] = 0; + setInfo(eVendor, cpu_vendor); + + setInfo(eStepping, getSysctlInt("machdep.cpu.stepping")); + setInfo(eModel, getSysctlInt("machdep.cpu.model")); + int family = getSysctlInt("machdep.cpu.family"); + int ext_family = getSysctlInt("machdep.cpu.extfamily"); + setInfo(eFamily, family); + setInfo(eExtendedFamily, ext_family); + setInfo(eFamilyName, compute_CPUFamilyName(cpu_vendor, family, ext_family)); + setInfo(eExtendedModel, getSysctlInt("machdep.cpu.extmodel")); + setInfo(eBrandID, getSysctlInt("machdep.cpu.brand")); + setInfo(eType, 0); // ? where to find this? + + //setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8); + //setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff); + setConfig(eCacheLineSize, getSysctlInt("machdep.cpu.cache.linesize")); + setConfig(eL2Associativity, getSysctlInt("machdep.cpu.cache.L2_associativity")); + setConfig(eCacheSizeK, getSysctlInt("machdep.cpu.cache.size")); + + uint64_t feature_info = getSysctlInt64("machdep.cpu.feature_bits"); + S32 *feature_infos = (S32*)(&feature_info); + + setConfig(eFeatureBits, feature_infos[0]); - // We only mask the unified L2 cache masks (never heard of an - // L2 cache that is divided in data and code parts) - if (((ecxreg >> 12) & 0xF) > 0) + for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1) { - CPUInfo._L2.bPresent = true; - snprintf(CPUInfo._L2.strSize, sizeof(CPUInfo._L2.strSize), "%d KB", ecxreg >> 16); /* Flawfinder: ignore */ - switch ((ecxreg >> 12) & 0xF) + if(feature_info & bit) { - case 1: - CPUInfo._L2.uiAssociativeWays = 1; - break; - case 2: - CPUInfo._L2.uiAssociativeWays = 2; - break; - case 4: - CPUInfo._L2.uiAssociativeWays = 4; - break; - case 6: - CPUInfo._L2.uiAssociativeWays = 8; - break; - case 8: - CPUInfo._L2.uiAssociativeWays = 16; - break; - case 0xF: - CPUInfo._L2.uiAssociativeWays = (unsigned int) -1; - break; - default: - CPUInfo._L2.uiAssociativeWays = 0; - break; + setExtension(cpu_feature_names[index]); } - CPUInfo._L2.uiLineSize = ecxreg & 0xFF; } - } - else - { - // If we could not detect the ext. CPUID level 0x80000006 we - // try to read the standard processor configuration. - GetStandardProcessorConfiguration(); - } - // After reading we translate the configuration to strings - TranslateProcessorConfiguration(); - - // And finally exit - return true; -#else - return FALSE; -#endif -} - -// bool CProcessor::AnalyzeUnknownProcessor() -// ========================================== -// Private class function to analyze an unknown (No Intel or AMD) processor -/////////////////////////////////////////////////////////////////////////// -bool CProcessor::AnalyzeUnknownProcessor() -{ -#if LL_WINDOWS - unsigned long eaxreg, ebxreg; - - // We check if the CPUID command is available - if (!CheckCPUIDPresence()) - return false; - - // First of all we read the standard CPUID level 0x00000001 - // This level should be available on every x86-processor clone - __asm - { - mov eax, 1 - cpuid - mov eaxreg, eax - mov ebxreg, ebx - } - // Then we mask the processor model, family, type and stepping - CPUInfo.uiStepping = eaxreg & 0xF; - CPUInfo.uiModel = (eaxreg >> 4) & 0xF; - CPUInfo.uiFamily = (eaxreg >> 8) & 0xF; - CPUInfo.uiType = (eaxreg >> 12) & 0x3; - - // To have complete information we also mask the brand id - CPUInfo.uiBrandID = ebxreg & 0xF; - - // Then we get the standard processor extensions - GetStandardProcessorExtensions(); - - // Now we mark everything we do not know as unknown - strcpy(strCPUName, "Unknown"); /*Flawfinder: ignore*/ - - strcpy(CPUInfo._Data.strTLB, "Unknown"); /*Flawfinder: ignore*/ - strcpy(CPUInfo._Instruction.strTLB, "Unknown"); /*Flawfinder: ignore*/ - - strcpy(CPUInfo._Trace.strCache, "Unknown"); /*Flawfinder: ignore*/ - strcpy(CPUInfo._L1.Data.strCache, "Unknown"); /*Flawfinder: ignore*/ - strcpy(CPUInfo._L1.Instruction.strCache, "Unknown"); /*Flawfinder: ignore*/ - strcpy(CPUInfo._L2.strCache, "Unknown"); /*Flawfinder: ignore*/ - strcpy(CPUInfo._L3.strCache, "Unknown"); /*Flawfinder: ignore*/ - - strcpy(CPUInfo.strProcessorSerial, "Unknown / Not supported"); /*Flawfinder: ignore*/ - - // For the family, model and brand id we can only print the numeric value - snprintf(CPUInfo.strBrandID, sizeof(CPUInfo.strBrandID), "Brand-ID number %d", CPUInfo.uiBrandID); /* Flawfinder: ignore */ - snprintf(CPUInfo.strFamily, sizeof(CPUInfo.strFamily), "Family number %d", CPUInfo.uiFamily); /* Flawfinder: ignore */ - snprintf(CPUInfo.strModel, sizeof(CPUInfo.strModel), "Model number %d", CPUInfo.uiModel); /* Flawfinder: ignore */ - - // And thats it - return true; -#else - return FALSE; -#endif -} - -// bool CProcessor::CheckCPUIDPresence() -// ===================================== -// This function checks if the CPUID command is available on the current -// processor -//////////////////////////////////////////////////////////////////////// -bool CProcessor::CheckCPUIDPresence() -{ -#if LL_WINDOWS - unsigned long BitChanged; - - // We've to check if we can toggle the flag register bit 21 - // If we can't the processor does not support the CPUID command - __asm - { - pushfd - pop eax - mov ebx, eax - xor eax, 0x00200000 - push eax - popfd - pushfd - pop eax - xor eax,ebx - mov BitChanged, eax - } - return ((BitChanged) ? true : false); -#else - return FALSE; -#endif -} + // *NOTE:Mani - I didn't find any docs that assure me that machdep.cpu.feature_bits will always be + // The feature bits I think it is. Here's a test: +#ifndef LL_RELEASE_FOR_DOWNLOAD + #if defined(__i386__) && defined(__PIC__) + /* %ebx may be the PIC register. */ + #define __cpuid(level, a, b, c, d) \ + __asm__ ("xchgl\t%%ebx, %1\n\t" \ + "cpuid\n\t" \ + "xchgl\t%%ebx, %1\n\t" \ + : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ + : "0" (level)) + #else + #define __cpuid(level, a, b, c, d) \ + __asm__ ("cpuid\n\t" \ + : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \ + : "0" (level)) + #endif + + unsigned int eax, ebx, ecx, edx; + __cpuid(0x1, eax, ebx, ecx, edx); + if(feature_infos[0] != (S32)edx) + { + llerrs << "machdep.cpu.feature_bits doesn't match expected cpuid result!" << llendl; + } +#endif // LL_RELEASE_FOR_DOWNLOAD -// void CProcessor::DecodeProcessorConfiguration(unsigned int cfg) -// =============================================================== -// This function (or switch ?!) just translates a one-byte processor configuration -// byte to understandable values -////////////////////////////////////////////////////////////////////////////////// -void CProcessor::DecodeProcessorConfiguration(unsigned int cfg) -{ - // First we ensure that there's only one single byte - cfg &= 0xFF; - // Then we do a big switch - switch(cfg) - { - case 0: // cfg = 0: Unused - break; - case 0x1: // cfg = 0x1: code TLB present, 4 KB pages, 4 ways, 32 entries - CPUInfo._Instruction.bPresent = true; - strcpy(CPUInfo._Instruction.strPageSize, "4 KB"); /*Flawfinder: ignore*/ - CPUInfo._Instruction.uiAssociativeWays = 4; - CPUInfo._Instruction.uiEntries = 32; - break; - case 0x2: // cfg = 0x2: code TLB present, 4 MB pages, fully associative, 2 entries - CPUInfo._Instruction.bPresent = true; - strcpy(CPUInfo._Instruction.strPageSize, "4 MB"); /*Flawfinder: ignore*/ - CPUInfo._Instruction.uiAssociativeWays = 4; - CPUInfo._Instruction.uiEntries = 2; - break; - case 0x3: // cfg = 0x3: data TLB present, 4 KB pages, 4 ways, 64 entries - CPUInfo._Data.bPresent = true; - strcpy(CPUInfo._Data.strPageSize, "4 KB"); /*Flawfinder: ignore*/ - CPUInfo._Data.uiAssociativeWays = 4; - CPUInfo._Data.uiEntries = 64; - break; - case 0x4: // cfg = 0x4: data TLB present, 4 MB pages, 4 ways, 8 entries - CPUInfo._Data.bPresent = true; - strcpy(CPUInfo._Data.strPageSize, "4 MB"); /*Flawfinder: ignore*/ - CPUInfo._Data.uiAssociativeWays = 4; - CPUInfo._Data.uiEntries = 8; - break; - case 0x6: // cfg = 0x6: code L1 cache present, 8 KB, 4 ways, 32 byte lines - CPUInfo._L1.Instruction.bPresent = true; - strcpy(CPUInfo._L1.Instruction.strSize, "8 KB"); /*Flawfinder: ignore*/ - CPUInfo._L1.Instruction.uiAssociativeWays = 4; - CPUInfo._L1.Instruction.uiLineSize = 32; - break; - case 0x8: // cfg = 0x8: code L1 cache present, 16 KB, 4 ways, 32 byte lines - CPUInfo._L1.Instruction.bPresent = true; - strcpy(CPUInfo._L1.Instruction.strSize, "16 KB"); /*Flawfinder: ignore*/ - CPUInfo._L1.Instruction.uiAssociativeWays = 4; - CPUInfo._L1.Instruction.uiLineSize = 32; - break; - case 0xA: // cfg = 0xA: data L1 cache present, 8 KB, 2 ways, 32 byte lines - CPUInfo._L1.Data.bPresent = true; - strcpy(CPUInfo._L1.Data.strSize, "8 KB"); /*Flawfinder: ignore*/ - CPUInfo._L1.Data.uiAssociativeWays = 2; - CPUInfo._L1.Data.uiLineSize = 32; - break; - case 0xC: // cfg = 0xC: data L1 cache present, 16 KB, 4 ways, 32 byte lines - CPUInfo._L1.Data.bPresent = true; - strcpy(CPUInfo._L1.Data.strSize, "16 KB"); /*Flawfinder: ignore*/ - CPUInfo._L1.Data.uiAssociativeWays = 4; - CPUInfo._L1.Data.uiLineSize = 32; - break; - case 0x22: // cfg = 0x22: code and data L3 cache present, 512 KB, 4 ways, 64 byte lines, sectored - CPUInfo._L3.bPresent = true; - strcpy(CPUInfo._L3.strSize, "512 KB"); /*Flawfinder: ignore*/ - CPUInfo._L3.uiAssociativeWays = 4; - CPUInfo._L3.uiLineSize = 64; - CPUInfo._L3.bSectored = true; - break; - case 0x23: // cfg = 0x23: code and data L3 cache present, 1024 KB, 8 ways, 64 byte lines, sectored - CPUInfo._L3.bPresent = true; - strcpy(CPUInfo._L3.strSize, "1024 KB"); /*Flawfinder: ignore*/ - CPUInfo._L3.uiAssociativeWays = 8; - CPUInfo._L3.uiLineSize = 64; - CPUInfo._L3.bSectored = true; - break; - case 0x25: // cfg = 0x25: code and data L3 cache present, 2048 KB, 8 ways, 64 byte lines, sectored - CPUInfo._L3.bPresent = true; - strcpy(CPUInfo._L3.strSize, "2048 KB"); /*Flawfinder: ignore*/ - CPUInfo._L3.uiAssociativeWays = 8; - CPUInfo._L3.uiLineSize = 64; - CPUInfo._L3.bSectored = true; - break; - case 0x29: // cfg = 0x29: code and data L3 cache present, 4096 KB, 8 ways, 64 byte lines, sectored - CPUInfo._L3.bPresent = true; - strcpy(CPUInfo._L3.strSize, "4096 KB"); /*Flawfinder: ignore*/ - CPUInfo._L3.uiAssociativeWays = 8; - CPUInfo._L3.uiLineSize = 64; - CPUInfo._L3.bSectored = true; - break; - case 0x40: // cfg = 0x40: no integrated L2 cache (P6 core) or L3 cache (P4 core) - break; - case 0x41: // cfg = 0x41: code and data L2 cache present, 128 KB, 4 ways, 32 byte lines - CPUInfo._L2.bPresent = true; - strcpy(CPUInfo._L2.strSize, "128 KB"); /*Flawfinder: ignore*/ - CPUInfo._L2.uiAssociativeWays = 4; - CPUInfo._L2.uiLineSize = 32; - break; - case 0x42: // cfg = 0x42: code and data L2 cache present, 256 KB, 4 ways, 32 byte lines - CPUInfo._L2.bPresent = true; - strcpy(CPUInfo._L2.strSize, "256 KB"); /*Flawfinder: ignore*/ - CPUInfo._L2.uiAssociativeWays = 4; - CPUInfo._L2.uiLineSize = 32; - break; - case 0x43: // cfg = 0x43: code and data L2 cache present, 512 KB, 4 ways, 32 byte lines - CPUInfo._L2.bPresent = true; - strcpy(CPUInfo._L2.strSize, "512 KB"); /* Flawfinder: ignore */ - CPUInfo._L2.uiAssociativeWays = 4; - CPUInfo._L2.uiLineSize = 32; - break; - case 0x44: // cfg = 0x44: code and data L2 cache present, 1024 KB, 4 ways, 32 byte lines - CPUInfo._L2.bPresent = true; - strcpy(CPUInfo._L2.strSize, "1 MB"); /* Flawfinder: ignore */ - CPUInfo._L2.uiAssociativeWays = 4; - CPUInfo._L2.uiLineSize = 32; - break; - case 0x45: // cfg = 0x45: code and data L2 cache present, 2048 KB, 4 ways, 32 byte lines - CPUInfo._L2.bPresent = true; - strcpy(CPUInfo._L2.strSize, "2 MB"); /* Flawfinder: ignore */ - CPUInfo._L2.uiAssociativeWays = 4; - CPUInfo._L2.uiLineSize = 32; - break; - case 0x50: // cfg = 0x50: code TLB present, 4 KB / 4 MB / 2 MB pages, fully associative, 64 entries - CPUInfo._Instruction.bPresent = true; - strcpy(CPUInfo._Instruction.strPageSize, "4 KB / 2 MB / 4 MB"); /* Flawfinder: ignore */ - CPUInfo._Instruction.uiAssociativeWays = (unsigned int) -1; - CPUInfo._Instruction.uiEntries = 64; - break; - case 0x51: // cfg = 0x51: code TLB present, 4 KB / 4 MB / 2 MB pages, fully associative, 128 entries - CPUInfo._Instruction.bPresent = true; - strcpy(CPUInfo._Instruction.strPageSize, "4 KB / 2 MB / 4 MB"); /* Flawfinder: ignore */ - CPUInfo._Instruction.uiAssociativeWays = (unsigned int) -1; - CPUInfo._Instruction.uiEntries = 128; - break; - case 0x52: // cfg = 0x52: code TLB present, 4 KB / 4 MB / 2 MB pages, fully associative, 256 entries - CPUInfo._Instruction.bPresent = true; - strcpy(CPUInfo._Instruction.strPageSize, "4 KB / 2 MB / 4 MB"); /* Flawfinder: ignore */ - CPUInfo._Instruction.uiAssociativeWays = (unsigned int) -1; - CPUInfo._Instruction.uiEntries = 256; - break; - case 0x5B: // cfg = 0x5B: data TLB present, 4 KB / 4 MB pages, fully associative, 64 entries - CPUInfo._Data.bPresent = true; - strcpy(CPUInfo._Data.strPageSize, "4 KB / 4 MB"); /* Flawfinder: ignore */ - CPUInfo._Data.uiAssociativeWays = (unsigned int) -1; - CPUInfo._Data.uiEntries = 64; - break; - case 0x5C: // cfg = 0x5C: data TLB present, 4 KB / 4 MB pages, fully associative, 128 entries - CPUInfo._Data.bPresent = true; - strcpy(CPUInfo._Data.strPageSize, "4 KB / 4 MB"); /* Flawfinder: ignore */ - CPUInfo._Data.uiAssociativeWays = (unsigned int) -1; - CPUInfo._Data.uiEntries = 128; - break; - case 0x5d: // cfg = 0x5D: data TLB present, 4 KB / 4 MB pages, fully associative, 256 entries - CPUInfo._Data.bPresent = true; - strcpy(CPUInfo._Data.strPageSize, "4 KB / 4 MB"); /* Flawfinder: ignore */ - CPUInfo._Data.uiAssociativeWays = (unsigned int) -1; - CPUInfo._Data.uiEntries = 256; - break; - case 0x66: // cfg = 0x66: data L1 cache present, 8 KB, 4 ways, 64 byte lines, sectored - CPUInfo._L1.Data.bPresent = true; - strcpy(CPUInfo._L1.Data.strSize, "8 KB"); /* Flawfinder: ignore */ - CPUInfo._L1.Data.uiAssociativeWays = 4; - CPUInfo._L1.Data.uiLineSize = 64; - break; - case 0x67: // cfg = 0x67: data L1 cache present, 16 KB, 4 ways, 64 byte lines, sectored - CPUInfo._L1.Data.bPresent = true; - strcpy(CPUInfo._L1.Data.strSize, "16 KB"); /* Flawfinder: ignore */ - CPUInfo._L1.Data.uiAssociativeWays = 4; - CPUInfo._L1.Data.uiLineSize = 64; - break; - case 0x68: // cfg = 0x68: data L1 cache present, 32 KB, 4 ways, 64 byte lines, sectored - CPUInfo._L1.Data.bPresent = true; - strcpy(CPUInfo._L1.Data.strSize, "32 KB"); /* Flawfinder: ignore */ - CPUInfo._L1.Data.uiAssociativeWays = 4; - CPUInfo._L1.Data.uiLineSize = 64; - break; - case 0x70: // cfg = 0x70: trace L1 cache present, 12 KuOPs, 4 ways - CPUInfo._Trace.bPresent = true; - strcpy(CPUInfo._Trace.strSize, "12 K-micro-ops"); /* Flawfinder: ignore */ - CPUInfo._Trace.uiAssociativeWays = 4; - break; - case 0x71: // cfg = 0x71: trace L1 cache present, 16 KuOPs, 4 ways - CPUInfo._Trace.bPresent = true; - strcpy(CPUInfo._Trace.strSize, "16 K-micro-ops"); /* Flawfinder: ignore */ - CPUInfo._Trace.uiAssociativeWays = 4; - break; - case 0x72: // cfg = 0x72: trace L1 cache present, 32 KuOPs, 4 ways - CPUInfo._Trace.bPresent = true; - strcpy(CPUInfo._Trace.strSize, "32 K-micro-ops"); /* Flawfinder: ignore */ - CPUInfo._Trace.uiAssociativeWays = 4; - break; - case 0x79: // cfg = 0x79: code and data L2 cache present, 128 KB, 8 ways, 64 byte lines, sectored - CPUInfo._L2.bPresent = true; - strcpy(CPUInfo._L2.strSize, "128 KB"); /* Flawfinder: ignore */ - CPUInfo._L2.uiAssociativeWays = 8; - CPUInfo._L2.uiLineSize = 64; - CPUInfo._L2.bSectored = true; - break; - case 0x7A: // cfg = 0x7A: code and data L2 cache present, 256 KB, 8 ways, 64 byte lines, sectored - CPUInfo._L2.bPresent = true; - strcpy(CPUInfo._L2.strSize, "256 KB"); /* Flawfinder: ignore */ - CPUInfo._L2.uiAssociativeWays = 8; - CPUInfo._L2.uiLineSize = 64; - CPUInfo._L2.bSectored = true; - break; - case 0x7B: // cfg = 0x7B: code and data L2 cache present, 512 KB, 8 ways, 64 byte lines, sectored - CPUInfo._L2.bPresent = true; - strcpy(CPUInfo._L2.strSize, "512 KB"); /* Flawfinder: ignore */ - CPUInfo._L2.uiAssociativeWays = 8; - CPUInfo._L2.uiLineSize = 64; - CPUInfo._L2.bSectored = true; - break; - case 0x7C: // cfg = 0x7C: code and data L2 cache present, 1024 KB, 8 ways, 64 byte lines, sectored - CPUInfo._L2.bPresent = true; - strcpy(CPUInfo._L2.strSize, "1 MB"); /* Flawfinder: ignore */ - CPUInfo._L2.uiAssociativeWays = 8; - CPUInfo._L2.uiLineSize = 64; - CPUInfo._L2.bSectored = true; - break; - case 0x81: // cfg = 0x81: code and data L2 cache present, 128 KB, 8 ways, 32 byte lines - CPUInfo._L2.bPresent = true; - strcpy(CPUInfo._L2.strSize, "128 KB"); /* Flawfinder: ignore */ - CPUInfo._L2.uiAssociativeWays = 8; - CPUInfo._L2.uiLineSize = 32; - break; - case 0x82: // cfg = 0x82: code and data L2 cache present, 256 KB, 8 ways, 32 byte lines - CPUInfo._L2.bPresent = true; - strcpy(CPUInfo._L2.strSize, "256 KB"); /* Flawfinder: ignore */ - CPUInfo._L2.uiAssociativeWays = 8; - CPUInfo._L2.uiLineSize = 32; - break; - case 0x83: // cfg = 0x83: code and data L2 cache present, 512 KB, 8 ways, 32 byte lines - CPUInfo._L2.bPresent = true; - strcpy(CPUInfo._L2.strSize, "512 KB"); /* Flawfinder: ignore */ - CPUInfo._L2.uiAssociativeWays = 8; - CPUInfo._L2.uiLineSize = 32; - break; - case 0x84: // cfg = 0x84: code and data L2 cache present, 1024 KB, 8 ways, 32 byte lines - CPUInfo._L2.bPresent = true; - strcpy(CPUInfo._L2.strSize, "1 MB"); /* Flawfinder: ignore */ - CPUInfo._L2.uiAssociativeWays = 8; - CPUInfo._L2.uiLineSize = 32; - break; - case 0x85: // cfg = 0x85: code and data L2 cache present, 2048 KB, 8 ways, 32 byte lines - CPUInfo._L2.bPresent = true; - strcpy(CPUInfo._L2.strSize, "2 MB"); /* Flawfinder: ignore */ - CPUInfo._L2.uiAssociativeWays = 8; - CPUInfo._L2.uiLineSize = 32; - break; + uint64_t ext_feature_info = getSysctlInt64("machdep.cpu.extfeature_bits"); + S32 *ext_feature_infos = (S32*)(&ext_feature_info); + setConfig(eExtFeatureBits, ext_feature_infos[0]); } -} +}; -FORCEINLINE static char *TranslateAssociativeWays(unsigned int uiWays, char *buf) -{ - // We define 0xFFFFFFFF (= -1) as fully associative - if (uiWays == ((unsigned int) -1)) - strcpy(buf, "fully associative"); /* Flawfinder: ignore */ - else - { - if (uiWays == 1) // A one way associative cache is just direct mapped - strcpy(buf, "direct mapped"); /* Flawfinder: ignore */ - else if (uiWays == 0) // This should not happen... - strcpy(buf, "unknown associative ways"); /* Flawfinder: ignore */ - else // The x-way associative cache - sprintf(buf, "%d ways associative", uiWays); /* Flawfinder: ignore */ - } - // To ease the function use we return the buffer - return buf; -} -FORCEINLINE static void TranslateTLB(ProcessorTLB *tlb) -{ - char buf[64]; /* Flawfinder: ignore */ +#elif LL_LINUX +const char CPUINFO_FILE[] = "/proc/cpuinfo"; - // We just check if the TLB is present - if (tlb->bPresent) - snprintf(tlb->strTLB,sizeof(tlb->strTLB), "%s page size, %s, %d entries", tlb->strPageSize, TranslateAssociativeWays(tlb->uiAssociativeWays, buf), tlb->uiEntries); /* Flawfinder: ignore */ - else - strcpy(tlb->strTLB, "Not present"); /* Flawfinder: ignore */ -} -FORCEINLINE static void TranslateCache(ProcessorCache *cache) +class LLProcessorInfoLinuxImpl : public LLProcessorInfoImpl { - char buf[64]; /* Flawfinder: ignore */ - - // We just check if the cache is present - if (cache->bPresent) - { - // If present we construct the string - snprintf(cache->strCache, sizeof(cache->strCache), "%s cache size, %s, %d bytes line size", cache->strSize, TranslateAssociativeWays(cache->uiAssociativeWays, buf), cache->uiLineSize); /* Flawfinder: ignore */ - if (cache->bSectored) - strncat(cache->strCache, ", sectored", sizeof(cache->strCache)-strlen(cache->strCache)-1); /* Flawfinder: ignore */ - } - else +public: + LLProcessorInfoLinuxImpl() { - // Else we just say "Not present" - strcpy(cache->strCache, "Not present"); /* Flawfinder: ignore */ + get_proc_cpuinfo(); } -} - -// void CProcessor::TranslateProcessorConfiguration() -// ================================================== -// Private class function to translate the processor configuration values -// to strings -///////////////////////////////////////////////////////////////////////// -void CProcessor::TranslateProcessorConfiguration() -{ - // We just call the small functions defined above - TranslateTLB(&CPUInfo._Data); - TranslateTLB(&CPUInfo._Instruction); - TranslateCache(&CPUInfo._Trace); + virtual ~LLProcessorInfoLinuxImpl() {} +private: - TranslateCache(&CPUInfo._L1.Instruction); - TranslateCache(&CPUInfo._L1.Data); - TranslateCache(&CPUInfo._L2); - TranslateCache(&CPUInfo._L3); -} - -// void CProcessor::GetStandardProcessorConfiguration() -// ==================================================== -// Private class function to read the standard processor configuration -////////////////////////////////////////////////////////////////////// -void CProcessor::GetStandardProcessorConfiguration() -{ -#if LL_WINDOWS - unsigned long eaxreg, ebxreg, ecxreg, edxreg; - - // We check if the CPUID function is available - if (!CheckCPUIDPresence()) - return; - - // First we check if the processor supports the standard - // CPUID level 0x00000002 - if (CPUInfo.MaxSupportedLevel >= 2) + void get_proc_cpuinfo() { - // Now we go read the std. CPUID level 0x00000002 the first time - unsigned long count, num = 255; - for (count = 0; count < num; count++) + std::map< std::string, std::string > cpuinfo; + LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb"); + if(cpuinfo_fp) { - __asm - { - mov eax, 2 - cpuid - mov eaxreg, eax - mov ebxreg, ebx - mov ecxreg, ecx - mov edxreg, edx - } - // We have to repeat this reading for 'num' times - num = eaxreg & 0xFF; - - // Then we call the big decode switch function - DecodeProcessorConfiguration(eaxreg >> 8); - DecodeProcessorConfiguration(eaxreg >> 16); - DecodeProcessorConfiguration(eaxreg >> 24); - - // If ebx contains additional data we also decode it - if ((ebxreg & 0x80000000) == 0) + char line[MAX_STRING]; + memset(line, 0, MAX_STRING); + while(fgets(line, MAX_STRING, cpuinfo_fp)) { - DecodeProcessorConfiguration(ebxreg); - DecodeProcessorConfiguration(ebxreg >> 8); - DecodeProcessorConfiguration(ebxreg >> 16); - DecodeProcessorConfiguration(ebxreg >> 24); - } - // And also the ecx register - if ((ecxreg & 0x80000000) == 0) - { - DecodeProcessorConfiguration(ecxreg); - DecodeProcessorConfiguration(ecxreg >> 8); - DecodeProcessorConfiguration(ecxreg >> 16); - DecodeProcessorConfiguration(ecxreg >> 24); - } - // At last the edx processor register - if ((edxreg & 0x80000000) == 0) - { - DecodeProcessorConfiguration(edxreg); - DecodeProcessorConfiguration(edxreg >> 8); - DecodeProcessorConfiguration(edxreg >> 16); - DecodeProcessorConfiguration(edxreg >> 24); + // /proc/cpuinfo on Linux looks like: + // name\t*: value\n + char* tabspot = strchr( line, '\t' ); + if (tabspot == NULL) + continue; + char* colspot = strchr( tabspot, ':' ); + if (colspot == NULL) + continue; + char* spacespot = strchr( colspot, ' ' ); + if (spacespot == NULL) + continue; + char* nlspot = strchr( line, '\n' ); + if (nlspot == NULL) + nlspot = line + strlen( line ); // Fallback to terminating NUL + std::string linename( line, tabspot ); + std::string llinename(linename); + LLStringUtil::toLower(llinename); + std::string lineval( spacespot + 1, nlspot ); + cpuinfo[ llinename ] = lineval; } + fclose(cpuinfo_fp); + } +# if LL_X86 + +// *NOTE:Mani - eww, macros! srry. +#define LLPI_SET_INFO_STRING(llpi_id, cpuinfo_id) \ + if (!cpuinfo[cpuinfo_id].empty()) \ + { setInfo(llpi_id, cpuinfo[cpuinfo_id]);} + +#define LLPI_SET_INFO_INT(llpi_id, cpuinfo_id) \ + {\ + S32 result; \ + if (!cpuinfo[cpuinfo_id].empty() \ + && LLStringUtil::convertToS32(cpuinfo[cpuinfo_id], result)) \ + { setInfo(llpi_id, result);} \ + } + + F64 mhz; + if (LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhz) + && 200.0 < mhz && mhz < 10000.0) + { + setInfo(eFrequency,(F64)(mhz)); } - } -#endif -} -// void CProcessor::GetStandardProcessorExtensions() -// ================================================= -// Private class function to read the standard processor extensions -/////////////////////////////////////////////////////////////////// -void CProcessor::GetStandardProcessorExtensions() -{ -#if LL_WINDOWS - unsigned long ebxreg, edxreg; + LLPI_SET_INFO_STRING(eBrandName, "model name"); + LLPI_SET_INFO_STRING(eVendor, "vendor_id"); - // We check if the CPUID command is available - if (!CheckCPUIDPresence()) - return; - // We just get the standard CPUID level 0x00000001 which should be - // available on every x86 processor - __asm - { - mov eax, 1 - cpuid - mov ebxreg, ebx - mov edxreg, edx - } - - // Then we mask some bits - CPUInfo._Ext.FPU_FloatingPointUnit = CheckBit(edxreg, 0); - CPUInfo._Ext.VME_Virtual8086ModeEnhancements = CheckBit(edxreg, 1); - CPUInfo._Ext.DE_DebuggingExtensions = CheckBit(edxreg, 2); - CPUInfo._Ext.PSE_PageSizeExtensions = CheckBit(edxreg, 3); - CPUInfo._Ext.TSC_TimeStampCounter = CheckBit(edxreg, 4); - CPUInfo._Ext.MSR_ModelSpecificRegisters = CheckBit(edxreg, 5); - CPUInfo._Ext.PAE_PhysicalAddressExtension = CheckBit(edxreg, 6); - CPUInfo._Ext.MCE_MachineCheckException = CheckBit(edxreg, 7); - CPUInfo._Ext.CX8_COMPXCHG8B_Instruction = CheckBit(edxreg, 8); - CPUInfo._Ext.APIC_AdvancedProgrammableInterruptController = CheckBit(edxreg, 9); - CPUInfo._Ext.APIC_ID = (ebxreg >> 24) & 0xFF; - CPUInfo._Ext.SEP_FastSystemCall = CheckBit(edxreg, 11); - CPUInfo._Ext.MTRR_MemoryTypeRangeRegisters = CheckBit(edxreg, 12); - CPUInfo._Ext.PGE_PTE_GlobalFlag = CheckBit(edxreg, 13); - CPUInfo._Ext.MCA_MachineCheckArchitecture = CheckBit(edxreg, 14); - CPUInfo._Ext.CMOV_ConditionalMoveAndCompareInstructions = CheckBit(edxreg, 15); - CPUInfo._Ext.FGPAT_PageAttributeTable = CheckBit(edxreg, 16); - CPUInfo._Ext.PSE36_36bitPageSizeExtension = CheckBit(edxreg, 17); - CPUInfo._Ext.PN_ProcessorSerialNumber = CheckBit(edxreg, 18); - CPUInfo._Ext.CLFSH_CFLUSH_Instruction = CheckBit(edxreg, 19); - CPUInfo._Ext.CLFLUSH_InstructionCacheLineSize = (ebxreg >> 8) & 0xFF; - CPUInfo._Ext.DS_DebugStore = CheckBit(edxreg, 21); - CPUInfo._Ext.ACPI_ThermalMonitorAndClockControl = CheckBit(edxreg, 22); - CPUInfo._Ext.MMX_MultimediaExtensions = CheckBit(edxreg, 23); - CPUInfo._Ext.FXSR_FastStreamingSIMD_ExtensionsSaveRestore = CheckBit(edxreg, 24); - CPUInfo._Ext.SSE_StreamingSIMD_Extensions = CheckBit(edxreg, 25); - CPUInfo._Ext.SSE2_StreamingSIMD2_Extensions = CheckBit(edxreg, 26); - CPUInfo._Ext.Altivec_Extensions = false; - CPUInfo._Ext.SS_SelfSnoop = CheckBit(edxreg, 27); - CPUInfo._Ext.HT_HyperThreading = CheckBit(edxreg, 28); - CPUInfo._Ext.HT_HyterThreadingSiblings = (ebxreg >> 16) & 0xFF; - CPUInfo._Ext.TM_ThermalMonitor = CheckBit(edxreg, 29); - CPUInfo._Ext.IA64_Intel64BitArchitecture = CheckBit(edxreg, 30); -#endif -} + LLPI_SET_INFO_INT(eStepping, "stepping"); + LLPI_SET_INFO_INT(eModel, "model"); -// const ProcessorInfo *CProcessor::GetCPUInfo() -// ============================================= -// Calls all the other detection function to create an detailed -// processor information -/////////////////////////////////////////////////////////////// -const ProcessorInfo *CProcessor::GetCPUInfo() -{ -#if LL_WINDOWS - unsigned long eaxreg, ebxreg, ecxreg, edxreg; + + S32 family; + if (!cpuinfo["cpu family"].empty() + && LLStringUtil::convertToS32(cpuinfo["cpu family"], family)) + { + setInfo(eFamily, family); + } - // First of all we check if the CPUID command is available - if (!CheckCPUIDPresence()) - return NULL; + setInfo(eFamilyName, compute_CPUFamilyName(cpuinfo["vendor_id"].c_str(), family)); - // We read the standard CPUID level 0x00000000 which should - // be available on every x86 processor - __asm - { - mov eax, 0 - cpuid - mov eaxreg, eax - mov ebxreg, ebx - mov edxreg, edx - mov ecxreg, ecx - } - // Then we connect the single register values to the vendor string - *((unsigned long *) CPUInfo.strVendor) = ebxreg; - *((unsigned long *) (CPUInfo.strVendor+4)) = edxreg; - *((unsigned long *) (CPUInfo.strVendor+8)) = ecxreg; - // Null terminate for string comparisons below. - CPUInfo.strVendor[12] = 0; - - // We can also read the max. supported standard CPUID level - CPUInfo.MaxSupportedLevel = eaxreg & 0xFFFF; - - // Then we read the ext. CPUID level 0x80000000 - __asm - { - mov eax, 0x80000000 - cpuid - mov eaxreg, eax - } - // ...to check the max. supportted extended CPUID level - CPUInfo.MaxSupportedExtendedLevel = eaxreg; - - // Then we switch to the specific processor vendors - // See http://www.sandpile.org/ia32/cpuid.htm - if (!strcmp(CPUInfo.strVendor, "GenuineIntel")) - { - AnalyzeIntelProcessor(); - } - else if (!strcmp(CPUInfo.strVendor, "AuthenticAMD")) - { - AnalyzeAMDProcessor(); - } - else if (!strcmp(CPUInfo.strVendor, "UMC UMC UMC")) - { - AnalyzeUnknownProcessor(); - } - else if (!strcmp(CPUInfo.strVendor, "CyrixInstead")) - { - AnalyzeUnknownProcessor(); - } - else if (!strcmp(CPUInfo.strVendor, "NexGenDriven")) - { - AnalyzeUnknownProcessor(); - } - else if (!strcmp(CPUInfo.strVendor, "CentaurHauls")) - { - AnalyzeUnknownProcessor(); - } - else if (!strcmp(CPUInfo.strVendor, "RiseRiseRise")) - { - AnalyzeUnknownProcessor(); - } - else if (!strcmp(CPUInfo.strVendor, "SiS SiS SiS")) - { - AnalyzeUnknownProcessor(); - } - else if (!strcmp(CPUInfo.strVendor, "GenuineTMx86")) - { - // Transmeta - AnalyzeUnknownProcessor(); - } - else if (!strcmp(CPUInfo.strVendor, "Geode by NSC")) - { - AnalyzeUnknownProcessor(); - } - else - { - AnalyzeUnknownProcessor(); - } -#endif - // After all we return the class CPUInfo member var - return (&CPUInfo); -} + // setInfo(eExtendedModel, getSysctlInt("machdep.cpu.extmodel")); + // setInfo(eBrandID, getSysctlInt("machdep.cpu.brand")); + // setInfo(eType, 0); // ? where to find this? -#elif LL_SOLARIS -#include <kstat.h> - -#if defined(__i386) -#include <sys/auxv.h> -#endif - -// ====================== -// Class constructor: -///////////////////////// -CProcessor::CProcessor() -{ - uqwFrequency = 0; - strCPUName[0] = 0; - memset(&CPUInfo, 0, sizeof(CPUInfo)); -} - -// unsigned __int64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs) -// ========================================================================= -// Function to query the current CPU frequency -//////////////////////////////////////////////////////////////////////////// -F64 CProcessor::GetCPUFrequency(unsigned int /*uiMeasureMSecs*/) -{ - if(uqwFrequency == 0){ - GetCPUInfo(); - } - - return uqwFrequency; -} - -// const ProcessorInfo *CProcessor::GetCPUInfo() -// ============================================= -// Calls all the other detection function to create an detailed -// processor information -/////////////////////////////////////////////////////////////// -const ProcessorInfo *CProcessor::GetCPUInfo() -{ - // In Solaris the CPU info is in the kstats - // try "psrinfo" or "kstat cpu_info" to see all - // that's available - int ncpus=0, i; - kstat_ctl_t *kc; - kstat_t *ks; - kstat_named_t *ksinfo, *ksi; - kstat_t *CPU_stats_list; - - kc = kstat_open(); - - if((int)kc == -1){ - llwarns << "kstat_open(0 failed!" << llendl; - return (&CPUInfo); - } - - for (ks = kc->kc_chain; ks != NULL; ks = ks->ks_next) { - if (strncmp(ks->ks_module, "cpu_info", 8) == 0 && - strncmp(ks->ks_name, "cpu_info", 8) == 0) - ncpus++; - } - - if(ncpus < 1){ - llwarns << "No cpus found in kstats!" << llendl; - return (&CPUInfo); - } - - for (ks = kc->kc_chain; ks; ks = ks->ks_next) { - if (strncmp(ks->ks_module, "cpu_info", 8) == 0 - && strncmp(ks->ks_name, "cpu_info", 8) == 0 - && kstat_read(kc, ks, NULL) != -1){ - CPU_stats_list = ks; // only looking at the first CPU - - break; - } - } - - if(ncpus > 1) - snprintf(strCPUName, sizeof(strCPUName), "%d x ", ncpus); - - kstat_read(kc, CPU_stats_list, NULL); - ksinfo = (kstat_named_t *)CPU_stats_list->ks_data; - for(i=0; i < (int)(CPU_stats_list->ks_ndata); ++i){ // Walk the kstats for this cpu gathering what we need - ksi = ksinfo++; - if(!strcmp(ksi->name, "brand")){ - strncat(strCPUName, (char *)KSTAT_NAMED_STR_PTR(ksi), - sizeof(strCPUName)-strlen(strCPUName)-1); - strncat(CPUInfo.strFamily, (char *)KSTAT_NAMED_STR_PTR(ksi), - sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); - strncpy(CPUInfo.strBrandID, strCPUName,sizeof(CPUInfo.strBrandID)-1); - CPUInfo.strBrandID[sizeof(CPUInfo.strBrandID)-1]='\0'; - // DEBUG llinfos << "CPU brand: " << strCPUName << llendl; - continue; - } + //setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8); + //setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff); + //setConfig(eCacheLineSize, getSysctlInt("machdep.cpu.cache.linesize")); + //setConfig(eL2Associativity, getSysctlInt("machdep.cpu.cache.L2_associativity")); + //setConfig(eCacheSizeK, getSysctlInt("machdep.cpu.cache.size")); + + // Read extensions + std::string flags = " " + cpuinfo["flags"] + " "; + LLStringUtil::toLower(flags); - if(!strcmp(ksi->name, "clock_MHz")){ -#if defined(__sparc) - llinfos << "Raw kstat clock rate is: " << ksi->value.l << llendl; - uqwFrequency = (F64)(ksi->value.l * 1000000); -#else - uqwFrequency = (F64)(ksi->value.i64 * 1000000); -#endif - //DEBUG llinfos << "CPU frequency: " << uqwFrequency << llendl; - continue; + if( flags.find( " sse " ) != std::string::npos ) + { + setExtension(cpu_feature_names[eSSE_Ext]); } -#if defined(__i386) - if(!strcmp(ksi->name, "vendor_id")){ - strncpy(CPUInfo.strVendor, (char *)KSTAT_NAMED_STR_PTR(ksi), sizeof(CPUInfo.strVendor)-1); - // DEBUG llinfos << "CPU vendor: " << CPUInfo.strVendor << llendl; - continue; + if( flags.find( " sse2 " ) != std::string::npos ) + { + setExtension(cpu_feature_names[eSSE2_Ext]); } -#endif - } - - kstat_close(kc); - -#if defined(__sparc) // SPARC does not define a vendor string in kstat - strncpy(CPUInfo.strVendor, "Sun Microsystems, Inc.", sizeof(CPUInfo.strVendor)-1); -#endif - - // DEBUG llinfo << "The system has " << ncpus << " CPUs with a clock rate of " << uqwFrequency << "MHz." << llendl; - -#if defined (__i386) // we really don't care about the CPU extensions on SPARC but on x86... - - // Now get cpu extensions - - uint_t ui; - - (void) getisax(&ui, 1); - if(ui & AV_386_FPU) - CPUInfo._Ext.FPU_FloatingPointUnit = true; - if(ui & AV_386_CX8) - CPUInfo._Ext.CX8_COMPXCHG8B_Instruction = true; - if(ui & AV_386_MMX) - CPUInfo._Ext.MMX_MultimediaExtensions = true; - if(ui & AV_386_AMD_MMX) - CPUInfo._Ext.MMX_MultimediaExtensions = true; - if(ui & AV_386_FXSR) - CPUInfo._Ext.FXSR_FastStreamingSIMD_ExtensionsSaveRestore = true; - if(ui & AV_386_SSE) - CPUInfo._Ext.SSE_StreamingSIMD_Extensions = true; - if(ui & AV_386_SSE2) - CPUInfo._Ext.SSE2_StreamingSIMD2_Extensions = true; -/* Left these here since they may get used later - if(ui & AV_386_SSE3) - CPUInfo._Ext.... = true; - if(ui & AV_386_AMD_3DNow) - CPUInfo._Ext.... = true; - if(ui & AV_386_AMD_3DNowx) - CPUInfo._Ext.... = true; -*/ -#endif - return (&CPUInfo); -} - -#else -// LL_DARWIN - -#include <mach/machine.h> -#include <sys/sysctl.h> - -static char *TranslateAssociativeWays(unsigned int uiWays, char *buf) -{ - // We define 0xFFFFFFFF (= -1) as fully associative - if (uiWays == ((unsigned int) -1)) - strcpy(buf, "fully associative"); /* Flawfinder: ignore */ - else - { - if (uiWays == 1) // A one way associative cache is just direct mapped - strcpy(buf, "direct mapped"); /* Flawfinder: ignore */ - else if (uiWays == 0) // This should not happen... - strcpy(buf, "unknown associative ways"); /* Flawfinder: ignore */ - else // The x-way associative cache - sprintf(buf, "%d ways associative", uiWays); /* Flawfinder: ignore */ +# endif // LL_X86 } - // To ease the function use we return the buffer - return buf; -} -static void TranslateTLB(ProcessorTLB *tlb) -{ - char buf[64]; /* Flawfinder: ignore */ - - // We just check if the TLB is present - if (tlb->bPresent) - snprintf(tlb->strTLB, sizeof(tlb->strTLB), "%s page size, %s, %d entries", tlb->strPageSize, TranslateAssociativeWays(tlb->uiAssociativeWays, buf), tlb->uiEntries); /* Flawfinder: ignore */ - else - strcpy(tlb->strTLB, "Not present"); /* Flawfinder: ignore */ -} -static void TranslateCache(ProcessorCache *cache) -{ - char buf[64]; /* Flawfinder: ignore */ - // We just check if the cache is present - if (cache->bPresent) + std::string getCPUFeatureDescription() const { - // If present we construct the string - snprintf(cache->strCache,sizeof(cache->strCache), "%s cache size, %s, %d bytes line size", cache->strSize, TranslateAssociativeWays(cache->uiAssociativeWays, buf), cache->uiLineSize); /* Flawfinder: ignore */ - if (cache->bSectored) - strncat(cache->strCache, ", sectored", sizeof(cache->strCache)-strlen(cache->strCache)-1); /* Flawfinder: ignore */ - } - else - { - // Else we just say "Not present" - strcpy(cache->strCache, "Not present"); /* Flawfinder: ignore */ - } -} - -// void CProcessor::TranslateProcessorConfiguration() -// ================================================== -// Private class function to translate the processor configuration values -// to strings -///////////////////////////////////////////////////////////////////////// -void CProcessor::TranslateProcessorConfiguration() -{ - // We just call the small functions defined above - TranslateTLB(&CPUInfo._Data); - TranslateTLB(&CPUInfo._Instruction); - - TranslateCache(&CPUInfo._Trace); + std::ostringstream s; - TranslateCache(&CPUInfo._L1.Instruction); - TranslateCache(&CPUInfo._L1.Data); - TranslateCache(&CPUInfo._L2); - TranslateCache(&CPUInfo._L3); -} - -// CProcessor::CProcessor -// ====================== -// Class constructor: -///////////////////////// -CProcessor::CProcessor() -{ - uqwFrequency = 0; - strCPUName[0] = 0; - memset(&CPUInfo, 0, sizeof(CPUInfo)); -} - -// unsigned __int64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs) -// ========================================================================= -// Function to query the current CPU frequency -//////////////////////////////////////////////////////////////////////////// -F64 CProcessor::GetCPUFrequency(unsigned int /*uiMeasureMSecs*/) -{ - U64 frequency = 0; - size_t len = sizeof(frequency); - - if(sysctlbyname("hw.cpufrequency", &frequency, &len, NULL, 0) == 0) - { - uqwFrequency = (F64)frequency; - } - - return uqwFrequency; -} - -static bool hasFeature(const char *name) -{ - bool result = false; - int val = 0; - size_t len = sizeof(val); - - if(sysctlbyname(name, &val, &len, NULL, 0) == 0) - { - if(val != 0) - result = true; - } - - return result; -} - -// const ProcessorInfo *CProcessor::GetCPUInfo() -// ============================================= -// Calls all the other detection function to create an detailed -// processor information -/////////////////////////////////////////////////////////////// -const ProcessorInfo *CProcessor::GetCPUInfo() -{ - int pagesize = 0; - int cachelinesize = 0; - int l1icachesize = 0; - int l1dcachesize = 0; - int l2settings = 0; - int l2cachesize = 0; - int l3settings = 0; - int l3cachesize = 0; - int ncpu = 0; - int cpusubtype = 0; - - // sysctl knows all. - int mib[2]; - size_t len; - mib[0] = CTL_HW; - - mib[1] = HW_PAGESIZE; - len = sizeof(pagesize); - sysctl(mib, 2, &pagesize, &len, NULL, 0); - - mib[1] = HW_CACHELINE; - len = sizeof(cachelinesize); - sysctl(mib, 2, &cachelinesize, &len, NULL, 0); - - mib[1] = HW_L1ICACHESIZE; - len = sizeof(l1icachesize); - sysctl(mib, 2, &l1icachesize, &len, NULL, 0); - - mib[1] = HW_L1DCACHESIZE; - len = sizeof(l1dcachesize); - sysctl(mib, 2, &l1dcachesize, &len, NULL, 0); - - mib[1] = HW_L2SETTINGS; - len = sizeof(l2settings); - sysctl(mib, 2, &l2settings, &len, NULL, 0); - - mib[1] = HW_L2CACHESIZE; - len = sizeof(l2cachesize); - sysctl(mib, 2, &l2cachesize, &len, NULL, 0); - - mib[1] = HW_L3SETTINGS; - len = sizeof(l3settings); - sysctl(mib, 2, &l3settings, &len, NULL, 0); - - mib[1] = HW_L3CACHESIZE; - len = sizeof(l3cachesize); - sysctl(mib, 2, &l3cachesize, &len, NULL, 0); - - mib[1] = HW_NCPU; - len = sizeof(ncpu); - sysctl(mib, 2, &ncpu, &len, NULL, 0); - - sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0); - - strCPUName[0] = 0; - - if((ncpu == 0) || (ncpu == 1)) - { - // Uhhh... - } - else if(ncpu == 2) - { - strncat(strCPUName, "Dual ", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - } - else - { - snprintf(strCPUName, sizeof(strCPUName), "%d x ", ncpu); /* Flawfinder: ignore */ - } - -#if __ppc__ - switch(cpusubtype) - { - case CPU_SUBTYPE_POWERPC_601:// ((cpu_subtype_t) 1) - strncat(strCPUName, "PowerPC 601", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ - - break; - case CPU_SUBTYPE_POWERPC_602:// ((cpu_subtype_t) 2) - strncat(strCPUName, "PowerPC 602", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ - break; - case CPU_SUBTYPE_POWERPC_603:// ((cpu_subtype_t) 3) - strncat(strCPUName, "PowerPC 603", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ - break; - case CPU_SUBTYPE_POWERPC_603e:// ((cpu_subtype_t) 4) - strncat(strCPUName, "PowerPC 603e", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ - break; - case CPU_SUBTYPE_POWERPC_603ev:// ((cpu_subtype_t) 5) - strncat(strCPUName, "PowerPC 603ev", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ - break; - case CPU_SUBTYPE_POWERPC_604:// ((cpu_subtype_t) 6) - strncat(strCPUName, "PowerPC 604", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ - break; - case CPU_SUBTYPE_POWERPC_604e:// ((cpu_subtype_t) 7) - strncat(strCPUName, "PowerPC 604e", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ - break; - case CPU_SUBTYPE_POWERPC_620:// ((cpu_subtype_t) 8) - strncat(strCPUName, "PowerPC 620", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - strncat(CPUInfo.strFamily, "PowerPC", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ - break; - case CPU_SUBTYPE_POWERPC_750:// ((cpu_subtype_t) 9) - strncat(strCPUName, "PowerPC 750", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - strncat(CPUInfo.strFamily, "PowerPC G3", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ - break; - case CPU_SUBTYPE_POWERPC_7400:// ((cpu_subtype_t) 10) - strncat(strCPUName, "PowerPC 7400", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - strncat(CPUInfo.strFamily, "PowerPC G4", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ - break; - case CPU_SUBTYPE_POWERPC_7450:// ((cpu_subtype_t) 11) - strncat(strCPUName, "PowerPC 7450", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - strncat(CPUInfo.strFamily, "PowerPC G4", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ - break; - case CPU_SUBTYPE_POWERPC_970:// ((cpu_subtype_t) 100) - strncat(strCPUName, "PowerPC 970", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - strncat(CPUInfo.strFamily, "PowerPC G5", sizeof(CPUInfo.strFamily)-strlen(CPUInfo.strFamily)-1); /* Flawfinder: ignore */ - break; - - default: - strncat(strCPUName, "PowerPC (Unknown)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - break; - } - - CPUInfo._Ext.EMMX_MultimediaExtensions = - CPUInfo._Ext.MMX_MultimediaExtensions = - CPUInfo._Ext.SSE_StreamingSIMD_Extensions = - CPUInfo._Ext.SSE2_StreamingSIMD2_Extensions = false; - - CPUInfo._Ext.Altivec_Extensions = hasFeature("hw.optional.altivec"); - -#endif - -#if __i386__ - // MBW -- XXX -- TODO -- make this call AnalyzeIntelProcessor()? - switch(cpusubtype) - { - default: - strncat(strCPUName, "i386 (Unknown)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - break; - } - - CPUInfo._Ext.EMMX_MultimediaExtensions = hasFeature("hw.optional.mmx"); // MBW -- XXX -- this may be wrong... - CPUInfo._Ext.MMX_MultimediaExtensions = hasFeature("hw.optional.mmx"); - CPUInfo._Ext.SSE_StreamingSIMD_Extensions = hasFeature("hw.optional.sse"); - CPUInfo._Ext.SSE2_StreamingSIMD2_Extensions = hasFeature("hw.optional.sse2"); - CPUInfo._Ext.Altivec_Extensions = false; - CPUInfo._Ext.AA64_AMD64BitArchitecture = hasFeature("hw.optional.x86_64"); - -#endif - - // Terse CPU info uses this string... - strncpy(CPUInfo.strBrandID, strCPUName,sizeof(CPUInfo.strBrandID)-1); /* Flawfinder: ignore */ - CPUInfo.strBrandID[sizeof(CPUInfo.strBrandID)-1]='\0'; - - // Fun cache config stuff... - - if(l1dcachesize != 0) - { - CPUInfo._L1.Data.bPresent = true; - snprintf(CPUInfo._L1.Data.strSize, sizeof(CPUInfo._L1.Data.strSize), "%d KB", l1dcachesize / 1024); /* Flawfinder: ignore */ -// CPUInfo._L1.Data.uiAssociativeWays = ???; - CPUInfo._L1.Data.uiLineSize = cachelinesize; + // *NOTE:Mani - This is for linux only. + LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb"); + if(cpuinfo) + { + char line[MAX_STRING]; + memset(line, 0, MAX_STRING); + while(fgets(line, MAX_STRING, cpuinfo)) + { + line[strlen(line)-1] = ' '; + s << line; + s << std::endl; + } + fclose(cpuinfo); + s << std::endl; + } + else + { + s << "Unable to collect processor information" << std::endl; + } + return s.str(); } + +}; - if(l1icachesize != 0) - { - CPUInfo._L1.Instruction.bPresent = true; - snprintf(CPUInfo._L1.Instruction.strSize, sizeof(CPUInfo._L1.Instruction.strSize), "%d KB", l1icachesize / 1024); /* Flawfinder: ignore */ -// CPUInfo._L1.Instruction.uiAssociativeWays = ???; - CPUInfo._L1.Instruction.uiLineSize = cachelinesize; - } - if(l2cachesize != 0) - { - CPUInfo._L2.bPresent = true; - snprintf(CPUInfo._L2.strSize, sizeof(CPUInfo._L2.strSize), "%d KB", l2cachesize / 1024); /* Flawfinder: ignore */ -// CPUInfo._L2.uiAssociativeWays = ???; - CPUInfo._L2.uiLineSize = cachelinesize; - } +#endif // LL_MSVC elif LL_DARWIN elif LL_LINUX - if(l3cachesize != 0) - { - CPUInfo._L2.bPresent = true; - snprintf(CPUInfo._L2.strSize, sizeof(CPUInfo._L2.strSize), "%d KB", l3cachesize / 1024); /* Flawfinder: ignore */ -// CPUInfo._L2.uiAssociativeWays = ???; - CPUInfo._L2.uiLineSize = cachelinesize; +////////////////////////////////////////////////////// +// Interface definition +LLProcessorInfo::LLProcessorInfo() : mImpl(NULL) +{ + // *NOTE:Mani - not thread safe. + if(!mImpl) + { +#ifdef LL_MSVC + static LLProcessorInfoWindowsImpl the_impl; + mImpl = &the_impl; +#elif LL_DARWIN + static LLProcessorInfoDarwinImpl the_impl; + mImpl = &the_impl; +#else + static LLProcessorInfoLinuxImpl the_impl; + mImpl = &the_impl; +#endif // LL_MSVC } - - CPUInfo._Ext.FPU_FloatingPointUnit = hasFeature("hw.optional.floatingpoint"); - -// printf("pagesize = 0x%x\n", pagesize); -// printf("cachelinesize = 0x%x\n", cachelinesize); -// printf("l1icachesize = 0x%x\n", l1icachesize); -// printf("l1dcachesize = 0x%x\n", l1dcachesize); -// printf("l2settings = 0x%x\n", l2settings); -// printf("l2cachesize = 0x%x\n", l2cachesize); -// printf("l3settings = 0x%x\n", l3settings); -// printf("l3cachesize = 0x%x\n", l3cachesize); - - // After reading we translate the configuration to strings - TranslateProcessorConfiguration(); - - // After all we return the class CPUInfo member var - return (&CPUInfo); } -#endif // LL_DARWIN -// bool CProcessor::CPUInfoToText(char *strBuffer, unsigned int uiMaxLen) -// ====================================================================== -// Gets the frequency and processor information and writes it to a string -///////////////////////////////////////////////////////////////////////// -bool CProcessor::CPUInfoToText(char *strBuffer, unsigned int uiMaxLen) -{ -#define LENCHECK len = (unsigned int) strlen(buf); if (len >= uiMaxLen) return false; strcpy(strBuffer, buf); strBuffer += len; /*Flawfinder: ignore*/ -#define COPYADD(str) strcpy(buf, str); LENCHECK; /* Flawfinder: ignore */ -#define FORMATADD(format, var) sprintf(buf, format, var); LENCHECK; /* Flawfinder: ignore */ -#define BOOLADD(str, boolvar) COPYADD(str); if (boolvar) { COPYADD(" Yes\n"); } else { COPYADD(" No\n"); } - - char buf[1024]; /* Flawfinder: ignore */ - unsigned int len; - - // First we have to get the frequency - GetCPUFrequency(50); - - // Then we get the processor information - GetCPUInfo(); - - // Now we construct the string (see the macros at function beginning) - strBuffer[0] = 0; - - COPYADD("// CPU General Information\n//////////////////////////\n"); - FORMATADD("Processor name: %s\n", strCPUName); - FORMATADD("Frequency: %.2f MHz\n\n", (float) uqwFrequency / 1000000.0f); - FORMATADD("Vendor: %s\n", CPUInfo.strVendor); - FORMATADD("Family: %s\n", CPUInfo.strFamily); - FORMATADD("Extended family: %d\n", CPUInfo.uiExtendedFamily); - FORMATADD("Model: %s\n", CPUInfo.strModel); - FORMATADD("Extended model: %d\n", CPUInfo.uiExtendedModel); - FORMATADD("Type: %s\n", CPUInfo.strType); - FORMATADD("Brand ID: %s\n", CPUInfo.strBrandID); - if (CPUInfo._Ext.PN_ProcessorSerialNumber) - { - FORMATADD("Processor Serial: %s\n", CPUInfo.strProcessorSerial); - } - else - { - COPYADD("Processor Serial: Disabled\n"); - } -#if !LL_SOLARIS // NOTE: Why bother printing all this when it's irrelavent - - COPYADD("\n\n// CPU Configuration\n////////////////////\n"); - FORMATADD("L1 instruction cache: %s\n", CPUInfo._L1.Instruction.strCache); - FORMATADD("L1 data cache: %s\n", CPUInfo._L1.Data.strCache); - FORMATADD("L2 cache: %s\n", CPUInfo._L2.strCache); - FORMATADD("L3 cache: %s\n", CPUInfo._L3.strCache); - FORMATADD("Trace cache: %s\n", CPUInfo._Trace.strCache); - FORMATADD("Instruction TLB: %s\n", CPUInfo._Instruction.strTLB); - FORMATADD("Data TLB: %s\n", CPUInfo._Data.strTLB); - FORMATADD("Max Supported CPUID-Level: 0x%08lX\n", CPUInfo.MaxSupportedLevel); - FORMATADD("Max Supported Ext. CPUID-Level: 0x%08lX\n", CPUInfo.MaxSupportedExtendedLevel); - - COPYADD("\n\n// CPU Extensions\n/////////////////\n"); - BOOLADD("AA64 AMD 64-bit Architecture: ", CPUInfo._Ext.AA64_AMD64BitArchitecture); - BOOLADD("ACPI Thermal Monitor And Clock Control: ", CPUInfo._Ext.ACPI_ThermalMonitorAndClockControl); - BOOLADD("APIC Advanced Programmable Interrupt Controller: ", CPUInfo._Ext.APIC_AdvancedProgrammableInterruptController); - FORMATADD(" APIC-ID: %d\n", CPUInfo._Ext.APIC_ID); - BOOLADD("CLFSH CLFLUSH Instruction Presence: ", CPUInfo._Ext.CLFSH_CFLUSH_Instruction); - FORMATADD(" CLFLUSH Instruction Cache Line Size: %d\n", CPUInfo._Ext.CLFLUSH_InstructionCacheLineSize); - BOOLADD("CMOV Conditional Move And Compare Instructions: ", CPUInfo._Ext.CMOV_ConditionalMoveAndCompareInstructions); - BOOLADD("CX8 COMPXCHG8B Instruction: ", CPUInfo._Ext.CX8_COMPXCHG8B_Instruction); - BOOLADD("DE Debugging Extensions: ", CPUInfo._Ext.DE_DebuggingExtensions); - BOOLADD("DS Debug Store: ", CPUInfo._Ext.DS_DebugStore); - BOOLADD("FGPAT Page Attribute Table: ", CPUInfo._Ext.FGPAT_PageAttributeTable); - BOOLADD("FPU Floating Point Unit: ", CPUInfo._Ext.FPU_FloatingPointUnit); - BOOLADD("FXSR Fast Streaming SIMD Extensions Save/Restore:", CPUInfo._Ext.FXSR_FastStreamingSIMD_ExtensionsSaveRestore); - BOOLADD("HT Hyper Threading: ", CPUInfo._Ext.HT_HyperThreading); - BOOLADD("IA64 Intel 64-Bit Architecture: ", CPUInfo._Ext.IA64_Intel64BitArchitecture); - BOOLADD("MCA Machine Check Architecture: ", CPUInfo._Ext.MCA_MachineCheckArchitecture); - BOOLADD("MCE Machine Check Exception: ", CPUInfo._Ext.MCE_MachineCheckException); - BOOLADD("MMX Multimedia Extensions: ", CPUInfo._Ext.MMX_MultimediaExtensions); - BOOLADD("MMX+ Multimedia Extensions: ", CPUInfo._Ext.EMMX_MultimediaExtensions); - BOOLADD("MSR Model Specific Registers: ", CPUInfo._Ext.MSR_ModelSpecificRegisters); - BOOLADD("MTRR Memory Type Range Registers: ", CPUInfo._Ext.MTRR_MemoryTypeRangeRegisters); - BOOLADD("PAE Physical Address Extension: ", CPUInfo._Ext.PAE_PhysicalAddressExtension); - BOOLADD("PGE PTE Global Flag: ", CPUInfo._Ext.PGE_PTE_GlobalFlag); - if (CPUInfo._Ext.PN_ProcessorSerialNumber) - { - FORMATADD("PN Processor Serial Number: %s\n", CPUInfo.strProcessorSerial); - } - else - { - COPYADD("PN Processor Serial Number: Disabled\n"); - } - BOOLADD("PSE Page Size Extensions: ", CPUInfo._Ext.PSE_PageSizeExtensions); - BOOLADD("PSE36 36-bit Page Size Extension: ", CPUInfo._Ext.PSE36_36bitPageSizeExtension); - BOOLADD("SEP Fast System Call: ", CPUInfo._Ext.SEP_FastSystemCall); - BOOLADD("SS Self Snoop: ", CPUInfo._Ext.SS_SelfSnoop); - BOOLADD("SSE Streaming SIMD Extensions: ", CPUInfo._Ext.SSE_StreamingSIMD_Extensions); - BOOLADD("SSE2 Streaming SIMD 2 Extensions: ", CPUInfo._Ext.SSE2_StreamingSIMD2_Extensions); - BOOLADD("ALTVEC Altivec Extensions: ", CPUInfo._Ext.Altivec_Extensions); - BOOLADD("TM Thermal Monitor: ", CPUInfo._Ext.TM_ThermalMonitor); - BOOLADD("TSC Time Stamp Counter: ", CPUInfo._Ext.TSC_TimeStampCounter); - BOOLADD("VME Virtual 8086 Mode Enhancements: ", CPUInfo._Ext.VME_Virtual8086ModeEnhancements); - BOOLADD("3DNow! Instructions: ", CPUInfo._Ext._3DNOW_InstructionExtensions); - BOOLADD("Enhanced 3DNow! Instructions: ", CPUInfo._Ext._E3DNOW_InstructionExtensions); -#endif - // Yippie!!! - return true; -} +LLProcessorInfo::~LLProcessorInfo() {} +F64 LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); } +bool LLProcessorInfo::hasSSE() const { return mImpl->hasSSE(); } +bool LLProcessorInfo::hasSSE2() const { return mImpl->hasSSE2(); } +bool LLProcessorInfo::hasAltivec() const { return mImpl->hasAltivec(); } +std::string LLProcessorInfo::getCPUFamilyName() const { return mImpl->getCPUFamilyName(); } +std::string LLProcessorInfo::getCPUBrandName() const { return mImpl->getCPUBrandName(); } +std::string LLProcessorInfo::getCPUFeatureDescription() const { return mImpl->getCPUFeatureDescription(); } -// bool CProcessor::WriteInfoTextFile(const std::string& strFilename) -// =========================================================== -// Takes use of CProcessor::CPUInfoToText and saves the string to a -// file -/////////////////////////////////////////////////////////////////// -bool CProcessor::WriteInfoTextFile(const std::string& strFilename) -{ - char buf[16384]; /* Flawfinder: ignore */ - - // First we get the string - if (!CPUInfoToText(buf, 16383)) - return false; - - // Then we create a new file (CREATE_ALWAYS) - LLFILE *file = LLFile::fopen(strFilename, "w"); /* Flawfinder: ignore */ - if (!file) - return false; - - // After that we write the string to the file - unsigned long dwBytesToWrite, dwBytesWritten; - dwBytesToWrite = (unsigned long) strlen(buf); /*Flawfinder: ignore*/ - dwBytesWritten = (unsigned long) fwrite(buf, 1, dwBytesToWrite, file); - fclose(file); - if (dwBytesToWrite != dwBytesWritten) - return false; - - // Done - return true; -} diff --git a/indra/llcommon/llprocessor.h b/indra/llcommon/llprocessor.h index 746d007a7f..fc2c8dacfb 100644 --- a/indra/llcommon/llprocessor.h +++ b/indra/llcommon/llprocessor.h @@ -30,167 +30,26 @@ * $/LicenseInfo$ */ -// Author: Benjamin Jurke -// File history: 27.02.2002 File created. -/////////////////////////////////////////// - #ifndef LLPROCESSOR_H #define LLPROCESSOR_H +class LLProcessorInfoImpl; -// Options: -/////////// -#if LL_WINDOWS -#define PROCESSOR_FREQUENCY_MEASURE_AVAILABLE -#endif - -#if LL_MSVC && _M_X64 -# define LL_X86_64 1 -# define LL_X86 1 -#elif LL_MSVC && _M_IX86 -# define LL_X86 1 -#elif LL_GNUC && ( defined(__amd64__) || defined(__x86_64__) ) -# define LL_X86_64 1 -# define LL_X86 1 -#elif LL_GNUC && ( defined(__i386__) ) -# define LL_X86 1 -#elif LL_GNUC && ( defined(__powerpc__) || defined(__ppc__) ) -# define LL_PPC 1 -#endif - - -struct ProcessorExtensions -{ - bool FPU_FloatingPointUnit; - bool VME_Virtual8086ModeEnhancements; - bool DE_DebuggingExtensions; - bool PSE_PageSizeExtensions; - bool TSC_TimeStampCounter; - bool MSR_ModelSpecificRegisters; - bool PAE_PhysicalAddressExtension; - bool MCE_MachineCheckException; - bool CX8_COMPXCHG8B_Instruction; - bool APIC_AdvancedProgrammableInterruptController; - unsigned int APIC_ID; - bool SEP_FastSystemCall; - bool MTRR_MemoryTypeRangeRegisters; - bool PGE_PTE_GlobalFlag; - bool MCA_MachineCheckArchitecture; - bool CMOV_ConditionalMoveAndCompareInstructions; - bool FGPAT_PageAttributeTable; - bool PSE36_36bitPageSizeExtension; - bool PN_ProcessorSerialNumber; - bool CLFSH_CFLUSH_Instruction; - unsigned int CLFLUSH_InstructionCacheLineSize; - bool DS_DebugStore; - bool ACPI_ThermalMonitorAndClockControl; - bool EMMX_MultimediaExtensions; - bool MMX_MultimediaExtensions; - bool FXSR_FastStreamingSIMD_ExtensionsSaveRestore; - bool SSE_StreamingSIMD_Extensions; - bool SSE2_StreamingSIMD2_Extensions; - bool Altivec_Extensions; - bool SS_SelfSnoop; - bool HT_HyperThreading; - unsigned int HT_HyterThreadingSiblings; - bool TM_ThermalMonitor; - bool IA64_Intel64BitArchitecture; - bool _3DNOW_InstructionExtensions; - bool _E3DNOW_InstructionExtensions; - bool AA64_AMD64BitArchitecture; -}; - -struct ProcessorCache -{ - bool bPresent; - char strSize[32]; /* Flawfinder: ignore */ - unsigned int uiAssociativeWays; - unsigned int uiLineSize; - bool bSectored; - char strCache[128]; /* Flawfinder: ignore */ -}; - -struct ProcessorL1Cache -{ - ProcessorCache Instruction; - ProcessorCache Data; -}; - -struct ProcessorTLB +class LL_COMMON_API LLProcessorInfo { - bool bPresent; - char strPageSize[32]; /* Flawfinder: ignore */ - unsigned int uiAssociativeWays; - unsigned int uiEntries; - char strTLB[128]; /* Flawfinder: ignore */ -}; - -struct ProcessorInfo -{ - char strVendor[16]; /* Flawfinder: ignore */ - unsigned int uiFamily; - unsigned int uiExtendedFamily; - char strFamily[64]; /* Flawfinder: ignore */ - unsigned int uiModel; - unsigned int uiExtendedModel; - char strModel[128]; /* Flawfinder: ignore */ - unsigned int uiStepping; - unsigned int uiType; - char strType[64]; /* Flawfinder: ignore */ - unsigned int uiBrandID; - char strBrandID[64]; /* Flawfinder: ignore */ - char strProcessorSerial[64]; /* Flawfinder: ignore */ - unsigned long MaxSupportedLevel; - unsigned long MaxSupportedExtendedLevel; - ProcessorExtensions _Ext; - ProcessorL1Cache _L1; - ProcessorCache _L2; - ProcessorCache _L3; - ProcessorCache _Trace; - ProcessorTLB _Instruction; - ProcessorTLB _Data; -}; - - -// CProcessor -// ========== -// Class for detecting the processor name, type and available -// extensions as long as it's speed. -///////////////////////////////////////////////////////////// -class CProcessor -{ -// Constructor / Destructor: -//////////////////////////// public: - CProcessor(); - -// Private vars: -//////////////// -public: - F64 uqwFrequency; - char strCPUName[128]; /* Flawfinder: ignore */ - ProcessorInfo CPUInfo; - -// Private functions: -///////////////////// + LLProcessorInfo(); + ~LLProcessorInfo(); + + F64 getCPUFrequency() const; + bool hasSSE() const; + bool hasSSE2() const; + bool hasAltivec() const; + std::string getCPUFamilyName() const; + std::string getCPUBrandName() const; + std::string getCPUFeatureDescription() const; private: - bool AnalyzeIntelProcessor(); - bool AnalyzeAMDProcessor(); - bool AnalyzeUnknownProcessor(); - bool CheckCPUIDPresence(); - void DecodeProcessorConfiguration(unsigned int cfg); - void TranslateProcessorConfiguration(); - void GetStandardProcessorConfiguration(); - void GetStandardProcessorExtensions(); - -// Public functions: -//////////////////// -public: - F64 GetCPUFrequency(unsigned int uiMeasureMSecs); - const ProcessorInfo *GetCPUInfo(); - bool CPUInfoToText(char *strBuffer, unsigned int uiMaxLen); - bool WriteInfoTextFile(const std::string& strFilename); + LLProcessorInfoImpl* mImpl; }; - -#endif +#endif // LLPROCESSOR_H diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 52b1b63209..d41d0c8a3f 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -58,7 +58,6 @@ # include <unistd.h> # include <sys/sysinfo.h> const char MEMINFO_FILE[] = "/proc/meminfo"; -const char CPUINFO_FILE[] = "/proc/cpuinfo"; #elif LL_SOLARIS # include <stdio.h> # include <unistd.h> @@ -513,71 +512,21 @@ U32 LLOSInfo::getProcessResidentSizeKB() LLCPUInfo::LLCPUInfo() { std::ostringstream out; - CProcessor proc; - const ProcessorInfo* info = proc.GetCPUInfo(); + LLProcessorInfo proc; // proc.WriteInfoTextFile("procInfo.txt"); - mHasSSE = info->_Ext.SSE_StreamingSIMD_Extensions; - mHasSSE2 = info->_Ext.SSE2_StreamingSIMD2_Extensions; - mHasAltivec = info->_Ext.Altivec_Extensions; - mCPUMHz = (F64)(proc.GetCPUFrequency(50)/1000000.0F); - mFamily.assign( info->strFamily ); + mHasSSE = proc.hasSSE(); + mHasSSE2 = proc.hasSSE2(); + mHasAltivec = proc.hasAltivec(); + mCPUMHz = (F64)proc.getCPUFrequency(); + mFamily = proc.getCPUFamilyName(); mCPUString = "Unknown"; -#if LL_WINDOWS || LL_DARWIN || LL_SOLARIS - out << proc.strCPUName; + out << proc.getCPUBrandName(); if (200 < mCPUMHz && mCPUMHz < 10000) // *NOTE: cpu speed is often way wrong, do a sanity check { out << " (" << mCPUMHz << " MHz)"; } mCPUString = out.str(); - -#elif LL_LINUX - std::map< std::string, std::string > cpuinfo; - LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb"); - if(cpuinfo_fp) - { - char line[MAX_STRING]; - memset(line, 0, MAX_STRING); - while(fgets(line, MAX_STRING, cpuinfo_fp)) - { - // /proc/cpuinfo on Linux looks like: - // name\t*: value\n - char* tabspot = strchr( line, '\t' ); - if (tabspot == NULL) - continue; - char* colspot = strchr( tabspot, ':' ); - if (colspot == NULL) - continue; - char* spacespot = strchr( colspot, ' ' ); - if (spacespot == NULL) - continue; - char* nlspot = strchr( line, '\n' ); - if (nlspot == NULL) - nlspot = line + strlen( line ); // Fallback to terminating NUL - std::string linename( line, tabspot ); - std::string llinename(linename); - LLStringUtil::toLower(llinename); - std::string lineval( spacespot + 1, nlspot ); - cpuinfo[ llinename ] = lineval; - } - fclose(cpuinfo_fp); - } -# if LL_X86 - std::string flags = " " + cpuinfo["flags"] + " "; - LLStringUtil::toLower(flags); - mHasSSE = ( flags.find( " sse " ) != std::string::npos ); - mHasSSE2 = ( flags.find( " sse2 " ) != std::string::npos ); - - F64 mhz; - if (LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhz) - && 200.0 < mhz && mhz < 10000.0) - { - mCPUMHz = (F64)(mhz); - } - if (!cpuinfo["model name"].empty()) - mCPUString = cpuinfo["model name"]; -# endif // LL_X86 -#endif // LL_LINUX } bool LLCPUInfo::hasAltivec() const @@ -607,38 +556,9 @@ std::string LLCPUInfo::getCPUString() const void LLCPUInfo::stream(std::ostream& s) const { -#if LL_WINDOWS || LL_DARWIN || LL_SOLARIS // gather machine information. - char proc_buf[CPUINFO_BUFFER_SIZE]; /* Flawfinder: ignore */ - CProcessor proc; - if(proc.CPUInfoToText(proc_buf, CPUINFO_BUFFER_SIZE)) - { - s << proc_buf; - } - else - { - s << "Unable to collect processor information" << std::endl; - } -#else - // *NOTE: This works on linux. What will it do on other systems? - LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb"); - if(cpuinfo) - { - char line[MAX_STRING]; - memset(line, 0, MAX_STRING); - while(fgets(line, MAX_STRING, cpuinfo)) - { - line[strlen(line)-1] = ' '; - s << line; - } - fclose(cpuinfo); - s << std::endl; - } - else - { - s << "Unable to collect processor information" << std::endl; - } -#endif + s << LLProcessorInfo().getCPUFeatureDescription(); + // These are interesting as they reflect our internal view of the // CPU's attributes regardless of platform s << "->mHasSSE: " << (U32)mHasSSE << std::endl; diff --git a/indra/llcommon/llversionserver.h b/indra/llcommon/llversionserver.h index e3663544db..87fe7001e0 100644 --- a/indra/llcommon/llversionserver.h +++ b/indra/llcommon/llversionserver.h @@ -33,10 +33,10 @@ #ifndef LL_LLVERSIONSERVER_H #define LL_LLVERSIONSERVER_H -const S32 LL_VERSION_MAJOR = 1; -const S32 LL_VERSION_MINOR = 31; +const S32 LL_VERSION_MAJOR = 2; +const S32 LL_VERSION_MINOR = 1; const S32 LL_VERSION_PATCH = 0; -const S32 LL_VERSION_BUILD = 203110; +const S32 LL_VERSION_BUILD = 0; const char * const LL_CHANNEL = "Second Life Server"; diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index fc3ce6df7e..6e341b83a1 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -34,8 +34,8 @@ #define LL_LLVERSIONVIEWER_H const S32 LL_VERSION_MAJOR = 2; -const S32 LL_VERSION_MINOR = 0; -const S32 LL_VERSION_PATCH = 2; +const S32 LL_VERSION_MINOR = 1; +const S32 LL_VERSION_PATCH = 0; const S32 LL_VERSION_BUILD = 0; const char * const LL_CHANNEL = "Second Life Developer"; diff --git a/indra/llcommon/tests/llprocessor_test.cpp b/indra/llcommon/tests/llprocessor_test.cpp new file mode 100644 index 0000000000..a9e312b70b --- /dev/null +++ b/indra/llcommon/tests/llprocessor_test.cpp @@ -0,0 +1,67 @@ +/** + * @file llprocessor_test.cpp + * @date 2010-06-01 + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "../test/lltut.h" + +#include "../llprocessor.h" + + +namespace tut +{ + struct processor + { + }; + + typedef test_group<processor> processor_t; + typedef processor_t::object processor_object_t; + tut::processor_t tut_processor("processor"); + + template<> template<> + void processor_object_t::test<1>() + { + set_test_name("LLProcessorInfo regression test"); + + LLProcessorInfo pi; + F64 freq = pi.getCPUFrequency(); + //bool sse = pi.hasSSE(); + //bool sse2 = pi.hasSSE2(); + //bool alitvec = pi.hasAltivec(); + std::string family = pi.getCPUFamilyName(); + std::string brand = pi.getCPUBrandName(); + //std::string steam = pi.getCPUFeatureDescription(); + + ensure_not_equals("Unknown Brand name", brand, "Unknown"); + ensure_not_equals("Unknown Family name", family, "Unknown"); + ensure("Reasonable CPU Frequency > 100 && < 10000", freq > 100 && freq < 10000); + } +} |