diff options
Diffstat (limited to 'indra/llcommon')
47 files changed, 1864 insertions, 2758 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index ab8c9b6f9a..763a3a3d73 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -35,6 +35,7 @@ set(llcommon_SOURCE_FILES llbase32.cpp llbase64.cpp llcommon.cpp + llcommonutils.cpp llcoros.cpp llcrc.cpp llcriticaldamp.cpp @@ -50,7 +51,8 @@ set(llcommon_SOURCE_FILES lleventdispatcher.cpp lleventfilter.cpp llevents.cpp - llfasttimer.cpp + lleventtimer.cpp + llfasttimer_class.cpp llfile.cpp llfindlocale.cpp llfixedbuffer.cpp @@ -123,6 +125,7 @@ set(llcommon_HEADER_FILES llchat.h llclickaction.h llcommon.h + llcommonutils.h llcoros.h llcrc.h llcriticaldamp.h @@ -164,7 +167,6 @@ set(llcommon_HEADER_FILES llhttpstatuscodes.h llindexedqueue.h llinstancetracker.h - llinstancetracker.h llkeythrottle.h lllazy.h lllistenerwrapper.h @@ -249,7 +251,7 @@ list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES}) if(LLCOMMON_LINK_SHARED) add_library (llcommon SHARED ${llcommon_SOURCE_FILES}) - ll_stage_sharedlib(llcommon) + ll_stage_sharedlib(llcommon) else(LLCOMMON_LINK_SHARED) add_library (llcommon ${llcommon_SOURCE_FILES}) endif(LLCOMMON_LINK_SHARED) diff --git a/indra/llcommon/llallocator_heap_profile.cpp b/indra/llcommon/llallocator_heap_profile.cpp index 0a807702d0..e50d59fd4b 100644 --- a/indra/llcommon/llallocator_heap_profile.cpp +++ b/indra/llcommon/llallocator_heap_profile.cpp @@ -113,21 +113,24 @@ void LLAllocatorHeapProfile::parse(std::string const & prof_text) ++j; while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens - llassert_always(j != line_elems.end()); - ++j; // skip the '@' - - mLines.push_back(line(live_count, live_size, tot_count, tot_size)); - line & current_line = mLines.back(); - - for(; j != line_elems.end(); ++j) - { - if(!j->empty()) { - U32 marker = boost::lexical_cast<U32>(*j); - current_line.mTrace.push_back(marker); - } - } + llassert(j != line_elems.end()); + if (j != line_elems.end()) + { + ++j; // skip the '@' + + mLines.push_back(line(live_count, live_size, tot_count, tot_size)); + line & current_line = mLines.back(); + + for(; j != line_elems.end(); ++j) + { + if(!j->empty()) + { + U32 marker = boost::lexical_cast<U32>(*j); + current_line.mTrace.push_back(marker); + } + } + } } - // *TODO - parse MAPPED_LIBRARIES section here if we're ever interested in it } diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index 968b92d1e7..6b2d1b7c20 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -41,7 +41,7 @@ #include "lllivefile.h" #include "llmemory.h" #include "llstl.h" // for DeletePointer() -#include "lltimer.h" +#include "lleventtimer.h" // // Signal handling diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index 27a52cdd99..e5b8edf9c3 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -235,7 +235,7 @@ public: // Child process handling (Unix only for now) // // Set a callback to be run on exit of a child process - // WARNING! This callback is run from the signal handler due to the extreme crappiness of + // WARNING! This callback is run from the signal handler due to // Linux threading requiring waitpid() to be called from the thread that spawned the process. // At some point I will make this more behaved, but I'm not going to fix this right now - djs void setChildCallback(pid_t pid, LLAppChildCallback callback); diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index ed70b1d9f2..7330b00bcf 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -543,14 +543,13 @@ S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nb return 0; } - S32 off; - if (offset < 0) - off = LLAPRFile::seek(file_handle, APR_END, 0); - else - off = LLAPRFile::seek(file_handle, APR_SET, offset); + llassert(offset >= 0); + + if (offset > 0) + offset = LLAPRFile::seek(file_handle, APR_SET, offset); apr_size_t bytes_read; - if (off < 0) + if (offset < 0) { bytes_read = 0; } diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index b05a222b33..08cf11e593 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -182,7 +182,7 @@ typedef LLAtomic32<U32> LLAtomicU32; typedef LLAtomic32<S32> LLAtomicS32; // File IO convenience functions. -// Returns NULL if the file fails to openm sets *sizep to file size of not NULL +// Returns NULL if the file fails to open, sets *sizep to file size if not NULL // abbreviated flags #define LL_APR_R (APR_READ) // "r" #define LL_APR_W (APR_CREATE|APR_TRUNCATE|APR_WRITE) // "w" @@ -200,7 +200,7 @@ typedef LLAtomic32<S32> LLAtomicS32; // especially do not put some time-costly operations between open() and close(). // otherwise it might lock the APRFilePool. //there are two different apr_pools the APRFile can use: -// 1, a temperary pool passed to an APRFile function, which is used within this function and only once. +// 1, a temporary pool passed to an APRFile function, which is used within this function and only once. // 2, a global pool. // @@ -255,12 +255,12 @@ public: // Returns bytes read/written, 0 if read/write fails: static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); - static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); + static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); // offset<0 means append //******************************************************************************************************************************* }; /** - * @brief Function which approprately logs error or remains quiet on + * @brief Function which appropriately logs error or remains quiet on * APR_SUCCESS. * @return Returns <code>true</code> if status is an error condition. */ diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index 6d5b12d840..2cd29448ae 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -45,12 +45,16 @@ struct AssetEntry : public LLDictionaryEntry AssetEntry(const char *desc_name, const char *type_name, // 8 character limit! const char *human_name, // for decoding to human readable form; put any and as many printable characters you want in each one - bool can_link) // can you create a link to this type? + bool can_link, // can you create a link to this type? + bool can_fetch, // can you fetch this asset by ID? + bool can_know) // can you see this asset's ID? : LLDictionaryEntry(desc_name), mTypeName(type_name), mHumanName(human_name), - mCanLink(can_link) + mCanLink(can_link), + mCanFetch(can_fetch), + mCanKnow(can_know) { llassert(strlen(mTypeName) <= 8); } @@ -58,6 +62,8 @@ struct AssetEntry : public LLDictionaryEntry const char *mTypeName; const char *mHumanName; bool mCanLink; + bool mCanFetch; + bool mCanKnow; }; class LLAssetDictionary : public LLSingleton<LLAssetDictionary>, @@ -69,32 +75,32 @@ public: LLAssetDictionary::LLAssetDictionary() { - // DESCRIPTION TYPE NAME HUMAN NAME CAN LINK? - // |--------------------|-----------|-------------------|-----------| - addEntry(LLAssetType::AT_TEXTURE, new AssetEntry("TEXTURE", "texture", "texture", FALSE)); - addEntry(LLAssetType::AT_SOUND, new AssetEntry("SOUND", "sound", "sound", FALSE)); - addEntry(LLAssetType::AT_CALLINGCARD, new AssetEntry("CALLINGCARD", "callcard", "calling card", FALSE)); - addEntry(LLAssetType::AT_LANDMARK, new AssetEntry("LANDMARK", "landmark", "landmark", FALSE)); - addEntry(LLAssetType::AT_SCRIPT, new AssetEntry("SCRIPT", "script", "legacy script", FALSE)); - addEntry(LLAssetType::AT_CLOTHING, new AssetEntry("CLOTHING", "clothing", "clothing", TRUE)); - addEntry(LLAssetType::AT_OBJECT, new AssetEntry("OBJECT", "object", "object", TRUE)); - addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", FALSE)); - addEntry(LLAssetType::AT_CATEGORY, new AssetEntry("CATEGORY", "category", "folder", TRUE)); - addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", FALSE)); - addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", FALSE)); - addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", FALSE)); - addEntry(LLAssetType::AT_BODYPART, new AssetEntry("BODYPART", "bodypart", "body part", TRUE)); - addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", FALSE)); - addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", FALSE)); - addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", FALSE)); - addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", FALSE)); - addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", TRUE)); - addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", FALSE)); - - addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "symbolic link", FALSE)); - addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "symbolic folder link", FALSE)); - - addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE)); + // DESCRIPTION TYPE NAME HUMAN NAME CAN LINK? CAN FETCH? CAN KNOW? + // |--------------------|-----------|-------------------|-----------|-----------|---------| + addEntry(LLAssetType::AT_TEXTURE, new AssetEntry("TEXTURE", "texture", "texture", true, false, true)); + addEntry(LLAssetType::AT_SOUND, new AssetEntry("SOUND", "sound", "sound", true, true, true)); + addEntry(LLAssetType::AT_CALLINGCARD, new AssetEntry("CALLINGCARD", "callcard", "calling card", true, false, false)); + addEntry(LLAssetType::AT_LANDMARK, new AssetEntry("LANDMARK", "landmark", "landmark", true, true, true)); + addEntry(LLAssetType::AT_SCRIPT, new AssetEntry("SCRIPT", "script", "legacy script", true, false, false)); + addEntry(LLAssetType::AT_CLOTHING, new AssetEntry("CLOTHING", "clothing", "clothing", true, true, true)); + addEntry(LLAssetType::AT_OBJECT, new AssetEntry("OBJECT", "object", "object", true, false, false)); + addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", true, false, true)); + addEntry(LLAssetType::AT_CATEGORY, new AssetEntry("CATEGORY", "category", "folder", true, false, false)); + addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", true, false, false)); + addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", true, false, false)); + addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", true, false, false)); + addEntry(LLAssetType::AT_BODYPART, new AssetEntry("BODYPART", "bodypart", "body part", true, true, true)); + addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", true, false, false)); + addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", true, false, false)); + addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", true, false, false)); + addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", true, true, true)); + addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", true, true, true)); + addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", false, false, false)); + + addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "sym link", false, false, true)); + addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "sym folder link", false, false, true)); + + addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, false, false, false)); }; // static @@ -225,3 +231,27 @@ const std::string &LLAssetType::badLookup() return sBadLookup; } + +// static +bool LLAssetType::lookupIsAssetFetchByIDAllowed(EType asset_type) +{ + const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); + const AssetEntry *entry = dict->lookup(asset_type); + if (entry) + { + return entry->mCanFetch; + } + return false; +} + +// static +bool LLAssetType::lookupIsAssetIDKnowable(EType asset_type) +{ + const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); + const AssetEntry *entry = dict->lookup(asset_type); + if (entry) + { + return entry->mCanKnow; + } + return false; +} diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index c7bbc2e74a..2c2dc27aaa 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -146,6 +146,9 @@ public: static bool lookupCanLink(EType asset_type); static bool lookupIsLinkType(EType asset_type); + static bool lookupIsAssetFetchByIDAllowed(EType asset_type); // the asset allows direct download + static bool lookupIsAssetIDKnowable(EType asset_type); // asset data can be known by the viewer + static const std::string& badLookup(); // error string when a lookup fails protected: diff --git a/indra/llcommon/llchat.h b/indra/llcommon/llchat.h index 5af7991006..f1b9091298 100644 --- a/indra/llcommon/llchat.h +++ b/indra/llcommon/llchat.h @@ -43,7 +43,8 @@ typedef enum e_chat_source_type { CHAT_SOURCE_SYSTEM = 0, CHAT_SOURCE_AGENT = 1, - CHAT_SOURCE_OBJECT = 2 + CHAT_SOURCE_OBJECT = 2, + CHAT_SOURCE_UNKNOWN = 3 } EChatSourceType; typedef enum e_chat_type @@ -68,7 +69,8 @@ typedef enum e_chat_audible_level typedef enum e_chat_style { CHAT_STYLE_NORMAL, - CHAT_STYLE_IRC + CHAT_STYLE_IRC, + CHAT_STYLE_HISTORY }EChatStyle; // A piece of chat @@ -79,6 +81,7 @@ public: : mText(text), mFromName(), mFromID(), + mNotifId(), mSourceType(CHAT_SOURCE_AGENT), mChatType(CHAT_TYPE_NORMAL), mAudible(CHAT_AUDIBLE_FULLY), @@ -87,12 +90,14 @@ public: mTimeStr(), mPosAgent(), mURL(), - mChatStyle(CHAT_STYLE_NORMAL) + mChatStyle(CHAT_STYLE_NORMAL), + mSessionID() { } std::string mText; // UTF-8 line of text std::string mFromName; // agent or object name LLUUID mFromID; // agent id or object id + LLUUID mNotifId; EChatSourceType mSourceType; EChatType mChatType; EChatAudible mAudible; @@ -102,6 +107,7 @@ public: LLVector3 mPosAgent; std::string mURL; EChatStyle mChatStyle; + LLUUID mSessionID; }; #endif diff --git a/indra/llcommon/llcommonutils.cpp b/indra/llcommon/llcommonutils.cpp new file mode 100644 index 0000000000..0022dc6915 --- /dev/null +++ b/indra/llcommon/llcommonutils.cpp @@ -0,0 +1,61 @@ +/** + * @file llcommonutils.h + * @brief Commin utils + * + * $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 "llcommonutils.h" + +void LLCommonUtils::computeDifference( + const uuid_vec_t& vnew, + const uuid_vec_t& vcur, + uuid_vec_t& vadded, + uuid_vec_t& vremoved) +{ + uuid_vec_t vnew_copy(vnew); + uuid_vec_t vcur_copy(vcur); + + std::sort(vnew_copy.begin(), vnew_copy.end()); + std::sort(vcur_copy.begin(), vcur_copy.end()); + + size_t maxsize = llmax(vnew_copy.size(), vcur_copy.size()); + vadded.resize(maxsize); + vremoved.resize(maxsize); + + uuid_vec_t::iterator it; + // what was removed + it = set_difference(vcur_copy.begin(), vcur_copy.end(), vnew_copy.begin(), vnew_copy.end(), vremoved.begin()); + vremoved.erase(it, vremoved.end()); + + // what was added + it = set_difference(vnew_copy.begin(), vnew_copy.end(), vcur_copy.begin(), vcur_copy.end(), vadded.begin()); + vadded.erase(it, vadded.end()); +} + +// EOF diff --git a/indra/llcommon/llcommonutils.h b/indra/llcommon/llcommonutils.h new file mode 100644 index 0000000000..ad0d884e37 --- /dev/null +++ b/indra/llcommon/llcommonutils.h @@ -0,0 +1,56 @@ +/** + * @file llcommonutils.h + * @brief Common utils + * + * $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$ + */ + +#ifndef LL_LLCOMMONUTILS_H +#define LL_LLCOMMONUTILS_H + +namespace LLCommonUtils +{ + /** + * Computes difference between 'vnew' and 'vcur' vectors. + * Items present in 'vnew' and missing in 'vcur' are treated as added and are copied into 'vadded' + * Items missing in 'vnew' and present in 'vcur' are treated as removed and are copied into 'vremoved' + * + * @param vnew[in] - incoming IDs + * @param vcur[in] - current IDs + * @param vadded[out] - difference between incoming and current IDS - added IDs + * @param vremoved[out] - difference between incoming and current IDS - removed IDs + */ + LL_COMMON_API void computeDifference( + const uuid_vec_t& vnew, + const uuid_vec_t& vcur, + uuid_vec_t& vadded, + uuid_vec_t& vremoved); +}; + +#endif //LL_LLCOMMONUTILS_H + +// EOF diff --git a/indra/llcommon/llcursortypes.cpp b/indra/llcommon/llcursortypes.cpp index 23ede97af3..6751c235f6 100644 --- a/indra/llcommon/llcursortypes.cpp +++ b/indra/llcommon/llcursortypes.cpp @@ -72,6 +72,9 @@ ECursorType getCursorFromString(const std::string& cursor_string) cursor_string_table["UI_CURSOR_TOOLPAUSE"] = UI_CURSOR_TOOLPAUSE; cursor_string_table["UI_CURSOR_TOOLMEDIAOPEN"] = UI_CURSOR_TOOLMEDIAOPEN; cursor_string_table["UI_CURSOR_PIPETTE"] = UI_CURSOR_PIPETTE; + cursor_string_table["UI_CURSOR_TOOLSIT"] = UI_CURSOR_TOOLSIT; + cursor_string_table["UI_CURSOR_TOOLBUY"] = UI_CURSOR_TOOLBUY; + cursor_string_table["UI_CURSOR_TOOLOPEN"] = UI_CURSOR_TOOLOPEN; } std::map<std::string,U32>::const_iterator iter = cursor_string_table.find(cursor_string); diff --git a/indra/llcommon/llcursortypes.h b/indra/llcommon/llcursortypes.h index a1b8178bfe..143c2c64cf 100644 --- a/indra/llcommon/llcursortypes.h +++ b/indra/llcommon/llcursortypes.h @@ -68,6 +68,9 @@ enum ECursorType { UI_CURSOR_TOOLPAUSE, UI_CURSOR_TOOLMEDIAOPEN, UI_CURSOR_PIPETTE, + UI_CURSOR_TOOLSIT, + UI_CURSOR_TOOLBUY, + UI_CURSOR_TOOLOPEN, UI_CURSOR_COUNT // Number of elements in this enum (NOT a cursor) }; diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index ca7e471bf2..de7f2ead74 100644 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -152,7 +152,8 @@ void LLDate::toStream(std::ostream& s) const s << '.' << std::setw(2) << (int)(exp_time.tm_usec / (LL_APR_USEC_PER_SEC / 100)); } - s << 'Z'; + s << 'Z' + << std::setfill(' '); } bool LLDate::split(S32 *year, S32 *month, S32 *day, S32 *hour, S32 *min, S32 *sec) const diff --git a/indra/llcommon/lldictionary.h b/indra/llcommon/lldictionary.h index 95178b41e7..4a2bfb9f3f 100644 --- a/indra/llcommon/lldictionary.h +++ b/indra/llcommon/lldictionary.h @@ -76,11 +76,16 @@ public: return dictionary_iter->first; } } - llassert(false); - return Index(-1); + return notFound(); } protected: + virtual Index notFound() const + { + // default is to assert + llassert(false); + return Index(-1); + } void addEntry(Index index, Entry *entry) { if (lookup(index)) diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index 5a4c644859..09812de2b8 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -242,7 +242,7 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; do { \ static LLError::CallSite _site( \ level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__, broadTag, narrowTag, once);\ - if (_site.shouldLog()) \ + if (LL_UNLIKELY(_site.shouldLog())) \ { \ std::ostringstream* _out = LLError::Log::out(); \ (*_out) diff --git a/indra/llcommon/llerrorlegacy.h b/indra/llcommon/llerrorlegacy.h index 7a970b1466..476d75380f 100644 --- a/indra/llcommon/llerrorlegacy.h +++ b/indra/llcommon/llerrorlegacy.h @@ -34,7 +34,7 @@ #ifndef LL_LLERRORLEGACY_H #define LL_LLERRORLEGACY_H - +#include "llpreprocessor.h" /* LEGACY -- DO NOT USE THIS STUFF ANYMORE @@ -75,6 +75,10 @@ const int LL_ERR_PRICE_MISMATCH = -23018; #define SHOW_ASSERT #else // _DEBUG +#ifdef LL_RELEASE_WITH_DEBUG_INFO +#define SHOW_ASSERT +#endif // LL_RELEASE_WITH_DEBUG_INFO + #ifdef RELEASE_SHOW_DEBUG #define SHOW_DEBUG #endif @@ -103,7 +107,7 @@ const int LL_ERR_PRICE_MISMATCH = -23018; #define llwarning(msg, num) llwarns << "Warning # " << num << ": " << msg << llendl; -#define llassert_always(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl; +#define llassert_always(func) if (LL_UNLIKELY(!(func))) llerrs << "ASSERT (" << #func << ")" << llendl; #ifdef SHOW_ASSERT #define llassert(func) llassert_always(func) diff --git a/indra/llcommon/lleventtimer.cpp b/indra/llcommon/lleventtimer.cpp new file mode 100644 index 0000000000..d44e7ec1e6 --- /dev/null +++ b/indra/llcommon/lleventtimer.cpp @@ -0,0 +1,95 @@ +/** + * @file lleventtimer.cpp + * @brief Cross-platform objects for doing timing + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, 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 "lleventtimer.h" + +#include "u64.h" + + +////////////////////////////////////////////////////////////////////////////// +// +// LLEventTimer Implementation +// +////////////////////////////////////////////////////////////////////////////// + +LLEventTimer::LLEventTimer(F32 period) +: mEventTimer() +{ + mPeriod = period; +} + +LLEventTimer::LLEventTimer(const LLDate& time) +: mEventTimer() +{ + mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch()); +} + + +LLEventTimer::~LLEventTimer() +{ +} + +//static +void LLEventTimer::updateClass() +{ + std::list<LLEventTimer*> completed_timers; + + { + LLInstanceTrackerScopedGuard guard; + for (instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); ) + { + LLEventTimer& timer = *iter++; + F32 et = timer.mEventTimer.getElapsedTimeF32(); + if (timer.mEventTimer.getStarted() && et > timer.mPeriod) { + timer.mEventTimer.reset(); + if ( timer.tick() ) + { + completed_timers.push_back( &timer ); + } + } + } + } + + if ( completed_timers.size() > 0 ) + { + for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin(); + completed_iter != completed_timers.end(); + completed_iter++ ) + { + delete *completed_iter; + } + } +} + + diff --git a/indra/llcommon/lleventtimer.h b/indra/llcommon/lleventtimer.h new file mode 100644 index 0000000000..5181cce52d --- /dev/null +++ b/indra/llcommon/lleventtimer.h @@ -0,0 +1,60 @@ +/** + * @file lleventtimer.h + * @brief Cross-platform objects for doing timing + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, 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$ + */ + +#ifndef LL_EVENTTIMER_H +#define LL_EVENTTIMER_H + +#include "stdtypes.h" +#include "lldate.h" +#include "llinstancetracker.h" +#include "lltimer.h" + +// class for scheduling a function to be called at a given frequency (approximate, inprecise) +class LL_COMMON_API LLEventTimer : protected LLInstanceTracker<LLEventTimer> +{ +public: + LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds + LLEventTimer(const LLDate& time); + virtual ~LLEventTimer(); + + //function to be called at the supplied frequency + // Normally return FALSE; TRUE will delete the timer after the function returns. + virtual BOOL tick() = 0; + + static void updateClass(); + +protected: + LLTimer mEventTimer; + F32 mPeriod; +}; + +#endif //LL_EVENTTIMER_H diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 8af79c90fd..840d09d970 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -1,6 +1,6 @@ /** * @file llfasttimer.h - * @brief Declaration of a fast timer. + * @brief Inline implementations of fast timers. * * $LicenseInfo:firstyear=2004&license=viewergpl$ * @@ -33,13 +33,17 @@ #ifndef LL_FASTTIMER_H #define LL_FASTTIMER_H -#include "llinstancetracker.h" +// pull in the actual class definition +#include "llfasttimer_class.h" -#define FAST_TIMER_ON 1 -#define TIME_FAST_TIMERS 0 +// +// Important note: These implementations must be FAST! +// #if LL_WINDOWS -#define LL_INLINE __forceinline +// +// Windows implementation of CPU clock +// // // NOTE: put back in when we aren't using platform sdk anymore @@ -52,21 +56,21 @@ //#undef _interlockedbittestandset //#undef _interlockedbittestandreset -//inline U32 get_cpu_clock_count_32() +//inline U32 LLFastTimer::getCPUClockCount32() //{ // U64 time_stamp = __rdtsc(); // return (U32)(time_stamp >> 8); //} // //// return full timer value, *not* shifted by 8 bits -//inline U64 get_cpu_clock_count_64() +//inline U64 LLFastTimer::getCPUClockCount64() //{ // return __rdtsc(); //} // shift off lower 8 bits for lower resolution but longer term timing // on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing -inline U32 get_cpu_clock_count_32() +inline U32 LLFastTimer::getCPUClockCount32() { U32 ret_val; __asm @@ -82,7 +86,7 @@ inline U32 get_cpu_clock_count_32() } // return full timer value, *not* shifted by 8 bits -inline U64 get_cpu_clock_count_64() +inline U64 LLFastTimer::getCPUClockCount64() { U64 ret_val; __asm @@ -96,269 +100,73 @@ inline U64 get_cpu_clock_count_64() } return ret_val; } -#else -#define LL_INLINE #endif + +#if (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__)) +// +// Linux and Solaris implementation of CPU clock - non-x86. +// This is accurate but SLOW! Only use out of desperation. +// +// Try to use the MONOTONIC clock if available, this is a constant time counter +// with nanosecond resolution (but not necessarily accuracy) and attempts are +// made to synchronize this value between cores at kernel start. It should not +// be affected by CPU frequency. If not available use the REALTIME clock, but +// this may be affected by NTP adjustments or other user activity affecting +// the system time. +inline U64 LLFastTimer::getCPUClockCount64() +{ + struct timespec tp; + +#ifdef CLOCK_MONOTONIC // MONOTONIC supported at build-time? + if (-1 == clock_gettime(CLOCK_MONOTONIC,&tp)) // if MONOTONIC isn't supported at runtime then ouch, try REALTIME +#endif + clock_gettime(CLOCK_REALTIME,&tp); + + return (tp.tv_sec*LLFastTimer::sClockResolution)+tp.tv_nsec; +} + +inline U32 LLFastTimer::getCPUClockCount32() +{ + return (U32)(LLFastTimer::getCPUClockCount64() >> 8); +} +#endif // (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__)) + + #if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__)) -inline U32 get_cpu_clock_count_32() +// +// Mac+Linux+Solaris FAST x86 implementation of CPU clock +inline U32 LLFastTimer::getCPUClockCount32() { U64 x; __asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); - return (U32)x >> 8; + return (U32)(x >> 8); } -inline U32 get_cpu_clock_count_64() +inline U64 LLFastTimer::getCPUClockCount64() { U64 x; __asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); - return x >> 8; + return x; } #endif -#if ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__))) || (LL_SOLARIS && defined(__sparc__)) + +#if ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__))) // -// Mac PPC (deprecated) & Solaris SPARC implementation of CPU clock +// Mac PPC (deprecated) implementation of CPU clock // // Just use gettimeofday implementation for now -inline U32 get_cpu_clock_count_32() +inline U32 LLFastTimer::getCPUClockCount32() { - return (U32)get_clock_count(); + return (U32)(get_clock_count()>>8); } -inline U32 get_cpu_clock_count_64() +inline U64 LLFastTimer::getCPUClockCount64() { return get_clock_count(); } #endif -class LLMutex; - -#include <queue> -#include "llsd.h" - -class LL_COMMON_API LLFastTimer -{ -public: - - class NamedTimer; - - struct LL_COMMON_API FrameState - { - FrameState(NamedTimer* timerp); - - U32 mSelfTimeCounter; - U32 mCalls; - FrameState* mParent; // info for caller timer - FrameState* mLastCaller; // used to bootstrap tree construction - NamedTimer* mTimer; - U16 mActiveCount; // number of timers with this ID active on stack - bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame - }; - - // stores a "named" timer instance to be reused via multiple LLFastTimer stack instances - class LL_COMMON_API NamedTimer - : public LLInstanceTracker<NamedTimer> - { - friend class DeclareTimer; - public: - ~NamedTimer(); - - enum { HISTORY_NUM = 60 }; - - const std::string& getName() const { return mName; } - NamedTimer* getParent() const { return mParent; } - void setParent(NamedTimer* parent); - S32 getDepth(); - std::string getToolTip(S32 history_index = -1); - - typedef std::vector<NamedTimer*>::const_iterator child_const_iter; - child_const_iter beginChildren(); - child_const_iter endChildren(); - std::vector<NamedTimer*>& getChildren(); - - void setCollapsed(bool collapsed) { mCollapsed = collapsed; } - bool getCollapsed() const { return mCollapsed; } - - U32 getCountAverage() const { return mCountAverage; } - U32 getCallAverage() const { return mCallAverage; } - - U32 getHistoricalCount(S32 history_index = 0) const; - U32 getHistoricalCalls(S32 history_index = 0) const; - - static NamedTimer& getRootNamedTimer(); - - S32 getFrameStateIndex() const { return mFrameStateIndex; } - - FrameState& getFrameState() const; - - private: - friend class LLFastTimer; - friend class NamedTimerFactory; - - // - // methods - // - NamedTimer(const std::string& name); - // recursive call to gather total time from children - static void accumulateTimings(); - - // updates cumulative times and hierarchy, - // can be called multiple times in a frame, at any point - static void processTimes(); - - static void buildHierarchy(); - static void resetFrame(); - static void reset(); - - // - // members - // - S32 mFrameStateIndex; - - std::string mName; - - U32 mTotalTimeCounter; - - U32 mCountAverage; - U32 mCallAverage; - - U32* mCountHistory; - U32* mCallHistory; - - // tree structure - NamedTimer* mParent; // NamedTimer of caller(parent) - std::vector<NamedTimer*> mChildren; - bool mCollapsed; // don't show children - bool mNeedsSorting; // sort children whenever child added - }; - - // used to statically declare a new named timer - class LL_COMMON_API DeclareTimer - : public LLInstanceTracker<DeclareTimer> - { - friend class LLFastTimer; - public: - DeclareTimer(const std::string& name, bool open); - DeclareTimer(const std::string& name); - - static void updateCachedPointers(); - - private: - NamedTimer& mTimer; - FrameState* mFrameState; - }; - -public: - LLFastTimer(LLFastTimer::FrameState* state); - - LL_INLINE LLFastTimer(LLFastTimer::DeclareTimer& timer) - : mFrameState(timer.mFrameState) - { -#if TIME_FAST_TIMERS - U64 timer_start = get_cpu_clock_count_64(); -#endif -#if FAST_TIMER_ON - LLFastTimer::FrameState* frame_state = mFrameState; - mStartTime = get_cpu_clock_count_32(); - - frame_state->mActiveCount++; - frame_state->mCalls++; - // keep current parent as long as it is active when we are - frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0); - - LLFastTimer::CurTimerData* cur_timer_data = &LLFastTimer::sCurTimerData; - mLastTimerData = *cur_timer_data; - cur_timer_data->mCurTimer = this; - cur_timer_data->mFrameState = frame_state; - cur_timer_data->mChildTime = 0; -#endif -#if TIME_FAST_TIMERS - U64 timer_end = get_cpu_clock_count_64(); - sTimerCycles += timer_end - timer_start; -#endif - } - - LL_INLINE ~LLFastTimer() - { -#if TIME_FAST_TIMERS - U64 timer_start = get_cpu_clock_count_64(); -#endif -#if FAST_TIMER_ON - LLFastTimer::FrameState* frame_state = mFrameState; - U32 total_time = get_cpu_clock_count_32() - mStartTime; - - frame_state->mSelfTimeCounter += total_time - LLFastTimer::sCurTimerData.mChildTime; - frame_state->mActiveCount--; - - // store last caller to bootstrap tree creation - // do this in the destructor in case of recursion to get topmost caller - frame_state->mLastCaller = mLastTimerData.mFrameState; - - // we are only tracking self time, so subtract our total time delta from parents - mLastTimerData.mChildTime += total_time; - - LLFastTimer::sCurTimerData = mLastTimerData; -#endif -#if TIME_FAST_TIMERS - U64 timer_end = get_cpu_clock_count_64(); - sTimerCycles += timer_end - timer_start; - sTimerCalls++; -#endif - } - -public: - static LLMutex* sLogLock; - static std::queue<LLSD> sLogQueue; - static BOOL sLog; - static BOOL sMetricLog; - static bool sPauseHistory; - static bool sResetHistory; - static U64 sTimerCycles; - static U32 sTimerCalls; - - typedef std::vector<FrameState> info_list_t; - static info_list_t& getFrameStateList(); - - - // call this once a frame to reset timers - static void nextFrame(); - - // dumps current cumulative frame stats to log - // call nextFrame() to reset timers - static void dumpCurTimes(); - - // call this to reset timer hierarchy, averages, etc. - static void reset(); - - static U64 countsPerSecond(); - static S32 getLastFrameIndex() { return sLastFrameIndex; } - static S32 getCurFrameIndex() { return sCurFrameIndex; } - - static void writeLog(std::ostream& os); - static const NamedTimer* getTimerByName(const std::string& name); - - struct CurTimerData - { - LLFastTimer* mCurTimer; - FrameState* mFrameState; - U32 mChildTime; - }; - static CurTimerData sCurTimerData; - -private: - static S32 sCurFrameIndex; - static S32 sLastFrameIndex; - static U64 sLastFrameTime; - static info_list_t* sTimerInfos; - - U32 mStartTime; - LLFastTimer::FrameState* mFrameState; - LLFastTimer::CurTimerData mLastTimerData; - -}; - -typedef class LLFastTimer LLFastTimer; - #endif // LL_LLFASTTIMER_H diff --git a/indra/llcommon/llfasttimer_class.cpp b/indra/llcommon/llfasttimer_class.cpp new file mode 100644 index 0000000000..20727dd76e --- /dev/null +++ b/indra/llcommon/llfasttimer_class.cpp @@ -0,0 +1,768 @@ +/** + * @file llfasttimer_class.cpp + * @brief Implementation of the fast timer. + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2007, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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 "llfasttimer.h" + +#include "llmemory.h" +#include "llprocessor.h" +#include "llsingleton.h" +#include "lltreeiterators.h" +#include "llsdserialize.h" + +#include <boost/bind.hpp> + +#if LL_WINDOWS +#elif LL_LINUX || LL_SOLARIS +#include <sys/time.h> +#include <sched.h> +#elif LL_DARWIN +#include <sys/time.h> +#include "lltimer.h" // get_clock_count() +#else +#error "architecture not supported" +#endif + +////////////////////////////////////////////////////////////////////////////// +// statics + +S32 LLFastTimer::sCurFrameIndex = -1; +S32 LLFastTimer::sLastFrameIndex = -1; +U64 LLFastTimer::sLastFrameTime = LLFastTimer::getCPUClockCount64(); +bool LLFastTimer::sPauseHistory = 0; +bool LLFastTimer::sResetHistory = 0; +LLFastTimer::CurTimerData LLFastTimer::sCurTimerData; +BOOL LLFastTimer::sLog = FALSE; +BOOL LLFastTimer::sMetricLog = FALSE; +LLMutex* LLFastTimer::sLogLock = NULL; +std::queue<LLSD> LLFastTimer::sLogQueue; + +#if LL_LINUX || LL_SOLARIS +U64 LLFastTimer::sClockResolution = 1000000000; // Nanosecond resolution +#else +U64 LLFastTimer::sClockResolution = 1000000; // Microsecond resolution +#endif + +std::vector<LLFastTimer::FrameState>* LLFastTimer::sTimerInfos = NULL; +U64 LLFastTimer::sTimerCycles = 0; +U32 LLFastTimer::sTimerCalls = 0; + + +// FIXME: move these declarations to the relevant modules + +// helper functions +typedef LLTreeDFSPostIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_bottom_up_iterator_t; + +static timer_tree_bottom_up_iterator_t begin_timer_tree_bottom_up(LLFastTimer::NamedTimer& id) +{ + return timer_tree_bottom_up_iterator_t(&id, + boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1), + boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1)); +} + +static timer_tree_bottom_up_iterator_t end_timer_tree_bottom_up() +{ + return timer_tree_bottom_up_iterator_t(); +} + +typedef LLTreeDFSIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_dfs_iterator_t; + + +static timer_tree_dfs_iterator_t begin_timer_tree(LLFastTimer::NamedTimer& id) +{ + return timer_tree_dfs_iterator_t(&id, + boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1), + boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1)); +} + +static timer_tree_dfs_iterator_t end_timer_tree() +{ + return timer_tree_dfs_iterator_t(); +} + + + +// factory class that creates NamedTimers via static DeclareTimer objects +class NamedTimerFactory : public LLSingleton<NamedTimerFactory> +{ +public: + NamedTimerFactory() + : mActiveTimerRoot(NULL), + mTimerRoot(NULL), + mAppTimer(NULL), + mRootFrameState(NULL) + {} + + /*virtual */ void initSingleton() + { + mTimerRoot = new LLFastTimer::NamedTimer("root"); + + mActiveTimerRoot = new LLFastTimer::NamedTimer("Frame"); + mActiveTimerRoot->setCollapsed(false); + + mRootFrameState = new LLFastTimer::FrameState(mActiveTimerRoot); + mRootFrameState->mParent = &mTimerRoot->getFrameState(); + mActiveTimerRoot->setParent(mTimerRoot); + + mAppTimer = new LLFastTimer(mRootFrameState); + } + + ~NamedTimerFactory() + { + std::for_each(mTimers.begin(), mTimers.end(), DeletePairedPointer()); + + delete mAppTimer; + delete mActiveTimerRoot; + delete mTimerRoot; + delete mRootFrameState; + } + + LLFastTimer::NamedTimer& createNamedTimer(const std::string& name) + { + timer_map_t::iterator found_it = mTimers.find(name); + if (found_it != mTimers.end()) + { + return *found_it->second; + } + + LLFastTimer::NamedTimer* timer = new LLFastTimer::NamedTimer(name); + timer->setParent(mTimerRoot); + mTimers.insert(std::make_pair(name, timer)); + + return *timer; + } + + LLFastTimer::NamedTimer* getTimerByName(const std::string& name) + { + timer_map_t::iterator found_it = mTimers.find(name); + if (found_it != mTimers.end()) + { + return found_it->second; + } + return NULL; + } + + LLFastTimer::NamedTimer* getActiveRootTimer() { return mActiveTimerRoot; } + LLFastTimer::NamedTimer* getRootTimer() { return mTimerRoot; } + const LLFastTimer* getAppTimer() { return mAppTimer; } + LLFastTimer::FrameState& getRootFrameState() { return *mRootFrameState; } + + typedef std::map<std::string, LLFastTimer::NamedTimer*> timer_map_t; + timer_map_t::iterator beginTimers() { return mTimers.begin(); } + timer_map_t::iterator endTimers() { return mTimers.end(); } + S32 timerCount() { return mTimers.size(); } + +private: + timer_map_t mTimers; + + LLFastTimer::NamedTimer* mActiveTimerRoot; + LLFastTimer::NamedTimer* mTimerRoot; + LLFastTimer* mAppTimer; + LLFastTimer::FrameState* mRootFrameState; +}; + +void update_cached_pointers_if_changed() +{ + // detect when elements have moved and update cached pointers + static LLFastTimer::FrameState* sFirstTimerAddress = NULL; + if (&*(LLFastTimer::getFrameStateList().begin()) != sFirstTimerAddress) + { + LLFastTimer::DeclareTimer::updateCachedPointers(); + } + sFirstTimerAddress = &*(LLFastTimer::getFrameStateList().begin()); +} + +LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name, bool open ) +: mTimer(NamedTimerFactory::instance().createNamedTimer(name)) +{ + mTimer.setCollapsed(!open); + mFrameState = &mTimer.getFrameState(); + update_cached_pointers_if_changed(); +} + +LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name) +: mTimer(NamedTimerFactory::instance().createNamedTimer(name)) +{ + mFrameState = &mTimer.getFrameState(); + update_cached_pointers_if_changed(); +} + +// static +void LLFastTimer::DeclareTimer::updateCachedPointers() +{ + DeclareTimer::LLInstanceTrackerScopedGuard guard; + // propagate frame state pointers to timer declarations + for (DeclareTimer::instance_iter it = guard.beginInstances(); + it != guard.endInstances(); + ++it) + { + // update cached pointer + it->mFrameState = &it->mTimer.getFrameState(); + } +} + +//static +#if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__)) +U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer +{ + return sClockResolution >> 8; +} +#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(LLProcessorInfo().getCPUFrequency()); + + // we drop the low-order byte in our timers, so report a lower frequency + return sCPUClockFrequency >> 8; +} +#endif + +LLFastTimer::FrameState::FrameState(LLFastTimer::NamedTimer* timerp) +: mActiveCount(0), + mCalls(0), + mSelfTimeCounter(0), + mParent(NULL), + mLastCaller(NULL), + mMoveUpTree(false), + mTimer(timerp) +{} + + +LLFastTimer::NamedTimer::NamedTimer(const std::string& name) +: mName(name), + mCollapsed(true), + mParent(NULL), + mTotalTimeCounter(0), + mCountAverage(0), + mCallAverage(0), + mNeedsSorting(false) +{ + info_list_t& frame_state_list = getFrameStateList(); + mFrameStateIndex = frame_state_list.size(); + getFrameStateList().push_back(FrameState(this)); + + mCountHistory = new U32[HISTORY_NUM]; + memset(mCountHistory, 0, sizeof(U32) * HISTORY_NUM); + mCallHistory = new U32[HISTORY_NUM]; + memset(mCallHistory, 0, sizeof(U32) * HISTORY_NUM); +} + +LLFastTimer::NamedTimer::~NamedTimer() +{ + delete[] mCountHistory; + delete[] mCallHistory; +} + +std::string LLFastTimer::NamedTimer::getToolTip(S32 history_idx) +{ + if (history_idx < 0) + { + // by default, show average number of calls + return llformat("%s (%d calls)", getName().c_str(), (S32)getCallAverage()); + } + else + { + return llformat("%s (%d calls)", getName().c_str(), (S32)getHistoricalCalls(history_idx)); + } +} + +void LLFastTimer::NamedTimer::setParent(NamedTimer* parent) +{ + llassert_always(parent != this); + llassert_always(parent != NULL); + + if (mParent) + { + // subtract our accumulated from previous parent + for (S32 i = 0; i < HISTORY_NUM; i++) + { + mParent->mCountHistory[i] -= mCountHistory[i]; + } + + // subtract average timing from previous parent + mParent->mCountAverage -= mCountAverage; + + std::vector<NamedTimer*>& children = mParent->getChildren(); + std::vector<NamedTimer*>::iterator found_it = std::find(children.begin(), children.end(), this); + if (found_it != children.end()) + { + children.erase(found_it); + } + } + + mParent = parent; + if (parent) + { + getFrameState().mParent = &parent->getFrameState(); + parent->getChildren().push_back(this); + parent->mNeedsSorting = true; + } +} + +S32 LLFastTimer::NamedTimer::getDepth() +{ + S32 depth = 0; + NamedTimer* timerp = mParent; + while(timerp) + { + depth++; + timerp = timerp->mParent; + } + return depth; +} + +// static +void LLFastTimer::NamedTimer::processTimes() +{ + if (sCurFrameIndex < 0) return; + + buildHierarchy(); + accumulateTimings(); +} + +// sort timer info structs by depth first traversal order +struct SortTimersDFS +{ + bool operator()(const LLFastTimer::FrameState& i1, const LLFastTimer::FrameState& i2) + { + return i1.mTimer->getFrameStateIndex() < i2.mTimer->getFrameStateIndex(); + } +}; + +// sort child timers by name +struct SortTimerByName +{ + bool operator()(const LLFastTimer::NamedTimer* i1, const LLFastTimer::NamedTimer* i2) + { + return i1->getName() < i2->getName(); + } +}; + +//static +void LLFastTimer::NamedTimer::buildHierarchy() +{ + if (sCurFrameIndex < 0 ) return; + + // set up initial tree + { + NamedTimer::LLInstanceTrackerScopedGuard guard; + for (instance_iter it = guard.beginInstances(); + it != guard.endInstances(); + ++it) + { + NamedTimer& timer = *it; + if (&timer == NamedTimerFactory::instance().getRootTimer()) continue; + + // bootstrap tree construction by attaching to last timer to be on stack + // when this timer was called + if (timer.getFrameState().mLastCaller && timer.mParent == NamedTimerFactory::instance().getRootTimer()) + { + timer.setParent(timer.getFrameState().mLastCaller->mTimer); + // no need to push up tree on first use, flag can be set spuriously + timer.getFrameState().mMoveUpTree = false; + } + } + } + + // bump timers up tree if they've been flagged as being in the wrong place + // do this in a bottom up order to promote descendants first before promoting ancestors + // this preserves partial order derived from current frame's observations + for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(*NamedTimerFactory::instance().getRootTimer()); + it != end_timer_tree_bottom_up(); + ++it) + { + NamedTimer* timerp = *it; + // skip root timer + if (timerp == NamedTimerFactory::instance().getRootTimer()) continue; + + if (timerp->getFrameState().mMoveUpTree) + { + // since ancestors have already been visited, reparenting won't affect tree traversal + //step up tree, bringing our descendants with us + //llinfos << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() << + // " to child of " << timerp->getParent()->getParent()->getName() << llendl; + timerp->setParent(timerp->getParent()->getParent()); + timerp->getFrameState().mMoveUpTree = false; + + // don't bubble up any ancestors until descendants are done bubbling up + it.skipAncestors(); + } + } + + // sort timers by time last called, so call graph makes sense + for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer()); + it != end_timer_tree(); + ++it) + { + NamedTimer* timerp = (*it); + if (timerp->mNeedsSorting) + { + std::sort(timerp->getChildren().begin(), timerp->getChildren().end(), SortTimerByName()); + } + timerp->mNeedsSorting = false; + } +} + +//static +void LLFastTimer::NamedTimer::accumulateTimings() +{ + U32 cur_time = getCPUClockCount32(); + + // walk up stack of active timers and accumulate current time while leaving timing structures active + LLFastTimer* cur_timer = sCurTimerData.mCurTimer; + // root defined by parent pointing to self + CurTimerData* cur_data = &sCurTimerData; + while(cur_timer->mLastTimerData.mCurTimer != cur_timer) + { + U32 cumulative_time_delta = cur_time - cur_timer->mStartTime; + U32 self_time_delta = cumulative_time_delta - cur_data->mChildTime; + cur_data->mChildTime = 0; + cur_timer->mFrameState->mSelfTimeCounter += self_time_delta; + cur_timer->mStartTime = cur_time; + + cur_data = &cur_timer->mLastTimerData; + cur_data->mChildTime += cumulative_time_delta; + + cur_timer = cur_timer->mLastTimerData.mCurTimer; + } + + // traverse tree in DFS post order, or bottom up + for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(*NamedTimerFactory::instance().getActiveRootTimer()); + it != end_timer_tree_bottom_up(); + ++it) + { + NamedTimer* timerp = (*it); + timerp->mTotalTimeCounter = timerp->getFrameState().mSelfTimeCounter; + for (child_const_iter child_it = timerp->beginChildren(); child_it != timerp->endChildren(); ++child_it) + { + timerp->mTotalTimeCounter += (*child_it)->mTotalTimeCounter; + } + + S32 cur_frame = sCurFrameIndex; + if (cur_frame >= 0) + { + // update timer history + int hidx = cur_frame % HISTORY_NUM; + + timerp->mCountHistory[hidx] = timerp->mTotalTimeCounter; + timerp->mCountAverage = (timerp->mCountAverage * cur_frame + timerp->mTotalTimeCounter) / (cur_frame+1); + timerp->mCallHistory[hidx] = timerp->getFrameState().mCalls; + timerp->mCallAverage = (timerp->mCallAverage * cur_frame + timerp->getFrameState().mCalls) / (cur_frame+1); + } + } +} + +// static +void LLFastTimer::NamedTimer::resetFrame() +{ + if (sLog) + { //output current frame counts to performance log + F64 iclock_freq = 1000.0 / countsPerSecond(); // good place to calculate clock frequency + + F64 total_time = 0; + LLSD sd; + + { + NamedTimer::LLInstanceTrackerScopedGuard guard; + for (NamedTimer::instance_iter it = guard.beginInstances(); + it != guard.endInstances(); + ++it) + { + NamedTimer& timer = *it; + FrameState& info = timer.getFrameState(); + sd[timer.getName()]["Time"] = (LLSD::Real) (info.mSelfTimeCounter*iclock_freq); + sd[timer.getName()]["Calls"] = (LLSD::Integer) info.mCalls; + + // computing total time here because getting the root timer's getCountHistory + // doesn't work correctly on the first frame + total_time = total_time + info.mSelfTimeCounter * iclock_freq; + } + } + + sd["Total"]["Time"] = (LLSD::Real) total_time; + sd["Total"]["Calls"] = (LLSD::Integer) 1; + + { + LLMutexLock lock(sLogLock); + sLogQueue.push(sd); + } + } + + + // tag timers by position in depth first traversal of tree + S32 index = 0; + for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer()); + it != end_timer_tree(); + ++it) + { + NamedTimer* timerp = (*it); + + timerp->mFrameStateIndex = index; + index++; + + llassert_always(timerp->mFrameStateIndex < (S32)getFrameStateList().size()); + } + + // sort timers by dfs traversal order to improve cache coherency + std::sort(getFrameStateList().begin(), getFrameStateList().end(), SortTimersDFS()); + + // update pointers into framestatelist now that we've sorted it + DeclareTimer::updateCachedPointers(); + + // reset for next frame + { + NamedTimer::LLInstanceTrackerScopedGuard guard; + for (NamedTimer::instance_iter it = guard.beginInstances(); + it != guard.endInstances(); + ++it) + { + NamedTimer& timer = *it; + + FrameState& info = timer.getFrameState(); + info.mSelfTimeCounter = 0; + info.mCalls = 0; + info.mLastCaller = NULL; + info.mMoveUpTree = false; + // update parent pointer in timer state struct + if (timer.mParent) + { + info.mParent = &timer.mParent->getFrameState(); + } + } + } + + //sTimerCycles = 0; + //sTimerCalls = 0; +} + +//static +void LLFastTimer::NamedTimer::reset() +{ + resetFrame(); // reset frame data + + // walk up stack of active timers and reset start times to current time + // effectively zeroing out any accumulated time + U32 cur_time = getCPUClockCount32(); + + // root defined by parent pointing to self + CurTimerData* cur_data = &sCurTimerData; + LLFastTimer* cur_timer = cur_data->mCurTimer; + while(cur_timer->mLastTimerData.mCurTimer != cur_timer) + { + cur_timer->mStartTime = cur_time; + cur_data->mChildTime = 0; + + cur_data = &cur_timer->mLastTimerData; + cur_timer = cur_data->mCurTimer; + } + + // reset all history + { + NamedTimer::LLInstanceTrackerScopedGuard guard; + for (NamedTimer::instance_iter it = guard.beginInstances(); + it != guard.endInstances(); + ++it) + { + NamedTimer& timer = *it; + if (&timer != NamedTimerFactory::instance().getRootTimer()) + { + timer.setParent(NamedTimerFactory::instance().getRootTimer()); + } + + timer.mCountAverage = 0; + timer.mCallAverage = 0; + memset(timer.mCountHistory, 0, sizeof(U32) * HISTORY_NUM); + memset(timer.mCallHistory, 0, sizeof(U32) * HISTORY_NUM); + } + } + + sLastFrameIndex = 0; + sCurFrameIndex = 0; +} + +//static +LLFastTimer::info_list_t& LLFastTimer::getFrameStateList() +{ + if (!sTimerInfos) + { + sTimerInfos = new info_list_t(); + } + return *sTimerInfos; +} + + +U32 LLFastTimer::NamedTimer::getHistoricalCount(S32 history_index) const +{ + S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::NamedTimer::HISTORY_NUM; + return mCountHistory[history_idx]; +} + +U32 LLFastTimer::NamedTimer::getHistoricalCalls(S32 history_index ) const +{ + S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::NamedTimer::HISTORY_NUM; + return mCallHistory[history_idx]; +} + +LLFastTimer::FrameState& LLFastTimer::NamedTimer::getFrameState() const +{ + llassert_always(mFrameStateIndex >= 0); + if (this == NamedTimerFactory::instance().getActiveRootTimer()) + { + return NamedTimerFactory::instance().getRootFrameState(); + } + return getFrameStateList()[mFrameStateIndex]; +} + +// static +LLFastTimer::NamedTimer& LLFastTimer::NamedTimer::getRootNamedTimer() +{ + return *NamedTimerFactory::instance().getActiveRootTimer(); +} + +std::vector<LLFastTimer::NamedTimer*>::const_iterator LLFastTimer::NamedTimer::beginChildren() +{ + return mChildren.begin(); +} + +std::vector<LLFastTimer::NamedTimer*>::const_iterator LLFastTimer::NamedTimer::endChildren() +{ + return mChildren.end(); +} + +std::vector<LLFastTimer::NamedTimer*>& LLFastTimer::NamedTimer::getChildren() +{ + return mChildren; +} + +//static +void LLFastTimer::nextFrame() +{ + countsPerSecond(); // good place to calculate clock frequency + U64 frame_time = getCPUClockCount64(); + if ((frame_time - sLastFrameTime) >> 8 > 0xffffffff) + { + llinfos << "Slow frame, fast timers inaccurate" << llendl; + } + + if (sPauseHistory) + { + sResetHistory = true; + } + else if (sResetHistory) + { + sLastFrameIndex = 0; + sCurFrameIndex = 0; + sResetHistory = false; + } + else // not paused + { + NamedTimer::processTimes(); + sLastFrameIndex = sCurFrameIndex++; + } + + // get ready for next frame + NamedTimer::resetFrame(); + sLastFrameTime = frame_time; +} + +//static +void LLFastTimer::dumpCurTimes() +{ + // accumulate timings, etc. + NamedTimer::processTimes(); + + F64 clock_freq = (F64)countsPerSecond(); + F64 iclock_freq = 1000.0 / clock_freq; // clock_ticks -> milliseconds + + // walk over timers in depth order and output timings + for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer()); + it != end_timer_tree(); + ++it) + { + NamedTimer* timerp = (*it); + F64 total_time_ms = ((F64)timerp->getHistoricalCount(0) * iclock_freq); + // Don't bother with really brief times, keep output concise + if (total_time_ms < 0.1) continue; + + std::ostringstream out_str; + for (S32 i = 0; i < timerp->getDepth(); i++) + { + out_str << "\t"; + } + + + out_str << timerp->getName() << " " + << std::setprecision(3) << total_time_ms << " ms, " + << timerp->getHistoricalCalls(0) << " calls"; + + llinfos << out_str.str() << llendl; + } +} + +//static +void LLFastTimer::reset() +{ + NamedTimer::reset(); +} + + +//static +void LLFastTimer::writeLog(std::ostream& os) +{ + while (!sLogQueue.empty()) + { + LLSD& sd = sLogQueue.front(); + LLSDSerialize::toXML(sd, os); + LLMutexLock lock(sLogLock); + sLogQueue.pop(); + } +} + +//static +const LLFastTimer::NamedTimer* LLFastTimer::getTimerByName(const std::string& name) +{ + return NamedTimerFactory::instance().getTimerByName(name); +} + +LLFastTimer::LLFastTimer(LLFastTimer::FrameState* state) +: mFrameState(state) +{ + U32 start_time = getCPUClockCount32(); + mStartTime = start_time; + mFrameState->mActiveCount++; + LLFastTimer::sCurTimerData.mCurTimer = this; + LLFastTimer::sCurTimerData.mFrameState = mFrameState; + LLFastTimer::sCurTimerData.mChildTime = 0; + mLastTimerData = LLFastTimer::sCurTimerData; +} + + +////////////////////////////////////////////////////////////////////////////// diff --git a/indra/llcommon/llfasttimer_class.h b/indra/llcommon/llfasttimer_class.h new file mode 100644 index 0000000000..ddb1a74793 --- /dev/null +++ b/indra/llcommon/llfasttimer_class.h @@ -0,0 +1,272 @@ +/** + * @file llfasttimer_class.h + * @brief Declaration of a fast timer. + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, 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$ + */ + +#ifndef LL_FASTTIMER_CLASS_H +#define LL_FASTTIMER_CLASS_H + +#include "llinstancetracker.h" + +#define FAST_TIMER_ON 1 +#define TIME_FAST_TIMERS 0 + +class LLMutex; + +#include <queue> +#include "llsd.h" + +class LL_COMMON_API LLFastTimer +{ +public: + class NamedTimer; + + struct LL_COMMON_API FrameState + { + FrameState(NamedTimer* timerp); + + U32 mSelfTimeCounter; + U32 mCalls; + FrameState* mParent; // info for caller timer + FrameState* mLastCaller; // used to bootstrap tree construction + NamedTimer* mTimer; + U16 mActiveCount; // number of timers with this ID active on stack + bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame + }; + + // stores a "named" timer instance to be reused via multiple LLFastTimer stack instances + class LL_COMMON_API NamedTimer + : public LLInstanceTracker<NamedTimer> + { + friend class DeclareTimer; + public: + ~NamedTimer(); + + enum { HISTORY_NUM = 60 }; + + const std::string& getName() const { return mName; } + NamedTimer* getParent() const { return mParent; } + void setParent(NamedTimer* parent); + S32 getDepth(); + std::string getToolTip(S32 history_index = -1); + + typedef std::vector<NamedTimer*>::const_iterator child_const_iter; + child_const_iter beginChildren(); + child_const_iter endChildren(); + std::vector<NamedTimer*>& getChildren(); + + void setCollapsed(bool collapsed) { mCollapsed = collapsed; } + bool getCollapsed() const { return mCollapsed; } + + U32 getCountAverage() const { return mCountAverage; } + U32 getCallAverage() const { return mCallAverage; } + + U32 getHistoricalCount(S32 history_index = 0) const; + U32 getHistoricalCalls(S32 history_index = 0) const; + + static NamedTimer& getRootNamedTimer(); + + S32 getFrameStateIndex() const { return mFrameStateIndex; } + + FrameState& getFrameState() const; + + private: + friend class LLFastTimer; + friend class NamedTimerFactory; + + // + // methods + // + NamedTimer(const std::string& name); + // recursive call to gather total time from children + static void accumulateTimings(); + + // updates cumulative times and hierarchy, + // can be called multiple times in a frame, at any point + static void processTimes(); + + static void buildHierarchy(); + static void resetFrame(); + static void reset(); + + // + // members + // + S32 mFrameStateIndex; + + std::string mName; + + U32 mTotalTimeCounter; + + U32 mCountAverage; + U32 mCallAverage; + + U32* mCountHistory; + U32* mCallHistory; + + // tree structure + NamedTimer* mParent; // NamedTimer of caller(parent) + std::vector<NamedTimer*> mChildren; + bool mCollapsed; // don't show children + bool mNeedsSorting; // sort children whenever child added + }; + + // used to statically declare a new named timer + class LL_COMMON_API DeclareTimer + : public LLInstanceTracker<DeclareTimer> + { + friend class LLFastTimer; + public: + DeclareTimer(const std::string& name, bool open); + DeclareTimer(const std::string& name); + + static void updateCachedPointers(); + + private: + NamedTimer& mTimer; + FrameState* mFrameState; + }; + +public: + LLFastTimer(LLFastTimer::FrameState* state); + + LL_FORCE_INLINE LLFastTimer(LLFastTimer::DeclareTimer& timer) + : mFrameState(timer.mFrameState) + { +#if TIME_FAST_TIMERS + U64 timer_start = getCPUClockCount64(); +#endif +#if FAST_TIMER_ON + LLFastTimer::FrameState* frame_state = mFrameState; + mStartTime = getCPUClockCount32(); + + frame_state->mActiveCount++; + frame_state->mCalls++; + // keep current parent as long as it is active when we are + frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0); + + LLFastTimer::CurTimerData* cur_timer_data = &LLFastTimer::sCurTimerData; + mLastTimerData = *cur_timer_data; + cur_timer_data->mCurTimer = this; + cur_timer_data->mFrameState = frame_state; + cur_timer_data->mChildTime = 0; +#endif +#if TIME_FAST_TIMERS + U64 timer_end = getCPUClockCount64(); + sTimerCycles += timer_end - timer_start; +#endif + } + + LL_FORCE_INLINE ~LLFastTimer() + { +#if TIME_FAST_TIMERS + U64 timer_start = getCPUClockCount64(); +#endif +#if FAST_TIMER_ON + LLFastTimer::FrameState* frame_state = mFrameState; + U32 total_time = getCPUClockCount32() - mStartTime; + + frame_state->mSelfTimeCounter += total_time - LLFastTimer::sCurTimerData.mChildTime; + frame_state->mActiveCount--; + + // store last caller to bootstrap tree creation + // do this in the destructor in case of recursion to get topmost caller + frame_state->mLastCaller = mLastTimerData.mFrameState; + + // we are only tracking self time, so subtract our total time delta from parents + mLastTimerData.mChildTime += total_time; + + LLFastTimer::sCurTimerData = mLastTimerData; +#endif +#if TIME_FAST_TIMERS + U64 timer_end = getCPUClockCount64(); + sTimerCycles += timer_end - timer_start; + sTimerCalls++; +#endif + } + +public: + static LLMutex* sLogLock; + static std::queue<LLSD> sLogQueue; + static BOOL sLog; + static BOOL sMetricLog; + static bool sPauseHistory; + static bool sResetHistory; + static U64 sTimerCycles; + static U32 sTimerCalls; + + typedef std::vector<FrameState> info_list_t; + static info_list_t& getFrameStateList(); + + + // call this once a frame to reset timers + static void nextFrame(); + + // dumps current cumulative frame stats to log + // call nextFrame() to reset timers + static void dumpCurTimes(); + + // call this to reset timer hierarchy, averages, etc. + static void reset(); + + static U64 countsPerSecond(); + static S32 getLastFrameIndex() { return sLastFrameIndex; } + static S32 getCurFrameIndex() { return sCurFrameIndex; } + + static void writeLog(std::ostream& os); + static const NamedTimer* getTimerByName(const std::string& name); + + struct CurTimerData + { + LLFastTimer* mCurTimer; + FrameState* mFrameState; + U32 mChildTime; + }; + static CurTimerData sCurTimerData; + +private: + static U32 getCPUClockCount32(); + static U64 getCPUClockCount64(); + static U64 sClockResolution; + + static S32 sCurFrameIndex; + static S32 sLastFrameIndex; + static U64 sLastFrameTime; + static info_list_t* sTimerInfos; + + U32 mStartTime; + LLFastTimer::FrameState* mFrameState; + LLFastTimer::CurTimerData mLastTimerData; + +}; + +typedef class LLFastTimer LLFastTimer; + +#endif // LL_LLFASTTIMER_CLASS_H diff --git a/indra/llcommon/llfoldertype.cpp b/indra/llcommon/llfoldertype.cpp index 079e670b1a..2610fe9e6a 100644 --- a/indra/llcommon/llfoldertype.cpp +++ b/indra/llcommon/llfoldertype.cpp @@ -59,6 +59,11 @@ class LLFolderDictionary : public LLSingleton<LLFolderDictionary>, { public: LLFolderDictionary(); +protected: + virtual LLFolderType::EType notFound() const + { + return LLFolderType::FT_NONE; + } }; LLFolderDictionary::LLFolderDictionary() diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp new file mode 100644 index 0000000000..c962cb5be1 --- /dev/null +++ b/indra/llcommon/llinstancetracker.cpp @@ -0,0 +1,20 @@ +/** + * @file lllinstancetracker.cpp + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * Copyright (c) 2009, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "llinstancetracker.h" +// STL headers +// std headers +// external library headers +// other Linden headers + +// llinstancetracker.h is presently header-only. This file exists only because our CMake +// test macro ADD_BUILD_TEST requires it. +int dummy = 0; diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index 11fe523651..9df7998273 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -98,7 +98,10 @@ private: mKey = key; getMap_()[key] = static_cast<T*>(this); } - void remove_() { getMap_().erase(mKey); } + void remove_() + { + getMap_().erase(mKey); + } static InstanceMap& getMap_() { @@ -129,31 +132,65 @@ public: /// for completeness of analogy with the generic implementation static T* getInstance(T* k) { return k; } - static key_iter beginKeys() { return getSet_().begin(); } - static key_iter endKeys() { return getSet_().end(); } - static instance_iter beginInstances() { return instance_iter(getSet_().begin()); } - static instance_iter endInstances() { return instance_iter(getSet_().end()); } static S32 instanceCount() { return getSet_().size(); } + // Instantiate this to get access to iterators for this type. It's a 'guard' in the sense + // that it treats deletes of this type as errors as long as there is an instance of + // this class alive in scope somewhere (i.e. deleting while iterating is bad). + class LLInstanceTrackerScopedGuard + { + public: + LLInstanceTrackerScopedGuard() + { + ++sIterationNestDepth; + } + + ~LLInstanceTrackerScopedGuard() + { + --sIterationNestDepth; + } + + static instance_iter beginInstances() { return instance_iter(getSet_().begin()); } + static instance_iter endInstances() { return instance_iter(getSet_().end()); } + static key_iter beginKeys() { return getSet_().begin(); } + static key_iter endKeys() { return getSet_().end(); } + }; + protected: - LLInstanceTracker() { getSet_().insert(static_cast<T*>(this)); } - virtual ~LLInstanceTracker() { getSet_().erase(static_cast<T*>(this)); } + LLInstanceTracker() + { + // it's safe but unpredictable to create instances of this type while all instances are being iterated over. I hate unpredictable. This assert will probably be turned on early in the next development cycle. + //llassert(sIterationNestDepth == 0); + getSet_().insert(static_cast<T*>(this)); + } + virtual ~LLInstanceTracker() + { + // it's unsafe to delete instances of this type while all instances are being iterated over. + llassert(sIterationNestDepth == 0); + getSet_().erase(static_cast<T*>(this)); + } - LLInstanceTracker(const LLInstanceTracker& other) { getSet_().insert(static_cast<T*>(this)); } + LLInstanceTracker(const LLInstanceTracker& other) + { + //llassert(sIterationNestDepth == 0); + getSet_().insert(static_cast<T*>(this)); + } - static InstanceSet& getSet_() // called after getReady() but before go() - { - if (! sInstances) - { - sInstances = new InstanceSet; - } - return *sInstances; - } + static InstanceSet& getSet_() + { + if (! sInstances) + { + sInstances = new InstanceSet; + } + return *sInstances; + } static InstanceSet* sInstances; + static S32 sIterationNestDepth; }; template <typename T, typename KEY> typename LLInstanceTracker<T, KEY>::InstanceMap* LLInstanceTracker<T, KEY>::sInstances = NULL; template <typename T> typename LLInstanceTracker<T, T*>::InstanceSet* LLInstanceTracker<T, T*>::sInstances = NULL; +template <typename T> S32 LLInstanceTracker<T, T*>::sIterationNestDepth = 0; #endif diff --git a/indra/llcommon/lllivefile.cpp b/indra/llcommon/lllivefile.cpp index effda6c49c..5ca90d82ba 100644 --- a/indra/llcommon/lllivefile.cpp +++ b/indra/llcommon/lllivefile.cpp @@ -33,7 +33,7 @@ #include "lllivefile.h" #include "llframetimer.h" -#include "lltimer.h" +#include "lleventtimer.h" const F32 DEFAULT_CONFIG_FILE_REFRESH = 5.0f; diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index 2c37eadcc6..e6c736a263 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -95,7 +95,6 @@ public: bool notNull() const { return (mPointer != NULL); } operator Type*() const { return mPointer; } - operator const Type*() const { return mPointer; } bool operator !=(Type* ptr) const { return (mPointer != ptr); } bool operator ==(Type* ptr) const { return (mPointer == ptr); } bool operator ==(const LLPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); } diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index 5eefa6a16b..1c1503ca7b 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -55,13 +55,28 @@ #define LL_BIG_ENDIAN 1 #endif + // Per-compiler switches + #ifdef __GNUC__ #define LL_FORCE_INLINE inline __attribute__((always_inline)) #else #define LL_FORCE_INLINE __forceinline #endif +// Mark-up expressions with branch prediction hints. Do NOT use +// this with reckless abandon - it's an obfuscating micro-optimization +// outside of inner loops or other places where you are OVERWHELMINGLY +// sure which way an expression almost-always evaluates. +#if __GNUC__ >= 3 +# define LL_LIKELY(EXPR) __builtin_expect (!!(EXPR), true) +# define LL_UNLIKELY(EXPR) __builtin_expect (!!(EXPR), false) +#else +# define LL_LIKELY(EXPR) (EXPR) +# define LL_UNLIKELY(EXPR) (EXPR) +#endif + + // Figure out differences between compilers #if defined(__GNUC__) #define GCC_VERSION (__GNUC__ * 10000 \ diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index 459d57e155..463b07a7a5 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -556,14 +556,6 @@ public: virtual ~LLProcessorInfoDarwinImpl() {} - virtual F64 getCPUFrequency() const { return 0; } - virtual bool hasSSE() const { return false; } - virtual bool hasSSE2() const { return false; } - virtual bool hasAltivec() const { return false; } - virtual std::string getCPUFamilyName() const { return "Unknown"; } - virtual std::string getCPUBrandName() const { return "Unknown"; } - virtual std::string getCPUFeatureDescription() const { return "Unknown"; } - private: int getSysctlInt(const char* name) { @@ -678,2327 +670,186 @@ private: } }; -#endif // LL_MSVC - -////////////////////////////////////////////////////// -// 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 - #error "Unimplemented" -#endif // LL_MSVC - } -} - -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(); } - -#if 0 -// 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::cpu_infoToText 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 "processor.h" - -#include <memory> - -#if LL_WINDOWS -# define WIN32_LEAN_AND_MEAN -# include <winsock2.h> -# include <windows.h> -#endif - -#if !LL_DARWIN && !LL_SOLARIS - -#ifdef PROCESSOR_FREQUENCY_MEASURE_AVAILABLE -// We need the QueryPerformanceCounter and Sleep functions -#define FORCEINLINE __forceinline -#else -#define FORCEINLINE -#endif - - -// Some macros we often need -//////////////////////////// -#define CheckBit(var, bit) ((var & (1 << bit)) ? true : false) - -#ifdef PROCESSOR_FREQUENCY_MEASURE_AVAILABLE -// Delays for the specified amount of milliseconds -static void _Delay(unsigned int ms) -{ - LARGE_INTEGER freq, c1, c2; - __int64 x; - - // 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 - QueryPerformanceCounter(&c1); - do - { - // 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(&cpu_info, 0, sizeof(cpu_info)); -} +#elif LL_LINUX -// unsigned __int64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs) -// ========================================================================= -// Function to measure the current CPU frequency -//////////////////////////////////////////////////////////////////////////// -F64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs) +class LLProcessorInfoLinuxImpl : public LLProcessorInfoImpl { -#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 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 (!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 - // first processor in the multiprocessor system. - HANDLE hProcess = GetCurrentProcess(); - HANDLE hThread = GetCurrentThread(); - unsigned long dwCurPriorityClass = GetPriorityClass(hProcess); - int iCurThreadPriority = GetThreadPriority(hThread); - unsigned long dwProcessMask, dwSystemMask, dwNewMask = 1; - GetProcessAffinityMask(hProcess, &dwProcessMask, &dwSystemMask); - - SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS); - 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 - - // 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 - } - - // Now we wart for some msecs - _Delay(uiMeasureMSecs); -// 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 - } - - // Now we can restore the default process and thread priorities - SetProcessAffinityMask(hProcess, dwProcessMask); - SetThreadPriority(hThread, iCurThreadPriority); - SetPriorityClass(hProcess, dwCurPriorityClass); - - // Then we calculate the time and clock differences - dif = end - start; - timedif = endtime - starttime; - - // And finally the frequency is the clock difference divided by the time - // difference. - uqwFrequency = (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 -} - -// bool CProcessor::AnalyzeIntelProcessor() -// ======================================== -// Private class function for analyzing an Intel processor -////////////////////////////////////////////////////////// -bool CProcessor::AnalyzeIntelProcessor() -{ - // *NOTE:Mani - http://www.intel.com/Assets/PDF/appnote/241618.pdf - // According to the above doc, a lot of this what follows is wrong. -#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 - { - mov eax, 1 - cpuid - mov eaxreg, eax - mov ebxreg, ebx - mov edxreg, edx - } - - // Then get the cpu model, family, type, stepping and brand id by masking - // the eax and ebx register - cpu_info.uiStepping = eaxreg & 0xF; - cpu_info.uiModel = (eaxreg >> 4) & 0xF; - cpu_info.uiFamily = (eaxreg >> 8) & 0xF; - cpu_info.uiType = (eaxreg >> 12) & 0x3; - cpu_info.uiBrandID = ebxreg & 0xF; - - // *NOTE:Mani - see http://www.intel.com/assets/pdf/appnote/241618.pdf - // These values are composed according to section 2.1.2.2 of the above doc. - cpu_info.uiExtendedFamily = ((eaxreg >> 20) & 0xFF) + cpu_info.uiFamily; - cpu_info.uiExtendedModel = (((eaxreg >> 16) & 0xFF) << 4) + cpu_info.uiModel; - - // Getting the Brand ID string if supported. - if (cpu_info.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 - { - 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(cpu_info.strBrandID, tmp,sizeof(cpu_info.strBrandID)-1); - cpu_info.strBrandID[sizeof(cpu_info.strBrandID)-1]="\0"; - } - else +public: + LLProcessorInfoLinuxImpl() { - static const char* INTEL_BRAND[] = + std::map< std::string, std::string > cpuinfo; + LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb"); + if(cpuinfo_fp) { - /* 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 Getcpu_info(). JC - if ( cpu_info.uiBrandID < LL_ARRAY_SIZE(INTEL_BRAND) ) - { - strcpy(cpu_info.strBrandID, INTEL_BRAND[cpu_info.uiBrandID]); - - if (cpu_info.uiBrandID == 3 && cpu_info.uiModel == 6) + char line[MAX_STRING]; + memset(line, 0, MAX_STRING); + while(fgets(line, MAX_STRING, cpuinfo_fp)) { - strcpy(cpu_info.strBrandID, "0.18 micron Intel Pentium III Xeon"); + // /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); - // Then we translate the cpu family - switch (cpu_info.uiFamily) - { - case 3: // Family = 3: i386 (80386) processor family - strcpy(cpu_info.strFamily, "Intel i386"); /* Flawfinder: ignore */ - break; - case 4: // Family = 4: i486 (80486) processor family - strcpy(cpu_info.strFamily, "Intel i486"); /* Flawfinder: ignore */ - break; - case 5: // Family = 5: Pentium (80586) processor family - strcpy(cpu_info.strFamily, "Intel Pentium"); /* Flawfinder: ignore */ - break; - case 6: // Family = 6: Pentium Pro (80686) processor family - strcpy(cpu_info.strFamily, "Intel Pentium Pro/2/3, Core"); /* Flawfinder: ignore */ - break; - case 15: // Family = 15: Extended family specific - // Masking the extended family - cpu_info.uiExtendedFamily = (eaxreg >> 20) & 0xFF; - switch (cpu_info.uiExtendedFamily) - { - case 0: // Family = 15, Ext. Family = 0: Pentium 4 (80786 ??) processor family - strcpy(cpu_info.strFamily, "Intel Pentium 4"); /* Flawfinder: ignore */ - break; - case 1: // Family = 15, Ext. Family = 1: McKinley (64-bit) processor family - strcpy(cpu_info.strFamily, "Intel McKinley (IA-64)"); /* Flawfinder: ignore */ - break; - default: // Sure is sure - strcpy(cpu_info.strFamily, "Unknown Intel Pentium 4+"); /* Flawfinder: ignore */ - break; - } - break; - default: // Failsave - strcpy(cpu_info.strFamily, "Unknown"); /* Flawfinder: ignore */ - break; - } - - // Now we come to the big deal, the exact model name - switch (cpu_info.uiFamily) - { - case 3: // i386 (80386) processor family - strcpy(cpu_info.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 (cpu_info.uiModel) - { - case 0: // Model = 0: i486 DX-25/33 processor model - strcpy(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.strModel, "Intel i486 write-back enhanced DX4"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel i486 DX4", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - break; - default: // ... - strcpy(cpu_info.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 (cpu_info.uiModel) - { - case 0: // Model = 0: Pentium (P5 A-Step) processor model - strcpy(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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 (cpu_info.uiModel) - { - case 0: // Model = 0: Pentium Pro (P6 A-Step) processor model - strcpy(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.strModel, "Intel Pentium III/Celeron/Pentium III Xeon - internal L2 cache, 0.18 micron"); /*Flawfinder: ignore*/ - // We want to know it exactly: - switch (cpu_info.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(cpu_info.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(cpu_info.strModel, "Intel Pentium III/Celeron/Pentium III Xeon - internal L2 cache, 0.18 micron"); /*Flawfinder: ignore*/ - // Exact detection: - switch (cpu_info.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(cpu_info.strModel, "Intel Pentium III/Celeron/Pentium III Xeon - internal L2 cache, 0.13 micron"); /*Flawfinder: ignore*/ - // Omniscient: ;-) - switch (cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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 - cpu_info.uiExtendedModel = (eaxreg >> 16) & 0xFF; - switch (cpu_info.uiModel) - { - case 0: // Model = 0: Pentium 4 Willamette (A-Step) core - if ((cpu_info.uiBrandID) == 8) // Brand id = 8: P4 Willamette - { - strcpy(cpu_info.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(cpu_info.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 ((cpu_info.uiBrandID) == 8) // Brand id = 8: P4 Willamette - { - strcpy(cpu_info.strModel, "Intel Pentium 4 Willamette"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel Pentium 4 Willamette", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */ - } - else // else Xeon - { - strcpy(cpu_info.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 (((cpu_info.uiBrandID) == 9) || ((cpu_info.uiBrandID) == 0xA)) // P4 Willamette - { - strcpy(cpu_info.strModel, "Intel Pentium 4 Northwood"); /* Flawfinder: ignore */ - strncat(strCPUName, "Intel Pentium 4 Northwood", sizeof(strCPUName) - strlen(strCPUName) - 1); /* Flawfinder: ignore */ - } - else // Xeon - { - strcpy(cpu_info.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(cpu_info.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(cpu_info.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 (cpu_info.MaxSupportedLevel >= 3) - { - // If it supports the serial number CPUID level 0x00000003 we read the data - unsigned long sig1, sig2, sig3; - __asm + if( flags.find( " sse " ) != std::string::npos ) { - mov eax, 1 - cpuid - mov sig1, eax - mov eax, 3 - cpuid - mov sig2, ecx - mov sig3, edx + setExtension(eSSE_Ext); } - // Then we convert the data to a readable string - snprintf( /* Flawfinder: ignore */ - cpu_info.strProcessorSerial, - sizeof(cpu_info.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 */ - cpu_info.strProcessorSerial, - sizeof(cpu_info.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(); - // At last... - return true; -#else - return FALSE; -#endif -} - -// 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) - cpu_info.uiStepping = eaxreg & 0xF; - cpu_info.uiModel = (eaxreg >> 4) & 0xF; - cpu_info.uiFamily = (eaxreg >> 8) & 0xF; - cpu_info.uiType = (eaxreg >> 12) & 0x3; - - // Now we check if the processor supports the brand id string extended CPUID level - if (cpu_info.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 + if( flags.find( " sse2 " ) != std::string::npos ) { - 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 + setExtension(eSSE2_Ext); } - // And copy it to the brand id string - strncpy(cpu_info.strBrandID, tmp,sizeof(cpu_info.strBrandID)-1); - cpu_info.strBrandID[sizeof(cpu_info.strBrandID)-1]="\0"; - } - else - { - // Or just tell there is no brand id string support - strcpy(cpu_info.strBrandID, ""); /* Flawfinder: ignore */ - } - - // After that we translate the processor family - switch(cpu_info.uiFamily) - { - case 4: // Family = 4: 486 (80486) or 5x86 (80486) processor family - switch (cpu_info.uiModel) - { - case 3: // Thanks to AMD for this nice form of family - case 7: // detection.... *grmpf* - case 8: - case 9: - strcpy(cpu_info.strFamily, "AMD 80486"); /* Flawfinder: ignore */ - break; - case 0xE: - case 0xF: - strcpy(cpu_info.strFamily, "AMD 5x86"); /* Flawfinder: ignore */ - break; - default: - strcpy(cpu_info.strFamily, "Unknown family"); /* Flawfinder: ignore */ - break; - } - break; - case 5: // Family = 5: K5 or K6 processor family - switch (cpu_info.uiModel) - { - case 0: - case 1: - case 2: - case 3: - strcpy(cpu_info.strFamily, "AMD K5"); /* Flawfinder: ignore */ - break; - case 6: - case 7: - case 8: - case 9: - strcpy(cpu_info.strFamily, "AMD K6"); /* Flawfinder: ignore */ - break; - default: - strcpy(cpu_info.strFamily, "Unknown family"); /* Flawfinder: ignore */ - break; - } - break; - case 6: // Family = 6: K7 (Athlon, ...) processor family - strcpy(cpu_info.strFamily, "AMD K7"); /* Flawfinder: ignore */ - break; - default: // For security - strcpy(cpu_info.strFamily, "Unknown family"); /* Flawfinder: ignore */ - break; - } - - // After the family detection we come to the specific processor model - // detection - switch (cpu_info.uiFamily) - { - case 4: // Family = 4: 486 (80486) or 5x85 (80486) processor family - switch (cpu_info.uiModel) - { - case 3: // Model = 3: 80486 DX2 - strcpy(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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 (cpu_info.uiModel) - { - case 0: // Model = 0: K5 SSA 5 (Pentium Rating *ggg* 75, 90 and 100 Mhz) - strcpy(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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 (cpu_info.uiModel) - { - case 1: // Athlon - strcpy(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.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(cpu_info.strModel, "AMD Mobile Duron (Morgan)"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD Mobile Duron (Morgan core)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - default: // ... - strcpy(cpu_info.strModel, "Unknown AMD K7 model"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD K7 (Unknown model)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ - break; - } - break; - default: // ... - strcpy(cpu_info.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 (cpu_info.MaxSupportedExtendedLevel >= 0x80000001) - { - // If we can access the extended CPUID level 0x80000001 we get the - // edx register - __asm + + F64 mhz; + if (LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhz) + && 200.0 < mhz && mhz < 10000.0) { - mov eax, 0x80000001 - cpuid - mov edxreg, edx + setInfo(eFrequency,(F64)(mhz)); } - // Now we can mask some AMD specific cpu extensions - cpu_info._Ext.EMMX_MultimediaExtensions = CheckBit(edxreg, 22); - cpu_info._Ext.AA64_AMD64BitArchitecture = CheckBit(edxreg, 29); - cpu_info._Ext._E3DNOW_InstructionExtensions = CheckBit(edxreg, 30); - cpu_info._Ext._3DNOW_InstructionExtensions = CheckBit(edxreg, 31); + if (!cpuinfo["model name"].empty()) + mCPUString = cpuinfo["model name"]; +# endif // LL_X86 } - // After that we check if the processor supports the ext. CPUID level - // 0x80000006 - if (cpu_info.MaxSupportedExtendedLevel >= 0x80000006) - { - // 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 - } - - // Then we mask the L1 Data TLB information - if ((ebxreg >> 16) && (eaxreg >> 16)) - { - cpu_info._Data.bPresent = true; - strcpy(cpu_info._Data.strPageSize, "4 KB / 2 MB / 4MB"); /*Flawfinder: ignore*/ - cpu_info._Data.uiAssociativeWays = (eaxreg >> 24) & 0xFF; - cpu_info._Data.uiEntries = (eaxreg >> 16) & 0xFF; - } - else if (eaxreg >> 16) - { - cpu_info._Data.bPresent = true; - strcpy(cpu_info._Data.strPageSize, "2 MB / 4MB"); /*Flawfinder: ignore*/ - cpu_info._Data.uiAssociativeWays = (eaxreg >> 24) & 0xFF; - cpu_info._Data.uiEntries = (eaxreg >> 16) & 0xFF; - } - else if (ebxreg >> 16) - { - cpu_info._Data.bPresent = true; - strcpy(cpu_info._Data.strPageSize, "4 KB"); /*Flawfinder: ignore*/ - cpu_info._Data.uiAssociativeWays = (ebxreg >> 24) & 0xFF; - cpu_info._Data.uiEntries = (ebxreg >> 16) & 0xFF; - } - if (cpu_info._Data.uiAssociativeWays == 0xFF) - cpu_info._Data.uiAssociativeWays = (unsigned int) -1; - - // Now the L1 Instruction/Code TLB information - if ((ebxreg & 0xFFFF) && (eaxreg & 0xFFFF)) - { - cpu_info._Instruction.bPresent = true; - strcpy(cpu_info._Instruction.strPageSize, "4 KB / 2 MB / 4MB"); /*Flawfinder: ignore*/ - cpu_info._Instruction.uiAssociativeWays = (eaxreg >> 8) & 0xFF; - cpu_info._Instruction.uiEntries = eaxreg & 0xFF; - } - else if (eaxreg & 0xFFFF) - { - cpu_info._Instruction.bPresent = true; - strcpy(cpu_info._Instruction.strPageSize, "2 MB / 4MB"); /*Flawfinder: ignore*/ - cpu_info._Instruction.uiAssociativeWays = (eaxreg >> 8) & 0xFF; - cpu_info._Instruction.uiEntries = eaxreg & 0xFF; - } - else if (ebxreg & 0xFFFF) - { - cpu_info._Instruction.bPresent = true; - strcpy(cpu_info._Instruction.strPageSize, "4 KB"); /*Flawfinder: ignore*/ - cpu_info._Instruction.uiAssociativeWays = (ebxreg >> 8) & 0xFF; - cpu_info._Instruction.uiEntries = ebxreg & 0xFF; - } - if (cpu_info._Instruction.uiAssociativeWays == 0xFF) - cpu_info._Instruction.uiAssociativeWays = (unsigned int) -1; - - // Then we read the L1 data cache information - if ((ecxreg >> 24) > 0) - { - cpu_info._L1.Data.bPresent = true; - snprintf(cpu_info._L1.Data.strSize, sizeof(cpu_info._L1.Data.strSize), "%d KB", ecxreg >> 24); /* Flawfinder: ignore */ - cpu_info._L1.Data.uiAssociativeWays = (ecxreg >> 15) & 0xFF; - cpu_info._L1.Data.uiLineSize = ecxreg & 0xFF; - } - // After that we read the L2 instruction/code cache information - if ((edxreg >> 24) > 0) - { - cpu_info._L1.Instruction.bPresent = true; - snprintf(cpu_info._L1.Instruction.strSize, sizeof(cpu_info._L1.Instruction.strSize), "%d KB", edxreg >> 24); /* Flawfinder: ignore */ - cpu_info._L1.Instruction.uiAssociativeWays = (edxreg >> 15) & 0xFF; - cpu_info._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 - } + virtual ~LLProcessorInfoLinuxImpl() {} +private: - // 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) + void getCPUIDInfo() + { + std::map< std::string, std::string > cpuinfo; + LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb"); + if(cpuinfo_fp) { - cpu_info._L2.bPresent = true; - snprintf(cpu_info._L2.strSize, sizeof(cpu_info._L2.strSize), "%d KB", ecxreg >> 16); /* Flawfinder: ignore */ - switch ((ecxreg >> 12) & 0xF) + char line[MAX_STRING]; + memset(line, 0, MAX_STRING); + while(fgets(line, MAX_STRING, cpuinfo_fp)) { - case 1: - cpu_info._L2.uiAssociativeWays = 1; - break; - case 2: - cpu_info._L2.uiAssociativeWays = 2; - break; - case 4: - cpu_info._L2.uiAssociativeWays = 4; - break; - case 6: - cpu_info._L2.uiAssociativeWays = 8; - break; - case 8: - cpu_info._L2.uiAssociativeWays = 16; - break; - case 0xF: - cpu_info._L2.uiAssociativeWays = (unsigned int) -1; - break; - default: - cpu_info._L2.uiAssociativeWays = 0; - break; + // /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; } - cpu_info._L2.uiLineSize = ecxreg & 0xFF; + fclose(cpuinfo_fp); } - } - 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 - cpu_info.uiStepping = eaxreg & 0xF; - cpu_info.uiModel = (eaxreg >> 4) & 0xF; - cpu_info.uiFamily = (eaxreg >> 8) & 0xF; - cpu_info.uiType = (eaxreg >> 12) & 0x3; - - // To have complete information we also mask the brand id - cpu_info.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(cpu_info._Data.strTLB, "Unknown"); /*Flawfinder: ignore*/ - strcpy(cpu_info._Instruction.strTLB, "Unknown"); /*Flawfinder: ignore*/ - - strcpy(cpu_info._Trace.strCache, "Unknown"); /*Flawfinder: ignore*/ - strcpy(cpu_info._L1.Data.strCache, "Unknown"); /*Flawfinder: ignore*/ - strcpy(cpu_info._L1.Instruction.strCache, "Unknown"); /*Flawfinder: ignore*/ - strcpy(cpu_info._L2.strCache, "Unknown"); /*Flawfinder: ignore*/ - strcpy(cpu_info._L3.strCache, "Unknown"); /*Flawfinder: ignore*/ - - strcpy(cpu_info.strProcessorSerial, "Unknown / Not supported"); /*Flawfinder: ignore*/ +# if LL_X86 - // For the family, model and brand id we can only print the numeric value - snprintf(cpu_info.strBrandID, sizeof(cpu_info.strBrandID), "Brand-ID number %d", cpu_info.uiBrandID); /* Flawfinder: ignore */ - snprintf(cpu_info.strFamily, sizeof(cpu_info.strFamily), "Family number %d", cpu_info.uiFamily); /* Flawfinder: ignore */ - snprintf(cpu_info.strModel, sizeof(cpu_info.strModel), "Model number %d", cpu_info.uiModel); /* Flawfinder: ignore */ +// *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]);} - // 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 -} - -// 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 - cpu_info._Instruction.bPresent = true; - strcpy(cpu_info._Instruction.strPageSize, "4 KB"); /*Flawfinder: ignore*/ - cpu_info._Instruction.uiAssociativeWays = 4; - cpu_info._Instruction.uiEntries = 32; - break; - case 0x2: // cfg = 0x2: code TLB present, 4 MB pages, fully associative, 2 entries - cpu_info._Instruction.bPresent = true; - strcpy(cpu_info._Instruction.strPageSize, "4 MB"); /*Flawfinder: ignore*/ - cpu_info._Instruction.uiAssociativeWays = 4; - cpu_info._Instruction.uiEntries = 2; - break; - case 0x3: // cfg = 0x3: data TLB present, 4 KB pages, 4 ways, 64 entries - cpu_info._Data.bPresent = true; - strcpy(cpu_info._Data.strPageSize, "4 KB"); /*Flawfinder: ignore*/ - cpu_info._Data.uiAssociativeWays = 4; - cpu_info._Data.uiEntries = 64; - break; - case 0x4: // cfg = 0x4: data TLB present, 4 MB pages, 4 ways, 8 entries - cpu_info._Data.bPresent = true; - strcpy(cpu_info._Data.strPageSize, "4 MB"); /*Flawfinder: ignore*/ - cpu_info._Data.uiAssociativeWays = 4; - cpu_info._Data.uiEntries = 8; - break; - case 0x6: // cfg = 0x6: code L1 cache present, 8 KB, 4 ways, 32 byte lines - cpu_info._L1.Instruction.bPresent = true; - strcpy(cpu_info._L1.Instruction.strSize, "8 KB"); /*Flawfinder: ignore*/ - cpu_info._L1.Instruction.uiAssociativeWays = 4; - cpu_info._L1.Instruction.uiLineSize = 32; - break; - case 0x8: // cfg = 0x8: code L1 cache present, 16 KB, 4 ways, 32 byte lines - cpu_info._L1.Instruction.bPresent = true; - strcpy(cpu_info._L1.Instruction.strSize, "16 KB"); /*Flawfinder: ignore*/ - cpu_info._L1.Instruction.uiAssociativeWays = 4; - cpu_info._L1.Instruction.uiLineSize = 32; - break; - case 0xA: // cfg = 0xA: data L1 cache present, 8 KB, 2 ways, 32 byte lines - cpu_info._L1.Data.bPresent = true; - strcpy(cpu_info._L1.Data.strSize, "8 KB"); /*Flawfinder: ignore*/ - cpu_info._L1.Data.uiAssociativeWays = 2; - cpu_info._L1.Data.uiLineSize = 32; - break; - case 0xC: // cfg = 0xC: data L1 cache present, 16 KB, 4 ways, 32 byte lines - cpu_info._L1.Data.bPresent = true; - strcpy(cpu_info._L1.Data.strSize, "16 KB"); /*Flawfinder: ignore*/ - cpu_info._L1.Data.uiAssociativeWays = 4; - cpu_info._L1.Data.uiLineSize = 32; - break; - case 0x22: // cfg = 0x22: code and data L3 cache present, 512 KB, 4 ways, 64 byte lines, sectored - cpu_info._L3.bPresent = true; - strcpy(cpu_info._L3.strSize, "512 KB"); /*Flawfinder: ignore*/ - cpu_info._L3.uiAssociativeWays = 4; - cpu_info._L3.uiLineSize = 64; - cpu_info._L3.bSectored = true; - break; - case 0x23: // cfg = 0x23: code and data L3 cache present, 1024 KB, 8 ways, 64 byte lines, sectored - cpu_info._L3.bPresent = true; - strcpy(cpu_info._L3.strSize, "1024 KB"); /*Flawfinder: ignore*/ - cpu_info._L3.uiAssociativeWays = 8; - cpu_info._L3.uiLineSize = 64; - cpu_info._L3.bSectored = true; - break; - case 0x25: // cfg = 0x25: code and data L3 cache present, 2048 KB, 8 ways, 64 byte lines, sectored - cpu_info._L3.bPresent = true; - strcpy(cpu_info._L3.strSize, "2048 KB"); /*Flawfinder: ignore*/ - cpu_info._L3.uiAssociativeWays = 8; - cpu_info._L3.uiLineSize = 64; - cpu_info._L3.bSectored = true; - break; - case 0x29: // cfg = 0x29: code and data L3 cache present, 4096 KB, 8 ways, 64 byte lines, sectored - cpu_info._L3.bPresent = true; - strcpy(cpu_info._L3.strSize, "4096 KB"); /*Flawfinder: ignore*/ - cpu_info._L3.uiAssociativeWays = 8; - cpu_info._L3.uiLineSize = 64; - cpu_info._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 - cpu_info._L2.bPresent = true; - strcpy(cpu_info._L2.strSize, "128 KB"); /*Flawfinder: ignore*/ - cpu_info._L2.uiAssociativeWays = 4; - cpu_info._L2.uiLineSize = 32; - break; - case 0x42: // cfg = 0x42: code and data L2 cache present, 256 KB, 4 ways, 32 byte lines - cpu_info._L2.bPresent = true; - strcpy(cpu_info._L2.strSize, "256 KB"); /*Flawfinder: ignore*/ - cpu_info._L2.uiAssociativeWays = 4; - cpu_info._L2.uiLineSize = 32; - break; - case 0x43: // cfg = 0x43: code and data L2 cache present, 512 KB, 4 ways, 32 byte lines - cpu_info._L2.bPresent = true; - strcpy(cpu_info._L2.strSize, "512 KB"); /* Flawfinder: ignore */ - cpu_info._L2.uiAssociativeWays = 4; - cpu_info._L2.uiLineSize = 32; - break; - case 0x44: // cfg = 0x44: code and data L2 cache present, 1024 KB, 4 ways, 32 byte lines - cpu_info._L2.bPresent = true; - strcpy(cpu_info._L2.strSize, "1 MB"); /* Flawfinder: ignore */ - cpu_info._L2.uiAssociativeWays = 4; - cpu_info._L2.uiLineSize = 32; - break; - case 0x45: // cfg = 0x45: code and data L2 cache present, 2048 KB, 4 ways, 32 byte lines - cpu_info._L2.bPresent = true; - strcpy(cpu_info._L2.strSize, "2 MB"); /* Flawfinder: ignore */ - cpu_info._L2.uiAssociativeWays = 4; - cpu_info._L2.uiLineSize = 32; - break; - case 0x50: // cfg = 0x50: code TLB present, 4 KB / 4 MB / 2 MB pages, fully associative, 64 entries - cpu_info._Instruction.bPresent = true; - strcpy(cpu_info._Instruction.strPageSize, "4 KB / 2 MB / 4 MB"); /* Flawfinder: ignore */ - cpu_info._Instruction.uiAssociativeWays = (unsigned int) -1; - cpu_info._Instruction.uiEntries = 64; - break; - case 0x51: // cfg = 0x51: code TLB present, 4 KB / 4 MB / 2 MB pages, fully associative, 128 entries - cpu_info._Instruction.bPresent = true; - strcpy(cpu_info._Instruction.strPageSize, "4 KB / 2 MB / 4 MB"); /* Flawfinder: ignore */ - cpu_info._Instruction.uiAssociativeWays = (unsigned int) -1; - cpu_info._Instruction.uiEntries = 128; - break; - case 0x52: // cfg = 0x52: code TLB present, 4 KB / 4 MB / 2 MB pages, fully associative, 256 entries - cpu_info._Instruction.bPresent = true; - strcpy(cpu_info._Instruction.strPageSize, "4 KB / 2 MB / 4 MB"); /* Flawfinder: ignore */ - cpu_info._Instruction.uiAssociativeWays = (unsigned int) -1; - cpu_info._Instruction.uiEntries = 256; - break; - case 0x5B: // cfg = 0x5B: data TLB present, 4 KB / 4 MB pages, fully associative, 64 entries - cpu_info._Data.bPresent = true; - strcpy(cpu_info._Data.strPageSize, "4 KB / 4 MB"); /* Flawfinder: ignore */ - cpu_info._Data.uiAssociativeWays = (unsigned int) -1; - cpu_info._Data.uiEntries = 64; - break; - case 0x5C: // cfg = 0x5C: data TLB present, 4 KB / 4 MB pages, fully associative, 128 entries - cpu_info._Data.bPresent = true; - strcpy(cpu_info._Data.strPageSize, "4 KB / 4 MB"); /* Flawfinder: ignore */ - cpu_info._Data.uiAssociativeWays = (unsigned int) -1; - cpu_info._Data.uiEntries = 128; - break; - case 0x5d: // cfg = 0x5D: data TLB present, 4 KB / 4 MB pages, fully associative, 256 entries - cpu_info._Data.bPresent = true; - strcpy(cpu_info._Data.strPageSize, "4 KB / 4 MB"); /* Flawfinder: ignore */ - cpu_info._Data.uiAssociativeWays = (unsigned int) -1; - cpu_info._Data.uiEntries = 256; - break; - case 0x66: // cfg = 0x66: data L1 cache present, 8 KB, 4 ways, 64 byte lines, sectored - cpu_info._L1.Data.bPresent = true; - strcpy(cpu_info._L1.Data.strSize, "8 KB"); /* Flawfinder: ignore */ - cpu_info._L1.Data.uiAssociativeWays = 4; - cpu_info._L1.Data.uiLineSize = 64; - break; - case 0x67: // cfg = 0x67: data L1 cache present, 16 KB, 4 ways, 64 byte lines, sectored - cpu_info._L1.Data.bPresent = true; - strcpy(cpu_info._L1.Data.strSize, "16 KB"); /* Flawfinder: ignore */ - cpu_info._L1.Data.uiAssociativeWays = 4; - cpu_info._L1.Data.uiLineSize = 64; - break; - case 0x68: // cfg = 0x68: data L1 cache present, 32 KB, 4 ways, 64 byte lines, sectored - cpu_info._L1.Data.bPresent = true; - strcpy(cpu_info._L1.Data.strSize, "32 KB"); /* Flawfinder: ignore */ - cpu_info._L1.Data.uiAssociativeWays = 4; - cpu_info._L1.Data.uiLineSize = 64; - break; - case 0x70: // cfg = 0x70: trace L1 cache present, 12 KuOPs, 4 ways - cpu_info._Trace.bPresent = true; - strcpy(cpu_info._Trace.strSize, "12 K-micro-ops"); /* Flawfinder: ignore */ - cpu_info._Trace.uiAssociativeWays = 4; - break; - case 0x71: // cfg = 0x71: trace L1 cache present, 16 KuOPs, 4 ways - cpu_info._Trace.bPresent = true; - strcpy(cpu_info._Trace.strSize, "16 K-micro-ops"); /* Flawfinder: ignore */ - cpu_info._Trace.uiAssociativeWays = 4; - break; - case 0x72: // cfg = 0x72: trace L1 cache present, 32 KuOPs, 4 ways - cpu_info._Trace.bPresent = true; - strcpy(cpu_info._Trace.strSize, "32 K-micro-ops"); /* Flawfinder: ignore */ - cpu_info._Trace.uiAssociativeWays = 4; - break; - case 0x79: // cfg = 0x79: code and data L2 cache present, 128 KB, 8 ways, 64 byte lines, sectored - cpu_info._L2.bPresent = true; - strcpy(cpu_info._L2.strSize, "128 KB"); /* Flawfinder: ignore */ - cpu_info._L2.uiAssociativeWays = 8; - cpu_info._L2.uiLineSize = 64; - cpu_info._L2.bSectored = true; - break; - case 0x7A: // cfg = 0x7A: code and data L2 cache present, 256 KB, 8 ways, 64 byte lines, sectored - cpu_info._L2.bPresent = true; - strcpy(cpu_info._L2.strSize, "256 KB"); /* Flawfinder: ignore */ - cpu_info._L2.uiAssociativeWays = 8; - cpu_info._L2.uiLineSize = 64; - cpu_info._L2.bSectored = true; - break; - case 0x7B: // cfg = 0x7B: code and data L2 cache present, 512 KB, 8 ways, 64 byte lines, sectored - cpu_info._L2.bPresent = true; - strcpy(cpu_info._L2.strSize, "512 KB"); /* Flawfinder: ignore */ - cpu_info._L2.uiAssociativeWays = 8; - cpu_info._L2.uiLineSize = 64; - cpu_info._L2.bSectored = true; - break; - case 0x7C: // cfg = 0x7C: code and data L2 cache present, 1024 KB, 8 ways, 64 byte lines, sectored - cpu_info._L2.bPresent = true; - strcpy(cpu_info._L2.strSize, "1 MB"); /* Flawfinder: ignore */ - cpu_info._L2.uiAssociativeWays = 8; - cpu_info._L2.uiLineSize = 64; - cpu_info._L2.bSectored = true; - break; - case 0x81: // cfg = 0x81: code and data L2 cache present, 128 KB, 8 ways, 32 byte lines - cpu_info._L2.bPresent = true; - strcpy(cpu_info._L2.strSize, "128 KB"); /* Flawfinder: ignore */ - cpu_info._L2.uiAssociativeWays = 8; - cpu_info._L2.uiLineSize = 32; - break; - case 0x82: // cfg = 0x82: code and data L2 cache present, 256 KB, 8 ways, 32 byte lines - cpu_info._L2.bPresent = true; - strcpy(cpu_info._L2.strSize, "256 KB"); /* Flawfinder: ignore */ - cpu_info._L2.uiAssociativeWays = 8; - cpu_info._L2.uiLineSize = 32; - break; - case 0x83: // cfg = 0x83: code and data L2 cache present, 512 KB, 8 ways, 32 byte lines - cpu_info._L2.bPresent = true; - strcpy(cpu_info._L2.strSize, "512 KB"); /* Flawfinder: ignore */ - cpu_info._L2.uiAssociativeWays = 8; - cpu_info._L2.uiLineSize = 32; - break; - case 0x84: // cfg = 0x84: code and data L2 cache present, 1024 KB, 8 ways, 32 byte lines - cpu_info._L2.bPresent = true; - strcpy(cpu_info._L2.strSize, "1 MB"); /* Flawfinder: ignore */ - cpu_info._L2.uiAssociativeWays = 8; - cpu_info._L2.uiLineSize = 32; - break; - case 0x85: // cfg = 0x85: code and data L2 cache present, 2048 KB, 8 ways, 32 byte lines - cpu_info._L2.bPresent = true; - strcpy(cpu_info._L2.strSize, "2 MB"); /* Flawfinder: ignore */ - cpu_info._L2.uiAssociativeWays = 8; - cpu_info._L2.uiLineSize = 32; - break; - } -} - -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 */ - - // 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) -{ - 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 - { - // 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(&cpu_info._Data); - TranslateTLB(&cpu_info._Instruction); - - TranslateCache(&cpu_info._Trace); - - TranslateCache(&cpu_info._L1.Instruction); - TranslateCache(&cpu_info._L1.Data); - TranslateCache(&cpu_info._L2); - TranslateCache(&cpu_info._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; +#define LLPI_SET_INFO_INT(llpi_id, cpuinfo_id) \ + if (!cpuinfo[cpuinfo_id].empty()) { setInfo(llpi_id, LLStringUtil::convertToS32(cpuinfo[cpuinfo_id]));} - // We check if the CPUID function is available - if (!CheckCPUIDPresence()) - return; - - // First we check if the processor supports the standard - // CPUID level 0x00000002 - if (cpu_info.MaxSupportedLevel >= 2) - { - // Now we go read the std. CPUID level 0x00000002 the first time - unsigned long count, num = 255; - for (count = 0; count < num; count++) + F64 mhz; + if (LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhz) + && 200.0 < mhz && mhz < 10000.0) { - __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) - { - 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); - } + 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; - - // 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 - cpu_info._Ext.FPU_FloatingPointUnit = CheckBit(edxreg, 0); - cpu_info._Ext.VME_Virtual8086ModeEnhancements = CheckBit(edxreg, 1); - cpu_info._Ext.DE_DebuggingExtensions = CheckBit(edxreg, 2); - cpu_info._Ext.PSE_PageSizeExtensions = CheckBit(edxreg, 3); - cpu_info._Ext.TSC_TimeStampCounter = CheckBit(edxreg, 4); - cpu_info._Ext.MSR_ModelSpecificRegisters = CheckBit(edxreg, 5); - cpu_info._Ext.PAE_PhysicalAddressExtension = CheckBit(edxreg, 6); - cpu_info._Ext.MCE_MachineCheckException = CheckBit(edxreg, 7); - cpu_info._Ext.CX8_COMPXCHG8B_Instruction = CheckBit(edxreg, 8); - cpu_info._Ext.APIC_AdvancedProgrammableInterruptController = CheckBit(edxreg, 9); - cpu_info._Ext.APIC_ID = (ebxreg >> 24) & 0xFF; - cpu_info._Ext.SEP_FastSystemCall = CheckBit(edxreg, 11); - cpu_info._Ext.MTRR_MemoryTypeRangeRegisters = CheckBit(edxreg, 12); - cpu_info._Ext.PGE_PTE_GlobalFlag = CheckBit(edxreg, 13); - cpu_info._Ext.MCA_MachineCheckArchitecture = CheckBit(edxreg, 14); - cpu_info._Ext.CMOV_ConditionalMoveAndCompareInstructions = CheckBit(edxreg, 15); - cpu_info._Ext.FGPAT_PageAttributeTable = CheckBit(edxreg, 16); - cpu_info._Ext.PSE36_36bitPageSizeExtension = CheckBit(edxreg, 17); - cpu_info._Ext.PN_ProcessorSerialNumber = CheckBit(edxreg, 18); - cpu_info._Ext.CLFSH_CFLUSH_Instruction = CheckBit(edxreg, 19); - cpu_info._Ext.CLFLUSH_InstructionCacheLineSize = (ebxreg >> 8) & 0xFF; - cpu_info._Ext.DS_DebugStore = CheckBit(edxreg, 21); - cpu_info._Ext.ACPI_ThermalMonitorAndClockControl = CheckBit(edxreg, 22); - cpu_info._Ext.MMX_MultimediaExtensions = CheckBit(edxreg, 23); - cpu_info._Ext.FXSR_FastStreamingSIMD_ExtensionsSaveRestore = CheckBit(edxreg, 24); - cpu_info._Ext.SSE_StreamingSIMD_Extensions = CheckBit(edxreg, 25); - cpu_info._Ext.SSE2_StreamingSIMD2_Extensions = CheckBit(edxreg, 26); - cpu_info._Ext.Altivec_Extensions = false; - cpu_info._Ext.SS_SelfSnoop = CheckBit(edxreg, 27); - cpu_info._Ext.HT_HyperThreading = CheckBit(edxreg, 28); - cpu_info._Ext.HT_HyterThreadingSiblings = (ebxreg >> 16) & 0xFF; - cpu_info._Ext.TM_ThermalMonitor = CheckBit(edxreg, 29); - cpu_info._Ext.IA64_Intel64BitArchitecture = CheckBit(edxreg, 30); -#endif -} - -// const ProcessorInfo *CProcessor::Getcpu_info() -// ============================================= -// Calls all the other detection function to create an detailed -// processor information -/////////////////////////////////////////////////////////////// -const ProcessorInfo *CProcessor::Getcpu_info() -{ -#if LL_WINDOWS - unsigned long eaxreg, ebxreg, ecxreg, edxreg; - - // First of all we check if the CPUID command is available - if (!CheckCPUIDPresence()) - return NULL; - - // 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 *) cpu_info.strVendor) = ebxreg; - *((unsigned long *) (cpu_info.strVendor+4)) = edxreg; - *((unsigned long *) (cpu_info.strVendor+8)) = ecxreg; - // Null terminate for string comparisons below. - cpu_info.strVendor[12] = 0; - - // We can also read the max. supported standard CPUID level - cpu_info.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 - cpu_info.MaxSupportedExtendedLevel = eaxreg; - - // Then we switch to the specific processor vendors - // See http://www.sandpile.org/ia32/cpuid.htm - if (!strcmp(cpu_info.strVendor, "GenuineIntel")) - { - AnalyzeIntelProcessor(); - } - else if (!strcmp(cpu_info.strVendor, "AuthenticAMD")) - { - AnalyzeAMDProcessor(); - } - else if (!strcmp(cpu_info.strVendor, "UMC UMC UMC")) - { - AnalyzeUnknownProcessor(); - } - else if (!strcmp(cpu_info.strVendor, "CyrixInstead")) - { - AnalyzeUnknownProcessor(); - } - else if (!strcmp(cpu_info.strVendor, "NexGenDriven")) - { - AnalyzeUnknownProcessor(); - } - else if (!strcmp(cpu_info.strVendor, "CentaurHauls")) - { - AnalyzeUnknownProcessor(); - } - else if (!strcmp(cpu_info.strVendor, "RiseRiseRise")) - { - AnalyzeUnknownProcessor(); - } - else if (!strcmp(cpu_info.strVendor, "SiS SiS SiS")) - { - AnalyzeUnknownProcessor(); - } - else if (!strcmp(cpu_info.strVendor, "GenuineTMx86")) - { - // Transmeta - AnalyzeUnknownProcessor(); - } - else if (!strcmp(cpu_info.strVendor, "Geode by NSC")) - { - AnalyzeUnknownProcessor(); - } - else - { - AnalyzeUnknownProcessor(); - } -#endif - // After all we return the class cpu_info member var - return (&cpu_info); -} -#elif LL_SOLARIS -#include <kstat.h> + LLPI_SET_INFO_STRING(eBrandName, "model name"); + LLPI_SET_INFO_STRING(eVendor, "vendor_id"); -#if defined(__i386) -#include <sys/auxv.h> -#endif - -// ====================== -// Class constructor: -///////////////////////// -CProcessor::CProcessor() -{ - uqwFrequency = 0; - strCPUName[0] = 0; - memset(&cpu_info, 0, sizeof(cpu_info)); -} - -// unsigned __int64 CProcessor::GetCPUFrequency(unsigned int uiMeasureMSecs) -// ========================================================================= -// Function to query the current CPU frequency -//////////////////////////////////////////////////////////////////////////// -F64 CProcessor::GetCPUFrequency(unsigned int /*uiMeasureMSecs*/) -{ - if(uqwFrequency == 0){ - Getcpu_info(); - } - - return uqwFrequency; -} - -// const ProcessorInfo *CProcessor::Getcpu_info() -// ============================================= -// Calls all the other detection function to create an detailed -// processor information -/////////////////////////////////////////////////////////////// -const ProcessorInfo *CProcessor::Getcpu_info() -{ - // 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 (&cpu_info); - } - - 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 (&cpu_info); - } - - 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; - } - } + LLPI_SET_INFO_INT(eStepping, "stepping"); + LLPI_SET_INFO_INT(eModel, "model"); + int family = LLStringUtil::convertTos32getSysctlInt("machdep.cpu.family"); + int ext_family = getSysctlInt("machdep.cpu.extfamily"); + LLPI_SET_INFO_INT(eFamily, "cpu family"); + //LLPI_SET_INFO_INT(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? - 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(cpu_info.strFamily, (char *)KSTAT_NAMED_STR_PTR(ksi), - sizeof(cpu_info.strFamily)-strlen(cpu_info.strFamily)-1); - strncpy(cpu_info.strBrandID, strCPUName,sizeof(cpu_info.strBrandID)-1); - cpu_info.strBrandID[sizeof(cpu_info.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(eSSE_Ext); } -#if defined(__i386) - if(!strcmp(ksi->name, "vendor_id")){ - strncpy(cpu_info.strVendor, (char *)KSTAT_NAMED_STR_PTR(ksi), sizeof(cpu_info.strVendor)-1); - // DEBUG llinfos << "CPU vendor: " << cpu_info.strVendor << llendl; - continue; + if( flags.find( " sse2 " ) != std::string::npos ) + { + setExtension(eSSE2_Ext); } -#endif - } - - kstat_close(kc); - -#if defined(__sparc) // SPARC does not define a vendor string in kstat - strncpy(cpu_info.strVendor, "Sun Microsystems, Inc.", sizeof(cpu_info.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) - cpu_info._Ext.FPU_FloatingPointUnit = true; - if(ui & AV_386_CX8) - cpu_info._Ext.CX8_COMPXCHG8B_Instruction = true; - if(ui & AV_386_MMX) - cpu_info._Ext.MMX_MultimediaExtensions = true; - if(ui & AV_386_AMD_MMX) - cpu_info._Ext.MMX_MultimediaExtensions = true; - if(ui & AV_386_FXSR) - cpu_info._Ext.FXSR_FastStreamingSIMD_ExtensionsSaveRestore = true; - if(ui & AV_386_SSE) - cpu_info._Ext.SSE_StreamingSIMD_Extensions = true; - if(ui & AV_386_SSE2) - cpu_info._Ext.SSE2_StreamingSIMD2_Extensions = true; -/* Left these here since they may get used later - if(ui & AV_386_SSE3) - cpu_info._Ext.... = true; - if(ui & AV_386_AMD_3DNow) - cpu_info._Ext.... = true; - if(ui & AV_386_AMD_3DNowx) - cpu_info._Ext.... = true; -*/ -#endif - return (&cpu_info); -} - -#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) - { - // 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(&cpu_info._Data); - TranslateTLB(&cpu_info._Instruction); - - TranslateCache(&cpu_info._Trace); - - TranslateCache(&cpu_info._L1.Instruction); - TranslateCache(&cpu_info._L1.Data); - TranslateCache(&cpu_info._L2); - TranslateCache(&cpu_info._L3); -} - -// CProcessor::CProcessor -// ====================== -// Class constructor: -///////////////////////// -CProcessor::CProcessor() -{ - uqwFrequency = 0; - strCPUName[0] = 0; - memset(&cpu_info, 0, sizeof(cpu_info)); -} +}; -// 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; -} +#endif // LL_MSVC elif LL_DARWIN elif LL_LINUX -// const ProcessorInfo *CProcessor::Getcpu_info() -// ============================================= -// Calls all the other detection function to create an detailed -// processor information -/////////////////////////////////////////////////////////////// -const ProcessorInfo *CProcessor::Getcpu_info() +////////////////////////////////////////////////////// +// Interface definition +LLProcessorInfo::LLProcessorInfo() : mImpl(NULL) { - 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(cpu_info.strFamily, "PowerPC", sizeof(cpu_info.strFamily)-strlen(cpu_info.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(cpu_info.strFamily, "PowerPC", sizeof(cpu_info.strFamily)-strlen(cpu_info.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(cpu_info.strFamily, "PowerPC", sizeof(cpu_info.strFamily)-strlen(cpu_info.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(cpu_info.strFamily, "PowerPC", sizeof(cpu_info.strFamily)-strlen(cpu_info.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(cpu_info.strFamily, "PowerPC", sizeof(cpu_info.strFamily)-strlen(cpu_info.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(cpu_info.strFamily, "PowerPC", sizeof(cpu_info.strFamily)-strlen(cpu_info.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(cpu_info.strFamily, "PowerPC", sizeof(cpu_info.strFamily)-strlen(cpu_info.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(cpu_info.strFamily, "PowerPC", sizeof(cpu_info.strFamily)-strlen(cpu_info.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(cpu_info.strFamily, "PowerPC G3", sizeof(cpu_info.strFamily)-strlen(cpu_info.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(cpu_info.strFamily, "PowerPC G4", sizeof(cpu_info.strFamily)-strlen(cpu_info.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(cpu_info.strFamily, "PowerPC G4", sizeof(cpu_info.strFamily)-strlen(cpu_info.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(cpu_info.strFamily, "PowerPC G5", sizeof(cpu_info.strFamily)-strlen(cpu_info.strFamily)-1); /* Flawfinder: ignore */ - break; - - default: - strncat(strCPUName, "PowerPC (Unknown)", sizeof(strCPUName)-strlen(strCPUName)-1); /* Flawfinder: ignore */ - break; - } - - cpu_info._Ext.EMMX_MultimediaExtensions = - cpu_info._Ext.MMX_MultimediaExtensions = - cpu_info._Ext.SSE_StreamingSIMD_Extensions = - cpu_info._Ext.SSE2_StreamingSIMD2_Extensions = false; - - cpu_info._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; - } - - cpu_info._Ext.EMMX_MultimediaExtensions = hasFeature("hw.optional.mmx"); // MBW -- XXX -- this may be wrong... - cpu_info._Ext.MMX_MultimediaExtensions = hasFeature("hw.optional.mmx"); - cpu_info._Ext.SSE_StreamingSIMD_Extensions = hasFeature("hw.optional.sse"); - cpu_info._Ext.SSE2_StreamingSIMD2_Extensions = hasFeature("hw.optional.sse2"); - cpu_info._Ext.Altivec_Extensions = false; - cpu_info._Ext.AA64_AMD64BitArchitecture = hasFeature("hw.optional.x86_64"); - -#endif - - // Terse CPU info uses this string... - strncpy(cpu_info.strBrandID, strCPUName,sizeof(cpu_info.strBrandID)-1); /* Flawfinder: ignore */ - cpu_info.strBrandID[sizeof(cpu_info.strBrandID)-1]="\0"; - - // Fun cache config stuff... - - if(l1dcachesize != 0) - { - cpu_info._L1.Data.bPresent = true; - snprintf(cpu_info._L1.Data.strSize, sizeof(cpu_info._L1.Data.strSize), "%d KB", l1dcachesize / 1024); /* Flawfinder: ignore */ -// cpu_info._L1.Data.uiAssociativeWays = ???; - cpu_info._L1.Data.uiLineSize = cachelinesize; - } - - if(l1icachesize != 0) - { - cpu_info._L1.Instruction.bPresent = true; - snprintf(cpu_info._L1.Instruction.strSize, sizeof(cpu_info._L1.Instruction.strSize), "%d KB", l1icachesize / 1024); /* Flawfinder: ignore */ -// cpu_info._L1.Instruction.uiAssociativeWays = ???; - cpu_info._L1.Instruction.uiLineSize = cachelinesize; - } - - if(l2cachesize != 0) - { - cpu_info._L2.bPresent = true; - snprintf(cpu_info._L2.strSize, sizeof(cpu_info._L2.strSize), "%d KB", l2cachesize / 1024); /* Flawfinder: ignore */ -// cpu_info._L2.uiAssociativeWays = ???; - cpu_info._L2.uiLineSize = cachelinesize; - } - - if(l3cachesize != 0) + // *NOTE:Mani - not thread safe. + if(!mImpl) { - cpu_info._L2.bPresent = true; - snprintf(cpu_info._L2.strSize, sizeof(cpu_info._L2.strSize), "%d KB", l3cachesize / 1024); /* Flawfinder: ignore */ -// cpu_info._L2.uiAssociativeWays = ???; - cpu_info._L2.uiLineSize = cachelinesize; +#ifdef LL_MSVC + static LLProcessorInfoWindowsImpl the_impl; + mImpl = &the_impl; +#elif LL_DARWIN + static LLProcessorInfoDarwinImpl the_impl; + mImpl = &the_impl; +#else + #error "Unimplemented" +#endif // LL_MSVC } - - cpu_info._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 cpu_info member var - return (&cpu_info); } -#endif // LL_DARWIN - -// bool CProcessor::cpu_infoToText(char *strBuffer, unsigned int uiMaxLen) -// ====================================================================== -// Gets the frequency and processor information and writes it to a string -///////////////////////////////////////////////////////////////////////// -bool CProcessor::cpu_infoToText(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 - Getcpu_info(); - - // 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", cpu_info.strVendor); - FORMATADD("Family: %s\n", cpu_info.strFamily); - FORMATADD("Extended family: %d\n", cpu_info.uiExtendedFamily); - FORMATADD("Model: %s\n", cpu_info.strModel); - FORMATADD("Extended model: %d\n", cpu_info.uiExtendedModel); - FORMATADD("Type: %s\n", cpu_info.strType); - FORMATADD("Brand ID: %s\n", cpu_info.strBrandID); - if (cpu_info._Ext.PN_ProcessorSerialNumber) - { - FORMATADD("Processor Serial: %s\n", cpu_info.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", cpu_info._L1.Instruction.strCache); - FORMATADD("L1 data cache: %s\n", cpu_info._L1.Data.strCache); - FORMATADD("L2 cache: %s\n", cpu_info._L2.strCache); - FORMATADD("L3 cache: %s\n", cpu_info._L3.strCache); - FORMATADD("Trace cache: %s\n", cpu_info._Trace.strCache); - FORMATADD("Instruction TLB: %s\n", cpu_info._Instruction.strTLB); - FORMATADD("Data TLB: %s\n", cpu_info._Data.strTLB); - FORMATADD("Max Supported CPUID-Level: 0x%08lX\n", cpu_info.MaxSupportedLevel); - FORMATADD("Max Supported Ext. CPUID-Level: 0x%08lX\n", cpu_info.MaxSupportedExtendedLevel); - - COPYADD("\n\n// CPU Extensions\n/////////////////\n"); - BOOLADD("AA64 AMD 64-bit Architecture: ", cpu_info._Ext.AA64_AMD64BitArchitecture); - BOOLADD("ACPI Thermal Monitor And Clock Control: ", cpu_info._Ext.ACPI_ThermalMonitorAndClockControl); - BOOLADD("APIC Advanced Programmable Interrupt Controller: ", cpu_info._Ext.APIC_AdvancedProgrammableInterruptController); - FORMATADD(" APIC-ID: %d\n", cpu_info._Ext.APIC_ID); - BOOLADD("CLFSH CLFLUSH Instruction Presence: ", cpu_info._Ext.CLFSH_CFLUSH_Instruction); - FORMATADD(" CLFLUSH Instruction Cache Line Size: %d\n", cpu_info._Ext.CLFLUSH_InstructionCacheLineSize); - BOOLADD("CMOV Conditional Move And Compare Instructions: ", cpu_info._Ext.CMOV_ConditionalMoveAndCompareInstructions); - BOOLADD("CX8 COMPXCHG8B Instruction: ", cpu_info._Ext.CX8_COMPXCHG8B_Instruction); - BOOLADD("DE Debugging Extensions: ", cpu_info._Ext.DE_DebuggingExtensions); - BOOLADD("DS Debug Store: ", cpu_info._Ext.DS_DebugStore); - BOOLADD("FGPAT Page Attribute Table: ", cpu_info._Ext.FGPAT_PageAttributeTable); - BOOLADD("FPU Floating Point Unit: ", cpu_info._Ext.FPU_FloatingPointUnit); - BOOLADD("FXSR Fast Streaming SIMD Extensions Save/Restore:", cpu_info._Ext.FXSR_FastStreamingSIMD_ExtensionsSaveRestore); - BOOLADD("HT Hyper Threading: ", cpu_info._Ext.HT_HyperThreading); - BOOLADD("IA64 Intel 64-Bit Architecture: ", cpu_info._Ext.IA64_Intel64BitArchitecture); - BOOLADD("MCA Machine Check Architecture: ", cpu_info._Ext.MCA_MachineCheckArchitecture); - BOOLADD("MCE Machine Check Exception: ", cpu_info._Ext.MCE_MachineCheckException); - BOOLADD("MMX Multimedia Extensions: ", cpu_info._Ext.MMX_MultimediaExtensions); - BOOLADD("MMX+ Multimedia Extensions: ", cpu_info._Ext.EMMX_MultimediaExtensions); - BOOLADD("MSR Model Specific Registers: ", cpu_info._Ext.MSR_ModelSpecificRegisters); - BOOLADD("MTRR Memory Type Range Registers: ", cpu_info._Ext.MTRR_MemoryTypeRangeRegisters); - BOOLADD("PAE Physical Address Extension: ", cpu_info._Ext.PAE_PhysicalAddressExtension); - BOOLADD("PGE PTE Global Flag: ", cpu_info._Ext.PGE_PTE_GlobalFlag); - if (cpu_info._Ext.PN_ProcessorSerialNumber) - { - FORMATADD("PN Processor Serial Number: %s\n", cpu_info.strProcessorSerial); - } - else - { - COPYADD("PN Processor Serial Number: Disabled\n"); - } - BOOLADD("PSE Page Size Extensions: ", cpu_info._Ext.PSE_PageSizeExtensions); - BOOLADD("PSE36 36-bit Page Size Extension: ", cpu_info._Ext.PSE36_36bitPageSizeExtension); - BOOLADD("SEP Fast System Call: ", cpu_info._Ext.SEP_FastSystemCall); - BOOLADD("SS Self Snoop: ", cpu_info._Ext.SS_SelfSnoop); - BOOLADD("SSE Streaming SIMD Extensions: ", cpu_info._Ext.SSE_StreamingSIMD_Extensions); - BOOLADD("SSE2 Streaming SIMD 2 Extensions: ", cpu_info._Ext.SSE2_StreamingSIMD2_Extensions); - BOOLADD("ALTVEC Altivec Extensions: ", cpu_info._Ext.Altivec_Extensions); - BOOLADD("TM Thermal Monitor: ", cpu_info._Ext.TM_ThermalMonitor); - BOOLADD("TSC Time Stamp Counter: ", cpu_info._Ext.TSC_TimeStampCounter); - BOOLADD("VME Virtual 8086 Mode Enhancements: ", cpu_info._Ext.VME_Virtual8086ModeEnhancements); - BOOLADD("3DNow! Instructions: ", cpu_info._Ext._3DNOW_InstructionExtensions); - BOOLADD("Enhanced 3DNow! Instructions: ", cpu_info._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::cpu_infoToText 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 (!cpu_infoToText(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; -} -#endif diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index 06ceeb2bc3..809a626c93 100644 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -133,8 +133,11 @@ S32 LLQueuedThread::updateQueue(U32 max_time_ms) if (mThreaded) { pending = getPending(); + if(pending > 0) + { unpause(); } + } else { while (pending > 0) @@ -459,7 +462,7 @@ S32 LLQueuedThread::processNextRequest() req->setStatus(STATUS_QUEUED); mRequestQueue.insert(req); unlockData(); - if (mThreaded && start_priority <= PRIORITY_LOW) + if (mThreaded && start_priority < PRIORITY_NORMAL) { ms_sleep(1); // sleep the thread a little } diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp index 33b6875fb0..c90b52f482 100644 --- a/indra/llcommon/llrefcount.cpp +++ b/indra/llcommon/llrefcount.cpp @@ -35,6 +35,17 @@ #include "llerror.h" +LLRefCount::LLRefCount(const LLRefCount& other) +: mRef(0) +{ +} + +LLRefCount& LLRefCount::operator=(const LLRefCount&) +{ + // do nothing, since ref count is specific to *this* reference + return *this; +} + LLRefCount::LLRefCount() : mRef(0) { diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h index 9ab844eb22..a18f6706a9 100644 --- a/indra/llcommon/llrefcount.h +++ b/indra/llcommon/llrefcount.h @@ -41,22 +41,20 @@ class LL_COMMON_API LLRefCount { -private: - LLRefCount(const LLRefCount& other); // no implementation -private: - LLRefCount& operator=(const LLRefCount&); // no implementation protected: + LLRefCount(const LLRefCount& other); + LLRefCount& operator=(const LLRefCount&); virtual ~LLRefCount(); // use unref() public: LLRefCount(); - void ref() + void ref() const { mRef++; } - S32 unref() + S32 unref() const { llassert(mRef >= 1); if (0 == --mRef) @@ -67,13 +65,15 @@ public: return mRef; } + //NOTE: when passing around a const LLRefCount object, this can return different results + // at different types, since mRef is mutable S32 getNumRefs() const { return mRef; } private: - S32 mRef; + mutable S32 mRef; }; #endif diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index 7e1c2e35e0..fca173df47 100644 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -139,12 +139,8 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti case LLSD::TypeBoolean: ostr << pre << "<boolean>"; if(mBoolAlpha || -#if( LL_WINDOWS || __GNUC__ > 2) (ostr.flags() & std::ios::boolalpha) -#else - (ostr.flags() & 0x0100) -#endif - ) + ) { ostr << (data.asBoolean() ? "true" : "false"); } @@ -511,12 +507,7 @@ void LLSDXMLParser::Impl::reset() mSkipping = false; -#if( LL_WINDOWS || __GNUC__ > 2) mCurrentKey.clear(); -#else - mCurrentKey = std::string(); -#endif - XML_ParserReset(mParser, "utf-8"); XML_SetUserData(mParser, this); @@ -644,11 +635,7 @@ void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Ch LLSD& newElement = map[mCurrentKey]; mStack.push_back(&newElement); -#if( LL_WINDOWS || __GNUC__ > 2) mCurrentKey.clear(); -#else - mCurrentKey = std::string(); -#endif } else if (mStack.back()->isArray()) { diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 5f3d9d6582..b5a73ec1d1 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -911,6 +911,20 @@ bool LLStringUtil::simpleReplacement(std::string &replacement, std::string token return false; } +//static +template<> +void LLStringUtil::setLocale(std::string inLocale) +{ + sLocale = inLocale; +}; + +//static +template<> +std::string LLStringUtil::getLocale(void) +{ + return sLocale; +}; + // static template<> void LLStringUtil::formatNumber(std::string& numStr, std::string decimals) diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 31e70e0fe4..96588b29b9 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -241,8 +241,8 @@ public: LL_COMMON_API static S32 format(std::basic_string<T>& s, const LLSD& substitutions); LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const format_map_t& substitutions); LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const LLSD& substitutions); - static void setLocale (std::string inLocale) {sLocale = inLocale;}; - static std::string getLocale (void) {return sLocale;}; + LL_COMMON_API static void setLocale (std::string inLocale); + LL_COMMON_API static std::string getLocale (void); static bool isValidIndex(const std::basic_string<T>& string, size_type i) { @@ -882,6 +882,7 @@ void LLStringUtilBase<T>::addCRLF(std::basic_string<T>& string) } string.assign(t, size); + delete[] t; } } diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index fc3ce52aa8..d38fc1b013 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -518,15 +518,15 @@ LLCPUInfo::LLCPUInfo() mHasSSE = proc.hasSSE(); mHasSSE2 = proc.hasSSE2(); mHasAltivec = proc.hasAltivec(); - mCPUMhz = (S32)(proc.getCPUFrequency()/1000000.0); + mCPUMhz = (F64)(proc.getCPUFrequency()/1000000.0); mFamily = proc.getCPUFamilyName(); mCPUString = "Unknown"; #if LL_WINDOWS || LL_DARWIN || LL_SOLARIS out << proc.getCPUBrandName(); - if (200 < mCPUMhz && mCPUMhz < 10000) // *NOTE: cpu speed is often way wrong, do a sanity check + if (200 < mCPUMHz && mCPUMHz < 10000) // *NOTE: cpu speed is often way wrong, do a sanity check { - out << " (" << mCPUMhz << " MHz)"; + out << " (" << mCPUMHz << " MHz)"; } mCPUString = out.str(); @@ -571,7 +571,7 @@ LLCPUInfo::LLCPUInfo() if (LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhz) && 200.0 < mhz && mhz < 10000.0) { - mCPUMhz = (S32)llrint(mhz); + mCPUMHz = (F64)(mhz); } if (!cpuinfo["model name"].empty()) mCPUString = cpuinfo["model name"]; @@ -594,9 +594,9 @@ bool LLCPUInfo::hasSSE2() const return mHasSSE2; } -S32 LLCPUInfo::getMhz() const +F64 LLCPUInfo::getMHz() const { - return mCPUMhz; + return mCPUMHz; } std::string LLCPUInfo::getCPUString() const @@ -634,7 +634,7 @@ void LLCPUInfo::stream(std::ostream& s) const s << "->mHasSSE: " << (U32)mHasSSE << std::endl; s << "->mHasSSE2: " << (U32)mHasSSE2 << std::endl; s << "->mHasAltivec: " << (U32)mHasAltivec << std::endl; - s << "->mCPUMhz: " << mCPUMhz << std::endl; + s << "->mCPUMHz: " << mCPUMHz << std::endl; s << "->mCPUString: " << mCPUString << std::endl; } diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h index c2c45bec9a..0b34951149 100644 --- a/indra/llcommon/llsys.h +++ b/indra/llcommon/llsys.h @@ -81,7 +81,7 @@ public: bool hasAltivec() const; bool hasSSE() const; bool hasSSE2() const; - S32 getMhz() const; + F64 getMHz() const; // Family is "AMD Duron" or "Intel Pentium Pro" const std::string& getFamily() const { return mFamily; } @@ -90,7 +90,7 @@ private: bool mHasSSE; bool mHasSSE2; bool mHasAltivec; - S32 mCPUMhz; + F64 mCPUMHz; std::string mFamily; std::string mCPUString; }; diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index ef3e8dbc94..6111db2bfa 100644 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -209,7 +209,7 @@ F64 calc_clock_frequency(U32 uiMeasureMSecs) // Both Linux and Mac use gettimeofday for accurate time F64 calc_clock_frequency(unsigned int uiMeasureMSecs) { - return 1000000.0; // microseconds, so 1 Mhz. + return 1000000.0; // microseconds, so 1 MHz. } U64 get_clock_count() @@ -555,54 +555,3 @@ void secondsToTimecodeString(F32 current_time, std::string& tcstring) } -////////////////////////////////////////////////////////////////////////////// -// -// LLEventTimer Implementation -// -////////////////////////////////////////////////////////////////////////////// - -LLEventTimer::LLEventTimer(F32 period) -: mEventTimer() -{ - mPeriod = period; -} - -LLEventTimer::LLEventTimer(const LLDate& time) -: mEventTimer() -{ - mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch()); -} - - -LLEventTimer::~LLEventTimer() -{ -} - -void LLEventTimer::updateClass() -{ - std::list<LLEventTimer*> completed_timers; - for (instance_iter iter = beginInstances(); iter != endInstances(); ) - { - LLEventTimer& timer = *iter++; - F32 et = timer.mEventTimer.getElapsedTimeF32(); - if (timer.mEventTimer.getStarted() && et > timer.mPeriod) { - timer.mEventTimer.reset(); - if ( timer.tick() ) - { - completed_timers.push_back( &timer ); - } - } - } - - if ( completed_timers.size() > 0 ) - { - for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin(); - completed_iter != completed_timers.end(); - completed_iter++ ) - { - delete *completed_iter; - } - } -} - - diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h index d009c0f5f7..baba95bfa1 100644 --- a/indra/llcommon/lltimer.h +++ b/indra/llcommon/lltimer.h @@ -39,8 +39,6 @@ #include <limits.h> #include "stdtypes.h" -#include "lldate.h" -#include "llinstancetracker.h" #include <string> #include <list> @@ -171,25 +169,6 @@ LL_COMMON_API struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_dayli LL_COMMON_API void microsecondsToTimecodeString(U64 current_time, std::string& tcstring); LL_COMMON_API void secondsToTimecodeString(F32 current_time, std::string& tcstring); -// class for scheduling a function to be called at a given frequency (approximate, inprecise) -class LL_COMMON_API LLEventTimer : protected LLInstanceTracker<LLEventTimer> -{ -public: - LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds - LLEventTimer(const LLDate& time); - virtual ~LLEventTimer(); - - //function to be called at the supplied frequency - // Normally return FALSE; TRUE will delete the timer after the function returns. - virtual BOOL tick() = 0; - - static void updateClass(); - -protected: - LLTimer mEventTimer; - F32 mPeriod; -}; - U64 LL_COMMON_API totalTime(); // Returns current system time in microseconds #endif diff --git a/indra/llcommon/lltreeiterators.h b/indra/llcommon/lltreeiterators.h index c946566e84..cb1304c54e 100644 --- a/indra/llcommon/lltreeiterators.h +++ b/indra/llcommon/lltreeiterators.h @@ -343,20 +343,20 @@ public: /// Instantiate an LLTreeDFSIter to start a depth-first walk. Pass /// functors to extract the 'child begin' and 'child end' iterators from /// each node. - LLTreeDFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc): - mBeginFunc(beginfunc), - mEndFunc(endfunc), - mSkipChildren(false) + LLTreeDFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc) + : mBeginFunc(beginfunc), + mEndFunc(endfunc), + mSkipChildren(false) { // Only push back this node if it's non-NULL! if (node) mPending.push_back(node); } /// Instantiate an LLTreeDFSIter to mark the end of the walk - LLTreeDFSIter() {} + LLTreeDFSIter() : mSkipChildren(false) {} - /// flags iterator logic to skip traversing children of current node on next increment - void skipDescendants(bool skip = true) { mSkipChildren = skip; } + /// flags iterator logic to skip traversing children of current node on next increment + void skipDescendants(bool skip = true) { mSkipChildren = skip; } private: /// leverage boost::iterator_facade @@ -405,8 +405,8 @@ private: func_type mBeginFunc; /// functor to extract end() child iterator func_type mEndFunc; - /// flag which controls traversal of children (skip children of current node if true) - bool mSkipChildren; + /// flag which controls traversal of children (skip children of current node if true) + bool mSkipChildren; }; /** @@ -451,21 +451,21 @@ public: /// Instantiate an LLTreeDFSPostIter to start a depth-first walk. Pass /// functors to extract the 'child begin' and 'child end' iterators from /// each node. - LLTreeDFSPostIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc): - mBeginFunc(beginfunc), - mEndFunc(endfunc), - mSkipAncestors(false) - { + LLTreeDFSPostIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc) + : mBeginFunc(beginfunc), + mEndFunc(endfunc), + mSkipAncestors(false) + { if (! node) return; mPending.push_back(typename list_type::value_type(node, false)); makeCurrent(); } /// Instantiate an LLTreeDFSPostIter to mark the end of the walk - LLTreeDFSPostIter() {} + LLTreeDFSPostIter() : mSkipAncestors(false) {} - /// flags iterator logic to skip traversing ancestors of current node on next increment - void skipAncestors(bool skip = true) { mSkipAncestors = skip; } + /// flags iterator logic to skip traversing ancestors of current node on next increment + void skipAncestors(bool skip = true) { mSkipAncestors = skip; } private: /// leverage boost::iterator_facade diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp index f6e8f01f0e..9d4f3a98f0 100644 --- a/indra/llcommon/lluri.cpp +++ b/indra/llcommon/lluri.cpp @@ -46,10 +46,21 @@ void encode_character(std::ostream& ostr, std::string::value_type val) { - ostr << "%" << std::uppercase << std::hex << std::setw(2) << std::setfill('0') + ostr << "%" + + << std::uppercase + << std::hex + << std::setw(2) + << std::setfill('0') + // VWR-4010 Cannot cast to U32 because sign-extension on // chars > 128 will result in FFFFFFC3 instead of F3. - << static_cast<S32>(static_cast<U8>(val)); + << static_cast<S32>(static_cast<U8>(val)) + + // reset stream state + << std::nouppercase + << std::dec + << std::setfill(' '); } // static diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index c78fb12018..3a0d66e4a5 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -133,6 +133,7 @@ public: U8 mData[UUID_BYTES]; }; +typedef std::vector<LLUUID> uuid_vec_t; // Construct inline LLUUID::LLUUID() diff --git a/indra/llcommon/llversionserver.h b/indra/llcommon/llversionserver.h index 0f1e59a18c..e3663544db 100644 --- a/indra/llcommon/llversionserver.h +++ b/indra/llcommon/llversionserver.h @@ -36,7 +36,7 @@ const S32 LL_VERSION_MAJOR = 1; const S32 LL_VERSION_MINOR = 31; const S32 LL_VERSION_PATCH = 0; -const S32 LL_VERSION_BUILD = 200030; +const S32 LL_VERSION_BUILD = 203110; const char * const LL_CHANNEL = "Second Life Server"; diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index 540aea4252..fc9fcb2d9e 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -35,8 +35,8 @@ const S32 LL_VERSION_MAJOR = 2; const S32 LL_VERSION_MINOR = 0; -const S32 LL_VERSION_PATCH = 0; -const S32 LL_VERSION_BUILD = 200030; +const S32 LL_VERSION_PATCH = 1; +const S32 LL_VERSION_BUILD = 203110; const char * const LL_CHANNEL = "Second Life Developer"; diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp index 82c736266d..2629237f7e 100644 --- a/indra/llcommon/llworkerthread.cpp +++ b/indra/llcommon/llworkerthread.cpp @@ -65,6 +65,27 @@ LLWorkerThread::~LLWorkerThread() // ~LLQueuedThread() will be called here } +//called only in destructor. +void LLWorkerThread::clearDeleteList() +{ + // Delete any workers in the delete queue (should be safe - had better be!) + if (!mDeleteList.empty()) + { + llwarns << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() + << " entries in delete list." << llendl; + + mDeleteMutex->lock(); + for (delete_list_t::iterator iter = mDeleteList.begin(); iter != mDeleteList.end(); ++iter) + { + (*iter)->mRequestHandle = LLWorkerThread::nullHandle(); + (*iter)->clearFlags(LLWorkerClass::WCF_HAVE_WORK); + delete *iter ; + } + mDeleteList.clear() ; + mDeleteMutex->unlock() ; + } +} + // virtual S32 LLWorkerThread::update(U32 max_time_ms) { @@ -188,6 +209,7 @@ LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& na : mWorkerThread(workerthread), mWorkerClassName(name), mRequestHandle(LLWorkerThread::nullHandle()), + mRequestPriority(LLWorkerThread::PRIORITY_NORMAL), mMutex(NULL), mWorkFlags(0) { @@ -319,7 +341,20 @@ bool LLWorkerClass::checkWork(bool aborting) if (mRequestHandle != LLWorkerThread::nullHandle()) { LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); - llassert_always(workreq); + if(!workreq) + { + if(mWorkerThread->isQuitting() || mWorkerThread->isStopped()) //the mWorkerThread is not running + { + mRequestHandle = LLWorkerThread::nullHandle(); + clearFlags(WCF_HAVE_WORK); + } + else + { + llassert_always(workreq); + } + return true ; + } + LLQueuedThread::status_t status = workreq->getStatus(); if (status == LLWorkerThread::STATUS_ABORTED) { diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h index a1e85d2ecc..1756ebab6b 100644 --- a/indra/llcommon/llworkerthread.h +++ b/indra/llcommon/llworkerthread.h @@ -80,6 +80,9 @@ public: S32 mParam; }; +protected: + void clearDeleteList() ; + private: typedef std::list<LLWorkerClass*> delete_list_t; delete_list_t mDeleteList; diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp index 7415f2d33b..4bb3ec2922 100644 --- a/indra/llcommon/tests/llinstancetracker_test.cpp +++ b/indra/llcommon/tests/llinstancetracker_test.cpp @@ -138,23 +138,29 @@ namespace tut keys.insert(&one); keys.insert(&two); keys.insert(&three); - for (Unkeyed::key_iter ki(Unkeyed::beginKeys()), kend(Unkeyed::endKeys()); - ki != kend; ++ki) - { - ensure_equals("spurious key", keys.erase(*ki), 1); - } + { + Unkeyed::LLInstanceTrackerScopedGuard guard; + for (Unkeyed::key_iter ki(guard.beginKeys()), kend(guard.endKeys()); + ki != kend; ++ki) + { + ensure_equals("spurious key", keys.erase(*ki), 1); + } + } ensure_equals("unreported key", keys.size(), 0); KeySet instances; instances.insert(&one); instances.insert(&two); instances.insert(&three); - for (Unkeyed::instance_iter ii(Unkeyed::beginInstances()), iend(Unkeyed::endInstances()); - ii != iend; ++ii) - { - Unkeyed& ref = *ii; - ensure_equals("spurious instance", instances.erase(&ref), 1); - } + { + Unkeyed::LLInstanceTrackerScopedGuard guard; + for (Unkeyed::instance_iter ii(guard.beginInstances()), iend(guard.endInstances()); + ii != iend; ++ii) + { + Unkeyed& ref = *ii; + ensure_equals("spurious instance", instances.erase(&ref), 1); + } + } ensure_equals("unreported instance", instances.size(), 0); } } // namespace tut |