Merge remote-tracking branch 'shyotl/V2Renderer' into V2Renderer
This commit is contained in:
@@ -63,6 +63,7 @@ set(llcommon_SOURCE_FILES
|
||||
llsdutil.cpp
|
||||
llsecondlifeurls.cpp
|
||||
llstat.cpp
|
||||
llstacktrace.cpp
|
||||
llstreamtools.cpp
|
||||
llstring.cpp
|
||||
llstringtable.cpp
|
||||
@@ -92,12 +93,12 @@ set(llcommon_HEADER_FILES
|
||||
linden_common.h
|
||||
linked_lists.h
|
||||
llagentconstants.h
|
||||
llavatarname.h
|
||||
llapp.h
|
||||
llapr.h
|
||||
llassettype.h
|
||||
llassoclist.h
|
||||
llavatarconstants.h
|
||||
llavatarname.h
|
||||
llbase32.h
|
||||
llbase64.h
|
||||
llboost.h
|
||||
@@ -173,6 +174,7 @@ set(llcommon_HEADER_FILES
|
||||
llskiplist.h
|
||||
llskipmap.h
|
||||
llstack.h
|
||||
llstacktrace.h
|
||||
llstat.h
|
||||
llstatenums.h
|
||||
llstl.h
|
||||
|
||||
@@ -33,13 +33,18 @@
|
||||
|
||||
#include "llfasttimer.h"
|
||||
|
||||
#include "llmemory.h"
|
||||
#include "llprocessor.h"
|
||||
|
||||
|
||||
#if LL_WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include "lltimer.h"
|
||||
#elif LL_LINUX || LL_SOLARIS
|
||||
#include <sys/time.h>
|
||||
#include <sched.h>
|
||||
#include "lltimer.h"
|
||||
#elif LL_DARWIN
|
||||
#include <sys/time.h>
|
||||
#include "lltimer.h" // get_clock_count()
|
||||
@@ -65,7 +70,7 @@ S32 LLFastTimer::sLastFrameIndex = -1;
|
||||
int LLFastTimer::sPauseHistory = 0;
|
||||
int LLFastTimer::sResetHistory = 0;
|
||||
|
||||
F64 LLFastTimer::sCPUClockFrequency = 0.0;
|
||||
#define USE_RDTSC 0
|
||||
|
||||
#if LL_LINUX || LL_SOLARIS
|
||||
U64 LLFastTimer::sClockResolution = 1000000000; // 1e9, Nanosecond resolution
|
||||
@@ -73,81 +78,34 @@ U64 LLFastTimer::sClockResolution = 1000000000; // 1e9, Nanosecond resolution
|
||||
U64 LLFastTimer::sClockResolution = 1000000; // 1e6, Microsecond resolution
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
// CPU clock/other clock frequency and count functions
|
||||
//
|
||||
|
||||
#if LL_WINDOWS
|
||||
|
||||
U64 get_cpu_clock_count()
|
||||
{ U32 hi,lo;
|
||||
|
||||
__asm
|
||||
{
|
||||
_emit 0x0f
|
||||
_emit 0x31
|
||||
mov lo,eax
|
||||
mov hi,edx
|
||||
}
|
||||
|
||||
U64 ret = hi;
|
||||
ret *= 4294967296L;
|
||||
ret |= lo;
|
||||
return ret;
|
||||
};
|
||||
|
||||
#endif // LL_WINDOWS
|
||||
|
||||
#if LL_LINUX || LL_SOLARIS
|
||||
// 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.
|
||||
U64 get_cpu_clock_count()
|
||||
{
|
||||
struct timespec tp;
|
||||
|
||||
#ifdef CLOCK_MONOTONIC
|
||||
clock_gettime(CLOCK_MONOTONIC,&tp);
|
||||
#else
|
||||
clock_gettime(CLOCK_REALTIME,&tp);
|
||||
#endif
|
||||
return (tp.tv_sec*LLFastTimer::sClockResolution)+tp.tv_nsec;
|
||||
}
|
||||
#endif // (LL_LINUX || LL_SOLARIS))
|
||||
|
||||
#if LL_DARWIN
|
||||
//
|
||||
// Mac implementation of CPU clock
|
||||
//
|
||||
// Just use gettimeofday implementation for now
|
||||
|
||||
U64 get_cpu_clock_count()
|
||||
{
|
||||
return get_clock_count();
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//static
|
||||
#if LL_DARWIN || LL_LINUX || LL_SOLARIS
|
||||
U64 LLFastTimer::countsPerSecond()
|
||||
#if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
|
||||
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
|
||||
{
|
||||
return sClockResolution;
|
||||
return sClockResolution >> 8;
|
||||
}
|
||||
#else
|
||||
U64 LLFastTimer::countsPerSecond()
|
||||
#else // windows or x86-mac or x86-linux or x86-solaris
|
||||
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
|
||||
{
|
||||
if (!sCPUClockFrequency)
|
||||
#if USE_RDTSC || !LL_WINDOWS
|
||||
//getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz
|
||||
static U64 sCPUClockFrequency = U64(LLProcessorInfo().getCPUFrequency()*1000000.0);
|
||||
|
||||
// we drop the low-order byte in our timers, so report a lower frequency
|
||||
#else
|
||||
// If we're not using RDTSC, each fasttimer tick is just a performance counter tick.
|
||||
// Not redefining the clock frequency itself (in llprocessor.cpp/calculate_cpu_frequency())
|
||||
// since that would change displayed MHz stats for CPUs
|
||||
static bool firstcall = true;
|
||||
static U64 sCPUClockFrequency;
|
||||
if (firstcall)
|
||||
{
|
||||
CProcessor proc;
|
||||
sCPUClockFrequency = proc.GetCPUFrequency(50);
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&sCPUClockFrequency);
|
||||
firstcall = false;
|
||||
}
|
||||
return U64(sCPUClockFrequency);
|
||||
#endif
|
||||
return sCPUClockFrequency >> 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -200,3 +158,143 @@ void LLFastTimer::reset()
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Important note: These implementations must be FAST!
|
||||
//
|
||||
|
||||
|
||||
#if LL_WINDOWS
|
||||
//
|
||||
// Windows implementation of CPU clock
|
||||
//
|
||||
|
||||
//
|
||||
// NOTE: put back in when we aren't using platform sdk anymore
|
||||
//
|
||||
// because MS has different signatures for these functions in winnt.h
|
||||
// need to rename them to avoid conflicts
|
||||
//#define _interlockedbittestandset _renamed_interlockedbittestandset
|
||||
//#define _interlockedbittestandreset _renamed_interlockedbittestandreset
|
||||
//#include <intrin.h>
|
||||
//#undef _interlockedbittestandset
|
||||
//#undef _interlockedbittestandreset
|
||||
|
||||
//inline U32 LLFastTimer::getCPUClockCount32()
|
||||
//{
|
||||
// U64 time_stamp = __rdtsc();
|
||||
// return (U32)(time_stamp >> 8);
|
||||
//}
|
||||
//
|
||||
//// return full timer value, *not* shifted by 8 bits
|
||||
//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
|
||||
#if USE_RDTSC
|
||||
U32 LLFastTimer::getCPUClockCount32()
|
||||
{
|
||||
U32 ret_val;
|
||||
__asm
|
||||
{
|
||||
_emit 0x0f
|
||||
_emit 0x31
|
||||
shr eax,8
|
||||
shl edx,24
|
||||
or eax, edx
|
||||
mov dword ptr [ret_val], eax
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
// return full timer value, *not* shifted by 8 bits
|
||||
U64 LLFastTimer::getCPUClockCount64()
|
||||
{
|
||||
U64 ret_val;
|
||||
__asm
|
||||
{
|
||||
_emit 0x0f
|
||||
_emit 0x31
|
||||
mov eax,eax
|
||||
mov edx,edx
|
||||
mov dword ptr [ret_val+4], edx
|
||||
mov dword ptr [ret_val], eax
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
std::string LLFastTimer::sClockType = "rdtsc";
|
||||
|
||||
#else
|
||||
//LL_COMMON_API U64 get_clock_count(); // in lltimer.cpp
|
||||
// These use QueryPerformanceCounter, which is arguably fine and also works on amd architectures.
|
||||
U32 LLFastTimer::getCPUClockCount32()
|
||||
{
|
||||
return (U32)(get_clock_count()>>8);
|
||||
}
|
||||
|
||||
U64 LLFastTimer::getCPUClockCount64()
|
||||
{
|
||||
return get_clock_count();
|
||||
}
|
||||
|
||||
std::string LLFastTimer::sClockType = "QueryPerformanceCounter";
|
||||
#endif
|
||||
|
||||
#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.
|
||||
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;
|
||||
}
|
||||
|
||||
U32 LLFastTimer::getCPUClockCount32()
|
||||
{
|
||||
return (U32)(LLFastTimer::getCPUClockCount64() >> 8);
|
||||
}
|
||||
|
||||
std::string LLFastTimer::sClockType = "clock_gettime";
|
||||
|
||||
#endif // (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
|
||||
|
||||
|
||||
#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__))
|
||||
//
|
||||
// Mac+Linux+Solaris FAST x86 implementation of CPU clock
|
||||
U32 LLFastTimer::getCPUClockCount32()
|
||||
{
|
||||
U64 x;
|
||||
__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
|
||||
return (U32)(x >> 8);
|
||||
}
|
||||
|
||||
U64 LLFastTimer::getCPUClockCount64()
|
||||
{
|
||||
U64 x;
|
||||
__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
std::string LLFastTimer::sClockType = "rdtsc";
|
||||
#endif
|
||||
@@ -35,7 +35,6 @@
|
||||
|
||||
#define FAST_TIMER_ON 1
|
||||
|
||||
LL_COMMON_API U64 get_cpu_clock_count();
|
||||
|
||||
class LL_COMMON_API LLFastTimer
|
||||
{
|
||||
@@ -107,7 +106,23 @@ public:
|
||||
FTM_RENDER_BLOOM,
|
||||
FTM_RENDER_BLOOM_FBO,
|
||||
FTM_RENDER_FONTS,
|
||||
|
||||
|
||||
// deferred rendering
|
||||
FTM_RENDER_DEFERRED,
|
||||
FTM_BIND_DEFERRED,
|
||||
FTM_SUN_SHADOW,
|
||||
FTM_SOFTEN_SHADOW,
|
||||
FTM_EDGE_DETECTION,
|
||||
FTM_GI_TRACE,
|
||||
FTM_GI_GATHER,
|
||||
FTM_ATMOSPHERICS,
|
||||
FTM_LOCAL_LIGHTS,
|
||||
FTM_FULLSCREEN_LIGHTS,
|
||||
FTM_PROJECTORS,
|
||||
FTM_POST,
|
||||
|
||||
FTM_VISIBLE_CLOUD,
|
||||
|
||||
// newview specific
|
||||
FTM_MESSAGES,
|
||||
FTM_MOUSEHANDLER,
|
||||
@@ -211,7 +226,7 @@ public:
|
||||
//gTimerBins[gCurTimerBin]++;
|
||||
//LLTimer::sNumTimerCalls++;
|
||||
|
||||
U64 cpu_clocks = get_cpu_clock_count();
|
||||
U64 cpu_clocks = getCPUClockCount64();
|
||||
|
||||
sStart[sCurDepth] = cpu_clocks;
|
||||
sCurDepth++;
|
||||
@@ -226,7 +241,7 @@ public:
|
||||
// These don't get counted, because they use CPU clockticks
|
||||
//gTimerBins[gCurTimerBin]++;
|
||||
//LLTimer::sNumTimerCalls++;
|
||||
end = get_cpu_clock_count();
|
||||
end = getCPUClockCount64();
|
||||
|
||||
sCurDepth--;
|
||||
delta = end - sStart[sCurDepth];
|
||||
@@ -241,6 +256,7 @@ public:
|
||||
static void reset();
|
||||
static U64 countsPerSecond();
|
||||
|
||||
static std::string sClockType;
|
||||
public:
|
||||
static int sCurDepth;
|
||||
static U64 sStart[FTM_MAX_DEPTH];
|
||||
@@ -250,14 +266,17 @@ public:
|
||||
static U64 sCallAverage[FTM_NUM_TYPES];
|
||||
static U64 sCountHistory[FTM_HISTORY_NUM][FTM_NUM_TYPES];
|
||||
static U64 sCallHistory[FTM_HISTORY_NUM][FTM_NUM_TYPES];
|
||||
static S32 sCurFrameIndex;
|
||||
static S32 sLastFrameIndex;
|
||||
|
||||
static int sPauseHistory;
|
||||
static int sResetHistory;
|
||||
static F64 sCPUClockFrequency;
|
||||
static U64 sClockResolution;
|
||||
|
||||
private:
|
||||
static U32 getCPUClockCount32();
|
||||
static U64 getCPUClockCount64();
|
||||
|
||||
static U64 sClockResolution;
|
||||
static S32 sCurFrameIndex;
|
||||
static S32 sLastFrameIndex;
|
||||
|
||||
EFastTimerType mType;
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -30,166 +30,26 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// Author: Benjamin Jurke
|
||||
// File history: 27.02.2002 File created.
|
||||
///////////////////////////////////////////
|
||||
|
||||
|
||||
#ifndef LLPROCESSOR_H
|
||||
#define LLPROCESSOR_H
|
||||
class LLProcessorInfoImpl;
|
||||
|
||||
// Options:
|
||||
///////////
|
||||
#if LL_WINDOWS
|
||||
#define PROCESSOR_FREQUENCY_MEASURE_AVAILABLE
|
||||
#endif
|
||||
|
||||
#if LL_MSVC && _M_X64
|
||||
# define LL_X86_64 1
|
||||
# define LL_X86 1
|
||||
#elif LL_MSVC && _M_IX86
|
||||
# define LL_X86 1
|
||||
#elif LL_GNUC && ( defined(__amd64__) || defined(__x86_64__) )
|
||||
# define LL_X86_64 1
|
||||
# define LL_X86 1
|
||||
#elif LL_GNUC && ( defined(__i386__) )
|
||||
# define LL_X86 1
|
||||
#elif LL_GNUC && ( defined(__powerpc__) || defined(__ppc__) )
|
||||
# define LL_PPC 1
|
||||
#endif
|
||||
|
||||
|
||||
struct ProcessorExtensions
|
||||
class LL_COMMON_API LLProcessorInfo
|
||||
{
|
||||
bool FPU_FloatingPointUnit;
|
||||
bool VME_Virtual8086ModeEnhancements;
|
||||
bool DE_DebuggingExtensions;
|
||||
bool PSE_PageSizeExtensions;
|
||||
bool TSC_TimeStampCounter;
|
||||
bool MSR_ModelSpecificRegisters;
|
||||
bool PAE_PhysicalAddressExtension;
|
||||
bool MCE_MachineCheckException;
|
||||
bool CX8_COMPXCHG8B_Instruction;
|
||||
bool APIC_AdvancedProgrammableInterruptController;
|
||||
unsigned int APIC_ID;
|
||||
bool SEP_FastSystemCall;
|
||||
bool MTRR_MemoryTypeRangeRegisters;
|
||||
bool PGE_PTE_GlobalFlag;
|
||||
bool MCA_MachineCheckArchitecture;
|
||||
bool CMOV_ConditionalMoveAndCompareInstructions;
|
||||
bool FGPAT_PageAttributeTable;
|
||||
bool PSE36_36bitPageSizeExtension;
|
||||
bool PN_ProcessorSerialNumber;
|
||||
bool CLFSH_CFLUSH_Instruction;
|
||||
unsigned int CLFLUSH_InstructionCacheLineSize;
|
||||
bool DS_DebugStore;
|
||||
bool ACPI_ThermalMonitorAndClockControl;
|
||||
bool EMMX_MultimediaExtensions;
|
||||
bool MMX_MultimediaExtensions;
|
||||
bool FXSR_FastStreamingSIMD_ExtensionsSaveRestore;
|
||||
bool SSE_StreamingSIMD_Extensions;
|
||||
bool SSE2_StreamingSIMD2_Extensions;
|
||||
bool Altivec_Extensions;
|
||||
bool SS_SelfSnoop;
|
||||
bool HT_HyperThreading;
|
||||
unsigned int HT_HyterThreadingSiblings;
|
||||
bool TM_ThermalMonitor;
|
||||
bool IA64_Intel64BitArchitecture;
|
||||
bool _3DNOW_InstructionExtensions;
|
||||
bool _E3DNOW_InstructionExtensions;
|
||||
bool AA64_AMD64BitArchitecture;
|
||||
};
|
||||
|
||||
struct ProcessorCache
|
||||
{
|
||||
bool bPresent;
|
||||
char strSize[32]; /* Flawfinder: ignore */
|
||||
unsigned int uiAssociativeWays;
|
||||
unsigned int uiLineSize;
|
||||
bool bSectored;
|
||||
char strCache[128]; /* Flawfinder: ignore */
|
||||
};
|
||||
|
||||
struct ProcessorL1Cache
|
||||
{
|
||||
ProcessorCache Instruction;
|
||||
ProcessorCache Data;
|
||||
};
|
||||
|
||||
struct ProcessorTLB
|
||||
{
|
||||
bool bPresent;
|
||||
char strPageSize[32]; /* Flawfinder: ignore */
|
||||
unsigned int uiAssociativeWays;
|
||||
unsigned int uiEntries;
|
||||
char strTLB[128]; /* Flawfinder: ignore */
|
||||
};
|
||||
|
||||
struct ProcessorInfo
|
||||
{
|
||||
char strVendor[16]; /* Flawfinder: ignore */
|
||||
unsigned int uiFamily;
|
||||
unsigned int uiExtendedFamily;
|
||||
char strFamily[64]; /* Flawfinder: ignore */
|
||||
unsigned int uiModel;
|
||||
unsigned int uiExtendedModel;
|
||||
char strModel[128]; /* Flawfinder: ignore */
|
||||
unsigned int uiStepping;
|
||||
unsigned int uiType;
|
||||
char strType[64]; /* Flawfinder: ignore */
|
||||
unsigned int uiBrandID;
|
||||
char strBrandID[64]; /* Flawfinder: ignore */
|
||||
char strProcessorSerial[64]; /* Flawfinder: ignore */
|
||||
unsigned long MaxSupportedLevel;
|
||||
unsigned long MaxSupportedExtendedLevel;
|
||||
ProcessorExtensions _Ext;
|
||||
ProcessorL1Cache _L1;
|
||||
ProcessorCache _L2;
|
||||
ProcessorCache _L3;
|
||||
ProcessorCache _Trace;
|
||||
ProcessorTLB _Instruction;
|
||||
ProcessorTLB _Data;
|
||||
};
|
||||
|
||||
|
||||
// CProcessor
|
||||
// ==========
|
||||
// Class for detecting the processor name, type and available
|
||||
// extensions as long as it's speed.
|
||||
/////////////////////////////////////////////////////////////
|
||||
class CProcessor
|
||||
{
|
||||
// Constructor / Destructor:
|
||||
////////////////////////////
|
||||
public:
|
||||
CProcessor();
|
||||
LLProcessorInfo();
|
||||
~LLProcessorInfo();
|
||||
|
||||
// Private vars:
|
||||
////////////////
|
||||
public:
|
||||
F64 uqwFrequency;
|
||||
char strCPUName[128]; /* Flawfinder: ignore */
|
||||
ProcessorInfo CPUInfo;
|
||||
|
||||
// Private functions:
|
||||
/////////////////////
|
||||
F64 getCPUFrequency() const;
|
||||
bool hasSSE() const;
|
||||
bool hasSSE2() const;
|
||||
bool hasAltivec() const;
|
||||
std::string getCPUFamilyName() const;
|
||||
std::string getCPUBrandName() const;
|
||||
std::string getCPUFeatureDescription() const;
|
||||
private:
|
||||
bool AnalyzeIntelProcessor();
|
||||
bool AnalyzeAMDProcessor();
|
||||
bool AnalyzeUnknownProcessor();
|
||||
bool CheckCPUIDPresence();
|
||||
void DecodeProcessorConfiguration(unsigned int cfg);
|
||||
void TranslateProcessorConfiguration();
|
||||
void GetStandardProcessorConfiguration();
|
||||
void GetStandardProcessorExtensions();
|
||||
|
||||
// Public functions:
|
||||
////////////////////
|
||||
public:
|
||||
F64 GetCPUFrequency(unsigned int uiMeasureMSecs);
|
||||
const ProcessorInfo *GetCPUInfo();
|
||||
bool CPUInfoToText(char *strBuffer, unsigned int uiMaxLen);
|
||||
bool WriteInfoTextFile(const std::string& strFilename);
|
||||
LLProcessorInfoImpl* mImpl;
|
||||
};
|
||||
|
||||
|
||||
|
||||
143
indra/llcommon/llstacktrace.cpp
Normal file
143
indra/llcommon/llstacktrace.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* @file llstacktrace.cpp
|
||||
* @brief stack tracing functionality
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2001-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://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 "llstacktrace.h"
|
||||
|
||||
#ifdef LL_WINDOWS
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "windows.h"
|
||||
#include "Dbghelp.h"
|
||||
|
||||
typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(
|
||||
IN ULONG frames_to_skip,
|
||||
IN ULONG frames_to_capture,
|
||||
OUT PVOID *backtrace,
|
||||
OUT PULONG backtrace_hash);
|
||||
|
||||
static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
|
||||
(RtlCaptureStackBackTrace_Function*)
|
||||
GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace");
|
||||
|
||||
bool ll_get_stack_trace(std::vector<std::string>& lines)
|
||||
{
|
||||
const S32 MAX_STACK_DEPTH = 32;
|
||||
const S32 STRING_NAME_LENGTH = 200;
|
||||
const S32 FRAME_SKIP = 2;
|
||||
static BOOL symbolsLoaded = false;
|
||||
static BOOL firstCall = true;
|
||||
|
||||
HANDLE hProc = GetCurrentProcess();
|
||||
|
||||
// load the symbols if they're not loaded
|
||||
if(!symbolsLoaded && firstCall)
|
||||
{
|
||||
symbolsLoaded = SymInitialize(hProc, NULL, true);
|
||||
firstCall = false;
|
||||
}
|
||||
|
||||
// if loaded, get the call stack
|
||||
if(symbolsLoaded)
|
||||
{
|
||||
// create the frames to hold the addresses
|
||||
void* frames[MAX_STACK_DEPTH];
|
||||
memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH);
|
||||
S32 depth = 0;
|
||||
|
||||
// get the addresses
|
||||
depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL);
|
||||
|
||||
IMAGEHLP_LINE64 line;
|
||||
memset(&line, 0, sizeof(IMAGEHLP_LINE64));
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
|
||||
// create something to hold address info
|
||||
PIMAGEHLP_SYMBOL64 pSym;
|
||||
pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH);
|
||||
memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH);
|
||||
pSym->MaxNameLength = STRING_NAME_LENGTH;
|
||||
pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
|
||||
// get address info for each address frame
|
||||
// and store
|
||||
for(S32 i=0; i < depth; i++)
|
||||
{
|
||||
std::stringstream stack_line;
|
||||
BOOL ret;
|
||||
|
||||
DWORD64 addr = (DWORD64)frames[i];
|
||||
ret = SymGetSymFromAddr64(hProc, addr, 0, pSym);
|
||||
if(ret)
|
||||
{
|
||||
stack_line << pSym->Name << " ";
|
||||
}
|
||||
|
||||
DWORD dummy;
|
||||
ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line);
|
||||
if(ret)
|
||||
{
|
||||
std::string file_name = line.FileName;
|
||||
std::string::size_type index = file_name.rfind("\\");
|
||||
stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber;
|
||||
}
|
||||
|
||||
lines.push_back(stack_line.str());
|
||||
}
|
||||
|
||||
free(pSym);
|
||||
|
||||
// TODO: figure out a way to cleanup symbol loading
|
||||
// Not hugely necessary, however.
|
||||
//SymCleanup(hProc);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
lines.push_back("Stack Trace Failed. PDB symbol info not loaded");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool ll_get_stack_trace(std::vector<std::string>& lines)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
45
indra/llcommon/llstacktrace.h
Normal file
45
indra/llcommon/llstacktrace.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @file llstacktrace.h
|
||||
* @brief stack trace functions
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2001-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://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$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LL_LLSTACKTRACE_H
|
||||
#define LL_LLSTACKTRACE_H
|
||||
|
||||
#include "stdtypes.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
LL_COMMON_API bool ll_get_stack_trace(std::vector<std::string>& lines);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -52,13 +52,13 @@
|
||||
# include <sys/sysctl.h>
|
||||
# include <sys/utsname.h>
|
||||
# include <stdint.h>
|
||||
//# include <Carbon/Carbon.h> May be needed?
|
||||
#elif LL_LINUX
|
||||
# include <errno.h>
|
||||
# include <sys/utsname.h>
|
||||
# include <unistd.h>
|
||||
# include <sys/sysinfo.h>
|
||||
const char MEMINFO_FILE[] = "/proc/meminfo";
|
||||
const char CPUINFO_FILE[] = "/proc/cpuinfo";
|
||||
#elif LL_SOLARIS
|
||||
# include <stdio.h>
|
||||
# include <unistd.h>
|
||||
@@ -325,7 +325,58 @@ LLOSInfo::LLOSInfo() :
|
||||
}
|
||||
mOSString += compatibility_mode;
|
||||
|
||||
#elif LL_DARWIN
|
||||
|
||||
// Initialize mOSStringSimple to something like:
|
||||
// "Mac OS X 10.6.7"
|
||||
{
|
||||
const char * DARWIN_PRODUCT_NAME = "Mac OS X";
|
||||
|
||||
SInt32 major_version, minor_version, bugfix_version;
|
||||
OSErr r1 = Gestalt(gestaltSystemVersionMajor, &major_version);
|
||||
OSErr r2 = Gestalt(gestaltSystemVersionMinor, &minor_version);
|
||||
OSErr r3 = Gestalt(gestaltSystemVersionBugFix, &bugfix_version);
|
||||
|
||||
if((r1 == noErr) && (r2 == noErr) && (r3 == noErr))
|
||||
{
|
||||
mMajorVer = major_version;
|
||||
mMinorVer = minor_version;
|
||||
mBuild = bugfix_version;
|
||||
|
||||
std::stringstream os_version_string;
|
||||
os_version_string << DARWIN_PRODUCT_NAME << " " << mMajorVer << "." << mMinorVer << "." << mBuild;
|
||||
|
||||
// Put it in the OS string we are compiling
|
||||
mOSStringSimple.append(os_version_string.str());
|
||||
}
|
||||
else
|
||||
{
|
||||
mOSStringSimple.append("Unable to collect OS info");
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize mOSString to something like:
|
||||
// "Mac OS X 10.6.7 Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386"
|
||||
struct utsname un;
|
||||
if(uname(&un) != -1)
|
||||
{
|
||||
mOSString = mOSStringSimple;
|
||||
mOSString.append(" ");
|
||||
mOSString.append(un.sysname);
|
||||
mOSString.append(" ");
|
||||
mOSString.append(un.release);
|
||||
mOSString.append(" ");
|
||||
mOSString.append(un.version);
|
||||
mOSString.append(" ");
|
||||
mOSString.append(un.machine);
|
||||
}
|
||||
else
|
||||
{
|
||||
mOSString = mOSStringSimple;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct utsname un;
|
||||
if(uname(&un) != -1)
|
||||
{
|
||||
@@ -341,15 +392,7 @@ LLOSInfo::LLOSInfo() :
|
||||
|
||||
// Simplify 'Simple'
|
||||
std::string ostype = mOSStringSimple.substr(0, mOSStringSimple.find_first_of(" ", 0));
|
||||
if (ostype == "Darwin")
|
||||
{
|
||||
// Only care about major Darwin versions, truncate at first '.'
|
||||
S32 idx1 = mOSStringSimple.find_first_of(".", 0);
|
||||
std::string simple = mOSStringSimple.substr(0, idx1);
|
||||
if (simple.length() > 0)
|
||||
mOSStringSimple = simple;
|
||||
}
|
||||
else if (ostype == "Linux")
|
||||
if (ostype == "Linux")
|
||||
{
|
||||
// Only care about major and minor Linux versions, truncate at second '.'
|
||||
std::string::size_type idx1 = mOSStringSimple.find_first_of(".", 0);
|
||||
@@ -513,71 +556,21 @@ U32 LLOSInfo::getProcessResidentSizeKB()
|
||||
LLCPUInfo::LLCPUInfo()
|
||||
{
|
||||
std::ostringstream out;
|
||||
CProcessor proc;
|
||||
const ProcessorInfo* info = proc.GetCPUInfo();
|
||||
LLProcessorInfo proc;
|
||||
// proc.WriteInfoTextFile("procInfo.txt");
|
||||
mHasSSE = info->_Ext.SSE_StreamingSIMD_Extensions;
|
||||
mHasSSE2 = info->_Ext.SSE2_StreamingSIMD2_Extensions;
|
||||
mHasAltivec = info->_Ext.Altivec_Extensions;
|
||||
mCPUMHz = (F64)(proc.GetCPUFrequency(50)/1000000.0);
|
||||
mFamily.assign( info->strFamily );
|
||||
mHasSSE = proc.hasSSE();
|
||||
mHasSSE2 = proc.hasSSE2();
|
||||
mHasAltivec = proc.hasAltivec();
|
||||
mCPUMHz = (F64)proc.getCPUFrequency();
|
||||
mFamily = proc.getCPUFamilyName();
|
||||
mCPUString = "Unknown";
|
||||
|
||||
#if LL_WINDOWS || LL_DARWIN || LL_SOLARIS
|
||||
out << proc.strCPUName;
|
||||
out << proc.getCPUBrandName();
|
||||
if (200 < mCPUMHz && mCPUMHz < 10000) // *NOTE: cpu speed is often way wrong, do a sanity check
|
||||
{
|
||||
out << " (" << mCPUMHz << " MHz)";
|
||||
}
|
||||
mCPUString = out.str();
|
||||
|
||||
#elif LL_LINUX
|
||||
std::map< std::string, std::string > cpuinfo;
|
||||
LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb");
|
||||
if(cpuinfo_fp)
|
||||
{
|
||||
char line[MAX_STRING];
|
||||
memset(line, 0, MAX_STRING);
|
||||
while(fgets(line, MAX_STRING, cpuinfo_fp))
|
||||
{
|
||||
// /proc/cpuinfo on Linux looks like:
|
||||
// name\t*: value\n
|
||||
char* tabspot = strchr( line, '\t' );
|
||||
if (tabspot == NULL)
|
||||
continue;
|
||||
char* colspot = strchr( tabspot, ':' );
|
||||
if (colspot == NULL)
|
||||
continue;
|
||||
char* spacespot = strchr( colspot, ' ' );
|
||||
if (spacespot == NULL)
|
||||
continue;
|
||||
char* nlspot = strchr( line, '\n' );
|
||||
if (nlspot == NULL)
|
||||
nlspot = line + strlen( line ); // Fallback to terminating NUL
|
||||
std::string linename( line, tabspot );
|
||||
std::string llinename(linename);
|
||||
LLStringUtil::toLower(llinename);
|
||||
std::string lineval( spacespot + 1, nlspot );
|
||||
cpuinfo[ llinename ] = lineval;
|
||||
}
|
||||
fclose(cpuinfo_fp);
|
||||
}
|
||||
# if LL_X86
|
||||
std::string flags = " " + cpuinfo["flags"] + " ";
|
||||
LLStringUtil::toLower(flags);
|
||||
mHasSSE = ( flags.find( " sse " ) != std::string::npos );
|
||||
mHasSSE2 = ( flags.find( " sse2 " ) != std::string::npos );
|
||||
|
||||
F64 mhz;
|
||||
if (LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhz)
|
||||
&& 200.0 < mhz && mhz < 10000.0)
|
||||
{
|
||||
mCPUMHz = (F64)llrint(mhz);
|
||||
}
|
||||
if (!cpuinfo["model name"].empty())
|
||||
mCPUString = cpuinfo["model name"];
|
||||
# endif // LL_X86
|
||||
#endif // LL_LINUX
|
||||
}
|
||||
|
||||
bool LLCPUInfo::hasAltivec() const
|
||||
@@ -607,38 +600,9 @@ std::string LLCPUInfo::getCPUString() const
|
||||
|
||||
void LLCPUInfo::stream(std::ostream& s) const
|
||||
{
|
||||
#if LL_WINDOWS || LL_DARWIN || LL_SOLARIS
|
||||
// gather machine information.
|
||||
char proc_buf[CPUINFO_BUFFER_SIZE]; /* Flawfinder: ignore */
|
||||
CProcessor proc;
|
||||
if(proc.CPUInfoToText(proc_buf, CPUINFO_BUFFER_SIZE))
|
||||
{
|
||||
s << proc_buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
s << "Unable to collect processor information" << std::endl;
|
||||
}
|
||||
#else
|
||||
// *NOTE: This works on linux. What will it do on other systems?
|
||||
LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb");
|
||||
if(cpuinfo)
|
||||
{
|
||||
char line[MAX_STRING];
|
||||
memset(line, 0, MAX_STRING);
|
||||
while(fgets(line, MAX_STRING, cpuinfo))
|
||||
{
|
||||
line[strlen(line)-1] = ' ';
|
||||
s << line;
|
||||
}
|
||||
fclose(cpuinfo);
|
||||
s << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
s << "Unable to collect processor information" << std::endl;
|
||||
}
|
||||
#endif
|
||||
s << LLProcessorInfo().getCPUFeatureDescription();
|
||||
|
||||
// These are interesting as they reflect our internal view of the
|
||||
// CPU's attributes regardless of platform
|
||||
s << "->mHasSSE: " << (U32)mHasSSE << std::endl;
|
||||
|
||||
Reference in New Issue
Block a user