diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /external/vpc/public/tier0 | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'external/vpc/public/tier0')
39 files changed, 18966 insertions, 0 deletions
diff --git a/external/vpc/public/tier0/annotations.h b/external/vpc/public/tier0/annotations.h new file mode 100644 index 0000000..d10e530 --- /dev/null +++ b/external/vpc/public/tier0/annotations.h @@ -0,0 +1,116 @@ +#ifndef ANALYSIS_ANNOTATIONS_H +#define ANALYSIS_ANNOTATIONS_H + +#if _MSC_VER >= 1600 // VS 2010 and above. +//----------------------------------------------------------------------------- +// Upgrading important helpful warnings to errors +//----------------------------------------------------------------------------- +#pragma warning(error : 4789 ) // warning C4789: destination of memory copy is too small + +// Suppress some code analysis warnings +#ifdef _PREFAST_ +// Include the annotation header file. +#include <sal.h> + +// /Analyze warnings can only be suppressed when using a compiler that supports them, which VS 2010 +// Professional does not. + +// We don't care about these warnings because they are bugs that can only occur during resource +// exhaustion or other unexpected API failure, which we are nowhere near being able to handle. +#pragma warning(disable : 6308) // warning C6308: 'realloc' might return null pointer: assigning null pointer to 's_ppTestCases', which is passed as an argument to 'realloc', will cause the original memory block to be leaked +#pragma warning(disable : 6255) // warning C6255: _alloca indicates failure by raising a stack overflow exception. Consider using _malloca instead +#pragma warning(disable : 6387) // warning C6387: 'argument 1' might be '0': this does not adhere to the specification for the function 'GetProcAddress' +#pragma warning(disable : 6309) // warning C6309: Argument '1' is null: this does not adhere to function specification of 'GetProcAddress' +#pragma warning(disable : 6011) // warning C6011: Dereferencing NULL pointer 'm_ppTestCases' +#pragma warning(disable : 6211) // warning C6211: Leaking memory 'newKeyValue' due to an exception. Consider using a local catch block to clean up memory +#pragma warning(disable : 6031) // warning C6031: Return value ignored: '_getcwd' + +// These warnings are because /analyze doesn't like our use of constants, especially things like IsPC() +#pragma warning(disable : 6326) // warning C6326: Potential comparison of a constant with another constant +#pragma warning(disable : 6239) // warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator? +#pragma warning(disable : 6285) // warning C6285: (<non-zero constant> || <non-zero constant>) is always a non-zero constant. Did you intend to use the bitwise-and operator? +#pragma warning(disable : 6237) // warning C6237: (<zero> && <expression>) is always zero. <expression> is never evaluated and might have side effects +#pragma warning(disable : 6235) // warning C6235: (<non-zero constant> || <expression>) is always a non-zero constant +#pragma warning(disable : 6240) // warning C6240: (<expression> && <non-zero constant>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator? + +// These warnings aren't really important: +#pragma warning(disable : 6323) // warning C6323: Use of arithmetic operator on Boolean type(s) + +// Miscellaneous other /analyze warnings. We should consider fixing these at some point. +//#pragma warning(disable : 6204) // warning C6204: Possible buffer overrun in call to 'memcpy': use of unchecked parameter 'src' +//#pragma warning(disable : 6262) // warning C6262: Function uses '16464' bytes of stack: exceeds /analyze:stacksize'16384'. Consider moving some data to heap +// This is a serious warning. Don't suppress it. +//#pragma warning(disable : 6263) // warning C6263: Using _alloca in a loop: this can quickly overflow stack +// 6328 is also used for passing __int64 to printf when int is expected so we can't suppress it. +//#pragma warning(disable : 6328) // warning C6328: 'char' passed as parameter '1' when 'unsigned char' is required in call to 'V_isdigit' +// /analyze doesn't like GCOMPILER_ASSERT's implementation of compile-time asserts +#pragma warning(disable : 6326) // warning C6326: Potential comparison of a constant with another constant +#pragma warning(disable : 6335) // warning C6335: Leaking process information handle 'pi.hThread' +#pragma warning(disable : 6320) // warning C6320: Exception-filter expression is the constant EXCEPTION_EXECUTE_HANDLER. This might mask exceptions that were not intended to be handled +#pragma warning(disable : 6250) // warning C6250: Calling 'VirtualFree' without the MEM_RELEASE flag might free memory but not address descriptors (VADs). This causes address space leaks +#pragma warning(disable : 6384) // ientity2_class_h_schema_gen.cpp(76): warning C6384: Dividing sizeof a pointer by another value + +// For temporarily suppressing warnings -- the warnings are suppressed for the next source line. +#define ANALYZE_SUPPRESS(wnum) __pragma(warning(suppress: wnum)) +#define ANALYZE_SUPPRESS2(wnum1, wnum2) __pragma(warning(supress: wnum1 wnum2)) +#define ANALYZE_SUPPRESS3(wnum1, wnum2, wnum3) __pragma(warning(suppress: wnum1 wnum2 wnum3)) +#define ANALYZE_SUPPRESS4(wnum1, wnum2, wnum3, wnum4) __pragma(warning(suppress: wnum1 wnum2 wnum3 wnum4)) + +// Tag all printf style format strings with this +#define PRINTF_FORMAT_STRING _Printf_format_string_ +#define SCANF_FORMAT_STRING _Scanf_format_string_impl_ +// Various macros for specifying the capacity of the buffer pointed +// to by a function parameter. Variations include in/out/inout, +// CAP (elements) versus BYTECAP (bytes), and null termination or +// not (_Z). +#define IN_Z _In_z_ +#define IN_CAP(x) _In_count_(x) +#define IN_BYTECAP(x) _In_bytecount_(x) +#define OUT_Z_CAP(x) _Out_z_cap_(x) +#define OUT_CAP(x) _Out_cap_(x) +#define OUT_BYTECAP(x) _Out_bytecap_(x) +#define OUT_Z_BYTECAP(x) _Out_z_bytecap_(x) +#define INOUT_BYTECAP(x) _Inout_bytecap_(x) +#define INOUT_Z_CAP(x) _Inout_z_cap_(x) +#define INOUT_Z_BYTECAP(x) _Inout_z_bytecap_(x) +// These macros are use for annotating array reference parameters, typically used in functions +// such as V_strcpy_safe. Because they are array references the capacity is already known. +#if _MSC_VER >= 1700 +#define IN_Z_ARRAY _Pre_z_ +#define OUT_Z_ARRAY _Post_z_ +#define INOUT_Z_ARRAY _Prepost_z_ +#else +#define IN_Z_ARRAY _Deref_pre_z_ +#define OUT_Z_ARRAY _Deref_post_z_ +#define INOUT_Z_ARRAY _Deref_prepost_z_ +#endif // _MSC_VER >= 1700 +// Use the macros above to annotate string functions that fill buffers as shown here, +// in order to give VS's /analyze more opportunities to find bugs. +// void V_wcsncpy( OUT_Z_BYTECAP(maxLenInBytes) wchar_t *pDest, wchar_t const *pSrc, int maxLenInBytes ); +// int V_snwprintf( OUT_Z_CAP(maxLenInCharacters) wchar_t *pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const wchar_t *pFormat, ... ); + +#endif // _PREFAST_ +#endif // _MSC_VER >= 1600 // VS 2010 and above. + +#ifndef ANALYZE_SUPPRESS +#define ANALYZE_SUPPRESS(wnum) +#define ANALYZE_SUPPRESS2(wnum1, wnum2) +#define ANALYZE_SUPPRESS3(wnum1, wnum2, wnum3) +#define ANALYZE_SUPPRESS4(wnum1, wnum2, wnum3, wnum4) +#define PRINTF_FORMAT_STRING +#define SCANF_FORMAT_STRING +#define IN_Z +#define IN_CAP(x) +#define IN_BYTECAP(x) +#define OUT_Z_CAP(x) +#define OUT_CAP(x) +#define OUT_BYTECAP(x) +#define OUT_Z_BYTECAP(x) +#define INOUT_BYTECAP(x) +#define INOUT_Z_CAP(x) +#define INOUT_Z_BYTECAP(x) +#define OUT_Z_ARRAY +#define INOUT_Z_ARRAY +#endif + +#endif // ANALYSIS_ANNOTATIONS_H diff --git a/external/vpc/public/tier0/basetypes.h b/external/vpc/public/tier0/basetypes.h new file mode 100644 index 0000000..caa297e --- /dev/null +++ b/external/vpc/public/tier0/basetypes.h @@ -0,0 +1,650 @@ +//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BASETYPES_H +#define BASETYPES_H + +#ifdef COMPILER_MSVC +#pragma once +#endif + +// This is a trick to get the DLL extension off the -D option on the command line. +#define DLLExtTokenPaste(x) #x +#define DLLExtTokenPaste2(x) DLLExtTokenPaste(x) +#define DLL_EXT_STRING DLLExtTokenPaste2( _DLL_EXT ) + +////////////////////////////////////////////////////////////////////////// + +#ifndef schema +#define schema namespace ValveSchemaMarker {} +#endif + +#ifdef COMPILING_SCHEMA +#define UNSCHEMATIZED_METHOD( x ) +#else +#define UNSCHEMATIZED_METHOD( x ) x +#endif + +////////////////////////////////////////////////////////////////////////// + +#include "tier0/platform.h" +#include "commonmacros.h" +#include "wchartypes.h" +#ifdef _PS3 +#include <float.h> +#elif defined( PLATFORM_POSIX ) +#include <math.h> +#endif + +#include "tier0/valve_off.h" + +// There's a different version of this file in the xbox codeline +// so the PC version built in the xbox branch includes things like +// tickrate changes. +#include "xbox_codeline_defines.h" + +#if defined(_PS3) +#include <ppu_intrinsics.h> +#include <sys/fs.h> +#define PATH_MAX CELL_FS_MAX_FS_PATH_LENGTH +#define _MAX_PATH PATH_MAX +#endif +// stdio.h +#ifndef NULL +#define NULL 0 +#endif + +#ifdef PLATFORM_POSIX +#include <stdint.h> + +template<class T> +T abs( const T &a ) +{ + if ( a < 0 ) + return -a; + else + return a; +} +#endif + +#define ExecuteNTimes( nTimes, x ) \ + { \ + static int __executeCount=0;\ + if ( __executeCount < nTimes )\ + { \ + ++__executeCount; \ + x; \ + } \ + } + + +#define ExecuteOnce( x ) ExecuteNTimes( 1, x ) + + + +// Pad a number so it lies on an N byte boundary. +// So PAD_NUMBER(0,4) is 0 and PAD_NUMBER(1,4) is 4 +#define PAD_NUMBER(number, boundary) \ + ( ((number) + ((boundary)-1)) / (boundary) ) * (boundary) + +// In case this ever changes +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + +// #define COMPILETIME_MAX and COMPILETIME_MIN for max/min in constant expressions +#define COMPILETIME_MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) ) +#define COMPILETIME_MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) ) +#ifndef MIN +#define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) ) +#endif + +#ifndef MAX +#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) ) +#endif + + + + +#ifdef __cplusplus + +template< class T, class Y, class X > +inline T clamp( T const &val, Y const &minVal, X const &maxVal ) +{ + if( val < minVal ) + return minVal; + else if( val > maxVal ) + return maxVal; + else + return val; +} + +#else + +#define clamp(val, min, max) (((val) > (max)) ? (max) : (((val) < (min)) ? (min) : (val))) + +#endif + +#ifndef FALSE +#define FALSE 0 +#define TRUE (!FALSE) +#endif + +//----------------------------------------------------------------------------- +// fsel +//----------------------------------------------------------------------------- +#if !defined(_PS3) && !defined(_X360) + +#define fsel(c,x,y) ( (c) >= 0 ? (x) : (y) ) + +// integer conditional move +// if a >= 0, return x, else y +#define isel(a,x,y) ( ((a) >= 0) ? (x) : (y) ) + +// if x = y, return a, else b +#define ieqsel(x,y,a,b) (( (x) == (y) ) ? (a) : (b)) + +// if the nth bit of a is set (counting with 0 = LSB), +// return x, else y +// this is fast if nbit is a compile-time immediate +#define ibitsel(a, nbit, x, y) ( ( ((a) & (1 << (nbit))) != 0 ) ? (x) : (y) ) + + +FORCEINLINE double fpmin( double a, double b ) +{ + return a > b ? b : a; +} + +FORCEINLINE double fpmax( double a, double b ) +{ + return a >= b ? a : b; +} + +// clamp x to lie inside [a,b]. Assumes b>a +FORCEINLINE float fclamp( float x, float a, float b ) +{ + return fpmin( fpmax( x, a ), b ); +} +// clamp x to lie inside [a,b]. Assumes b>a +FORCEINLINE double fclamp( double x, double a, double b ) +{ + return fpmin( fpmax( x, a ), b ); +} + +// At some point, we will need a unified API. +#define imin( x, y ) ( (x) < (y) ? (x) : (y) ) +#define imax( x, y ) ( (x) > (y) ? (x) : (y) ) +#define iclamp clamp + +#else + +// __fsel(double fComparand, double fValGE, double fLT) == fComparand >= 0 ? fValGE : fLT +// this is much faster than if ( aFloat > 0 ) { x = .. } +// the XDK defines two intrinsics, one for floats and one for doubles -- it's the same +// opcode, but the __fself version tells the compiler not to do a wasteful unnecessary +// rounding op after each sel. +// #define fsel __fsel +#ifdef _X360 +FORCEINLINE double fsel(double fComparand, double fValGE, double fLT) { return __fsel( fComparand, fValGE, fLT ); } +FORCEINLINE float fsel(float fComparand, float fValGE, float fLT) { return __fself( fComparand, fValGE, fLT ); } +#else +FORCEINLINE double fsel(double fComparand, double fValGE, double fLT) { return __fsel( fComparand, fValGE, fLT ); } +FORCEINLINE float fsel(float fComparand, float fValGE, float fLT) { return __fsels( fComparand, fValGE, fLT ); } +#endif + +#if !defined(_X360) +FORCEINLINE float fpmin( float a, float b ) +{ + return fsel( a-b, b,a); +} +FORCEINLINE double fpmin( double a, double b ) +{ + return fsel( a-b, b,a); +} + +FORCEINLINE float fpmax( float a, float b ) +{ + return fsel( a-b, a,b); +} +FORCEINLINE double fpmax( double a, double b ) +{ + return fsel( a-b, a,b); +} + +// any mixed calls should promote to double +FORCEINLINE double fpmax(float a, double b) +{ + return fpmax( (double) a, b ); +} +// any mixed calls should promote to double +FORCEINLINE double fpmax(double a, float b) +{ + return fpmax( (double) a, (double) b ); +} +#endif + +// clamp x to lie inside [a,b]. Assumes b>a +FORCEINLINE float fclamp( float x, float a, float b ) +{ + return fpmin( fpmax( x, a ), b ); +} +// clamp x to lie inside [a,b]. Assumes b>a +FORCEINLINE double fclamp( double x, double a, double b ) +{ + return fpmin( fpmax( x, a ), b ); +} + +// if a >= 0, return x, else y +FORCEINLINE int isel( int a, int x, int y ) +{ + int mask = a >> 31; // arithmetic shift right, splat out the sign bit + return x + ((y - x) & mask); +}; + +// if a >= 0, return x, else y +FORCEINLINE unsigned isel( int a, unsigned x, unsigned y ) +{ + int mask = a >> 31; // arithmetic shift right, splat out the sign bit + return x + ((y - x) & mask); +}; + +// ( x == y ) ? a : b +FORCEINLINE unsigned ieqsel( unsigned x, unsigned y, unsigned a, unsigned b ) +{ + unsigned mask = (x == y) ? 0 : -1; + return a + ((b - a) & mask); +}; + +// ( x == y ) ? a : b +FORCEINLINE int ieqsel( int x, int y, int a, int b ) +{ + int mask = (x == y) ? 0 : -1; + return a + ((b - a) & mask); +}; + +FORCEINLINE int imin( int x, int y ) +{ + int nMaxSign = x - y; // Positive if x greater than y + int nMaxMask = nMaxSign >> 31; // 0 if x greater than y, 0xffffffff if x smaller than y + int nMaxSaturated = y + ( nMaxSign & nMaxMask ); + return nMaxSaturated; +} + +FORCEINLINE int imax( int x, int y ) +{ + int nMinSign = y - x; // Positive if x smaller than y + int nMinMask = nMinSign >> 31; // 0 if x smaller than y, 0xffffffff if x greater than y + int nMinSaturated = y - ( nMinSign & nMinMask); + return nMinSaturated; +} + +FORCEINLINE int iclamp( int x, int min, int max ) +{ + int nResult = imin( x, max ); + return imax( nResult, min ); +} + +// if the nth bit of a is set (counting with 0 = LSB), +// return x, else y +// this is fast if nbit is a compile-time immediate +#define ibitsel(a, nbit, x, y) ( (x) + (((y) - (x)) & (((a) & (1 << (nbit))) ? 0 : -1)) ) + +#endif + +#if CROSS_PLATFORM_VERSION < 1 + +#ifndef DONT_DEFINE_BOOL // Needed for Cocoa stuff to compile. +typedef int BOOL; +#endif + +typedef int qboolean; +//typedef uint32 ULONG; +typedef uint8 BYTE; +typedef uint8 byte; +typedef uint16 word; +#endif + +#if defined( _WIN32 ) || defined( _PS3 ) +typedef wchar_t ucs2; // under windows & PS3 wchar_t is ucs2 +#else +typedef unsigned short ucs2; +#endif + +enum ThreeState_t +{ + TRS_FALSE, + TRS_TRUE, + TRS_NONE, +}; + +typedef float vec_t; +#ifdef _WIN32 +typedef __int32 vec_t_as_gpr; // a general purpose register type equal in size to a vec_t (in case we have to avoid the fpu for some reason) +#endif + + +template <typename T> +inline T AlignValue( T val, uintp alignment ) +{ + return (T)( ( (uintp)val + alignment - 1 ) & ~( alignment - 1 ) ); +} + + +// FIXME: this should move +#ifndef __cplusplus +#define true TRUE +#define false FALSE +#endif + +//----------------------------------------------------------------------------- +// look for NANs, infinities, and underflows. +// This assumes the ANSI/IEEE 754-1985 standard +//----------------------------------------------------------------------------- + +#ifdef __cplusplus + +inline uint32 FloatBits( const vec_t &f ) +{ + union Convertor_t + { + vec_t f; + uint32 ul; + }tmp; + + switch( false ) { case false: ; case (sizeof( tmp ) == 4 && sizeof( tmp.f ) == 4 && sizeof( tmp.ul ) == 4):; }; + tmp.f = f; + return tmp.ul; +} + +inline vec_t BitsToFloat( uint32 i ) +{ + union Convertor_t + { + vec_t f; + uint32 ul; + }tmp; + switch( false ) { case false: ; case (sizeof( tmp ) == 4 && sizeof( tmp.f ) == 4 && sizeof( tmp.ul ) == 4 ):; }; + tmp.ul = i; + return tmp.f; +} + +inline bool IsFinite( const vec_t &f ) +{ +#ifdef _GAMECONSOLE + return f == f && fabs(f) <= FLT_MAX; +#else + return ((FloatBits(f) & 0x7F800000) != 0x7F800000); +#endif +} + +#if defined( WIN32 ) + +//#include <math.h> +// Just use prototype from math.h +#ifdef __cplusplus +extern "C" +{ +#endif + double __cdecl fabs(double); + //_CRT_JIT_INTRINSIC _CRTIMP float __cdecl fabsf( __in float _X); + float __cdecl fabsf( _In_ float ); +#ifdef __cplusplus +} +#endif + +// In win32 try to use the intrinsic fabs so the optimizer can do it's thing inline in the code +#pragma intrinsic( fabs ) +// Also, alias float make positive to use fabs, too +// NOTE: Is there a perf issue with double<->float conversion? +inline float FloatMakePositive( vec_t f ) +{ + return fabsf( f ); +} +#else +inline float FloatMakePositive( vec_t f ) +{ + return fabsf(f); // was since 2002: BitsToFloat( FloatBits(f) & 0x7FFFFFFF ); fixed in 2010 +} +#endif + +inline float FloatNegate( vec_t f ) +{ + return -f; //BitsToFloat( FloatBits(f) ^ 0x80000000 ); +} + + +#define FLOAT32_NAN_BITS (uint32)0x7FC00000 // not a number! +#define FLOAT32_NAN BitsToFloat( FLOAT32_NAN_BITS ) + +#define VEC_T_NAN FLOAT32_NAN + +#endif + +inline float FloatMakeNegative( vec_t f ) +{ + return -fabsf( f );// was since 2002: BitsToFloat( FloatBits(f) | 0x80000000 ); fixed in 2010 +} + + +// FIXME: why are these here? Hardly anyone actually needs them. +struct color24 +{ + byte r, g, b; +}; + +typedef struct color32_s +{ + bool operator!=( const struct color32_s &other ) const; + byte r, g, b, a; + + // assign and copy by using the whole register rather + // than byte-by-byte copy. (No, the compiler is not + // smart enough to do this for you. /FAcs if you + // don't believe me.) + inline unsigned *asInt(void) { return reinterpret_cast<unsigned*>(this); } + inline const unsigned *asInt(void) const { return reinterpret_cast<const unsigned*>(this); } + // This thing is in a union elsewhere, and union members can't have assignment + // operators, so you have to explicitly assign using this, or be slow. SUCK. + inline void Copy(const color32_s &rhs) + { + *asInt() = *rhs.asInt(); + } + +} color32; + +inline bool color32::operator!=( const color32 &other ) const +{ + return r != other.r || g != other.g || b != other.b || a != other.a; +} + +struct colorVec +{ + unsigned r, g, b, a; +}; + + +#ifndef NOTE_UNUSED +#define NOTE_UNUSED(arg) ((void)arg) // for pesky compiler / lint warnings +#endif +#ifdef __cplusplus + +struct vrect_t +{ + int x,y,width,height; + vrect_t *pnext; +}; + +#endif + + +//----------------------------------------------------------------------------- +// MaterialRect_t struct - used for DrawDebugText +//----------------------------------------------------------------------------- +struct Rect_t +{ + int x, y; + int width, height; +}; + +struct Rect3D_t +{ + int x, y, z; + int width, height, depth; + + FORCEINLINE Rect3D_t( int nX, int nY, int nZ, int nWidth, int nHeight, int nDepth ) + { + x = nX; + y = nY; + z = nZ; + width = nWidth; + height = nHeight; + depth = nDepth; + } + + FORCEINLINE Rect3D_t( void ) + { + } + +}; + + + +//----------------------------------------------------------------------------- +// Interval, used by soundemittersystem + the game +//----------------------------------------------------------------------------- +struct interval_t +{ + float start; + float range; +}; + + +//----------------------------------------------------------------------------- +// Declares a type-safe handle type; you can't assign one handle to the next +//----------------------------------------------------------------------------- + +// 32-bit pointer handles. + +// Typesafe 8-bit and 16-bit handles. +template< class HandleType > +class CBaseIntHandle +{ +public: + + inline bool operator==( const CBaseIntHandle &other ) { return m_Handle == other.m_Handle; } + inline bool operator!=( const CBaseIntHandle &other ) { return m_Handle != other.m_Handle; } + + // Only the code that doles out these handles should use these functions. + // Everyone else should treat them as a transparent type. + inline HandleType GetHandleValue() { return m_Handle; } + inline void SetHandleValue( HandleType val ) { m_Handle = val; } + + typedef HandleType HANDLE_TYPE; + +protected: + + HandleType m_Handle; +}; + +template< class DummyType > +class CIntHandle16 : public CBaseIntHandle< unsigned short > +{ +public: + inline CIntHandle16() {} + + static inline CIntHandle16<DummyType> MakeHandle( HANDLE_TYPE val ) + { + return CIntHandle16<DummyType>( val ); + } + +protected: + inline CIntHandle16( HANDLE_TYPE val ) + { + m_Handle = val; + } +}; + + +template< class DummyType > +class CIntHandle32 : public CBaseIntHandle< uint32 > +{ +public: + inline CIntHandle32() {} + + static inline CIntHandle32<DummyType> MakeHandle( HANDLE_TYPE val ) + { + return CIntHandle32<DummyType>( val ); + } + +protected: + inline CIntHandle32( HANDLE_TYPE val ) + { + m_Handle = val; + } +}; + + +// NOTE: This macro is the same as windows uses; so don't change the guts of it +#define DECLARE_HANDLE_16BIT(name) typedef CIntHandle16< struct name##__handle * > name; +#define DECLARE_HANDLE_32BIT(name) typedef CIntHandle32< struct name##__handle * > name; + +#define DECLARE_POINTER_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name +#define FORWARD_DECLARE_HANDLE(name) typedef struct name##__ *name + +#define DECLARE_DERIVED_POINTER_HANDLE( _name, _basehandle ) struct _name##__ : public _basehandle##__ {}; typedef struct _name##__ *_name +#define DECLARE_ALIASED_POINTER_HANDLE( _name, _alias ) typedef struct _alias##__ *name + +// @TODO: Find a better home for this +#if !defined(_STATIC_LINKED) && !defined(PUBLISH_DLL_SUBSYSTEM) +// for platforms built with dynamic linking, the dll interface does not need spoofing +#define PUBLISH_DLL_SUBSYSTEM() +#endif + +#define UID_PREFIX generated_id_ +#define UID_CAT1(a,c) a ## c +#define UID_CAT2(a,c) UID_CAT1(a,c) +#define EXPAND_CONCAT(a,c) UID_CAT1(a,c) +#ifdef _MSC_VER +#define UNIQUE_ID UID_CAT2(UID_PREFIX,__COUNTER__) +#else +#define UNIQUE_ID UID_CAT2(UID_PREFIX,__LINE__) +#endif + +#define _MKSTRING(arg) #arg +#define MKSTRING(arg) _MKSTRING(arg) + + +// this allows enumerations to be used as flags, and still remain type-safe! +#define DEFINE_ENUM_BITWISE_OPERATORS( Type ) \ + inline Type operator| ( Type a, Type b ) { return Type( int( a ) | int( b ) ); } \ + inline Type operator& ( Type a, Type b ) { return Type( int( a ) & int( b ) ); } \ + inline Type operator^ ( Type a, Type b ) { return Type( int( a ) ^ int( b ) ); } \ + inline Type operator<< ( Type a, int b ) { return Type( int( a ) << b ); } \ + inline Type operator>> ( Type a, int b ) { return Type( int( a ) >> b ); } \ + inline Type &operator|= ( Type &a, Type b ) { return a = a | b; } \ + inline Type &operator&= ( Type &a, Type b ) { return a = a & b; } \ + inline Type &operator^= ( Type &a, Type b ) { return a = a ^ b; } \ + inline Type &operator<<=( Type &a, int b ) { return a = a << b; } \ + inline Type &operator>>=( Type &a, int b ) { return a = a >> b; } \ + inline Type operator~( Type a ) { return Type( ~int( a ) ); } + +// defines increment/decrement operators for enums for easy iteration +#define DEFINE_ENUM_INCREMENT_OPERATORS( Type ) \ + inline Type &operator++( Type &a ) { return a = Type( int( a ) + 1 ); } \ + inline Type &operator--( Type &a ) { return a = Type( int( a ) - 1 ); } \ + inline Type operator++( Type &a, int ) { Type t = a; ++a; return t; } \ + inline Type operator--( Type &a, int ) { Type t = a; --a; return t; } + +// Max 2 player splitscreen in portal (don't merge this back), saves a bunch of memory [8/31/2010 tom] +#define MAX_SPLITSCREEN_CLIENT_BITS 1 +// this should == MAX_JOYSTICKS in InputEnums.h +#define MAX_SPLITSCREEN_CLIENTS ( 1 << MAX_SPLITSCREEN_CLIENT_BITS ) // 2 + +#include "tier0/valve_on.h" + +#endif // BASETYPES_H diff --git a/external/vpc/public/tier0/commonmacros.h b/external/vpc/public/tier0/commonmacros.h new file mode 100644 index 0000000..1c12442 --- /dev/null +++ b/external/vpc/public/tier0/commonmacros.h @@ -0,0 +1,149 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef COMMONMACROS_H +#define COMMONMACROS_H + +#ifdef _WIN32 +#pragma once +#endif + +// ------------------------------------------------------- +// +// commonmacros.h +// +// This should contain ONLY general purpose macros that are +// appropriate for use in engine/launcher/all tools +// +// ------------------------------------------------------- + +// Makes a 4-byte "packed ID" int out of 4 characters +#define MAKEID(d,c,b,a) ( ((int)(a) << 24) | ((int)(b) << 16) | ((int)(c) << 8) | ((int)(d)) ) + +// Compares a string with a 4-byte packed ID constant +#define STRING_MATCHES_ID( p, id ) ( (*((int *)(p)) == (id) ) ? true : false ) +#define ID_TO_STRING( id, p ) ( (p)[3] = (((id)>>24) & 0xFF), (p)[2] = (((id)>>16) & 0xFF), (p)[1] = (((id)>>8) & 0xFF), (p)[0] = (((id)>>0) & 0xFF) ) + +#define V_ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) + +#define SETBITS(iBitVector, bits) ((iBitVector) |= (bits)) +#define CLEARBITS(iBitVector, bits) ((iBitVector) &= ~(bits)) +#define FBitSet(iBitVector, bits) ((iBitVector) & (bits)) + +inline bool IsPowerOfTwo( int value ) +{ + return (value & ( value - 1 )) == 0; +} + +#ifndef REFERENCE +#define REFERENCE(arg) ((void)arg) +#endif + +#define CONST_INTEGER_AS_STRING(x) #x //Wraps the integer in quotes, allowing us to form constant strings with it +#define __HACK_LINE_AS_STRING__(x) CONST_INTEGER_AS_STRING(x) //__LINE__ can only be converted to an actual number by going through this, otherwise the output is literally "__LINE__" +#define __LINE__AS_STRING __HACK_LINE_AS_STRING__(__LINE__) //Gives you the line number in constant string form + +// Using ARRAYSIZE implementation from winnt.h: +#ifdef ARRAYSIZE +#undef ARRAYSIZE +#endif + +// Return the number of elements in a statically sized array. +// DWORD Buffer[100]; +// RTL_NUMBER_OF(Buffer) == 100 +// This is also popularly known as: NUMBER_OF, ARRSIZE, _countof, NELEM, etc. +// +#define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0])) + +#if defined(__cplusplus) && \ + !defined(MIDL_PASS) && \ + !defined(RC_INVOKED) && \ + !defined(_PREFAST_) && \ + (_MSC_FULL_VER >= 13009466) && \ + !defined(SORTPP_PASS) + +// From crtdefs.h +#if !defined(UNALIGNED) +#if defined(_M_IA64) || defined(_M_AMD64) +#define UNALIGNED __unaligned +#else +#define UNALIGNED +#endif +#endif + +// RtlpNumberOf is a function that takes a reference to an array of N Ts. +// +// typedef T array_of_T[N]; +// typedef array_of_T &reference_to_array_of_T; +// +// RtlpNumberOf returns a pointer to an array of N chars. +// We could return a reference instead of a pointer but older compilers do not accept that. +// +// typedef char array_of_char[N]; +// typedef array_of_char *pointer_to_array_of_char; +// +// sizeof(array_of_char) == N +// sizeof(*pointer_to_array_of_char) == N +// +// pointer_to_array_of_char RtlpNumberOf(reference_to_array_of_T); +// +// We never even call RtlpNumberOf, we just take the size of dereferencing its return type. +// We do not even implement RtlpNumberOf, we just decare it. +// +// Attempts to pass pointers instead of arrays to this macro result in compile time errors. +// That is the point. +extern "C++" // templates cannot be declared to have 'C' linkage +template <typename T, size_t N> +char (*RtlpNumberOf( UNALIGNED T (&)[N] ))[N]; + +#define RTL_NUMBER_OF_V2(A) (sizeof(*RtlpNumberOf(A))) + +// This does not work with: +// +// void Foo() +// { +// struct { int x; } y[2]; +// RTL_NUMBER_OF_V2(y); // illegal use of anonymous local type in template instantiation +// } +// +// You must instead do: +// +// struct Foo1 { int x; }; +// +// void Foo() +// { +// Foo1 y[2]; +// RTL_NUMBER_OF_V2(y); // ok +// } +// +// OR +// +// void Foo() +// { +// struct { int x; } y[2]; +// RTL_NUMBER_OF_V1(y); // ok +// } +// +// OR +// +// void Foo() +// { +// struct { int x; } y[2]; +// _ARRAYSIZE(y); // ok +// } + +#else +#define RTL_NUMBER_OF_V2(A) RTL_NUMBER_OF_V1(A) +#endif + +// ARRAYSIZE is more readable version of RTL_NUMBER_OF_V2 +// _ARRAYSIZE is a version useful for anonymous types +#define ARRAYSIZE(A) RTL_NUMBER_OF_V2(A) +#define _ARRAYSIZE(A) RTL_NUMBER_OF_V1(A) + +#endif // COMMONMACROS_H + diff --git a/external/vpc/public/tier0/dbg.h b/external/vpc/public/tier0/dbg.h new file mode 100644 index 0000000..2e54a47 --- /dev/null +++ b/external/vpc/public/tier0/dbg.h @@ -0,0 +1,716 @@ +//===== Copyright (c) Valve Corporation, All rights reserved. ========// +// +// Purpose: +// +// $NoKeywords: $ +// +//====================================================================// +#ifndef DBG_H +#define DBG_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "tier0/basetypes.h" +#include "dbgflag.h" +#include "logging.h" +#include <math.h> +#include <stdio.h> +#include <stdarg.h> + +//----------------------------------------------------------------------------- +// dll export stuff +//----------------------------------------------------------------------------- + +class Color; + + +//----------------------------------------------------------------------------- +// Usage model for the Dbg library +// +// 1. Assertions. +// +// Assertions are used to detect and warn about invalid states +// +// To use an assertion, use +// +// Assert( (f == 5) ); +// AssertMsg( (f == 5), ("F needs to be %d here!\n", 5) ); +// AssertFunc( (f == 5), BadFunc() ); +// AssertEquals( f, 5 ); +// AssertFloatEquals( f, 5.0f, 1e-3 ); +// +// The first will simply report that an assertion failed on a particular +// code file and line. The second version will display a print-f formatted message +// along with the file and line, the third will display a generic message and +// will also cause the function BadFunc to be executed, and the last two +// will report an error if f is not equal to 5 (the last one asserts within +// a particular tolerance). +// +// 2. Code activation +// +// To cause code to be run only in debug builds, use DBG_CODE: +// An example is below. +// +// DBG_CODE( +// { +// int x = 5; +// ++x; +// } +// ); +// +// Code can be activated based on the dynamic spew groups also. Use +// +// DBG_DCODE( "group", level, +// { int x = 5; ++x; } +// ); +// +// 3. Breaking into the debugger. +// +// To cause an unconditional break into the debugger in debug builds only, use DBG_BREAK +// +// DBG_BREAK(); +// +// You can force a break in any build (release or debug) using +// +// DebuggerBreak(); +//----------------------------------------------------------------------------- + +PLATFORM_INTERFACE void _ExitOnFatalAssert( const tchar* pFile, int line ); + +#if defined( DBGFLAG_STRINGS_STRIP ) +#define DbgFlagMacro_ExitOnFatalAssert( pFile, line ) _ExitOnFatalAssert( "", 0 ) +#else +#define DbgFlagMacro_ExitOnFatalAssert( pFile, line ) _ExitOnFatalAssert( pFile, line ) +#endif + +PLATFORM_INTERFACE bool ShouldUseNewAssertDialog(); + +PLATFORM_INTERFACE bool SetupWin32ConsoleIO(); + +// Returns true if they want to break in the debugger. +PLATFORM_INTERFACE bool DoNewAssertDialog( const tchar *pFile, int line, const tchar *pExpression ); + +#if defined( DBGFLAG_STRINGS_STRIP ) +#define DbgFlagMacro_DoNewAssertDialog( pFile, line, pExpression ) DoNewAssertDialog( "", 0, "" ) +#else +#define DbgFlagMacro_DoNewAssertDialog( pFile, line, pExpression ) DoNewAssertDialog( pFile, line, pExpression ) +#endif + +/* Used to define macros, never use these directly. */ + +#ifdef _PREFAST_ + // When doing /analyze builds define the assert macros to be __analysis_assume. This tells + // the compiler to assume that the condition is true, which helps to suppress many + // warnings. This define is done in debug and release builds, but debug builds should be + // preferred for static analysis because some asserts are compiled out in release. + // The unfortunate !! is necessary because otherwise /analyze is incapable of evaluating + // all of the logical expressions that the regular compiler can handle. + #define _AssertMsg( _exp, _msg, _executeExp, _bFatal ) __analysis_assume( !!(_exp) ) + #define _AssertMsgOnce( _exp, _msg, _bFatal ) __analysis_assume( !!(_exp) ) + // Force asserts on for /analyze so that we get a __analysis_assume of all of the constraints. + #define DBGFLAG_ASSERT + #define DBGFLAG_ASSERTFATAL +#else + #define _AssertMsg( _exp, _msg, _executeExp, _bFatal ) \ + do { \ + if (!(_exp)) \ + { \ + LoggingResponse_t ret = Log_Assert( "%s (%d) : %s\n", __TFILE__, __LINE__, _msg ); \ + _executeExp; \ + if ( ret == LR_DEBUGGER ) \ + { \ + if ( !ShouldUseNewAssertDialog() || DbgFlagMacro_DoNewAssertDialog( __TFILE__, __LINE__, _msg ) ) \ + DebuggerBreak(); \ + if ( _bFatal ) \ + DbgFlagMacro_ExitOnFatalAssert( __TFILE__, __LINE__ ); \ + } \ + } \ + } while (0) + + #define _AssertMsgOnce( _exp, _msg, _bFatal ) \ + do { \ + static bool fAsserted; \ + if (!fAsserted ) \ + { \ + _AssertMsg( _exp, _msg, (fAsserted = true), _bFatal ); \ + } \ + } while (0) +#endif + +/* Spew macros... */ + +// AssertFatal macros +// AssertFatal is used to detect an unrecoverable error condition. +// If enabled, it may display an assert dialog (if DBGFLAG_ASSERTDLG is turned on or running under the debugger), +// and always terminates the application + +#ifdef DBGFLAG_ASSERTFATAL + +#define AssertFatal( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), true ) +#define AssertFatalOnce( _exp ) _AssertMsgOnce( _exp, _T("Assertion Failed: ") _T(#_exp), true ) +#define AssertFatalMsg( _exp, _msg ) _AssertMsg( _exp, _msg, ((void)0), true ) +#define AssertFatalMsgOnce( _exp, _msg ) _AssertMsgOnce( _exp, _msg, true ) +#define AssertFatalFunc( _exp, _f ) _AssertMsg( _exp, _T("Assertion Failed: " _T(#_exp), _f, true ) +#define AssertFatalEquals( _exp, _expectedValue ) AssertFatalMsg2( (_exp) == (_expectedValue), _T("Expected %d but got %d!"), (_expectedValue), (_exp) ) +#define AssertFatalFloatEquals( _exp, _expectedValue, _tol ) AssertFatalMsg2( fabs((_exp) - (_expectedValue)) <= (_tol), _T("Expected %f but got %f!"), (_expectedValue), (_exp) ) +#define VerifyFatal( _exp ) AssertFatal( _exp ) +#define VerifyEqualsFatal( _exp, _expectedValue ) AssertFatalEquals( _exp, _expectedValue ) + +#define AssertFatalMsg1( _exp, _msg, a1 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1 ))) +#define AssertFatalMsg2( _exp, _msg, a1, a2 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2 ))) +#define AssertFatalMsg3( _exp, _msg, a1, a2, a3 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3 ))) +#define AssertFatalMsg4( _exp, _msg, a1, a2, a3, a4 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4 ))) +#define AssertFatalMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5 ))) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6 ))) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6 ))) +#define AssertFatalMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7 ))) +#define AssertFatalMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7, a8 ))) +#define AssertFatalMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ))) + +#else // DBGFLAG_ASSERTFATAL + +#define AssertFatal( _exp ) ((void)0) +#define AssertFatalOnce( _exp ) ((void)0) +#define AssertFatalMsg( _exp, _msg ) ((void)0) +#define AssertFatalMsgOnce( _exp, _msg ) ((void)0) +#define AssertFatalFunc( _exp, _f ) ((void)0) +#define AssertFatalEquals( _exp, _expectedValue ) ((void)0) +#define AssertFatalFloatEquals( _exp, _expectedValue, _tol ) ((void)0) +#define VerifyFatal( _exp ) (_exp) +#define VerifyEqualsFatal( _exp, _expectedValue ) (_exp) + +#define AssertFatalMsg1( _exp, _msg, a1 ) ((void)0) +#define AssertFatalMsg2( _exp, _msg, a1, a2 ) ((void)0) +#define AssertFatalMsg3( _exp, _msg, a1, a2, a3 ) ((void)0) +#define AssertFatalMsg4( _exp, _msg, a1, a2, a3, a4 ) ((void)0) +#define AssertFatalMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) ((void)0) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertFatalMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) ((void)0) +#define AssertFatalMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ((void)0) +#define AssertFatalMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ((void)0) + +#endif // DBGFLAG_ASSERTFATAL + +// lightweight assert macros: in theory, can be run in release without slowing it down +#if defined(_CERT) || defined(_RETAIL) +#define AssertAligned(PTR) +#else +# if defined( _X360 ) +# define AssertAligned(PTR) __twnei( intp(PTR) & 0xF, 0 ) // trap if not equal to immediate value; unsigned comparison +# elif defined( DBGFLAG_ASSERT ) +# define AssertAligned( adr ) Assert( ( ( ( intp ) ( adr ) ) & 0xf ) == 0 ) +# else +# define AssertAligned(PTR) +# endif +#endif + +// Assert macros +// Assert is used to detect an important but survivable error. +// It's only turned on when DBGFLAG_ASSERT is true. + +#ifdef DBGFLAG_ASSERT + +#define Assert( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), false ) +#define AssertMsg_( _exp, _msg ) _AssertMsg( _exp, _msg, ((void)0), false ) +#define AssertOnce( _exp ) _AssertMsgOnce( _exp, _T("Assertion Failed: ") _T(#_exp), false ) +#define AssertMsgOnce( _exp, _msg ) _AssertMsgOnce( _exp, _msg, false ) +#define AssertFunc( _exp, _f ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), _f, false ) +#define AssertEquals( _exp, _expectedValue ) AssertMsg2( (_exp) == (_expectedValue), _T("Expected %d but got %d!"), (_expectedValue), (_exp) ) +#define AssertFloatEquals( _exp, _expectedValue, _tol ) AssertMsg2( fabs((_exp) - (_expectedValue)) <= (_tol), _T("Expected %f but got %f!"), (_expectedValue), (_exp) ) +#define Verify( _exp ) Assert( _exp ) +#define VerifyEquals( _exp, _expectedValue ) AssertEquals( _exp, _expectedValue ) + +#define AssertMsg( _exp, _msg ) AssertMsg_( _exp, _T( _msg ) ) +#define AssertMsg1( _exp, _msg, a1 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1 )) ) +#define AssertMsg2( _exp, _msg, a1, a2 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2 )) ) +#define AssertMsg3( _exp, _msg, a1, a2, a3 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3 )) ) +#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4 )) ) +#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5 )) ) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5, a6 )) ) +#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5, a6, a7 )) ) +#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5, a6, a7, a8 )) ) +#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5, a6, a7, a8, a9 )) ) + +#else // DBGFLAG_ASSERT + +#define Assert( _exp ) ((void)0) +#define AssertOnce( _exp ) ((void)0) +#define AssertMsg( _exp, _msg ) ((void)0) +#define AssertMsgOnce( _exp, _msg ) ((void)0) +#define AssertFunc( _exp, _f ) ((void)0) +#define AssertEquals( _exp, _expectedValue ) ((void)0) +#define AssertFloatEquals( _exp, _expectedValue, _tol ) ((void)0) +#define Verify( _exp ) (_exp) +#define VerifyEquals( _exp, _expectedValue ) (_exp) + +#define AssertMsg1( _exp, _msg, a1 ) ((void)0) +#define AssertMsg2( _exp, _msg, a1, a2 ) ((void)0) +#define AssertMsg3( _exp, _msg, a1, a2, a3 ) ((void)0) +#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) ((void)0) +#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) ((void)0) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) ((void)0) +#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ((void)0) +#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ((void)0) + +#endif // DBGFLAG_ASSERT + +#define STRINGIFY_INTERNAL(x) #x +#define STRINGIFY(x) STRINGIFY_INTERNAL(x) + +#define FILE_LINE_FUNCTION_STRING __FILE__ "(" STRINGIFY(__LINE__) "):" __FUNCTION__ ":" +#define FILE_LINE_STRING __FILE__ "(" STRINGIFY(__LINE__) "):" +#define FUNCTION_LINE_STRING __FUNCTION__ "(" STRINGIFY(__LINE__) "): " + + +////////////////////////////////////////////////////////////////////////// +// Legacy Logging System +////////////////////////////////////////////////////////////////////////// + +// Channels which map the legacy logging system to the new system. + +// Channel for all default Msg/Warning/Error commands. +DECLARE_LOGGING_CHANNEL( LOG_GENERAL ); +// Channel for all asserts. +DECLARE_LOGGING_CHANNEL( LOG_ASSERT ); +// Channel for all ConMsg and ConColorMsg commands. +DECLARE_LOGGING_CHANNEL( LOG_CONSOLE ); +// Channel for all DevMsg and DevWarning commands with level < 2. +DECLARE_LOGGING_CHANNEL( LOG_DEVELOPER ); +// Channel for ConDMsg commands. +DECLARE_LOGGING_CHANNEL( LOG_DEVELOPER_CONSOLE ); +// Channel for all DevMsg and DevWarning commands with level >= 2. +DECLARE_LOGGING_CHANNEL( LOG_DEVELOPER_VERBOSE ); + +// Legacy logging functions + +PLATFORM_INTERFACE void Error( const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); +PLATFORM_INTERFACE void Error_SpewCallStack( int iMaxCallStackLength, const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); + +#if defined( DBGFLAG_STRINGS_STRIP ) && !defined( TIER0_DLL_EXPORT ) + +#define Msg( ... ) ((void)0) +#define Warning( ... ) ((void)0) +#define Warning_SpewCallStack( ... ) ((void)0) +#define DevMsg( ... ) ((void)0) +#define DevWarning( ... ) ((void)0) +#define ConColorMsg( ... ) ((void)0) +#define ConMsg( ... ) ((void)0) +#define ConDMsg( ... ) ((void)0) +#define COM_TimestampedLog( ... ) ((void)0) + +#else // #if defined( DBGFLAG_STRINGS_STRIP ) && !defined( TIER0_DLL_EXPORT ) + +PLATFORM_INTERFACE void Msg( const tchar* pMsg, ... ); +PLATFORM_INTERFACE void Warning( const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); +PLATFORM_INTERFACE void Warning_SpewCallStack( int iMaxCallStackLength, const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); + +#ifdef _PS3 + +PLATFORM_OVERLOAD void DevMsg( int level, const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 ); +PLATFORM_OVERLOAD void DevWarning( int level, const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); + +PLATFORM_INTERFACE void DevMsg( const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); +PLATFORM_INTERFACE void DevWarning( const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); + +PLATFORM_INTERFACE void ConColorMsg( const Color& clr, const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 ); +PLATFORM_INTERFACE void ConMsg( const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); + +#else // !_PS3 + +PLATFORM_INTERFACE void DevMsg( int level, const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 ); +PLATFORM_INTERFACE void DevWarning( int level, const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); + +PLATFORM_OVERLOAD void DevMsg( const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); +PLATFORM_OVERLOAD void DevWarning( const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); + +PLATFORM_OVERLOAD void ConColorMsg( const Color& clr, const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 ); +PLATFORM_OVERLOAD void ConMsg( const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); + +#endif // _PS3 + +PLATFORM_INTERFACE void ConDMsg( const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); + +PLATFORM_INTERFACE void COM_TimestampedLog( char const *fmt, ... ) FMTFUNCTION( 1, 2 ); + +#endif // #if defined( DBGFLAG_STRINGS_STRIP ) && !defined( TIER0_DLL_EXPORT ) + +// You can use this macro like a runtime assert macro. +// If the condition fails, then Error is called with the message. This macro is called +// like AssertMsg, where msg must be enclosed in parenthesis: +// +// ErrorIfNot( bCondition, ("a b c %d %d %d", 1, 2, 3) ); +#define ErrorIfNot( condition, msg ) \ + if ( (condition) ) \ + ; \ + else \ + { \ + Error msg; \ + } + +#ifdef _DEBUG +#define DebugMsg(...) DevMsg(__VA_ARGS__) +#else +#define DebugMsg(...) +#endif + +// @TODO: these callstack spew functions are currently disabled in the new logging system. Need to add support for these if desired. +PLATFORM_INTERFACE void _Warning_AlwaysSpewCallStack_Enable( bool bEnable ); +PLATFORM_INTERFACE void _Warning_AlwaysSpewCallStack_Length( int iMaxCallStackLength ); + +PLATFORM_INTERFACE void _Error_AlwaysSpewCallStack_Enable( bool bEnable ); +PLATFORM_INTERFACE void _Error_AlwaysSpewCallStack_Length( int iMaxCallStackLength ); + + +/* Code macros, debugger interface */ + +#ifdef _DEBUG + +#define DBG_CODE( _code ) if (0) ; else { _code } +#define DBG_CODE_NOSCOPE( _code ) _code +#define DBG_DCODE( _g, _l, _code ) if (IsSpewActive( _g, _l )) { _code } else {} +#define DBG_BREAK() DebuggerBreak() /* defined in platform.h */ + +#else /* not _DEBUG */ + +#define DBG_CODE( _code ) ((void)0) +#define DBG_CODE_NOSCOPE( _code ) +#define DBG_DCODE( _g, _l, _code ) ((void)0) +#define DBG_BREAK() ((void)0) + +#endif /* _DEBUG */ + +//----------------------------------------------------------------------------- +// Macro to assist in asserting constant invariants during compilation + +#ifdef _DEBUG +#define COMPILE_TIME_ASSERT( pred ) switch(0){case 0:case pred:;} +#define ASSERT_INVARIANT( pred ) static void UNIQUE_ID() { COMPILE_TIME_ASSERT( pred ) } +#else +#define COMPILE_TIME_ASSERT( pred ) +#define ASSERT_INVARIANT( pred ) +#endif + +#ifdef _DEBUG +template<typename DEST_POINTER_TYPE, typename SOURCE_POINTER_TYPE> +inline DEST_POINTER_TYPE assert_cast(SOURCE_POINTER_TYPE* pSource) +{ + Assert( static_cast<DEST_POINTER_TYPE>(pSource) == dynamic_cast<DEST_POINTER_TYPE>(pSource) ); + return static_cast<DEST_POINTER_TYPE>(pSource); +} +#else +#define assert_cast static_cast +#endif + +//----------------------------------------------------------------------------- +// Templates to assist in validating pointers: + +// Have to use these stubs so we don't have to include windows.h here. +PLATFORM_INTERFACE void _AssertValidReadPtr( void* ptr, int count = 1 ); +PLATFORM_INTERFACE void _AssertValidWritePtr( void* ptr, int count = 1 ); +PLATFORM_INTERFACE void _AssertValidReadWritePtr( void* ptr, int count = 1 ); +PLATFORM_INTERFACE void _AssertValidStringPtr( const tchar* ptr, int maxchar ); + +#ifdef DBGFLAG_ASSERT +inline void AssertValidStringPtr( const tchar* ptr, int maxchar = 0xFFFFFF ) { _AssertValidStringPtr( ptr, maxchar ); } +template<class T> inline void AssertValidReadPtr( T* ptr, int count = 1 ) { _AssertValidReadPtr( (void*)ptr, count ); } +template<class T> inline void AssertValidWritePtr( T* ptr, int count = 1 ) { _AssertValidWritePtr( (void*)ptr, count ); } +template<class T> inline void AssertValidReadWritePtr( T* ptr, int count = 1 ) { _AssertValidReadWritePtr( (void*)ptr, count ); } +#define AssertValidThis() AssertValidReadWritePtr(this,sizeof(*this)) + +#else + +inline void AssertValidStringPtr( const tchar* ptr, int maxchar = 0xFFFFFF ) { } +template<class T> inline void AssertValidReadPtr( T* ptr, int count = 1 ) { } +template<class T> inline void AssertValidWritePtr( T* ptr, int count = 1 ) { } +template<class T> inline void AssertValidReadWritePtr( T* ptr, int count = 1 ) { } +#define AssertValidThis() +#endif + +//----------------------------------------------------------------------------- +// Macro to protect functions that are not reentrant + +#ifdef _DEBUG +class CReentryGuard +{ +public: + CReentryGuard(int *pSemaphore) + : m_pSemaphore(pSemaphore) + { + ++(*m_pSemaphore); + } + + ~CReentryGuard() + { + --(*m_pSemaphore); + } + +private: + int *m_pSemaphore; +}; + +#define ASSERT_NO_REENTRY() \ + static int fSemaphore##__LINE__; \ + Assert( !fSemaphore##__LINE__ ); \ + CReentryGuard ReentryGuard##__LINE__( &fSemaphore##__LINE__ ) +#else +#define ASSERT_NO_REENTRY() +#endif + +// Tier0 uses these for string functions since this abstraction is normally done in tier1. +#ifdef POSIX + #define Tier0Internal_sntprintf snprintf + #define Tier0Internal_vsntprintf vsnprintf + #define Tier0Internal_vsnprintf vsnprintf +#else + #define Tier0Internal_sntprintf _sntprintf + #define Tier0Internal_vsntprintf _vsntprintf + #define Tier0Internal_vsnprintf _vsnprintf +#endif + +//----------------------------------------------------------------------------- +// +// Purpose: Inline string formatter +// + +#include "tier0/valve_off.h" +class CDbgFmtMsg +{ +public: + CDbgFmtMsg(const tchar *pszFormat, ...) + { + va_list arg_ptr; + + va_start(arg_ptr, pszFormat); + Tier0Internal_vsntprintf(m_szBuf, sizeof(m_szBuf)-1, pszFormat, arg_ptr); + va_end(arg_ptr); + + m_szBuf[sizeof(m_szBuf)-1] = 0; + } + + operator const tchar *() const + { + return m_szBuf; + } + +private: + tchar m_szBuf[256]; +}; +#include "tier0/valve_on.h" + +//----------------------------------------------------------------------------- +// +// Purpose: Embed debug info in each file. +// +#if defined( _WIN32 ) && !defined( _X360 ) + + #ifdef _DEBUG + #pragma comment(compiler) + #endif + +#endif + +//----------------------------------------------------------------------------- +// +// Purpose: Wrap around a variable to create a simple place to put a breakpoint +// + +#ifdef _DEBUG + +template< class Type > +class CDataWatcher +{ +public: + const Type& operator=( const Type &val ) + { + return Set( val ); + } + + const Type& operator=( const CDataWatcher<Type> &val ) + { + return Set( val.m_Value ); + } + + const Type& Set( const Type &val ) + { + // Put your breakpoint here + m_Value = val; + return m_Value; + } + + Type& GetForModify() + { + return m_Value; + } + + const Type& operator+=( const Type &val ) + { + return Set( m_Value + val ); + } + + const Type& operator-=( const Type &val ) + { + return Set( m_Value - val ); + } + + const Type& operator/=( const Type &val ) + { + return Set( m_Value / val ); + } + + const Type& operator*=( const Type &val ) + { + return Set( m_Value * val ); + } + + const Type& operator^=( const Type &val ) + { + return Set( m_Value ^ val ); + } + + const Type& operator|=( const Type &val ) + { + return Set( m_Value | val ); + } + + const Type& operator++() + { + return (*this += 1); + } + + Type operator--() + { + return (*this -= 1); + } + + Type operator++( int ) // postfix version.. + { + Type val = m_Value; + (*this += 1); + return val; + } + + Type operator--( int ) // postfix version.. + { + Type val = m_Value; + (*this -= 1); + return val; + } + + // For some reason the compiler only generates type conversion warnings for this operator when used like + // CNetworkVarBase<unsigned tchar> = 0x1 + // (it warns about converting from an int to an unsigned char). + template< class C > + const Type& operator&=( C val ) + { + return Set( m_Value & val ); + } + + operator const Type&() const + { + return m_Value; + } + + const Type& Get() const + { + return m_Value; + } + + const Type* operator->() const + { + return &m_Value; + } + + Type m_Value; + +}; + +#else + +template< class Type > +class CDataWatcher +{ +private: + CDataWatcher(); // refuse to compile in non-debug builds +}; + +#endif + +// Code for programmatically setting/unsetting hardware breakpoints (there's probably a 360 and +#ifdef IS_WINDOWS_PC + +typedef void * HardwareBreakpointHandle_t; + +enum EHardwareBreakpointType +{ + BREAKPOINT_EXECUTE = 0, + BREAKPOINT_WRITE, + BREAKPOINT_READWRITE, +}; + +enum EHardwareBreakpointSize +{ + BREAKPOINT_SIZE_1 = 1, + BREAKPOINT_SIZE_2 = 2, + BREAKPOINT_SIZE_4 = 4, + BREAKPOINT_SIZE_8 = 8, +}; + +PLATFORM_INTERFACE HardwareBreakpointHandle_t SetHardwareBreakpoint( EHardwareBreakpointType eType, EHardwareBreakpointSize eSize, const void *pvLocation ); +PLATFORM_INTERFACE bool ClearHardwareBreakpoint( HardwareBreakpointHandle_t handle ); + +class CHardwareBreakPointScopeGuard +{ +public: + CHardwareBreakPointScopeGuard( const void *pvLocation, size_t nLocationSize, EHardwareBreakpointType eType = BREAKPOINT_WRITE ) + { + EHardwareBreakpointSize eSize = BREAKPOINT_SIZE_4; + switch ( nLocationSize ) + { + case 1: + eSize = BREAKPOINT_SIZE_1; + break; + case 2: + eSize = BREAKPOINT_SIZE_2; + break; + case 4: + eSize = BREAKPOINT_SIZE_4; + break; + case 8: + eSize = BREAKPOINT_SIZE_8; + break; + default: + Warning( _T( "SetHardwareBreakpoint can only work with 1, 2, 4 or 8 byte data fields." ) ); + break; + } + + m_hBreakPoint = SetHardwareBreakpoint( eType, eSize, pvLocation ); + m_bActive = m_hBreakPoint != (HardwareBreakpointHandle_t)0; + } + + ~CHardwareBreakPointScopeGuard() + { + Release(); + } + + void Release() + { + if ( !m_bActive ) + return; + ClearHardwareBreakpoint( m_hBreakPoint ); + } + +private: + bool m_bActive; + HardwareBreakpointHandle_t m_hBreakPoint; +}; + +#endif // IS_WINDOWS_PC +//----------------------------------------------------------------------------- + +#endif /* DBG_H */ diff --git a/external/vpc/public/tier0/dbgflag.h b/external/vpc/public/tier0/dbgflag.h new file mode 100644 index 0000000..deee3e5 --- /dev/null +++ b/external/vpc/public/tier0/dbgflag.h @@ -0,0 +1,68 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: This file sets all of our debugging flags. It should be +// called before all other header files. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DBGFLAG_H +#define DBGFLAG_H +#ifdef _WIN32 +#pragma once +#endif + + +// Here are all the flags we support: +// DBGFLAG_MEMORY: Enables our memory debugging system, which overrides malloc & free +// DBGFLAG_MEMORY_NEWDEL: Enables new / delete tracking for memory debug system. Requires DBGFLAG_MEMORY to be enabled. +// DBGFLAG_VALIDATE: Enables our recursive validation system for checking integrity and memory leaks +// DBGFLAG_ASSERT: Turns Assert on or off (when off, it isn't compiled at all) +// DBGFLAG_ASSERTFATAL: Turns AssertFatal on or off (when off, it isn't compiled at all) +// DBGFLAG_ASSERTDLG: Turns assert dialogs on or off and debug breaks on or off when not under the debugger. +// (Dialogs will always be on when process is being debugged.) +// DBGFLAG_STRINGS: Turns on hardcore string validation (slow but safe) + +#undef DBGFLAG_MEMORY +#undef DBGFLAG_MEMORY_NEWDEL +#undef DBGFLAG_VALIDATE +#undef DBGFLAG_ASSERT +#undef DBGFLAG_ASSERTFATAL +#undef DBGFLAG_ASSERTDLG +#undef DBGFLAG_STRINGS + +//----------------------------------------------------------------------------- +// Default flags for debug builds +//----------------------------------------------------------------------------- +#if defined( _DEBUG ) && !defined( PS3MEMOVERRIDEWRAP ) + +#define DBGFLAG_MEMORY +#ifdef _SERVER // only enable new & delete tracking for server; on client it conflicts with CRT mem leak tracking +#define DBGFLAG_MEMORY_NEWDEL +#endif +#ifdef STEAM +#define DBGFLAG_VALIDATE +#endif +#define DBGFLAG_ASSERT +#define DBGFLAG_ASSERTFATAL +#define DBGFLAG_ASSERTDLG +#define DBGFLAG_STRINGS + + +//----------------------------------------------------------------------------- +// Default flags for release builds +//----------------------------------------------------------------------------- +#else // _DEBUG +#ifdef STEAM +#define DBGFLAG_ASSERT +#endif +#define DBGFLAG_ASSERTFATAL // note: fatal asserts are enabled in release builds +#define DBGFLAG_ASSERTDLG + +#endif // _DEBUG + +#if defined( _CERT ) +#define DBGFLAG_STRINGS_STRIP +#endif + +#endif // DBGFLAG_H diff --git a/external/vpc/public/tier0/etwprof.h b/external/vpc/public/tier0/etwprof.h new file mode 100644 index 0000000..ba9f8f5 --- /dev/null +++ b/external/vpc/public/tier0/etwprof.h @@ -0,0 +1,155 @@ +//============ Copyright (c) Valve Corporation, All rights reserved. ============ +// +// ETW (Event Tracing for Windows) profiling helpers. +// This allows easy insertion of Generic Event markers into ETW/xperf tracing +// which then aids in analyzing the traces and finding performance problems. +// The usage patterns are to use ETWBegin and ETWEnd (typically through the +// convenience class CETWScope) to bracket time-consuming operations. In addition +// ETWFrameMark marks the beginning of each frame, and ETWMark can be used to +// mark other notable events. More event types and providers can be added as needed. +// When recording xperf profiles add Valve-Main+Valve-FrameRate to the list of +// user-mode providers and be sure to register the providers with this sequence +// of commands: +// xcopy /y game\bin\tier0.dll %temp% +// wevtutil um src\tier0\ValveETWProvider.man +// wevtutil im src\tier0\ValveETWProvider.man +// +//=============================================================================== + +#ifndef ETWPROF_H +#define ETWPROF_H +#if defined( COMPILER_MSVC ) +#pragma once +#endif + +#include "tier0/platform.h" + +#ifdef IS_WINDOWS_PC +// ETW support should be compiled in for all Windows PC platforms. It isn't +// supported on Windows XP but that is determined at run-time. +#if !defined(STANDALONE_VPC) +#define ETW_MARKS_ENABLED +#endif +#endif + +#ifdef ETW_MARKS_ENABLED + +// Insert a single event to mark a point in an ETW trace. The return value is a 64-bit +// time stamp. +PLATFORM_INTERFACE int64 ETWMark( const char *pMessage ); +// Optionally do full printf formatting of the mark string. This will be more expensive, +// but only when tracing is enabled. +PLATFORM_INTERFACE int64 ETWMarkPrintf( PRINTF_FORMAT_STRING const char *pMessage, ... ) FMTFUNCTION( 1, 2 ); +// Optionally specify one to four floats. They will show up in separate columns in +// summary tables to allow sorting and easier transfer to spreadsheets. +PLATFORM_INTERFACE void ETWMark1F( const char *pMessage, float data1 ); +PLATFORM_INTERFACE void ETWMark2F( const char *pMessage, float data1, float data2 ); +PLATFORM_INTERFACE void ETWMark3F( const char *pMessage, float data1, float data2, float data3 ); +PLATFORM_INTERFACE void ETWMark4F( const char *pMessage, float data1, float data2, float data3, float data4 ); +// Optionally specify one to four ints. They will show up in separate columns in +// summary tables to allow sorting and easier transfer to spreadsheets. +PLATFORM_INTERFACE void ETWMark1I( const char *pMessage, int data1 ); +PLATFORM_INTERFACE void ETWMark2I( const char *pMessage, int data1, int data2 ); +PLATFORM_INTERFACE void ETWMark3I( const char *pMessage, int data1, int data2, int data3 ); +PLATFORM_INTERFACE void ETWMark4I( const char *pMessage, int data1, int data2, int data3, int data4 ); +// Optionally specify one to two strings. They will show up in separate columns in +// summary tables to allow sorting and easier transfer to spreadsheets. +PLATFORM_INTERFACE void ETWMark1S( const char *pMessage, const char* data1 ); +PLATFORM_INTERFACE void ETWMark2S( const char *pMessage, const char* data1, const char* data2 ); + +// Insert a begin event to mark the start of some work. The return value is a 64-bit +// time stamp which should be passed to the corresponding ETWEnd function. +PLATFORM_INTERFACE int64 ETWBegin( const char *pMessage ); + +// Insert a paired end event to mark the end of some work. +PLATFORM_INTERFACE int64 ETWEnd( const char *pMessage, int64 nStartTime ); + +// Mark the start of the next render frame. bIsServerProcess must be passed +// in consistently for a particular process. +PLATFORM_INTERFACE void ETWRenderFrameMark( bool bIsServerProcess ); +// Mark the start of the next simulation frame. bIsServerProcess must be passed +// in consistently for a particular process. +PLATFORM_INTERFACE void ETWSimFrameMark( bool bIsServerProcess ); +// Return the frame number recorded in the ETW trace -- useful for synchronization +// other profile information to the ETW trace. +PLATFORM_INTERFACE int ETWGetRenderFrameNumber(); + +PLATFORM_INTERFACE void ETWMouseDown( int nWhichButton, int nX, int nY ); +PLATFORM_INTERFACE void ETWMouseUp( int nWhichButton, int nX, int nY ); +PLATFORM_INTERFACE void ETWKeyDown( int nScanCode, int nVirtualCode, const char *pChar ); + +PLATFORM_INTERFACE void ETWSendPacket( const char *pTo, int nWireSize, int nOutSequenceNR, int nOutSequenceNrAck ); +PLATFORM_INTERFACE void ETWThrottled(); +PLATFORM_INTERFACE void ETWReadPacket( const char *pFrom, int nWireSize, int nInSequenceNR, int nOutSequenceNRAck ); + +// This class calls the ETW Begin and End functions in order to insert a +// pair of events to bracket some work. +class CETWScope +{ +public: + CETWScope( const char *pMessage ) + : m_pMessage( pMessage ) + { + m_nStartTime = ETWBegin( pMessage ); + } + ~CETWScope() + { + ETWEnd( m_pMessage, m_nStartTime ); + } +private: + // Private and unimplemented to disable copying. + CETWScope( const CETWScope& rhs ); + CETWScope& operator=( const CETWScope& rhs ); + + const char* m_pMessage; + int64 m_nStartTime; +}; + +#else + +inline int64 ETWMark( const char* ) { return 0; } +inline int64 ETWMarkPrintf( const char *, ... ) { return 0; } +inline void ETWMark1F( const char *, float ) { } +inline void ETWMark2F( const char *, float , float ) { } +inline void ETWMark3F( const char *, float , float , float ) { } +inline void ETWMark4F( const char *, float , float , float , float ) { } +inline void ETWMark1I( const char *, int ) { } +inline void ETWMark2I( const char *, int , int ) { } +inline void ETWMark3I( const char *, int , int , int ) { } +inline void ETWMark4I( const char *, int , int , int , int ) { } +// Optionally specify one to two strings. They will show up in separate columns in +// summary tables to allow sorting and easier transfer to spreadsheets. +inline void ETWMark1S( const char *, const char* ) { } +inline void ETWMark2S( const char *, const char* , const char* ) { } + +inline int64 ETWBegin( const char* ) { return 0; } +inline int64 ETWEnd( const char*, int64 ) { return 0; } +inline void ETWRenderFrameMark( bool ) {} +inline void ETWSimFrameMark( bool ) {} +inline int ETWGetRenderFrameNumber() { return 0; } + +inline void ETWMouseDown( int nWhichButton, int nX, int nY ) {} +inline void ETWMouseUp( int nWhichButton, int nX, int nY ) {} +inline void ETWKeyDown( int nScanCode, int nVirtualCode, const char *pChar ) {} + +inline void ETWSendPacket( const char *pTo, int nWireSize, int nOutSequenceNR, int nOutSequenceNrAck ) {} +inline void ETWThrottled() {} +inline void ETWReadPacket( const char *pFrom, int nWireSize, int nInSequenceNR, int nOutSequenceNRAck ) {} + +// This class calls the ETW Begin and End functions in order to insert a +// pair of events to bracket some work. +class CETWScope +{ +public: + CETWScope( const char* ) + { + } +private: + // Private and unimplemented to disable copying. + CETWScope( const CETWScope& rhs ); + CETWScope& operator=( const CETWScope& rhs ); +}; + +#endif + +#endif // ETWPROF_H diff --git a/external/vpc/public/tier0/eventmasks.h b/external/vpc/public/tier0/eventmasks.h new file mode 100644 index 0000000..4774809 --- /dev/null +++ b/external/vpc/public/tier0/eventmasks.h @@ -0,0 +1,480 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#pragma once + +typedef union EVENT_MASK(TC_deliver_mode) +{ + struct + { + uint16 DD:1; // both logical processors in deliver mode }, + uint16 DB:1; // logical processor 0 in deliver mode, 1 in build mode }, + uint16 DI:1; // logical processor 0 in deliver mode, 1 is inactive }, + uint16 BD:1; // logical processor 0 in build mode, 1 in deliver mode }, + uint16 BB:1; // both logical processors in build mode }, + uint16 BI:1; // logical processor 0 in build mode, 1 is inactive }, + uint16 ID:1; // logical processor 0 is inactive, 1 in deliver mode }, + uint16 IB:1; // logical processor 0 is inactive, 1 in build mode } + }; + uint16 flat; +} EVENT_MASK(TC_deliver_mode); + +typedef union EVENT_MASK(BPU_fetch_request) +{ + + struct + { + uint16 TCMISS:1; // Trace cache lookup miss }, + }; + uint16 flat; +} EVENT_MASK(BPU_fetch_request); + + +typedef union EVENT_MASK(ITLB_reference) +{ + struct + { + uint16 HIT : 1; //ITLB hit }, + uint16 MISS : 1;//ITLB miss }, + uint16 HIT_UC :1; // Uncacheable ITLB hit } + }; + uint16 flat; +} EVENT_MASK(ITLB_reference); + +typedef union EVENT_MASK(memory_cancel) +{ + struct + { + uint16 dummy : 2; + + uint16 ST_RB_FULL:1; //Replayed because no store request buffer is available }, + uint16 _64K_CONF:1; //Conflicts due to 64K aliasing } + }; + uint16 flat; +}EVENT_MASK(memory_cancel); + +typedef union EVENT_MASK(memory_complete) +{ + struct + { + uint16 LSC:1; // Load split completed, excluding UC/WC loads }, + uint16 SSC:1; //Any split stores completed } } + }; + uint16 flat; +} EVENT_MASK(memory_complete); + +typedef union EVENT_MASK(load_port_replay) +{ + struct + { + uint16 dummy:1; + uint16 SPLIT_LD:1; //Split load } } + }; + uint16 flat; +} EVENT_MASK(load_port_replay); + +typedef union EVENT_MASK(store_port_replay) +{ + struct + { + uint16 dummy0:1; + uint16 SPLIT_ST:1; //Split store } } + + }; + uint16 flat; +} EVENT_MASK(store_port_replay); + +typedef union EVENT_MASK(MOB_load_replay) +{ + struct + { + uint16 dummy0:1; + + uint16 NO_STA:1; //Replayed because of unknown store address }, + + uint16 dummy2:1; + + uint16 NO_STD:1; //Replayed because of unknown store data }, + uint16 PARTIAL_DATA:1; //Replayed because of partially overlapped data access between the load and store operations }, + uint16 UNALGN_ADDR:1; //Replayed because the lower 4 bits of the linear address do not match between the load and store operations } } + }; + uint16 flat; +}EVENT_MASK(MOB_load_replay); + +typedef union EVENT_MASK(page_walk_type) +{ + struct + { + uint16 DTMISS:1; // Page walk for a data TLB miss }, + uint16 ITMISS:1; // Page walk for an instruction TLB miss } } + }; + uint16 flat; +}EVENT_MASK(page_walk_type); + + +typedef union EVENT_MASK(BSQ_cache_reference) +{ + struct + { + uint16 RD_2ndL_HITS:1; // Read 2nd level cache hit Shared }, + uint16 RD_2ndL_HITE:1; // Read 2nd level cache hit Exclusive }, + uint16 RD_2ndL_HITM:1; // Read 2nd level cache hit Modified }, + uint16 RD_3rdL_HITS:1; // Read 3rd level cache hit Shared }, + uint16 RD_3rdL_HITE:1; // Read 3rd level cache hit Exclusive }, + uint16 RD_3rdL_HITM:1; // Read 3rd level cache hit Modified }, + uint16 dummy6:1; + uint16 dummy7:1; + uint16 RD_2ndL_MISS:1; // Read 2nd level cache miss }, + uint16 RD_3rdL_MISS:1; // Read 3rd level cache miss }, + uint16 WR_2ndL_MISS:1; // Writeback lookup from DAC misses the 2nd level cache } } + }; + uint16 flat; +} EVENT_MASK(BSQ_cache_reference) ; + +typedef union EVENT_MASK(IOQ) +{ + struct + { + uint16 bit0:1; // bus request type (use 00001 for invalid or default) + uint16 bit1:1; // + uint16 bit2:1; // + uint16 bit3:1; // + uint16 bit4:1; // + uint16 ALL_READ:1; // Count read entries }, + uint16 ALL_WRITE:1; // Count write entries }, + uint16 MEM_UC:1; // Count UC memory access entries }, + uint16 MEM_WC:1; // Count WC memory access entries }, + uint16 MEM_WT:1; // Count WT memory access entries }, + uint16 MEM_WP:1; // Count WP memory access entries }, + uint16 MEM_WB:1; // Count WB memory access entries }, + uint16 dummy12:1; + + uint16 OWN:1; // Count own store requests }, + uint16 OTHER:1; // Count other and DMA store requests }, + uint16 PREFETCH:1; // Include HW and SW prefetch requests } } + }; + uint16 flat; +} EVENT_MASK(IOQ) ; + +typedef union EVENT_MASK(FSB_data_activity) +{ + struct + { + /* DRDY_OWN is mutually exclusive with DRDY_OTHER */ + /* DBSY_OWN is mutually exclusive with DBSY_OTHER */ + uint16 DRDY_DRV:1; // Count when this processor drives data onto the bus }, + uint16 DRDY_OWN:1; // Count when this processor reads data from the bus }, + uint16 DRDY_OTHER:1; // Count when data is on the bus but not being sampled by the processor }, + uint16 DBSY_DRV:1; // Count when this processor reserves the bus for driving data }, + uint16 DBSY_OWN:1; // Count when this processor reserves the bus for sampling data }, + uint16 DBSY_OTHER:1; // Count when the bus is reserved for driving data this processor will not sample } } + }; + uint16 flat; +}EVENT_MASK(FSB_data_activity); + +typedef union EVENT_MASK(BSQ) +{ + struct + { + uint16 REQ_TYPE0:1; // Request type encoding bit 0 }, + uint16 REQ_TYPE1:1; // Request type encoding bit 1 }, + uint16 REQ_LEN0:1; // Request length encoding bit 0 }, + uint16 REQ_LEN1:1; // Request length encoding bit 1 }, + uint16 dummy4: 1; + uint16 REQ_IO_TYPE:1; // Request type is input or output }, + uint16 REQ_LOCK_TYPE:1; // Request type is bus lock }, + uint16 REQ_CACHE_TYPE:1; // Request type is cacheable }, + uint16 REQ_SPLIT_TYPE:1; // Request type is a bus 8-byte chunk split across 8-byte boundary }, + uint16 REQ_DEM_TYPE:1; // Request type is a demand (1) or prefetch (0) }, + uint16 REQ_ORD_TYPE:1; // Request is an ordered type }, + uint16 MEM_TYPE0:1; // Memory type encoding bit 0 }, + uint16 MEM_TYPE1:1; // Memory type encoding bit 1 }, + uint16 MEM_TYPE2:1; // Memory type encoding bit 2 } } + }; + uint16 flat; +} EVENT_MASK(BSQ); + +typedef union EVENT_MASK(firm_uop) +{ + struct + { + uint16 dummy15 : 15; + uint16 ALL:1; // count all uops of this type } } + }; + uint16 flat; +} EVENT_MASK(firm_uop); + + + +typedef union EVENT_MASK(TC_misc) +{ + struct + { + uint16 dymmy4 : 4; + uint16 FLUSH:1; // Number of flushes } } + }; + uint16 flat; +} EVENT_MASK(TC_misc); + +typedef union EVENT_MASK(global_power_events) +{ + struct + { + uint16 Running:1; // The processor is active } } + }; + uint16 flat; +} EVENT_MASK(global_power_events); + +typedef union EVENT_MASK(tc_ms_xfer) +{ + struct + { + uint16 CISC:1; // A TC to MS transfer ocurred } } + }; + uint16 flat; +}EVENT_MASK(tc_ms_xfer); + + + +typedef union EVENT_MASK(uop_queue_writes) +{ + struct + { + uint16 FROM_TC_BUILD:1; // uops written from TC build mode + uint16 FROM_TC_DELIVER:1; // uops written from TC deliver mode + uint16 FROM_ROM:1; // uops written from microcode ROM } } + }; + uint16 flat; +} EVENT_MASK(uop_queue_writes); + +typedef union EVENT_MASK(branch_type) +{ + struct + { + uint16 dummy : 1; + uint16 CONDITIONAL:1; // Conditional jumps + uint16 CALL:1; // Direct or indirect call + uint16 RETURN:1; // Return branches + uint16 INDIRECT:1; // Returns, indirect calls, or indirect jumps + }; + uint16 flat; +} EVENT_MASK(branch_type); + + + +typedef union EVENT_MASK(resource_stall) +{ + struct + { + uint16 dummy1 : 5; + uint16 SBFULL:1; // A Stall due to lack of store buffers } } + }; + uint16 flat; +} EVENT_MASK(resource_stall); + + + + +typedef union EVENT_MASK(WC_Buffer) +{ + struct + { + uint16 WCB_EVICTS : 1; // all causes }, + uint16 WCB_FULL_EVICT : 1; // no WC buffer is available }, + /* XXX: 245472-011 no longer lists bit 2, but that looks like + a table formatting error. Keeping it for now. */ + uint16 WCB_HITM_EVICT : 1; // store encountered a Hit Modified condition } } + }; + uint16 flat; +} EVENT_MASK(WC_Buffer); + + +typedef union EVENT_MASK(b2b_cycles) +{ + struct + { + uint16 dummy0 : 1; + uint16 bit1 : 1; // + uint16 bit2 : 1; // + uint16 bit3 : 1; // + uint16 bit4 : 1; // + uint16 bit5 : 1; // + uint16 bit6 : 1; // + + }; + uint16 flat; +} EVENT_MASK(b2b_cycles); + +typedef union EVENT_MASK(bnr) +{ + struct + { + uint16 bit0:1; // + uint16 bit1:1; // + uint16 bit2:1; // + }; + uint16 flat; +} EVENT_MASK(bnr); + + +typedef union EVENT_MASK(snoop) +{ + struct + { + uint16 dummy0 : 1; + uint16 dummy1 : 1; + + uint16 bit2:1; // + uint16 dummy3:1; // + uint16 dummy4:1; // + uint16 dummy5:1; // + uint16 bit6:1; // + uint16 bit7:1; // + }; + uint16 flat; +} EVENT_MASK(snoop); + + +typedef union EVENT_MASK(response) +{ + struct + { + uint16 dummy0:1; // + uint16 bit1:1; // + uint16 bit2:1; // + uint16 dummy3:1; // + uint16 dummy4:1; // + uint16 dummy5:1; // + uint16 dummy6:1; // + uint16 dummy7:1; // + uint16 bit8:1; // + uint16 bit9:1; // + }; + uint16 flat; +} EVENT_MASK(response); + + +typedef union EVENT_MASK(nbogus_bogus) +{ + struct + { + uint16 NBOGUS:1; // The marked uops are not bogus + uint16 BOGUS:1; // The marked uops are bogus + }; + uint16 flat; +} EVENT_MASK(nbogus_bogus); + + +typedef union EVENT_MASK(execution_event) +{ + struct + { + uint16 NBOGUS0:1; // non-bogus uops with tag bit 0 set }, + uint16 NBOGUS1:1; // non-bogus uops with tag bit 1 set }, + uint16 NBOGUS2:1; // non-bogus uops with tag bit 2 set }, + uint16 NBOGUS3:1; // non-bogus uops with tag bit 3 set }, + uint16 BOGUS0:1; // bogus uops with tag bit 0 set }, + uint16 BOGUS1:1; // bogus uops with tag bit 1 set }, + uint16 BOGUS2:1; // bogus uops with tag bit 2 set }, + uint16 BOGUS3:1; // bogus uops with tag bit 3 set } } + }; + uint16 flat; +}EVENT_MASK(execution_event); + +typedef union EVENT_MASK(instr_retired) +{ + struct + { + uint16 NBOGUSNTAG:1; // Non-bogus instructions that are not tagged }, + uint16 NBOGUSTAG:1; // Non-bogus instructions that are tagged }, + uint16 BOGUSNTAG:1; // Bogus instructions that are not tagged }, + uint16 BOGUSTAG:1; // Bogus instructions that are tagged } } + }; + uint16 flat; +} EVENT_MASK(instr_retired); + + +typedef union EVENT_MASK(uop_type) +{ + struct + { + uint16 dummy0 : 1; + uint16 TAGLOADS:1; // The uop is a load operation }, + uint16 TAGSTORES:1; // The uop is a store operation } } + }; + uint16 flat; +} EVENT_MASK(uop_type); + +typedef union EVENT_MASK(branch_retired) +{ + struct + { + uint16 MMNP:1; // Branch Not-taken Predicted + uint16 MMNM:1; // Branch Not-taken Mispredicted + uint16 MMTP:1; // Branch Taken Predicted + uint16 MMTM:1; // Branch Taken Mispredicted + }; + uint16 flat; +} EVENT_MASK(branch_retired); + +typedef union EVENT_MASK(mispred_branch_retired) +{ + struct + { + uint16 NBOGUS:1; // The retired branch is not bogus } } + }; + uint16 flat; +} EVENT_MASK(mispred_branch_retired); + + +typedef union EVENT_MASK(x87_assist) +{ + struct + { + uint16 FPSU:1; // FP stack underflow }, + uint16 FPSO:1; // FP stack overflow }, + uint16 POAO:1; // x87 output overflow }, + uint16 POAU:1; // x87 output underflow }, + uint16 PREA:1; // x87 input assist } } + }; + uint16 flat; +}EVENT_MASK(x87_assist); + +typedef union EVENT_MASK(machine_clear) +{ + struct + { + uint16 CLEAR:1; // Count a portion of the cycles when the machine is cleared }, + uint16 dummy1: 1; + uint16 MOCLEAR:1; // Count clears due to memory ordering issues }, + uint16 dummy3: 1; + uint16 dummy4: 1; + uint16 dummy5: 1; + + uint16 SMCLEAR:1;// Count clears due to self-modifying code issues } } + }; + uint16 flat; +} EVENT_MASK(machine_clear); + + +typedef union EVENT_MASK(x87_SIMD_moves_uop) +{ + struct + { + uint16 dummy3:3; + uint16 ALLP0:1; // Count all x87/SIMD store/move uops }, + uint16 ALLP2:1; // count all x87/SIMD load uops } } + }; + uint16 flat; +} EVENT_MASK(x87_SIMD_moves_uop); + + + + + + + diff --git a/external/vpc/public/tier0/eventmodes.h b/external/vpc/public/tier0/eventmodes.h new file mode 100644 index 0000000..05e5b21 --- /dev/null +++ b/external/vpc/public/tier0/eventmodes.h @@ -0,0 +1,1787 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef EVENTMODES_H +#define EVENTMODES_H + + +#pragma once + +/* + + + + Event Modes to choose from: + + P4Event_TC_deliver_mode + + P4Event_BPU_fetch_request + + P4Event_ITLB_reference + + P4Event_memory_cancel + + P4Event_memory_complete + + P4Event_load_port_replay + + P4Event_store_port_replay + + P4Event_MOB_load_replay + + P4Event_page_walk_type + + P4Event_BSQ_cache_reference + + P4Event_IOQ_allocation + + P4Event_IOQ_active_entries + + P4Event_FSB_data_activity + + P4Event_BSQ_allocation + + P4Event_BSQ_active_entries + + P4Event_SSE_input_assist + + P4Event_packed_SP_uop + + P4Event_packed_DP_uop + + P4Event_scalar_SP_uop + + P4Event_scalar_DP_uop + + P4Event_64bit_MMX_uop + + P4Event_128bit_MMX_uop + + P4Event_x87_FP_uop + + P4Event_x87_SIMD_moves_uop + + P4Event_TC_misc + + P4Event_global_power_events + + P4Event_tc_ms_xfer + + P4Event_uop_queue_writes + + P4Event_retired_mispred_branch_type + + P4Event_retired_branch_type + + P4Event_resource_stall + + P4Event_WC_Buffer + + P4Event_b2b_cycles + + P4Event_bnr + + P4Event_snoop + + P4Event_response + + P4Event_front_end_event + + P4Event_execution_event + + P4Event_replay_event + + P4Event_instr_retired + + P4Event_uops_retired + + P4Event_uop_type + + P4Event_branch_retired + + P4Event_mispred_branch_retired + + P4Event_x87_assist + + P4Event_machine_clear + + +*/ + + + +class P4P4Event_TC_deliver_mode: public P4BaseEvent +{ +public: + EVENT_MASK(TC_deliver_mode) * eventMask; + + P4P4Event_TC_deliver_mode() + { + eventMask = (EVENT_MASK(TC_deliver_mode) *)&m_eventMask; + + escr.ESCREventSelect = 0x01; + cccr.CCCRSelect = 0x01; + //// eventType = EVENT_TYPE(TC_deliver_mode); + description = _T("TC_deliver_mode"); + UseCounter4(); + } + + + void UseCounter4() + { + SetCounter(4);; + } + void UseCounter5() + { + SetCounter(5); + } + void UseCounter6() + { + SetCounter(6); + } + void UseCounter7() + { + SetCounter(7); + } +}; + +class P4P4Event_BPU_fetch_request: public P4BaseEvent + +{ +public: + EVENT_MASK(BPU_fetch_request)* eventMask; + + P4P4Event_BPU_fetch_request() + { + eventMask = (EVENT_MASK(BPU_fetch_request) *)&m_eventMask; + + escr.ESCREventSelect= 0x03; + cccr.CCCRSelect= 0x00; + // eventType = EVENT_TYPE(BPU_fetch_request); + description=_T("BPU_fetch_request"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } + +}; +class P4P4Event_ITLB_reference: public P4BaseEvent + +{ +public: + EVENT_MASK(ITLB_reference) * eventMask; + + P4P4Event_ITLB_reference() + { + eventMask = (EVENT_MASK(ITLB_reference) *)&m_eventMask; + + escr.ESCREventSelect= 0x18; + cccr.CCCRSelect= 0x03; + // eventType=EVENT_TYPE(ITLB_reference); + description=_T("ITLB_reference"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_memory_cancel: public P4BaseEvent + +{ +public: + EVENT_MASK(memory_cancel) * eventMask; + + P4Event_memory_cancel() + { + eventMask = (EVENT_MASK(memory_cancel) *)&m_eventMask; + + escr.ESCREventSelect= 0x02; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(memory_cancel); + description=_T("memory_cancel"); + UseCounter8(); + } + + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_memory_complete: public P4BaseEvent + +{ +public: + EVENT_MASK(memory_complete) * eventMask; + + P4Event_memory_complete() + { + eventMask = (EVENT_MASK(memory_complete) *)&m_eventMask; + + escr.ESCREventSelect= 0x08; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(memory_complete); + description=_T("memory_complete"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_load_port_replay: public P4BaseEvent + +{ +public: + EVENT_MASK(load_port_replay) * eventMask; + + P4Event_load_port_replay() + { + eventMask = (EVENT_MASK(load_port_replay) *)&m_eventMask; + + escr.ESCREventSelect= 0x04; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(load_port_replay); + description=_T("load_port_replay"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_store_port_replay: public P4BaseEvent + +{ +public: + EVENT_MASK(store_port_replay) * eventMask; + + P4Event_store_port_replay() + { + eventMask = (EVENT_MASK(store_port_replay) *)&m_eventMask; + + escr.ESCREventSelect= 0x05; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(store_port_replay); + description=_T("store_port_replay"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_MOB_load_replay: public P4BaseEvent + +{ +public: + EVENT_MASK(MOB_load_replay) * eventMask; + + P4Event_MOB_load_replay() + { + eventMask = (EVENT_MASK(MOB_load_replay) *)&m_eventMask; + + escr.ESCREventSelect= 0x03; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(MOB_load_replay); + description=_T("MOB_load_replay"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_page_walk_type: public P4BaseEvent + +{ +public: + EVENT_MASK(page_walk_type) * eventMask; + + P4Event_page_walk_type() + { + eventMask = (EVENT_MASK(page_walk_type) *)&m_eventMask; + + escr.ESCREventSelect= 0x01; + cccr.CCCRSelect= 0x04; + // eventType=EVENT_TYPE(page_walk_type); + description=_T("page_walk_type"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_BSQ_cache_reference: public P4BaseEvent + +{ +public: + EVENT_MASK(BSQ_cache_reference) * eventMask; + + P4Event_BSQ_cache_reference() + { + eventMask = (EVENT_MASK(BSQ_cache_reference) *)&m_eventMask; + + escr.ESCREventSelect= 0x0C; + cccr.CCCRSelect= 0x07; + // eventType=EVENT_TYPE(BSQ_cache_reference); + description=_T("BSQ_cache_reference"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_IOQ_allocation: public P4BaseEvent + +{ +public: + EVENT_MASK(IOQ) * eventMask; + + P4Event_IOQ_allocation() + { + eventMask = (EVENT_MASK(IOQ) *)&m_eventMask; + + escr.ESCREventSelect= 0x03; + cccr.CCCRSelect= 0x06; + // eventType=EVENT_TYPE(IOQ); + description=_T("IOQ_allocation"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_IOQ_active_entries: public P4BaseEvent + +{ +public: + EVENT_MASK(IOQ) * eventMask; + + P4Event_IOQ_active_entries() + { + eventMask = (EVENT_MASK(IOQ) *)&m_eventMask; + + escr.ESCREventSelect= 0x1A; + cccr.CCCRSelect= 0x06; + // eventType=EVENT_TYPE(IOQ); + description=_T("IOQ_active_entries"); + UseCounter2(); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_FSB_data_activity: public P4BaseEvent + +{ +public: + EVENT_MASK(FSB_data_activity) * eventMask; + + P4Event_FSB_data_activity() + { + eventMask = (EVENT_MASK(FSB_data_activity) *)&m_eventMask; + + escr.ESCREventSelect= 0x17; + cccr.CCCRSelect= 0x06; + // eventType=EVENT_TYPE(FSB_data_activity); + description=_T("FSB_data_activity"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_BSQ_allocation: public P4BaseEvent + +{ +public: + EVENT_MASK(BSQ) * eventMask; + + P4Event_BSQ_allocation() + { + eventMask = (EVENT_MASK(BSQ) *)&m_eventMask; + + escr.ESCREventSelect= 0x05; + cccr.CCCRSelect= 0x07; + // eventType=EVENT_TYPE(BSQ); + description=_T("BSQ_allocation"); + UseCounter0(); + } + + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + + } +}; +class P4Event_BSQ_active_entries: public P4BaseEvent + +{ +public: + EVENT_MASK(BSQ) * eventMask; + + P4Event_BSQ_active_entries() + { + eventMask = (EVENT_MASK(BSQ) *)&m_eventMask; + + escr.ESCREventSelect= 0x06; + cccr.CCCRSelect= 0x07; + // eventType=EVENT_TYPE(BSQ); + description=_T("bsq_active_entries"); + UseCounter2(); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_SSE_input_assist: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_SSE_input_assist() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x34; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("SSE_input_assist"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_packed_SP_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_packed_SP_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x08; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("packed_SP_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_packed_DP_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_packed_DP_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x0C; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("packed_DP_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_scalar_SP_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_scalar_SP_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x0A; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("scalar_SP_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_scalar_DP_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_scalar_DP_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x0E; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("scalar_DP_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_64bit_MMX_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_64bit_MMX_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x02; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("64bit_MMX_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_128bit_MMX_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_128bit_MMX_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x1A; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("128bit_MMX_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_x87_FP_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_x87_FP_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x04; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("x87_FP_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_x87_SIMD_moves_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(x87_SIMD_moves_uop) * eventMask; + + P4Event_x87_SIMD_moves_uop() + { + eventMask = (EVENT_MASK(x87_SIMD_moves_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x2E; + cccr.CCCRSelect= 0; + // eventType=EVENT_TYPE(x87_SIMD_moves_uop); + description=_T("x87_SIMD_moves_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_TC_misc: public P4BaseEvent + +{ +public: + EVENT_MASK(TC_misc) * eventMask; + + P4Event_TC_misc() + { + eventMask = (EVENT_MASK(TC_misc) *)&m_eventMask; + + escr.ESCREventSelect= 0x06; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(TC_misc); + description=_T("TC_misc"); + UseCounter4(); + } + + void UseCounter4() + { + SetCounter(4);; + } + void UseCounter5() + { + SetCounter(5); + } + void UseCounter6() + { + SetCounter(6); + } + void UseCounter7() + { + SetCounter(7); + } +}; +class P4Event_global_power_events: public P4BaseEvent + +{ +public: + EVENT_MASK(global_power_events) * eventMask; + + P4Event_global_power_events() + { + eventMask = (EVENT_MASK(global_power_events) *)&m_eventMask; + + escr.ESCREventSelect= 0x13; + cccr.CCCRSelect= 0x06; + // eventType=EVENT_TYPE(global_power_events); + description=_T("global_power_events"); + UseCounter0(); + } + + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_tc_ms_xfer: public P4BaseEvent + +{ +public: + EVENT_MASK(tc_ms_xfer) * eventMask; + + P4Event_tc_ms_xfer() + { + eventMask = (EVENT_MASK(tc_ms_xfer) *)&m_eventMask; + + escr.ESCREventSelect= 0x05; + cccr.CCCRSelect= 0x00; + // eventType=EVENT_TYPE(tc_ms_xfer); + description=_T("tc_ms_xfer"); + UseCounter4(); + } + + void UseCounter4() + { + SetCounter(4);; + } + void UseCounter5() + { + SetCounter(5); + } + void UseCounter6() + { + SetCounter(6); + } + void UseCounter7() + { + SetCounter(7); + } +}; +class P4Event_uop_queue_writes: public P4BaseEvent + +{ +public: + EVENT_MASK(uop_queue_writes) * eventMask; + + P4Event_uop_queue_writes() + { + eventMask = (EVENT_MASK(uop_queue_writes) *)&m_eventMask; + + escr.ESCREventSelect= 0x09; + cccr.CCCRSelect= 0x00; + // eventType=EVENT_TYPE(uop_queue_writes); + description=_T("uop_queue_writes"); + UseCounter4(); + } + + void UseCounter4() + { + SetCounter(4);; + } + void UseCounter5() + { + SetCounter(5); + } + void UseCounter6() + { + SetCounter(6); + } + void UseCounter7() + { + SetCounter(7); + } +}; +class P4Event_retired_mispred_branch_type: public P4BaseEvent + +{ +public: + EVENT_MASK(branch_type) * eventMask; + + P4Event_retired_mispred_branch_type() + { + eventMask = (EVENT_MASK(branch_type) *)&m_eventMask; + + escr.ESCREventSelect= 0x05; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(branch_type); + description=_T("retired_mispred_branch_type"); + UseCounter4(); + } + + void UseCounter4() + { + SetCounter(4);; + } + void UseCounter5() + { + SetCounter(5); + } + void UseCounter6() + { + SetCounter(6); + } + void UseCounter7() + { + SetCounter(7); + } +}; +class P4Event_retired_branch_type: public P4BaseEvent + +{ +public: + EVENT_MASK(branch_type) * eventMask; + + P4Event_retired_branch_type() + { + eventMask = (EVENT_MASK(branch_type) *)&m_eventMask; + + escr.ESCREventSelect= 0x04; + cccr.CCCRSelect= 0x04; + // eventType=EVENT_TYPE(branch_type); + description=_T("retired_branch_type"); + UseCounter4(); + } + + void UseCounter4() + { + SetCounter(4);; + } + void UseCounter5() + { + SetCounter(5); + } + void UseCounter6() + { + SetCounter(6); + } + void UseCounter7() + { + SetCounter(7); + } +}; +class P4Event_resource_stall: public P4BaseEvent + +{ +public: + EVENT_MASK(resource_stall) * eventMask; + + P4Event_resource_stall() + { + eventMask = (EVENT_MASK(resource_stall) *)&m_eventMask; + + escr.ESCREventSelect= 0x01; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(resource_stall); + description=_T("resource_stall"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } + +}; +class P4Event_WC_Buffer: public P4BaseEvent + +{ +public: + EVENT_MASK(WC_Buffer) * eventMask; + + P4Event_WC_Buffer() + { + eventMask = (EVENT_MASK(WC_Buffer) *)&m_eventMask; + + escr.ESCREventSelect= 0x05; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(WC_Buffer); + description=_T("WC_Buffer"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_b2b_cycles: public P4BaseEvent + +{ +public: + EVENT_MASK(b2b_cycles) * eventMask; + + P4Event_b2b_cycles() + { + eventMask = (EVENT_MASK(b2b_cycles) *)&m_eventMask; + + escr.ESCREventSelect= 0x16; + cccr.CCCRSelect= 0x03; + // eventType=EVENT_TYPE(b2b_cycles); + description=_T("b2b_cycles"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_bnr: public P4BaseEvent + +{ +public: + EVENT_MASK(bnr) * eventMask; + + P4Event_bnr() + { + eventMask = (EVENT_MASK(bnr) *)&m_eventMask; + + escr.ESCREventSelect= 0x08; + cccr.CCCRSelect= 0x03; + // eventType=EVENT_TYPE(bnr); + description=_T("bnr"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_snoop: public P4BaseEvent + +{ +public: + EVENT_MASK(snoop) * eventMask; + + P4Event_snoop() + { + eventMask = (EVENT_MASK(snoop) *)&m_eventMask; + + escr.ESCREventSelect= 0x06; + cccr.CCCRSelect= 0x03; + // eventType=EVENT_TYPE(snoop); + description=_T("snoop"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_response: public P4BaseEvent + +{ +public: + EVENT_MASK(response) * eventMask; + + P4Event_response() + { + eventMask = (EVENT_MASK(response) *)&m_eventMask; + + escr.ESCREventSelect= 0x04; + cccr.CCCRSelect= 0x03; + // eventType=EVENT_TYPE(response); + description=_T("response"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_front_end_event: public P4BaseEvent + +{ +public: + EVENT_MASK(nbogus_bogus) * eventMask; + + P4Event_front_end_event() + { + eventMask = (EVENT_MASK(nbogus_bogus) *)&m_eventMask; + + escr.ESCREventSelect= 0x08; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(nbogus_bogus); + description=_T("front_end_event"); + UseCounter12(); + } + + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_execution_event: public P4BaseEvent + +{ +public: + EVENT_MASK(execution_event) * eventMask; + + P4Event_execution_event() + { + eventMask = (EVENT_MASK(execution_event) *)&m_eventMask; + + escr.ESCREventSelect= 0x0C; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(execution_event); + description=_T("execution_event"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_replay_event: public P4BaseEvent + +{ +public: + EVENT_MASK(nbogus_bogus) * eventMask; + + P4Event_replay_event() + { + eventMask = (EVENT_MASK(nbogus_bogus) *)&m_eventMask; + + escr.ESCREventSelect= 0x09; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(nbogus_bogus); + description=_T("replay_event"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_instr_retired: public P4BaseEvent + +{ +public: + EVENT_MASK(instr_retired) * eventMask; + + P4Event_instr_retired() + { + eventMask = (EVENT_MASK(instr_retired) *)&m_eventMask; + + escr.ESCREventSelect= 0x02; + cccr.CCCRSelect= 0x04; + // eventType=EVENT_TYPE(instr_retired); + description=_T("instr_retired"); + UseCounter12(); + } + + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_uops_retired: public P4BaseEvent + +{ +public: + EVENT_MASK(nbogus_bogus) * eventMask; + + P4Event_uops_retired() + { + eventMask = (EVENT_MASK(nbogus_bogus) *)&m_eventMask; + + escr.ESCREventSelect= 0x01; + cccr.CCCRSelect= 0x04; + // eventType=EVENT_TYPE(nbogus_bogus); + description=_T("uops_retired"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_uop_type: public P4BaseEvent + +{ +public: + EVENT_MASK(uop_type) * eventMask; + + P4Event_uop_type() + { + eventMask = (EVENT_MASK(uop_type) *)&m_eventMask; + + escr.ESCREventSelect= 0x02; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(uop_type); + description=_T("uop_type"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_branch_retired: public P4BaseEvent + +{ +public: + EVENT_MASK(branch_retired) * eventMask; + + P4Event_branch_retired() + { + eventMask = (EVENT_MASK(branch_retired) *)&m_eventMask; + + escr.ESCREventSelect= 0x06; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(branch_retired); + description=_T("branch_retired"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_mispred_branch_retired: public P4BaseEvent + +{ +public: + EVENT_MASK(mispred_branch_retired) * eventMask; + + P4Event_mispred_branch_retired() + { + eventMask = (EVENT_MASK(mispred_branch_retired) *)&m_eventMask; + + escr.ESCREventSelect= 0x03; + cccr.CCCRSelect= 0x04; + // eventType=EVENT_TYPE(mispred_branch_retired); + description=_T("mispred_branch_retired"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_x87_assist: public P4BaseEvent + +{ +public: + EVENT_MASK(x87_assist) * eventMask; + + P4Event_x87_assist() + { + eventMask = (EVENT_MASK(x87_assist) *)&m_eventMask; + + escr.ESCREventSelect= 0x03; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(x87_assist); + description=_T("x87_assist"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_machine_clear: public P4BaseEvent + +{ +public: + EVENT_MASK(machine_clear) * eventMask; + + P4Event_machine_clear() + { + eventMask = (EVENT_MASK(machine_clear) *)&m_eventMask; + escr.ESCREventSelect= 0x02; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(machine_clear); + description=_T("machine_clear"); + UseCounter12(); + } + + + + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } + +}; + +#endif // EVENTMODES_H diff --git a/external/vpc/public/tier0/fasttimer.h b/external/vpc/public/tier0/fasttimer.h new file mode 100644 index 0000000..a820a60 --- /dev/null +++ b/external/vpc/public/tier0/fasttimer.h @@ -0,0 +1,625 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef FASTTIMER_H +#define FASTTIMER_H +#ifdef _WIN32 +#pragma once +#endif + +#include <assert.h> +#include "tier0/platform.h" +#ifdef _PS3 +#include "sys/sys_time.h" +#else +inline uint64 sys_time_get_timebase_frequency() +{ + DebuggerBreak(); // Error("sys_time_get_timebase_frequency called on non-PS3 platform."); + return 1; // this function should never ever be called. +} +#endif + +PLATFORM_INTERFACE uint64 g_ClockSpeed; +PLATFORM_INTERFACE unsigned long g_dwClockSpeed; + +PLATFORM_INTERFACE double g_ClockSpeedMicrosecondsMultiplier; +PLATFORM_INTERFACE double g_ClockSpeedMillisecondsMultiplier; +PLATFORM_INTERFACE double g_ClockSpeedSecondsMultiplier; + +#ifdef COMPILER_MSVC64 +extern "C" +{ + unsigned __int64 __rdtsc(); +} + +#pragma intrinsic(__rdtsc) +#endif + +class CCycleCount +{ + friend class CFastTimer; + +public: + CCycleCount(); + CCycleCount( uint64 cycles ); + + void Sample(); // Sample the clock. This takes about 34 clocks to execute (or 26,000 calls per millisecond on a P900). + + void Init(); // Set to zero. + void Init( float initTimeMsec ); + void Init( double initTimeMsec ) { Init( (float)initTimeMsec ); } + void Init( uint64 cycles ); + bool IsLessThan( CCycleCount const &other ) const; // Compare two counts. + + // Convert to other time representations. These functions are slow, so it's preferable to call them + // during display rather than inside a timing block. + unsigned long GetCycles() const; + uint64 GetLongCycles() const; + + unsigned long GetMicroseconds() const; + uint64 GetUlMicroseconds() const; + double GetMicrosecondsF() const; + void SetMicroseconds( unsigned long nMicroseconds ); + + unsigned long GetMilliseconds() const; + double GetMillisecondsF() const; + + double GetSeconds() const; + + CCycleCount& operator+=( CCycleCount const &other ); + + // dest = rSrc1 + rSrc2 + static void Add( CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest ); // Add two samples together. + + // dest = rSrc1 - rSrc2 + static void Sub( CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest ); // Add two samples together. + + static uint64 GetTimestamp(); + + uint64 m_Int64; +}; + +class CClockSpeedInit +{ +public: + CClockSpeedInit() + { + Init(); + } + + static void Init() + { + const CPUInformation& pi = GetCPUInformation(); + + if ( IsX360() ) + { + // cycle counter runs as doc'd at 1/64 Xbox 3.2GHz clock speed, thus 50 Mhz + g_ClockSpeed = pi.m_Speed / 64L; + } + else if ( IsPS3() ) + { + g_ClockSpeed = sys_time_get_timebase_frequency(); // CPU clock rate is totally unrelated to time base register frequency on PS3 + } + else + { + g_ClockSpeed = pi.m_Speed; + } + g_dwClockSpeed = (unsigned long)g_ClockSpeed; + + g_ClockSpeedMicrosecondsMultiplier = 1000000.0 / (double)g_ClockSpeed; + g_ClockSpeedMillisecondsMultiplier = 1000.0 / (double)g_ClockSpeed; + g_ClockSpeedSecondsMultiplier = 1.0f / (double)g_ClockSpeed; + } +}; + +class CFastTimer +{ +public: + // These functions are fast to call and should be called from your sampling code. + void Start(); + void End(); + + const CCycleCount & GetDuration() const; // Get the elapsed time between Start and End calls. + CCycleCount GetDurationInProgress() const; // Call without ending. Not that cheap. + + // Return number of cycles per second on this processor. + static inline unsigned long GetClockSpeed(); + +private: + CCycleCount m_Duration; +#ifdef DEBUG_FASTTIMER + bool m_bRunning; // Are we currently running? +#endif +}; + + +// This is a helper class that times whatever block of code it's in +class CTimeScope +{ +public: + CTimeScope( CFastTimer *pTimer ); + ~CTimeScope(); + +private: + CFastTimer *m_pTimer; +}; + +inline CTimeScope::CTimeScope( CFastTimer *pTotal ) +{ + m_pTimer = pTotal; + m_pTimer->Start(); +} + +inline CTimeScope::~CTimeScope() +{ + m_pTimer->End(); +} + +// This is a helper class that times whatever block of code it's in and +// adds the total (int microseconds) to a global counter. +class CTimeAdder +{ +public: + CTimeAdder( CCycleCount *pTotal ); + ~CTimeAdder(); + + void End(); + +private: + CCycleCount *m_pTotal; + CFastTimer m_Timer; +}; + +inline CTimeAdder::CTimeAdder( CCycleCount *pTotal ) +{ + m_pTotal = pTotal; + m_Timer.Start(); +} + +inline CTimeAdder::~CTimeAdder() +{ + End(); +} + +inline void CTimeAdder::End() +{ + if( m_pTotal ) + { + m_Timer.End(); + *m_pTotal += m_Timer.GetDuration(); + m_pTotal = 0; + } +} + + + +// -------------------------------------------------------------------------- // +// Simple tool to support timing a block of code, and reporting the results on +// program exit or at each iteration +// +// Macros used because dbg.h uses this header, thus Msg() is unavailable +// -------------------------------------------------------------------------- // + +#define PROFILE_SCOPE(name) \ + class C##name##ACC : public CAverageCycleCounter \ + { \ + public: \ + ~C##name##ACC() \ + { \ + Msg("%-48s: %6.3f avg (%8.1f total, %7.3f peak, %5d iters)\n", \ + #name, \ + GetAverageMilliseconds(), \ + GetTotalMilliseconds(), \ + GetPeakMilliseconds(), \ + GetIters() ); \ + } \ + }; \ + static C##name##ACC name##_ACC; \ + CAverageTimeMarker name##_ATM( &name##_ACC ) + +#define TIME_SCOPE(name) \ + class CTimeScopeMsg_##name \ + { \ + public: \ + CTimeScopeMsg_##name() { m_Timer.Start(); } \ + ~CTimeScopeMsg_##name() \ + { \ + m_Timer.End(); \ + Msg( #name "time: %.4fms\n", m_Timer.GetDuration().GetMillisecondsF() ); \ + } \ + private: \ + CFastTimer m_Timer; \ + } name##_TSM; + + +// -------------------------------------------------------------------------- // + +class CAverageCycleCounter +{ +public: + CAverageCycleCounter(); + + void Init(); + void MarkIter( const CCycleCount &duration ); + + unsigned GetIters() const; + + double GetAverageMilliseconds() const; + double GetTotalMilliseconds() const; + double GetPeakMilliseconds() const; + +private: + unsigned m_nIters; + CCycleCount m_Total; + CCycleCount m_Peak; + bool m_fReport; + const tchar *m_pszName; +}; + +// -------------------------------------------------------------------------- // + +class CAverageTimeMarker +{ +public: + CAverageTimeMarker( CAverageCycleCounter *pCounter ); + ~CAverageTimeMarker(); + +private: + CAverageCycleCounter *m_pCounter; + CFastTimer m_Timer; +}; + + +// -------------------------------------------------------------------------- // +// CCycleCount inlines. +// -------------------------------------------------------------------------- // + +inline CCycleCount::CCycleCount() +{ + Init( (uint64)0 ); +} + +inline CCycleCount::CCycleCount( uint64 cycles ) +{ + Init( cycles ); +} + +inline void CCycleCount::Init() +{ + Init( (uint64)0 ); +} + +inline void CCycleCount::Init( float initTimeMsec ) +{ + if ( g_ClockSpeedMillisecondsMultiplier > 0 ) + Init( (uint64)(initTimeMsec / g_ClockSpeedMillisecondsMultiplier) ); + else + Init( (uint64)0 ); +} + +inline void CCycleCount::Init( uint64 cycles ) +{ + m_Int64 = cycles; +} + +#if !COMPILER_GCC +#pragma warning(push) +#pragma warning(disable : 4189) // warning C4189: local variable is initialized but not referenced +#endif + +inline void CCycleCount::Sample() +{ +#ifdef COMPILER_MSVC64 + unsigned __int64* pSample = (unsigned __int64*)&m_Int64; + *pSample = __rdtsc(); + // Msg( "Sample = %I64x", pSample ); +#elif defined( _X360 ) + // only need lower 32 bits, avoids doc'd read bug and 32 bit rollover is in 85 seconds + m_Int64 = (uint64)__mftb32(); + // scale back up, needs to be viewed as 1 cycle/clock +#elif defined( _PS3 ) + // only need lower 32 bits, avoids doc'd read bug and 32 bit rollover is in 85 seconds + m_Int64 = (uint64)__mftb(); + // scale back up, needs to be viewed as 1 cycle/clock +#elif defined( __GNUC__ ) + union + { + unsigned long* pSample; + uint64 * pInt64; + } tmp; + tmp.pInt64 = &m_Int64; + __asm__ __volatile__ ( + "rdtsc\n\t" + "movl %%eax, (%0)\n\t" + "movl %%edx, 4(%0)\n\t" + : /* no output regs */ + : "D" (tmp.pSample) + : "%eax", "%edx" ); +#elif defined( _WIN32 ) + unsigned long* pSample = (unsigned long *)&m_Int64; + __asm + { + // force the cpu to synchronize the instruction queue + // NJS: CPUID can really impact performance in tight loops. + //cpuid + //cpuid + //cpuid + mov ecx, pSample + rdtsc + mov [ecx], eax + mov [ecx+4], edx + } +#elif defined( POSIX ) + unsigned long* pSample = (unsigned long *)&m_Int64; + __asm__ __volatile__ ( + "rdtsc\n\t" + "movl %%eax, (%0)\n\t" + "movl %%edx, 4(%0)\n\t" + : /* no output regs */ + : "D" (pSample) + : "%eax", "%edx" ); +#endif +} + +#if !COMPILER_GCC +#pragma warning(pop) +#endif + +inline CCycleCount& CCycleCount::operator+=( CCycleCount const &other ) +{ + m_Int64 += other.m_Int64; + return *this; +} + + +inline void CCycleCount::Add( CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest ) +{ + dest.m_Int64 = rSrc1.m_Int64 + rSrc2.m_Int64; +} + +inline void CCycleCount::Sub( CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest ) +{ + dest.m_Int64 = rSrc1.m_Int64 - rSrc2.m_Int64; +} + +inline uint64 CCycleCount::GetTimestamp() +{ + CCycleCount c; + c.Sample(); + return c.GetLongCycles(); +} + +inline bool CCycleCount::IsLessThan(CCycleCount const &other) const +{ + return m_Int64 < other.m_Int64; +} + + +inline unsigned long CCycleCount::GetCycles() const +{ + return (unsigned long)m_Int64; +} + +inline uint64 CCycleCount::GetLongCycles() const +{ + return m_Int64; +} + +inline unsigned long CCycleCount::GetMicroseconds() const +{ + return (unsigned long)((m_Int64 * 1000000) / g_ClockSpeed); +} + +inline uint64 CCycleCount::GetUlMicroseconds() const +{ + return ((m_Int64 * 1000000) / g_ClockSpeed); +} + + +inline double CCycleCount::GetMicrosecondsF() const +{ + return (double)( m_Int64 * g_ClockSpeedMicrosecondsMultiplier ); +} + + +inline void CCycleCount::SetMicroseconds( unsigned long nMicroseconds ) +{ + m_Int64 = ((uint64)nMicroseconds * g_ClockSpeed) / 1000000; +} + + +inline unsigned long CCycleCount::GetMilliseconds() const +{ + return (unsigned long)((m_Int64 * 1000) / g_ClockSpeed); +} + + +inline double CCycleCount::GetMillisecondsF() const +{ + return (double)( m_Int64 * g_ClockSpeedMillisecondsMultiplier ); +} + + +inline double CCycleCount::GetSeconds() const +{ + return (double)( m_Int64 * g_ClockSpeedSecondsMultiplier ); +} + + +// -------------------------------------------------------------------------- // +// CFastTimer inlines. +// -------------------------------------------------------------------------- // +inline void CFastTimer::Start() +{ + m_Duration.Sample(); +#ifdef DEBUG_FASTTIMER + m_bRunning = true; +#endif +} + + +inline void CFastTimer::End() +{ + CCycleCount cnt; + cnt.Sample(); + if ( IsX360() ) + { + // have to handle rollover, hires timer is only accurate to 32 bits + // more than one overflow should not have occurred, otherwise caller should use a slower timer + if ( (uint64)cnt.m_Int64 <= (uint64)m_Duration.m_Int64 ) + { + // rollover occurred + cnt.m_Int64 += 0x100000000LL; + } + } + + m_Duration.m_Int64 = cnt.m_Int64 - m_Duration.m_Int64; + +#ifdef DEBUG_FASTTIMER + m_bRunning = false; +#endif +} + +inline CCycleCount CFastTimer::GetDurationInProgress() const +{ + CCycleCount cnt; + cnt.Sample(); + if ( IsX360() ) + { + // have to handle rollover, hires timer is only accurate to 32 bits + // more than one overflow should not have occurred, otherwise caller should use a slower timer + if ( (uint64)cnt.m_Int64 <= (uint64)m_Duration.m_Int64 ) + { + // rollover occurred + cnt.m_Int64 += 0x100000000LL; + } + } + + CCycleCount result; + result.m_Int64 = cnt.m_Int64 - m_Duration.m_Int64; + + return result; +} + + +inline unsigned long CFastTimer::GetClockSpeed() +{ + return g_dwClockSpeed; +} + + +inline CCycleCount const& CFastTimer::GetDuration() const +{ +#ifdef DEBUG_FASTTIMER + assert( !m_bRunning ); +#endif + return m_Duration; +} + + +// -------------------------------------------------------------------------- // +// CAverageCycleCounter inlines + +inline CAverageCycleCounter::CAverageCycleCounter() + : m_nIters( 0 ) +{ +} + +inline void CAverageCycleCounter::Init() +{ + m_Total.Init(); + m_Peak.Init(); + m_nIters = 0; +} + +inline void CAverageCycleCounter::MarkIter( const CCycleCount &duration ) +{ + ++m_nIters; + m_Total += duration; + if ( m_Peak.IsLessThan( duration ) ) + m_Peak = duration; +} + +inline unsigned CAverageCycleCounter::GetIters() const +{ + return m_nIters; +} + +inline double CAverageCycleCounter::GetAverageMilliseconds() const +{ + if ( m_nIters ) + return (m_Total.GetMillisecondsF() / (double)m_nIters); + else + return 0; +} + +inline double CAverageCycleCounter::GetTotalMilliseconds() const +{ + return m_Total.GetMillisecondsF(); +} + +inline double CAverageCycleCounter::GetPeakMilliseconds() const +{ + return m_Peak.GetMillisecondsF(); +} + +// -------------------------------------------------------------------------- // + +inline CAverageTimeMarker::CAverageTimeMarker( CAverageCycleCounter *pCounter ) +{ + m_pCounter = pCounter; + m_Timer.Start(); +} + +inline CAverageTimeMarker::~CAverageTimeMarker() +{ + m_Timer.End(); + m_pCounter->MarkIter( m_Timer.GetDuration() ); +} + + +// CLimitTimer +// Use this to time whether a desired interval of time has passed. It's extremely fast +// to check while running. +class CLimitTimer +{ +public: + void SetLimit( uint64 m_cMicroSecDuration ); + bool BLimitReached( void ); + +private: + uint64 m_lCycleLimit; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Initializes the limit timer with a period of time to measure. +// Input : cMicroSecDuration - How long a time period to measure +//----------------------------------------------------------------------------- +inline void CLimitTimer::SetLimit( uint64 m_cMicroSecDuration ) +{ + uint64 dlCycles = ( ( uint64 ) m_cMicroSecDuration * ( uint64 ) g_dwClockSpeed ) / ( uint64 ) 1000000L; + CCycleCount cycleCount; + cycleCount.Sample( ); + m_lCycleLimit = cycleCount.GetLongCycles( ) + dlCycles; +} + + +//----------------------------------------------------------------------------- +// Purpose: Determines whether our specified time period has passed +// Output: true if at least the specified time period has passed +//----------------------------------------------------------------------------- +inline bool CLimitTimer::BLimitReached( ) +{ + CCycleCount cycleCount; + cycleCount.Sample( ); + return ( cycleCount.GetLongCycles( ) >= m_lCycleLimit ); +} + + + +#endif // FASTTIMER_H diff --git a/external/vpc/public/tier0/ia32detect.h b/external/vpc/public/tier0/ia32detect.h new file mode 100644 index 0000000..e4a63a7 --- /dev/null +++ b/external/vpc/public/tier0/ia32detect.h @@ -0,0 +1,383 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +#ifndef IA32DETECT_H +#define IA32DETECT_H + +#ifdef COMPILER_MSVC64 +extern "C" void __cpuid(int* CPUInfo, int InfoType); +#pragma intrinsic (__cpuid) +#endif +/* + This section from http://iss.cs.cornell.edu/ia32.htm + + + */ +typedef unsigned bit; + +enum CPUVendor +{ + INTEL, + AMD, + UNKNOWN_VENDOR +}; +class ia32detect +{ +public: + + enum type_t + { + type_OEM, + type_OverDrive, + type_Dual, + type_reserved + }; + + enum brand_t + { + brand_na, + brand_Celeron, + brand_PentiumIII, + brand_PentiumIIIXeon, + brand_reserved1, + brand_reserved2, + brand_PentiumIIIMobile, + brand_reserved3, + brand_Pentium4, + brand_invalid + }; + +# pragma pack(push, 1) + + struct version_t + { + bit Stepping : 4; + bit Model : 4; + bit Family : 4; + bit Type : 2; + bit Reserved1 : 2; + bit XModel : 4; + bit XFamily : 8; + bit Reserved2 : 4; + }; + + struct misc_t + { + byte Brand; + byte CLFLUSH; + byte Reserved; + byte APICId; + }; + + struct feature_t + { + bit FPU : 1; // Floating Point Unit On-Chip + bit VME : 1; // Virtual 8086 Mode Enhancements + bit DE : 1; // Debugging Extensions + bit PSE : 1; // Page Size Extensions + bit TSC : 1; // Time Stamp Counter + bit MSR : 1; // Model Specific Registers + bit PAE : 1; // Physical Address Extension + bit MCE : 1; // Machine Check Exception + bit CX8 : 1; // CMPXCHG8 Instruction + bit APIC : 1; // APIC On-Chip + bit Reserved1 : 1; + bit SEP : 1; // SYSENTER and SYSEXIT instructions + bit MTRR : 1; // Memory Type Range Registers + bit PGE : 1; // PTE Global Bit + bit MCA : 1; // Machine Check Architecture + bit CMOV : 1; // Conditional Move Instructions + bit PAT : 1; // Page Attribute Table + bit PSE36 : 1; // 32-bit Page Size Extension + bit PSN : 1; // Processor Serial Number + bit CLFSH : 1; // CLFLUSH Instruction + bit Reserved2 : 1; + bit DS : 1; // Debug Store + bit ACPI : 1; // Thermal Monitor and Software Controlled Clock Facilities + bit MMX : 1; // Intel MMX Technology + bit FXSR : 1; // FXSAVE and FXRSTOR Instructions + bit SSE : 1; // Intel SSE Technology + bit SSE2 : 1; // Intel SSE2 Technology + bit SS : 1; // Self Snoop + bit HTT : 1; // Hyper Threading + bit TM : 1; // Thermal Monitor + bit Reserved3 : 1; + bit PBE : 1; // Pending Brk. EN. + }; + +# pragma pack(pop) + + tstring vendor_name; + CPUVendor vendor; + tstring brand; + version_t version; + misc_t misc; + feature_t feature; + byte *cache; + + ia32detect () + { + + cache = 0; + uint32 m = init0(); + + uint32 *d = new uint32[m * 4]; + + for (uint32 i = 1; i <= m; i++) + { + +#ifdef COMPILER_MSVC64 + __cpuid((int *) (d + (i-1) * 4), i); + +#else + uint32 *t = d + (i - 1) * 4; + __asm + { + mov eax, i; + mov esi, t; + + cpuid; + + mov dword ptr [esi + 0x0], eax; + mov dword ptr [esi + 0x4], ebx; + mov dword ptr [esi + 0x8], ecx; + mov dword ptr [esi + 0xC], edx; + } +#endif + } + + if (m >= 1) + init1(d); + + if (m >= 2) + init2(d[4] & 0xFF); + + delete [] d; + + init0x80000000(); + + + //----------------------------------------------------------------------- + // Get the vendor of the processor + //----------------------------------------------------------------------- + if (_tcscmp(vendor_name.c_str(), _T("GenuineIntel")) == 0) + { + vendor = INTEL; + + } + else if (_tcscmp(vendor_name.c_str(), _T("AuthenticAMD")) == 0) + { + vendor = AMD; + + } + else + { + vendor = UNKNOWN_VENDOR; + } + } + + const tstring version_text () const + { + tchar b[128]; + + _stprintf(b, _T("%d.%d.%d %s XVersion(%d.%d)"), + version.Family, version.Model, version.Stepping, type_text(), version.XFamily, version.XModel); + + return tstring(b); + } + +protected: + + const tchar * type_text () const + { + static const tchar *text[] = + { + _T("Intel OEM Processor"), + _T("Intel OverDrive(R) Processor"), + _T("Intel Dual Processor"), + _T("reserved") + }; + + return text[version.Type]; + } + + const tstring brand_text () const + { + static const tchar *text[] = + { + _T("n/a"), + _T("Celeron"), + _T("Pentium III"), + _T("Pentium III Xeon"), + _T("reserved (4)"), + _T("reserved (5)"), + _T("Pentium III Mobile"), + _T("reserved (7)"), + _T("Pentium 4") + }; + + if (misc.Brand < brand_invalid) + return tstring(text[misc.Brand]); + else + { + tchar b[32]; + + _stprintf(b, _T("Brand %d (Update)"), misc.Brand); + + return tstring(b); + } + } + +private: + + uint32 init0 () + { + uint32 m; + +#ifdef COMPILER_MSVC64 + int data[4]; + tchar * s1; + + s1 = (tchar *) &data[1]; + s1[12] = '\0'; + __cpuid(data, 0); + m = data[0]; + vendor_name = s1; +#else + tchar s1[13]; + + s1[12] = '\0'; + __asm + { + xor eax, eax; + cpuid; + mov m, eax; + mov dword ptr s1 + 0, ebx; + mov dword ptr s1 + 4, edx; + mov dword ptr s1 + 8, ecx; + } + vendor_name = s1; +#endif + return m; + } + + void init1 (uint32 *d) + { + version = *(version_t *)&d[0]; + misc = *(misc_t *)&d[1]; + feature = *(feature_t *)&d[3]; + } + + void process2 (uint32 d, bool c[]) + { + if ((d & 0x80000000) == 0) + for (int i = 0; i < 32; i += 8) + c[(d >> i) & 0xFF] = true; + } + + void init2 (byte count) + { + uint32 d[4]; + bool c[256]; + + for (int ci1 = 0; ci1 < 256; ci1++) + c[ci1] = false; + + for (int i = 0; i < count; i++) + { +#ifdef COMPILER_MSVC64 + __cpuid((int *) d, 2); +#else + __asm + { + mov eax, 2; + lea esi, d; + cpuid; + mov [esi + 0x0], eax; + mov [esi + 0x4], ebx; + mov [esi + 0x8], ecx; + mov [esi + 0xC], edx; + } +#endif + + if (i == 0) + d[0] &= 0xFFFFFF00; + + process2(d[0], c); + process2(d[1], c); + process2(d[2], c); + process2(d[3], c); + } + + int m = 0; + + for (int ci2 = 0; ci2 < 256; ci2++) + if (c[ci2]) + m++; + + cache = new byte[m]; + + m = 0; + + for (int ci3 = 1; ci3 < 256; ci3++) + if (c[ci3]) + cache[m++] = ci3; + + cache[m] = 0; + } + + void init0x80000000 () + { + uint32 m; + +#ifdef COMPILER_MSVC64 + int data[4]; + __cpuid(data, 0x80000000); + m = data[0]; +#else + __asm + { + mov eax, 0x80000000; + cpuid; + mov m, eax + } +#endif + + if ((m & 0x80000000) != 0) + { + uint32 *d = new uint32[(m - 0x80000000) * 4]; + + for (uint32 i = 0x80000001; i <= m; i++) + { + uint32 *t = d + (i - 0x80000001) * 4; + +#ifdef COMPILER_MSVC64 + __cpuid((int *) (d + (i - 0x80000001) * 4), i); +#else + __asm + { + mov eax, i; + mov esi, t; + cpuid; + mov dword ptr [esi + 0x0], eax; + mov dword ptr [esi + 0x4], ebx; + mov dword ptr [esi + 0x8], ecx; + mov dword ptr [esi + 0xC], edx; + } +#endif + } + + if (m >= 0x80000002) + brand = (tchar *)(d + 4); + + // note the assignment to brand above does a copy, we need to delete + delete[] d; + } + } +}; + +#endif // IA32DETECT_H diff --git a/external/vpc/public/tier0/icommandline.h b/external/vpc/public/tier0/icommandline.h new file mode 100644 index 0000000..d56d5a3 --- /dev/null +++ b/external/vpc/public/tier0/icommandline.h @@ -0,0 +1,65 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +//===========================================================================// + +#ifndef TIER0_ICOMMANDLINE_H +#define TIER0_ICOMMANDLINE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + + +//----------------------------------------------------------------------------- +// Purpose: Interface to engine command line +//----------------------------------------------------------------------------- +abstract_class ICommandLine +{ +public: + virtual void CreateCmdLine( const char *commandline ) = 0; + virtual void CreateCmdLine( int argc, char **argv ) = 0; + virtual const char *GetCmdLine( void ) const = 0; + + // Check whether a particular parameter exists + virtual const char *CheckParm( const char *psz, const char **ppszValue = 0 ) const = 0; + virtual void RemoveParm( const char *parm ) = 0; + virtual void AppendParm( const char *pszParm, const char *pszValues ) = 0; + + // Returns the argument after the one specified, or the default if not found + virtual const char *ParmValue( const char *psz, const char *pDefaultVal = 0 ) const = 0; + virtual int ParmValue( const char *psz, int nDefaultVal ) const = 0; + virtual float ParmValue( const char *psz, float flDefaultVal ) const = 0; + + // Gets at particular parameters + virtual int ParmCount() const = 0; + virtual int FindParm( const char *psz ) const = 0; // Returns 0 if not found. + virtual const char* GetParm( int nIndex ) const = 0; + + // copies the string passwed + virtual void SetParm( int nIndex, char const *pNewParm ) =0; +}; + +//----------------------------------------------------------------------------- +// Gets a singleton to the commandline interface +// NOTE: The #define trickery here is necessary for backwards compat: +// this interface used to lie in the vstdlib library. +//----------------------------------------------------------------------------- +PLATFORM_INTERFACE ICommandLine *CommandLine(); + + +//----------------------------------------------------------------------------- +// Process related functions +//----------------------------------------------------------------------------- +PLATFORM_INTERFACE const tchar *Plat_GetCommandLine(); +#ifndef _WIN32 +// helper function for OS's that don't have a ::GetCommandLine() call +PLATFORM_INTERFACE void Plat_SetCommandLine( const char *cmdLine ); +#endif +PLATFORM_INTERFACE const char *Plat_GetCommandLineA(); + + +#endif // TIER0_ICOMMANDLINE_H + diff --git a/external/vpc/public/tier0/ioctlcodes.h b/external/vpc/public/tier0/ioctlcodes.h new file mode 100644 index 0000000..7fc8efb --- /dev/null +++ b/external/vpc/public/tier0/ioctlcodes.h @@ -0,0 +1,29 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef IOCTLCODES_H +#define IOCTLCODES_H +#pragma once + +// Define the IOCTL codes we will use. The IOCTL code contains a command +// identifier, plus other information about the device, the type of access +// with which the file must have been opened, and the type of buffering. + +// Device type -- in the "User Defined" range." +#define DEVICE_FILE_TYPE 40000 + + +// The IOCTL function codes from 0x800 to 0xFFF are for customer use. + +#define IOCTL_WRITE_MSR \ + CTL_CODE( DEVICE_FILE_TYPE, 0x900, METHOD_BUFFERED, FILE_READ_ACCESS ) + +#define IOCTL_READ_MSR \ + CTL_CODE( DEVICE_FILE_TYPE, 0x901, METHOD_BUFFERED, FILE_READ_ACCESS ) + + +#endif IOCTLCODES_H diff --git a/external/vpc/public/tier0/k8performancecounters.h b/external/vpc/public/tier0/k8performancecounters.h new file mode 100644 index 0000000..d405a8d --- /dev/null +++ b/external/vpc/public/tier0/k8performancecounters.h @@ -0,0 +1,2040 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +#ifndef K8PERFORMANCECOUNTERS_H +#define K8PERFORMANCECOUNTERS_H + +/* + * AMD K8 events. + * + */ + +#ifdef COMPILER_MSVC64 +extern "C" +{ + unsigned __int64 __readpmc(unsigned long); +} + +#pragma intrinsic(__readpmc) +#endif + + +typedef union EVENT_MASK(NULL_MASK) +{ + // no tests defined + uint16 flat; +} EVENT_MASK(NULL_MASK); + + +#define MSR_K8_EVNTSEL0 0xC0010000 /* .. 0xC0010003 */ +#define MSR_K8_PERFCTR0 0xC0010004 /* .. 0xC0010007 */ + +# pragma pack(push, 1) + + + +// access to these bits is through the methods +typedef union PerfEvtSel +{ + struct + { + uint64 EventMask : 8; + + uint64 UnitMask : 8; + uint64 USR : 1; + uint64 OS : 1; + uint64 Edge : 1; + uint64 PC : 1; + uint64 INTAPIC : 1; + uint64 Reserved21 : 1; + uint64 Enable : 1; + uint64 Complement : 1; // aka INV + uint64 Threshold : 8; // aka CounterMask + uint64 Reserver32 : 32; + }; + uint64 flat; + +} PerfEvtSel; + + +enum UnitEncode +{ + FP, + LS, + DC, + BU, + IC, + UE_Unknown, + FR, + NB +}; + +# pragma pack(pop) + +// Turn off the no return value warning in ReadCounter. +#pragma warning( disable : 4035 ) +#define k8NUM_COUNTERS 4 +class k8BaseEvent +{ +public: + + PME * pme; + + PerfEvtSel eventSelect[k8NUM_COUNTERS]; + + unsigned short m_eventMask; + int event_id; + tchar * name; + tchar revRequired; + int eventSelectNum; + UnitEncode unitEncode; + + + void SetCounter(int n) + { + if (n < 0) + n = 0; + else if (n > 3) + n = 3; + eventSelectNum = n; + + } + k8BaseEvent() + { + pme = PME::Instance(); + + for(int i = 0; i< k8NUM_COUNTERS; i++) + { + eventSelect[i].flat = 0; + + } + eventSelectNum = 0; + + m_eventMask = 0; + event_id = 0; + name = 0; + revRequired = 'A'; + + + } + + void SetCaptureMode(PrivilegeCapture priv) + { + PerfEvtSel & select = eventSelect[eventSelectNum]; + StopCounter(); + + switch (priv) + { + case OS_Only: + select.USR = 0; + select.OS = 1; + break; + + case USR_Only: + select.USR = 1; + select.OS = 0; + break; + + case OS_and_USR: + select.USR = 1; + select.OS = 1; + break; + } + + + select.UnitMask = m_eventMask; + select.EventMask = event_id; + + + int selectPort = MSR_K8_EVNTSEL0 + eventSelectNum; + pme->WriteMSR(selectPort, select.flat); + } + + + void SetFiltering(CompareState compareEnable, + CompareMethod compareMethod, + uint8 threshold, + EdgeState edgeEnable) + { + + PerfEvtSel & select = eventSelect[eventSelectNum]; + + StopCounter(); + + if (compareEnable == CompareDisable) + select.Threshold = 0; + else + select.Threshold = threshold; + + select.Complement = compareMethod; + + select.Edge = edgeEnable; + + int selectPort = MSR_K8_EVNTSEL0 + eventSelectNum; + pme->WriteMSR(selectPort, select.flat); + + + } + + + void StartCounter() + { + PerfEvtSel & select = eventSelect[eventSelectNum]; + + select.Enable = 1; + int selectPort = MSR_K8_EVNTSEL0 + eventSelectNum; + + pme->WriteMSR(selectPort, select.flat); + + } + void StopCounter() + { + PerfEvtSel & select = eventSelect[eventSelectNum]; + select.Enable = 0; + int selectPort = MSR_K8_EVNTSEL0 + eventSelectNum; + + pme->WriteMSR(selectPort, select.flat); + } + + + + void ClearCounter() + { + PerfEvtSel & select = eventSelect[eventSelectNum]; + + int counterPort = MSR_K8_PERFCTR0 + eventSelectNum; + + pme->WriteMSR(counterPort, 0ui64 ); // clear + } + + void WriteCounter(int64 value) + { + + PerfEvtSel & select = eventSelect[eventSelectNum]; + + int counterPort = MSR_K8_PERFCTR0 + eventSelectNum; + pme->WriteMSR(counterPort, value); // clear + } + + int64 ReadCounter() + { + +#if PME_DEBUG + PerfEvtSel & select = eventSelect[eventSelectNum]; + + if (select.USR == 0 && select.OS == 0) + return -1; // no area to collect, use SetCaptureMode + + if (select.EventMask == 0) + return -2; // no event mask set + + if (eventSelectNum < 0 || eventSelectNum > 3) + return -3; // counter not legal + + // check revision + +#endif + + // ReadMSR should work here too, but RDPMC should be faster + //ReadMSR(counterPort, int64); + + // we need to copy this into a temp for some reason +#ifdef COMPILER_MSVC64 + return __readpmc((unsigned long) eventSelectNum); +#else + int temp = eventSelectNum; + _asm + { + mov ecx, temp + RDPMC + } +#endif + + } + + +}; +#pragma warning( default : 4035 ) + + + + +typedef union EVENT_MASK(k8_dispatched_fpu_ops) +{ + // event 0 + struct + { + uint16 AddPipeOps:1; // Add pipe ops excluding junk ops" }, + uint16 MulPipeOps:1; // Multiply pipe ops excluding junk ops" },, + uint16 StoreOps:1; // Store pipe ops excluding junk ops" }, + uint16 AndPipeOpsJunk:1; // Add pipe junk ops" },, + uint16 MulPipeOpsJunk:1; // Multiply pipe junk ops" }, + uint16 StoreOpsJunk:1; // Store pipe junk ops" } } + }; + uint16 flat; +} EVENT_MASK(k8_dispatched_fpu_ops); + +class k8Event_DISPATCHED_FPU_OPS : public k8BaseEvent +{ +public: + + k8Event_DISPATCHED_FPU_OPS() + { + eventMask = (EVENT_MASK(k8_dispatched_fpu_ops) *)&m_eventMask; + + event_id = 0x00; + unitEncode = FP; + name = _T("Dispatched FPU ops"); + revRequired = 'B'; + } + EVENT_MASK(k8_dispatched_fpu_ops) * eventMask; + +}; + +////////////////////////////////////////////////////////// + + + +class k8Event_NO_FPU_OPS : public k8BaseEvent +{ +public: + + k8Event_NO_FPU_OPS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + event_id = 0x01; + unitEncode = FP; + + name = _T("Cycles with no FPU ops retired"); + revRequired = 'B'; + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + +////////////////////////////////////////////////////////// + +class k8Event_FAST_FPU_OPS : public k8BaseEvent +{ +public: + + k8Event_FAST_FPU_OPS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + event_id = 0x02; + unitEncode = FP; + + name = _T("Dispatched FPU ops that use the fast flag interface"); + revRequired = 'B'; + + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + +////////////////////////////////////////////////////////// + + +typedef union EVENT_MASK(k8_segment_register_load) +{ + + struct + { + uint16 ES:1; + uint16 CS:1; + uint16 SS:1; + uint16 DS:1; + uint16 FS:1; + uint16 GS:1; + uint16 HS:1; + }; + uint16 flat; +} EVENT_MASK(k8_segment_register_load); + + +class k8Event_SEG_REG_LOAD : public k8BaseEvent +{ +public: + + k8Event_SEG_REG_LOAD() + { + eventMask = (EVENT_MASK(k8_segment_register_load) *)&m_eventMask; + name = _T("Segment register load"); + event_id = 0x20; + unitEncode = LS; + + } + EVENT_MASK(k8_segment_register_load) * eventMask; + +}; + + +class k8Event_SELF_MODIFY_RESYNC : public k8BaseEvent +{ +public: + + k8Event_SELF_MODIFY_RESYNC() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Microarchitectural resync caused by self modifying code"); + event_id = 0x21; + unitEncode = LS; + + } + EVENT_MASK(NULL_MASK) * eventMask; + + +}; +class k8Event_LS_RESYNC_BY_SNOOP : public k8BaseEvent +{ +public: + + k8Event_LS_RESYNC_BY_SNOOP() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + event_id = 0x22; + unitEncode = LS; + + name = _T("Microarchitectural resync caused by snoop"); + } + EVENT_MASK(NULL_MASK) * eventMask; + + +}; +class k8Event_LS_BUFFER_FULL : public k8BaseEvent +{ +public: + + k8Event_LS_BUFFER_FULL() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("LS Buffer 2 Full"); + event_id = 0x23; + unitEncode = LS; + + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + +typedef union EVENT_MASK(k8_locked_op) +{ + + + struct + { + uint16 NumLockInstr : 1; //Number of lock instructions executed + uint16 NumCyclesInRequestGrant : 1; //Number of cycles spent in the lock request/grant stage + + uint16 NumCyclesForLock:1; + /*Number of cycles a lock takes to complete once it is + non-speculative and is the oldest load/store operation + (non-speculative cycles in Ls2 entry 0)*/ + + + }; + uint16 flat; + + +} EVENT_MASK(k8_locked_op); + + + +class k8Event_LOCKED_OP : public k8BaseEvent +{ +public: + + EVENT_MASK(k8_locked_op) * eventMask; + + k8Event_LOCKED_OP() + { + eventMask = (EVENT_MASK(k8_locked_op) *)&m_eventMask; + name = _T("Locked operation"); + event_id = 0x24; + unitEncode = LS; + + revRequired = 'C'; + } + + +}; + +class k8Event_OP_LATE_CANCEL : public k8BaseEvent +{ +public: + + k8Event_OP_LATE_CANCEL() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Microarchitectural late cancel of an operation"); + event_id = 0x25; + unitEncode = LS; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("OP_LATE_CANCEL"); + + +}; +class k8Event_CFLUSH_RETIRED : public k8BaseEvent +{ +public: + + k8Event_CFLUSH_RETIRED() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Retired CFLUSH instructions"); + event_id = 0x26; + unitEncode = LS; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("CFLUSH_RETIRED"); + + +}; +class k8Event_CPUID_RETIRED : public k8BaseEvent +{ +public: + + k8Event_CPUID_RETIRED() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Retired CPUID instructions"); + event_id = 0x27; + unitEncode = LS; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("CPUID_RETIRED"); + + +}; + +typedef union EVENT_MASK( k8_cache) +{ + + struct + { + uint16 Invalid:1; + uint16 Exclusive:1; + uint16 Shared:1; + uint16 Owner:1; + uint16 Modified:1; + }; + uint16 flat; + +}EVENT_MASK( k8_cache); + /* 0x40-0x47: from K7 official event set */ + + +class k8Event_DATA_CACHE_ACCESSES : public k8BaseEvent +{ + k8Event_DATA_CACHE_ACCESSES() + { + + event_id = 0x40; + unitEncode = DC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + //_T("DATA_CACHE_ACCESSES"), + name = _T("Data cache accesses"); + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + +class k8Event_DATA_CACHE_MISSES : public k8BaseEvent +{ + k8Event_DATA_CACHE_MISSES() + { + + event_id = 0x41; + unitEncode = DC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + //_T("DATA_CACHE_MISSES"), + name = _T("Data cache misses"); + } + EVENT_MASK(NULL_MASK) * eventMask; +}; + +class k8Event_DATA_CACHE_REFILLS_FROM_L2 : public k8BaseEvent +{ + k8Event_DATA_CACHE_REFILLS_FROM_L2() + { + + event_id = 0x42; + unitEncode = DC; + + eventMask = (EVENT_MASK(k8_cache) *)&m_eventMask; + + + name = _T("Data cache refills from L2"); + } + EVENT_MASK(k8_cache) * eventMask; + +}; + +class k8Event_DATA_CACHE_REFILLS_FROM_SYSTEM : public k8BaseEvent +{ + k8Event_DATA_CACHE_REFILLS_FROM_SYSTEM() + { + + event_id = 0x43; + unitEncode = DC; + + + eventMask = (EVENT_MASK(k8_cache) *)&m_eventMask; + + //UM(k7_um_moesi), + //_T("DATA_CACHE_REFILLS_FROM_SYSTEM"), + name = _T("Data cache refills from system"); + } + EVENT_MASK(k8_cache) * eventMask; + +}; + +class k8Event_DATA_CACHE_WRITEBACKS : public k8BaseEvent +{ + k8Event_DATA_CACHE_WRITEBACKS() + { + + event_id = 0x44; + unitEncode = DC; + + eventMask = (EVENT_MASK(k8_cache) *)&m_eventMask; + + //UM(k7_um_moesi), + //_T("DATA_CACHE_WRITEBACKS"), + name = _T("Data cache writebacks"); + } + EVENT_MASK(k8_cache) * eventMask; + + +}; + +class k8Event_L1_DTLB_MISSES_AND_L2_DTLB_HITS : public k8BaseEvent +{ + k8Event_L1_DTLB_MISSES_AND_L2_DTLB_HITS() + { + + event_id = 0x45; + unitEncode = DC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + name = _T("L1 DTLB misses and L2 DTLB hits"); + } + EVENT_MASK(NULL_MASK) * eventMask; + + +}; + +class k8Event_L1_AND_L2_DTLB_MISSES : public k8BaseEvent +{ + k8Event_L1_AND_L2_DTLB_MISSES() + { + + event_id = 0x46; + unitEncode = DC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + name = _T("L1 and L2 DTLB misses") ; + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + +class k8Event_MISALIGNED_DATA_REFERENCES : public k8BaseEvent +{ + k8Event_MISALIGNED_DATA_REFERENCES() + { + + event_id = 0x47; + unitEncode = DC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + //NULL, _T("MISALIGNED_DATA_REFERENCES"), + name = _T("Misaligned data references"); + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + + +class k8Event_ACCESS_CANCEL_LATE : public k8BaseEvent +{ +public: + + k8Event_ACCESS_CANCEL_LATE() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Microarchitectural late cancel of an access"); + event_id = 0x48; + unitEncode = DC; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("ACCESS_CANCEL_LATE"); + + +}; +class k8Event_ACCESS_CANCEL_EARLY : public k8BaseEvent +{ +public: + + k8Event_ACCESS_CANCEL_EARLY() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Microarchitectural early cancel of an access"); + event_id = 0x49; + unitEncode = DC; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("ACCESS_CANCEL_EARLY"); + + +}; +typedef union EVENT_MASK( k8_ecc) +{ + struct + { + uint16 ScrubberError : 1; // Scrubber error" }, + uint16 PiggybackScrubberErrors : 1; // Piggyback scrubber errors" } } + }; + uint16 flat; + +}EVENT_MASK( k8_ecc); + + +class k8Event_ECC_BIT_ERR : public k8BaseEvent +{ +public: + + k8Event_ECC_BIT_ERR() + { + eventMask = (EVENT_MASK(k8_ecc) *)&m_eventMask; + name = _T("One bit ECC error recorded found by scrubber"); + event_id = 0x4A; + unitEncode = DC; + + } + EVENT_MASK(k8_ecc) * eventMask; + // name = _T("ECC_BIT_ERR"); + + +}; + +// 4B +typedef union EVENT_MASK( k8_distpatch_prefetch_instructions) +{ + struct + { + uint16 Load : 1; + uint16 Store : 1; + uint16 NTA : 1; + }; + uint16 flat; + + +}EVENT_MASK( k8_distpatch_prefetch_instructions); + +class k8Event_DISPATCHED_PRE_INSTRS : public k8BaseEvent +{ +public: + + k8Event_DISPATCHED_PRE_INSTRS() + { + eventMask = (EVENT_MASK(k8_distpatch_prefetch_instructions) *)&m_eventMask; + name = _T("Dispatched prefetch instructions"); + event_id = 0x4B; + unitEncode = DC; + + } + EVENT_MASK(k8_distpatch_prefetch_instructions) * eventMask; + // name = _T("DISPATCHED_PRE_INSTRS"); + + /* 0x4C: added in Revision C */ + +}; + + + +typedef union EVENT_MASK( k8_lock_accesses) +{ + struct + { + uint16 DcacheAccesses:1; // Number of dcache accesses by lock instructions" }, + uint16 DcacheMisses:1; // Number of dcache misses by lock instructions" } } + }; + uint16 flat; + +}EVENT_MASK( k8_lock_accesses); + + + +class k8Event_LOCK_ACCESSES : public k8BaseEvent +{ +public: + + k8Event_LOCK_ACCESSES() + { + eventMask = (EVENT_MASK(k8_lock_accesses) *)&m_eventMask; + name = _T("DCACHE accesses by locks") ; + event_id = 0x4C; + unitEncode = DC; + + revRequired = 'C'; + } + EVENT_MASK(k8_lock_accesses) * eventMask; + + +}; + + +class k8Event_CYCLES_PROCESSOR_IS_RUNNING : public k8BaseEvent +{ +public: + + k8Event_CYCLES_PROCESSOR_IS_RUNNING() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Cycles processor is running (not in HLT or STPCLK)"); + event_id = 0x76; + unitEncode = BU; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("CYCLES_PROCESSOR_IS_RUNNING"); /* undocumented *; + + +}; + + +typedef union EVENT_MASK( k8_internal_L2_request) +{ + struct + { + uint16 ICFill:1; // IC fill" }, + uint16 DCFill:1; // DC fill" }, + uint16 TLBReload:1; // TLB reload" }, + uint16 TagSnoopRequest:1; // Tag snoop request" }, + uint16 CancelledRequest:1; // Cancelled request" } } + }; + uint16 flat; + + +}EVENT_MASK( k8_internal_L2_request); + +class k8Event_BU_INT_L2_REQ : public k8BaseEvent +{ +public: + + k8Event_BU_INT_L2_REQ() + { + eventMask = (EVENT_MASK(k8_internal_L2_request) *)&m_eventMask; + name = _T("Internal L2 request"); + unitEncode = BU; + event_id = 0x7D; + } + + EVENT_MASK(k8_internal_L2_request) * eventMask; +} ; + + // name = _T("BU_INT_L2_REQ"); + + + +// 7E +typedef union EVENT_MASK( k8_fill_request_missed_L2) +{ + + struct + { + uint16 ICFill:1; // IC fill" }, + uint16 DCFill:1; // DC fill" }, + uint16 TLBReload:1; // TLB reload" }, + }; + uint16 flat; + +} EVENT_MASK( k8_fill_request_missed_L2); + + +class k8Event_BU_FILL_REQ : public k8BaseEvent +{ +public: + + k8Event_BU_FILL_REQ() + { + eventMask = (EVENT_MASK(k8_fill_request_missed_L2) *)&m_eventMask; + name = _T("Fill request that missed in L2"); + event_id = 0x7E; + unitEncode = BU; + + } + EVENT_MASK(k8_fill_request_missed_L2) * eventMask; + // name = _T("BU_FILL_REQ"); + + + +}; + + + + +// 7F +typedef union EVENT_MASK( k8_fill_into_L2) +{ + + struct + { + uint16 DirtyL2Victim:1; // Dirty L2 victim + uint16 VictimFromL2:1; // Victim from L2 + }; + uint16 flat; + +}EVENT_MASK( k8_fill_into_L2); + +class k8Event_BU_FILL_L2 : public k8BaseEvent +{ +public: + + k8Event_BU_FILL_L2() + { + eventMask = (EVENT_MASK(k8_fill_into_L2) *)&m_eventMask; + name = _T("Fill into L2"); + event_id = 0x7F; + unitEncode = BU; + + } + EVENT_MASK(k8_fill_into_L2) * eventMask; + // name = _T("BU_FILL_L2"); + + +}; + +class k8Event_INSTRUCTION_CACHE_FETCHES : public k8BaseEvent +{ +public: + k8Event_INSTRUCTION_CACHE_FETCHES() + { + event_id = 0x80; + unitEncode = IC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + name = _T("Instruction cache fetches"); + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + +class k8Event_INSTRUCTION_CACHE_MISSES : public k8BaseEvent +{ +public: + k8Event_INSTRUCTION_CACHE_MISSES() + { + event_id = 0x81; + unitEncode = IC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + //0xF, NULL, _T("INSTRUCTION_CACHE_MISSES"), + name = _T("Instruction cache misses"); + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + +class k8Event_IC_REFILL_FROM_L2 : public k8BaseEvent +{ +public: + + k8Event_IC_REFILL_FROM_L2() + { + eventMask = (EVENT_MASK(k8_cache) *)&m_eventMask; + name = _T("Refill from L2"); + event_id = 0x82; + unitEncode = IC; + + } + EVENT_MASK(k8_cache) * eventMask; + // name = _T("IC_REFILL_FROM_L2"); + + + +}; +class k8Event_IC_REFILL_FROM_SYS : public k8BaseEvent +{ +public: + + k8Event_IC_REFILL_FROM_SYS() + { + eventMask = (EVENT_MASK(k8_cache) *)&m_eventMask; + name = _T("Refill from system"); + event_id = 0x83; + unitEncode = IC; + + } + EVENT_MASK(k8_cache) * eventMask; + // name = _T("IC_REFILL_FROM_SYS"); + + + +}; +class k8Event_L1_ITLB_MISSES_AND_L2_ITLB_HITS : public k8BaseEvent +{ +public: + k8Event_L1_ITLB_MISSES_AND_L2_ITLB_HITS() + { + + event_id = 0x84; + unitEncode = IC; + + name = _T("L1 ITLB misses (and L2 ITLB hits)"); + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + + } + EVENT_MASK(NULL_MASK) * eventMask; + + +}; + +class k8Event_L1_AND_L2_ITLB_MISSES : public k8BaseEvent +{ +public: + k8Event_L1_AND_L2_ITLB_MISSES() + { + event_id = 0x85; + unitEncode = IC; + + name = _T("(L1 and) L2 ITLB misses"); + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + + + +class k8Event_IC_RESYNC_BY_SNOOP : public k8BaseEvent +{ +public: + + k8Event_IC_RESYNC_BY_SNOOP() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + event_id = 0x86; + unitEncode = IC; + + name = _T("Microarchitectural resync caused by snoop"); + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("IC_RESYNC_BY_SNOOP"); + /* similar to 0x22; but IC unit instead of LS unit */ + + + +}; +class k8Event_IC_FETCH_STALL : public k8BaseEvent +{ +public: + + k8Event_IC_FETCH_STALL() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Instruction fetch stall"); + event_id = 0x87; + unitEncode = IC; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("IC_FETCH_STALL"); + + + +}; +class k8Event_IC_STACK_HIT : public k8BaseEvent +{ +public: + + k8Event_IC_STACK_HIT() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Return stack hit"); + event_id = 0x88; + unitEncode = IC; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("IC_STACK_HIT"); + + + +}; +class k8Event_IC_STACK_OVERFLOW : public k8BaseEvent +{ +public: + + k8Event_IC_STACK_OVERFLOW() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Return stack overflow"); + event_id = 0x89; + unitEncode = IC; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("IC_STACK_OVERFLOW"); + + + + +}; + + /* 0xC0-0xC7: from K7 official event set */ +class k8Event_RETIRED_INSTRUCTIONS : public k8BaseEvent +{ +public: + k8Event_RETIRED_INSTRUCTIONS() + { + event_id = 0xC0; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + //0xF, NULL, _T("RETIRED_INSTRUCTIONS"), + name = _T("Retired instructions (includes exceptions, interrupts, resyncs)"); + } + EVENT_MASK(NULL_MASK) * eventMask; +}; + +class k8Event_RETIRED_OPS : public k8BaseEvent +{ +public: + k8Event_RETIRED_OPS() + { + event_id = 0xC1; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_OPS"), + name = _T("Retired Ops") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; +class k8Event_RETIRED_BRANCHES : public k8BaseEvent +{ +public: + k8Event_RETIRED_BRANCHES() + { + event_id = 0xC2; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_BRANCHES"), + name = _T("Retired branches (conditional, unconditional, exceptions, interrupts)") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; +class k8Event_RETIRED_BRANCHES_MISPREDICTED : public k8BaseEvent +{ +public: + k8Event_RETIRED_BRANCHES_MISPREDICTED() + { + event_id = 0xC3; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_BRANCHES_MISPREDICTED"), + name = _T("Retired branches mispredicted") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; +class k8Event_RETIRED_TAKEN_BRANCHES : public k8BaseEvent +{ +public: + k8Event_RETIRED_TAKEN_BRANCHES() + { + event_id = 0xC4; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_TAKEN_BRANCHES"), + name = _T("Retired taken branches") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; +class k8Event_RETIRED_TAKEN_BRANCHES_MISPREDICTED : public k8BaseEvent +{ +public: + k8Event_RETIRED_TAKEN_BRANCHES_MISPREDICTED() + { + event_id = 0xC5; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_TAKEN_BRANCHES_MISPREDICTED"), + name = _T("Retired taken branches mispredicted") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; +class k8Event_RETIRED_FAR_CONTROL_TRANSFERS : public k8BaseEvent +{ +public: + k8Event_RETIRED_FAR_CONTROL_TRANSFERS() + { + event_id = 0xC6; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_FAR_CONTROL_TRANSFERS"), + name = _T("Retired far control transfers") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; +class k8Event_RETIRED_RESYNC_BRANCHES : public k8BaseEvent +{ +public: + k8Event_RETIRED_RESYNC_BRANCHES() + { + event_id = 0xC7; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_RESYNC_BRANCHES"), + name = _T("Retired resync branches (only non-control transfer branches counted)") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; + +class k8Event_RETIRED_NEAR_RETURNS : public k8BaseEvent +{ +public: + + k8Event_RETIRED_NEAR_RETURNS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Retired near returns"); + event_id = 0xC8; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + + + +}; +class k8Event_RETIRED_RETURNS_MISPREDICT : public k8BaseEvent +{ +public: + + k8Event_RETIRED_RETURNS_MISPREDICT() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Retired near returns mispredicted"); + event_id = 0xC9; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("RETIRED_RETURNS_MISPREDICT"); + + +}; +class k8Event_RETIRED_BRANCH_MISCOMPARE : public k8BaseEvent +{ +public: + + k8Event_RETIRED_BRANCH_MISCOMPARE() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Retired taken branches mispredicted due to address miscompare"); + event_id = 0xCA; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("RETIRED_BRANCH_MISCOMPARE"); + + +}; + + + /* Revision B and later */ + +typedef union EVENT_MASK( k8_retired_fpu_instr) +{ + struct + { + uint16 DirtyL2Victim:1; // x87 instructions + uint16 CombinedMMX_3DNow:1; // Combined MMX & 3DNow! instructions" }, + uint16 CombinedPackedSSE_SSE2:1; // Combined packed SSE and SSE2 instructions" }, + uint16 CombinedScalarSSE_SSE2:1; // Combined scalar SSE and SSE2 instructions" } } + }; + uint16 flat; + + +}EVENT_MASK( k8_retired_fpu_instr); + + +class k8Event_RETIRED_FPU_INSTRS : public k8BaseEvent +{ +public: + + k8Event_RETIRED_FPU_INSTRS() + { + eventMask = (EVENT_MASK(k8_retired_fpu_instr) *)&m_eventMask; + event_id = 0xCB; + unitEncode = FR; + + name = _T("Retired FPU instructions"); + revRequired = 'B'; + } + EVENT_MASK(k8_retired_fpu_instr) * eventMask; + /* Revision B and later */ + + + +}; + +// CC +typedef union EVENT_MASK( k8_retired_fastpath_double_op_instr ) +{ + + struct + { + uint16 LowOpPosition0:1; // With low op in position 0" }, + uint16 LowOpPosition1:1; // With low op in position 1" }, + uint16 LowOpPosition2:1; // With low op in position 2" } } + }; + uint16 flat; + + +}EVENT_MASK( k8_retired_fastpath_double_op_instr); + +class k8Event_RETIRED_FASTPATH_INSTRS : public k8BaseEvent +{ +public: + + k8Event_RETIRED_FASTPATH_INSTRS() + { + eventMask = (EVENT_MASK(k8_retired_fastpath_double_op_instr) *)&m_eventMask; + event_id = 0xCC; + unitEncode = FR; + + name = _T("Retired fastpath double op instructions"); + revRequired = 'B'; + + } + EVENT_MASK(k8_retired_fastpath_double_op_instr) * eventMask; + + +}; + +class k8Event_INTERRUPTS_MASKED_CYCLES : public k8BaseEvent +{ +public: + k8Event_INTERRUPTS_MASKED_CYCLES() + { + event_id = 0xCD; + unitEncode = FR; + + //0xF, NULL, _T("INTERRUPTS_MASKED_CYCLES"), + name = _T("Interrupts masked cycles (IF=0)") ; + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; +class k8Event_INTERRUPTS_MASKED_WHILE_PENDING_CYCLES : public k8BaseEvent +{ +public: + k8Event_INTERRUPTS_MASKED_WHILE_PENDING_CYCLES() + { + event_id = 0xCE; + unitEncode = FR; + + //0xF, NULL, _T("INTERRUPTS_MASKED_WHILE_PENDING_CYCLES"), + name = _T("Interrupts masked while pending cycles (INTR while IF=0)") ; + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; +class k8Event_NUMBER_OF_TAKEN_HARDWARE_INTERRUPTS : public k8BaseEvent +{ +public: + k8Event_NUMBER_OF_TAKEN_HARDWARE_INTERRUPTS() + { + event_id = 0xCF; + unitEncode = FR; + + //0xF, NULL, _T("NUMBER_OF_TAKEN_HARDWARE_INTERRUPTS"), + name = _T("Number of taken hardware interrupts") ; + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + +class k8Event_DECODER_EMPTY : public k8BaseEvent +{ +public: + + k8Event_DECODER_EMPTY() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Nothing to dispatch (decoder empty)"); + event_id = 0xD0; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DECODER_EMPTY"); + + +}; +class k8Event_DISPATCH_STALLS : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALLS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stalls (events 0xD2-0xDA combined)"); + event_id = 0xD1; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALLS"); + + + +}; +class k8Event_DISPATCH_STALL_FROM_BRANCH_ABORT : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_FROM_BRANCH_ABORT() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall from branch abort to retire"); + event_id = 0xD2; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_FROM_BRANCH_ABORT"); + + + +}; +class k8Event_DISPATCH_STALL_SERIALIZATION : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_SERIALIZATION() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall for serialization"); + event_id = 0xD3; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_SERIALIZATION"); + + +}; +class k8Event_DISPATCH_STALL_SEG_LOAD : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_SEG_LOAD() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall for segment load"); + event_id = 0xD4; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_SEG_LOAD"); + + + +}; +class k8Event_DISPATCH_STALL_REORDER_BUFFER : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_REORDER_BUFFER() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall when reorder buffer is full"); + event_id = 0xD5; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_REORDER_BUFFER"); + + +}; +class k8Event_DISPATCH_STALL_RESERVE_STATIONS : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_RESERVE_STATIONS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall when reservation stations are full"); + event_id = 0xD6; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_RESERVE_STATIONS"); + + +}; +class k8Event_DISPATCH_STALL_FPU : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_FPU() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall when FPU is full"); + event_id = 0xD7; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_FPU"); + + +}; +class k8Event_DISPATCH_STALL_LS : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_LS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall when LS is full"); + event_id = 0xD8; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_LS"); + + +}; +class k8Event_DISPATCH_STALL_QUIET_WAIT : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_QUIET_WAIT() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall when waiting for all to be quiet"); + event_id = 0xD9; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_QUIET_WAIT"); + + + +}; +class k8Event_DISPATCH_STALL_PENDING : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_PENDING() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall when far control transfer or resync branch is pending"); + event_id = 0xDA; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_PENDING"); + + + +}; + + +typedef union EVENT_MASK( k8_fpu_exceptions) +{ + + + + struct + { + uint16 x87ReclassMicrofaults:1; // x87 reclass microfaults" }, + uint16 SSERetypeMicrofaults:1; // SSE retype microfaults" }, + uint16 SSEReclassMicrofaults:1; // SSE reclass microfaults" }, + uint16 SSE_x87Microtraps:1; // SSE and x87 microtraps" } } + }; + uint16 flat; + + + +}EVENT_MASK( k8_fpu_exceptions); + +class k8Event_FPU_EXCEPTIONS : public k8BaseEvent +{ +public: + + k8Event_FPU_EXCEPTIONS() + { + eventMask = (EVENT_MASK(k8_fpu_exceptions) *)&m_eventMask; + event_id = 0xDB; + unitEncode = FR; + + name = _T("FPU exceptions"); + revRequired = 'B'; + + } + EVENT_MASK(k8_fpu_exceptions) * eventMask; + // name = _T("FPU_EXCEPTIONS"); + /* Revision B and later */ + + + +}; +class k8Event_DR0_BREAKPOINTS : public k8BaseEvent +{ +public: + + k8Event_DR0_BREAKPOINTS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Number of breakpoints for DR0"); + event_id = 0xDC; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DR0_BREAKPOINTS"); + + + +}; +class k8Event_DR1_BREAKPOINTS : public k8BaseEvent +{ +public: + + k8Event_DR1_BREAKPOINTS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Number of breakpoints for DR1"); + event_id = 0xDD; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DR1_BREAKPOINTS"); + + + +}; +class k8Event_DR2_BREAKPOINTS : public k8BaseEvent +{ +public: + + k8Event_DR2_BREAKPOINTS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Number of breakpoints for DR2"); + event_id = 0xDE; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DR2_BREAKPOINTS"); + + +}; +class k8Event_DR3_BREAKPOINTS : public k8BaseEvent +{ +public: + + k8Event_DR3_BREAKPOINTS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Number of breakpoints for DR3"); + event_id = 0xDF; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DR3_BREAKPOINTS"); + + +}; + + + +// E0 +typedef union EVENT_MASK( k8_page_access_event) +{ + struct + { + uint16 PageHit:1; // Page hit" }, + uint16 PageMiss:1; // Page miss" }, + uint16 PageConflict:1; // Page conflict" } } + }; + uint16 flat; + +}EVENT_MASK( k8_page_access_event); + +class k8Event_MEM_PAGE_ACCESS : public k8BaseEvent +{ +public: + + k8Event_MEM_PAGE_ACCESS() + { + eventMask = (EVENT_MASK(k8_page_access_event) *)&m_eventMask; + name = _T("Memory controller page access"); + event_id = 0xE0; + unitEncode = NB; + + } + EVENT_MASK(k8_page_access_event) * eventMask; + // name = _T("MEM_PAGE_ACCESS"); + + +}; +class k8Event_MEM_PAGE_TBL_OVERFLOW : public k8BaseEvent +{ +public: + + k8Event_MEM_PAGE_TBL_OVERFLOW() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Memory controller page table overflow"); + event_id = 0xE1; + unitEncode = NB; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("MEM_PAGE_TBL_OVERFLOW"); + + +}; +class k8Event_DRAM_SLOTS_MISSED : public k8BaseEvent +{ +public: + + k8Event_DRAM_SLOTS_MISSED() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Memory controller DRAM command slots missed (in MemClks)"); + event_id = 0xE2; + unitEncode = NB; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DRAM_SLOTS_MISSED"); + + +}; + + +// e3 +typedef union EVENT_MASK( k8_turnaround) +{ + + struct + { + uint16 DIMMTurnaround:1; //DIMM turnaround" }, + uint16 ReadToWriteTurnaround:1; //Read to write turnaround" }, + uint16 WriteToReadTurnaround:1; //Write to read turnaround" } } + }; + uint16 flat; + + +}EVENT_MASK( k8_turnaround); + +class k8Event_MEM_TURNAROUND : public k8BaseEvent +{ +public: + + k8Event_MEM_TURNAROUND() + { + eventMask = (EVENT_MASK(k8_turnaround) *)&m_eventMask; + name = _T("Memory controller turnaround"); + event_id = 0xE3; + unitEncode = NB; + + } + EVENT_MASK(k8_turnaround) * eventMask; + // name = _T("MEM_TURNAROUND"); + + +}; + + + + +// E4 +typedef union EVENT_MASK( k8_bypass_counter_saturation) +{ + struct + { + uint16 MEM_HighPriorityBypass:1; // Memory controller high priority bypass" }, + uint16 MEM_LowPriorityBypass:1; // Memory controller low priority bypass" }, + uint16 DRAM_InterfaceBypass:1; // DRAM controller interface bypass" }, + uint16 DRAM_QueueBypass:1; // DRAM controller queue bypass" } } + }; + uint16 flat; + +}EVENT_MASK( k8_bypass_counter_saturation); + +class k8Event_MEM_BYPASS_SAT : public k8BaseEvent +{ +public: + + k8Event_MEM_BYPASS_SAT() + { + eventMask = (EVENT_MASK(k8_bypass_counter_saturation) *)&m_eventMask; + name = _T("Memory controller bypass counter saturation"); + event_id = 0xE4; + unitEncode = NB; + + } + EVENT_MASK(k8_bypass_counter_saturation) * eventMask; + // name = _T("MEM_BYPASS_SAT"); + + +}; + + + +//EB +typedef union EVENT_MASK( k8_sized_commands) +{ + + struct + { + uint16 NonPostWrSzByte:1; // NonPostWrSzByte" }, + uint16 NonPostWrSzDword:1; // NonPostWrSzDword" }, + uint16 PostWrSzByte:1; // PostWrSzByte" }, + uint16 PostWrSzDword:1; // PostWrSzDword" }, + uint16 RdSzByte:1; // RdSzByte" }, + uint16 RdSzDword:1; // RdSzDword" }, + uint16 RdModWr:1; // RdModWr" } } + }; + uint16 flat; + + +}EVENT_MASK( k8_sized_commands); + + +class k8Event_SIZED_COMMANDS : public k8BaseEvent +{ +public: + + k8Event_SIZED_COMMANDS() + { + eventMask = (EVENT_MASK(k8_sized_commands) *)&m_eventMask; + name = _T("Sized commands"); + event_id = 0xEB; + unitEncode = NB; + + } + EVENT_MASK(k8_sized_commands) * eventMask; + // name = _T("SIZED_COMMANDS"); + + +}; + +typedef union EVENT_MASK( k8_probe_result) +{ + struct + { + uint16 ProbeMiss:1; // Probe miss" }, + uint16 ProbeHit:1; // Probe hit" }, + uint16 ProbeHitDirtyWithoutMemoryCancel:1; // Probe hit dirty without memory cancel" }, + uint16 ProbeHitDirtyWithMemoryCancel:1; // Probe hit dirty with memory cancel" } } + uint16 UpstreamDisplayRefreshReads:1; // Rev D and later + uint16 UpstreamNonDisplayRefreshReads:1; // Rev D and later + uint16 UpstreamWrites:1; // Rev D and later + }; + uint16 flat; + + +}EVENT_MASK( k8_probe_result); + + +class k8Event_PROBE_RESULT : public k8BaseEvent +{ +public: + + k8Event_PROBE_RESULT() + { + eventMask = (EVENT_MASK(k8_probe_result) *)&m_eventMask; + name = _T("Probe result"); + event_id = 0xEC; + unitEncode = NB; + + } + EVENT_MASK(k8_probe_result) * eventMask; + // name = _T("PROBE_RESULT"); + + +}; + +typedef union EVENT_MASK( k8_ht) +{ + + struct + { + uint16 CommandSent:1; //Command sent" }, + uint16 DataSent:1; //Data sent" }, + uint16 BufferReleaseSent:1; //Buffer release sent" + uint16 NopSent:1; //Nop sent" } } + }; + uint16 flat; + + +}EVENT_MASK( k8_ht); + + +class k8Event_HYPERTRANSPORT_BUS0_WIDTH : public k8BaseEvent +{ +public: + + k8Event_HYPERTRANSPORT_BUS0_WIDTH() + { + eventMask = (EVENT_MASK(k8_ht) *)&m_eventMask; + name = _T("Hypertransport (tm) bus 0 bandwidth"); + event_id = 0xF6; + unitEncode = NB; + + } + EVENT_MASK(k8_ht) * eventMask; + // name = _T("HYPERTRANSPORT_BUS0_WIDTH"); + + +}; +class k8Event_HYPERTRANSPORT_BUS1_WIDTH : public k8BaseEvent +{ +public: + + k8Event_HYPERTRANSPORT_BUS1_WIDTH() + { + eventMask = (EVENT_MASK(k8_ht) *)&m_eventMask; + name = _T("Hypertransport (tm) bus 1 bandwidth"); + event_id = 0xF7; + unitEncode = NB; + + } + EVENT_MASK(k8_ht) * eventMask; + // name = _T("HYPERTRANSPORT_BUS1_WIDTH"); + + +}; +class k8Event_HYPERTRANSPORT_BUS2_WIDTH : public k8BaseEvent +{ +public: + + k8Event_HYPERTRANSPORT_BUS2_WIDTH() + { + eventMask = (EVENT_MASK(k8_ht) *)&m_eventMask; + name = _T("Hypertransport (tm) bus 2 bandwidth"); + event_id = 0xF8; + unitEncode = NB; + + } + EVENT_MASK(k8_ht) * eventMask; + // name = _T("HYPERTRANSPORT_BUS2_WIDTH"); + +}; + +// +//typedef union EVENT_MASK( perfctr_event_set k8_common_event_set) +//{ +// +// .cpu_type = PERFCTR_X86_AMD_K8, +// .event_prefix = _T("K8_"), +// .include = &k7_official_event_set, +// .nevents = ARRAY_SIZE(k8_common_events), +// .events = k8_common_events, +//}EVENT_MASK( perfctr_event_set k8_common_event_set); +// +//typedef union EVENT_MASK( perfctr_event k8_events[]) +//{ +// +// { 0x24, 0xF, UM(NULL), _T("LOCKED_OP"), /* unit mask changed in Rev. C */ +// _T("Locked operation") }, +//}EVENT_MASK( perfctr_event k8_events[]); + + + + +//const struct perfctr_event_set perfctr_k8_event_set) +//{ +// +// .cpu_type = PERFCTR_X86_AMD_K8, +// .event_prefix = _T("K8_"), +// .include = &k8_common_event_set, +// .nevents = ARRAY_SIZE(k8_events), +// .events = k8_events, +//}; +// +/* + * K8 Revision C. Starts at CPUID 0xF58 for Opteron/Athlon64FX and + * CPUID 0xF48 for Athlon64. (CPUID 0xF51 is Opteron Revision B3.) + */ + + + + + + + + +// +//typedef union EVENT_MASK( k8_lock_accesses) +//{ +// struct +// { +// uint16 DcacheAccesses:1; // Number of dcache accesses by lock instructions" }, +// uint16 DcacheMisses:1; // Number of dcache misses by lock instructions" } } +// }; +// uint16 flat; +// +//}EVENT_MASK( k8_lock_accesses); +// + +#endif // K8PERFORMANCECOUNTERS_H diff --git a/external/vpc/public/tier0/l2cache.h b/external/vpc/public/tier0/l2cache.h new file mode 100644 index 0000000..db54695 --- /dev/null +++ b/external/vpc/public/tier0/l2cache.h @@ -0,0 +1,47 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// +#ifndef CL2CACHE_H +#define CL2CACHE_H +#ifdef _WIN32 +#pragma once +#endif + +class P4Event_BSQ_cache_reference; + +class CL2Cache +{ +public: + + CL2Cache(); + ~CL2Cache(); + + void Start( void ); + void End( void ); + + //------------------------------------------------------------------------- + // GetL2CacheMisses + //------------------------------------------------------------------------- + int GetL2CacheMisses( void ) + { + return m_iL2CacheMissCount; + } + +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, tchar *pchName ); // Validate our internal structures +#endif // DBGFLAG_VALIDATE + +private: + + int m_nID; + + P4Event_BSQ_cache_reference *m_pL2CacheEvent; + int64 m_i64Start; + int64 m_i64End; + int m_iL2CacheMissCount; +}; + +#endif // CL2CACHE_H + diff --git a/external/vpc/public/tier0/logging.h b/external/vpc/public/tier0/logging.h new file mode 100644 index 0000000..42b10c4 --- /dev/null +++ b/external/vpc/public/tier0/logging.h @@ -0,0 +1,767 @@ +//============ Copyright (c) Valve Corporation, All rights reserved. ============ +// +// Logging system declarations. +// +// The logging system is a channel-based output mechanism which allows +// subsystems to route their text/diagnostic output to various listeners +// +//=============================================================================== + +#ifndef LOGGING_H +#define LOGGING_H + +#if defined( COMPILER_MSVC ) +#pragma once +#endif + +#include "color.h" +#include "icommandline.h" +#include <stdio.h> + +// For XBX_** functions +#if defined( _X360 ) +#include "xbox/xbox_console.h" +#endif + +// Used by CColorizedLoggingListener +#if defined( _WIN32 ) || (defined(POSIX) && !defined(_GAMECONSOLE)) +#include "tier0/win32consoleio.h" +#endif + +/* + ---- Logging System ---- + + The logging system is a channel-based mechanism for all code (engine, + mod, tool) across all platforms to output information, warnings, + errors, etc. + + This system supersedes the existing Msg(), Warning(), Error(), DevMsg(), ConMsg() etc. functions. + There are channels defined in the new system through which all old messages are routed; + see LOG_GENERAL, LOG_CONSOLE, LOG_DEVELOPER, etc. + + To use the system, simply call one of the predefined macros: + + Log_Msg( ChannelID, [Color], Message, ... ) + Log_Warning( ChannelID, [Color], Message, ... ) + Log_Error( ChannelID, [Color], Message, ... ) + + A ChannelID is typically created by defining a logging channel with the + log channel macros: + + DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_ChannelName, "ChannelName", [Flags], [MinimumSeverity], [Color] ); + + or + + BEGIN_DEFINE_LOGGING_CHANNEL( LOG_ChannelName, "ChannelName", [Flags], [MinimumSeverity], [Color] ); + ADD_LOGGING_CHANNEL_TAG( "Tag1" ); + ADD_LOGGING_CHANNEL_TAG( "Tag2" ); + END_DEFINE_LOGGING_CHANNEL(); + + These macros create a global channel ID variable with the name specified + by the first parameter (in this example, LOG_ChannelName). This channel ID + can be used by various LoggingSystem_** functions to manipulate the channel settings. + + The optional [Flags] parameter is an OR'd together set of LoggingChannelFlags_t + values (default: 0). + + The optional [MinimumSeverity] parameter is the lowest threshold + above which messages will be processed (inclusive). The default is LS_MESSAGE, + which results in all messages, warnings, and errors being logged. + Variadic parameters to the Log_** functions will be ignored if a channel + is not enabled for a given severity (for performance reasons). + + Logging channels can have their minimum severity modified by name, ID, or tag. + + Logging channels are not hierarchical since there are situations in which + a channel needs to belong to multiple hierarchies. Use tags to create + categories or shallow hierarchies. + + @TODO (Feature wishlist): + 1) Callstack logging support + 2) Registering dynamic channels and unregistering channels at runtime + 3) Sentient robot to clean up the thousands of places using the old/legacy logging system. +*/ + +////////////////////////////////////////////////////////////////////////// +// Constants, Types, Forward Declares +////////////////////////////////////////////////////////////////////////// + +class CLoggingSystem; +class CThreadFastMutex; + +//----------------------------------------------------------------------------- +// Maximum length of a sprintf'ed logging message. +//----------------------------------------------------------------------------- +const int MAX_LOGGING_MESSAGE_LENGTH = 2048; + +//----------------------------------------------------------------------------- +// Maximum length of a channel or tag name. +//----------------------------------------------------------------------------- +const int MAX_LOGGING_IDENTIFIER_LENGTH = 32; + +//----------------------------------------------------------------------------- +// Maximum number of logging channels. Increase if needed. +//----------------------------------------------------------------------------- +const int MAX_LOGGING_CHANNEL_COUNT = 256; + +//----------------------------------------------------------------------------- +// Maximum number of logging tags across all channels. Increase if needed. +//----------------------------------------------------------------------------- +const int MAX_LOGGING_TAG_COUNT = 1024; + +//----------------------------------------------------------------------------- +// Maximum number of characters across all logging tags. Increase if needed. +//----------------------------------------------------------------------------- +const int MAX_LOGGING_TAG_CHARACTER_COUNT = 8192; + +//----------------------------------------------------------------------------- +// Maximum number of concurrent logging listeners in a given logging state. +//----------------------------------------------------------------------------- +const int MAX_LOGGING_LISTENER_COUNT = 16; + +//----------------------------------------------------------------------------- +// An invalid color set on a channel to imply that it should use +// a device-dependent default color where applicable. +//----------------------------------------------------------------------------- +const Color UNSPECIFIED_LOGGING_COLOR( 0, 0, 0, 0 ); + +//----------------------------------------------------------------------------- +// An ID returned by the logging system to refer to a logging channel. +//----------------------------------------------------------------------------- +typedef int LoggingChannelID_t; + +//----------------------------------------------------------------------------- +// A sentinel value indicating an invalid logging channel ID. +//----------------------------------------------------------------------------- +const LoggingChannelID_t INVALID_LOGGING_CHANNEL_ID = -1; + +//----------------------------------------------------------------------------- +// The severity of a logging operation. +//----------------------------------------------------------------------------- +enum LoggingSeverity_t +{ + //----------------------------------------------------------------------------- + // An informative logging message. + //----------------------------------------------------------------------------- + LS_MESSAGE = 0, + + //----------------------------------------------------------------------------- + // A warning, typically non-fatal + //----------------------------------------------------------------------------- + LS_WARNING = 1, + + //----------------------------------------------------------------------------- + // A message caused by an Assert**() operation. + //----------------------------------------------------------------------------- + LS_ASSERT = 2, + + //----------------------------------------------------------------------------- + // An error, typically fatal/unrecoverable. + //----------------------------------------------------------------------------- + LS_ERROR = 3, + + //----------------------------------------------------------------------------- + // A placeholder level, higher than any legal value. + // Not a real severity value! + //----------------------------------------------------------------------------- + LS_HIGHEST_SEVERITY = 4, +}; + +//----------------------------------------------------------------------------- +// Action which should be taken by logging system as a result of +// a given logged message. +// +// The logging system invokes ILoggingResponsePolicy::OnLog() on +// the specified policy object, which returns a LoggingResponse_t. +//----------------------------------------------------------------------------- +enum LoggingResponse_t +{ + LR_CONTINUE, + LR_DEBUGGER, + LR_ABORT, +}; + +//----------------------------------------------------------------------------- +// Logging channel behavior flags, set on channel creation. +//----------------------------------------------------------------------------- +enum LoggingChannelFlags_t +{ + //----------------------------------------------------------------------------- + // Indicates that the spew is only relevant to interactive consoles. + //----------------------------------------------------------------------------- + LCF_CONSOLE_ONLY = 0x00000001, + + //----------------------------------------------------------------------------- + // Indicates that spew should not be echoed to any output devices. + // A suitable logging listener must be registered which respects this flag + // (e.g. a file logger). + //----------------------------------------------------------------------------- + LCF_DO_NOT_ECHO = 0x00000002, +}; + +//----------------------------------------------------------------------------- +// A callback function used to register tags on a logging channel +// during initialization. +//----------------------------------------------------------------------------- +typedef void ( *RegisterTagsFunc )(); + +//----------------------------------------------------------------------------- +// A context structure passed to logging listeners and response policy classes. +//----------------------------------------------------------------------------- +struct LoggingContext_t +{ + // ID of the channel being logged to. + LoggingChannelID_t m_ChannelID; + // Flags associated with the channel. + LoggingChannelFlags_t m_Flags; + // Severity of the logging event. + LoggingSeverity_t m_Severity; + // Color of logging message if one was specified to Log_****() macro. + // If not specified, falls back to channel color. + // If channel color is not specified, this value is UNSPECIFIED_LOGGING_COLOR + // and indicates that a suitable default should be chosen. + Color m_Color; +}; + +//----------------------------------------------------------------------------- +// Interface for classes to handle logging output. +// +// The Log() function of this class is called synchronously and serially +// by the logging system on all registered instances of ILoggingListener +// in the current "logging state". +// +// Derived classes may do whatever they want with the message (write to disk, +// write to console, send over the network, drop on the floor, etc.). +// +// In general, derived classes should do one, simple thing with the output +// to allow callers to register multiple, orthogonal logging listener classes. +//----------------------------------------------------------------------------- +class ILoggingListener +{ +public: + virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage ) = 0; +}; + +//----------------------------------------------------------------------------- +// Interface for policy classes which determine how to behave when a +// message is logged. +// +// Can return: +// LR_CONTINUE (continue execution) +// LR_DEBUGGER (break into debugger if one is present, otherwise continue) +// LR_ABORT (terminate process immediately with a failure code of 1) +//----------------------------------------------------------------------------- +class ILoggingResponsePolicy +{ +public: + virtual LoggingResponse_t OnLog( const LoggingContext_t *pContext ) = 0; +}; + +////////////////////////////////////////////////////////////////////////// +// Common Logging Listeners & Logging Response Policies +////////////////////////////////////////////////////////////////////////// + +//----------------------------------------------------------------------------- +// A basic logging listener which prints to stdout and the debug channel. +//----------------------------------------------------------------------------- +class CSimpleLoggingListener : public ILoggingListener +{ +public: + CSimpleLoggingListener( bool bQuietPrintf = false, bool bQuietDebugger = false ) : + m_bQuietPrintf( bQuietPrintf ), + m_bQuietDebugger( bQuietDebugger ) + { + } + + virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage ) + { +#ifdef _X360 + if ( !m_bQuietDebugger && XBX_IsConsoleConnected() ) + { + // send to console + XBX_DebugString( XMAKECOLOR( 0,0,0 ), pMessage ); + } + else +#endif + { +#if !defined( _CERT ) && !defined( DBGFLAG_STRINGS_STRIP ) + if ( !m_bQuietPrintf ) + { + _tprintf( _T("%s"), pMessage ); + } +#endif + +#ifdef _WIN32 + if ( !m_bQuietDebugger && Plat_IsInDebugSession() ) + { + Plat_DebugString( pMessage ); + } +#endif + } + } + + // If set to true, does not print anything to stdout. + bool m_bQuietPrintf; + // If set to true, does not print anything to debugger. + bool m_bQuietDebugger; +}; + +//----------------------------------------------------------------------------- +// A basic logging listener for GUI applications +//----------------------------------------------------------------------------- +class CSimpleWindowsLoggingListener : public ILoggingListener +{ +public: + virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage ) + { + if ( Plat_IsInDebugSession() ) + { + Plat_DebugString( pMessage ); + } + if ( pContext->m_Severity == LS_ERROR ) + { + if ( Plat_IsInDebugSession() ) + DebuggerBreak(); + + Plat_MessageBox( "Error", pMessage ); + } + } +}; + + +//----------------------------------------------------------------------------- +// ** NOTE FOR INTEGRATION ** +// This was copied over from source 2 rather than integrated because +// source 2 has more significantly refactored tier0 logging. +// +// A logging listener with Win32 console API color support which which prints +// to stdout and the debug channel. +//----------------------------------------------------------------------------- +#if !defined(_GAMECONSOLE) +class CColorizedLoggingListener : public CSimpleLoggingListener +{ +public: + CColorizedLoggingListener( bool bQuietPrintf = false, bool bQuietDebugger = false ) : CSimpleLoggingListener( bQuietPrintf, bQuietDebugger ) + { + InitWin32ConsoleColorContext( &m_ColorContext ); + } + + virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage ) + { + if ( !m_bQuietPrintf ) + { + int nPrevColor = -1; + + if ( pContext->m_Color != UNSPECIFIED_LOGGING_COLOR ) + { + nPrevColor = SetWin32ConsoleColor( &m_ColorContext, + pContext->m_Color.r(), pContext->m_Color.g(), pContext->m_Color.b(), + MAX( MAX( pContext->m_Color.r(), pContext->m_Color.g() ), pContext->m_Color.b() ) > 128 ); + } + + _tprintf( _T("%s"), pMessage ); + + if ( nPrevColor >= 0 ) + { + RestoreWin32ConsoleColor( &m_ColorContext, nPrevColor ); + } + } + +#ifdef _WIN32 + if ( !m_bQuietDebugger && Plat_IsInDebugSession() ) + { + Plat_DebugString( pMessage ); + } +#endif + } + + Win32ConsoleColorContext_t m_ColorContext; +}; +#endif // !_GAMECONSOLE + + +//----------------------------------------------------------------------------- +// Default logging response policy used when one is not specified. +//----------------------------------------------------------------------------- +class CDefaultLoggingResponsePolicy : public ILoggingResponsePolicy +{ +public: + virtual LoggingResponse_t OnLog( const LoggingContext_t *pContext ) + { + if ( pContext->m_Severity == LS_ASSERT && !CommandLine()->FindParm( "-noassert" ) ) + { + return LR_DEBUGGER; + } + else if ( pContext->m_Severity == LS_ERROR ) + { + return LR_ABORT; + } + else + { + return LR_CONTINUE; + } + } +}; + +//----------------------------------------------------------------------------- +// A logging response policy which never terminates the process, even on error. +//----------------------------------------------------------------------------- +class CNonFatalLoggingResponsePolicy : public ILoggingResponsePolicy +{ +public: + virtual LoggingResponse_t OnLog( const LoggingContext_t *pContext ) + { + if ( ( pContext->m_Severity == LS_ASSERT && !CommandLine()->FindParm( "-noassert" ) ) || pContext->m_Severity == LS_ERROR ) + { + return LR_DEBUGGER; + } + else + { + return LR_CONTINUE; + } + } +}; + +////////////////////////////////////////////////////////////////////////// +// Central Logging System +////////////////////////////////////////////////////////////////////////// + +//----------------------------------------------------------------------------- +// The central logging system. +// +// Multiple instances can exist, though all exported tier0 functionality +// specifically works with a single global instance +// (via GetGlobalLoggingSystem()). +//----------------------------------------------------------------------------- +class CLoggingSystem +{ +public: + struct LoggingChannel_t; + + CLoggingSystem(); + ~CLoggingSystem(); + + //----------------------------------------------------------------------------- + // Register a logging channel with the logging system. + // The same channel can be registered multiple times, but the parameters + // in each call to RegisterLoggingChannel must either match across all calls + // or be set to defaults on any given call + // + // This function is not thread-safe and should generally only be called + // by a single thread. Using the logging channel definition macros ensures + // that this is called on the static initialization thread. + //----------------------------------------------------------------------------- + LoggingChannelID_t RegisterLoggingChannel( const char *pChannelName, RegisterTagsFunc registerTagsFunc, int flags = 0, LoggingSeverity_t minimumSeverity = LS_MESSAGE, Color spewColor = UNSPECIFIED_LOGGING_COLOR ); + + //----------------------------------------------------------------------------- + // Gets a channel ID from a string name. + // Performs a simple linear search; cache the value whenever possible + // or re-register the logging channel to get a global ID. + //----------------------------------------------------------------------------- + LoggingChannelID_t FindChannel( const char *pChannelName ) const; + + int GetChannelCount() const { return m_nChannelCount; } + + //----------------------------------------------------------------------------- + // Gets a pointer to the logging channel description. + //----------------------------------------------------------------------------- + LoggingChannel_t *GetChannel( LoggingChannelID_t channelID ); + const LoggingChannel_t *GetChannel( LoggingChannelID_t channelID ) const; + + //----------------------------------------------------------------------------- + // Returns true if the given channel has the specified tag. + //----------------------------------------------------------------------------- + bool HasTag( LoggingChannelID_t channelID, const char *pTag ) const { return GetChannel( channelID )->HasTag( pTag ); } + + //----------------------------------------------------------------------------- + // Returns true if the given channel has been initialized. + // The main purpose is catching m_nChannelCount being zero because no channels have been registered. + //----------------------------------------------------------------------------- + bool IsValidChannelID( LoggingChannelID_t channelID ) const { return ( channelID >= 0 ) && ( channelID < m_nChannelCount ); } + + //----------------------------------------------------------------------------- + // Returns true if the given channel will spew at the given severity level. + //----------------------------------------------------------------------------- + bool IsChannelEnabled( LoggingChannelID_t channelID, LoggingSeverity_t severity ) const { return IsValidChannelID( channelID ) && GetChannel( channelID )->IsEnabled( severity ); } + + //----------------------------------------------------------------------------- + // Functions to set the spew level of a channel either directly by ID or + // string name, or for all channels with a given tag. + // + // These functions are not technically thread-safe but calling them across + // multiple threads should cause no significant problems + // (the underlying data types being changed are 32-bit/atomic). + //----------------------------------------------------------------------------- + void SetChannelSpewLevel( LoggingChannelID_t channelID, LoggingSeverity_t minimumSeverity ); + void SetChannelSpewLevelByName( const char *pName, LoggingSeverity_t minimumSeverity ); + void SetChannelSpewLevelByTag( const char *pTag, LoggingSeverity_t minimumSeverity ); + + //----------------------------------------------------------------------------- + // Gets or sets the color of a logging channel. + // (The functions are not thread-safe, but the consequences are not + // significant.) + //----------------------------------------------------------------------------- + Color GetChannelColor( LoggingChannelID_t channelID ) const { return GetChannel( channelID )->m_SpewColor; } + void SetChannelColor( LoggingChannelID_t channelID, Color color ) { GetChannel( channelID )->m_SpewColor = color; } + + //----------------------------------------------------------------------------- + // Gets or sets the flags on a logging channel. + // (The functions are not thread-safe, but the consequences are not + // significant.) + //----------------------------------------------------------------------------- + LoggingChannelFlags_t GetChannelFlags( LoggingChannelID_t channelID ) const { return GetChannel( channelID )->m_Flags; } + void SetChannelFlags( LoggingChannelID_t channelID, LoggingChannelFlags_t flags ) { GetChannel( channelID )->m_Flags = flags; } + + //----------------------------------------------------------------------------- + // Adds a string tag to a channel. + // This is not thread-safe and should only be called by a RegisterTagsFunc + // callback passed in to RegisterLoggingChannel (via the + // channel definition macros). + //----------------------------------------------------------------------------- + void AddTagToCurrentChannel( const char *pTagName ); + + //----------------------------------------------------------------------------- + // Functions to save/restore the current logging state. + // Set bThreadLocal to true on a matching Push/Pop call if the intent + // is to override the logging listeners on the current thread only. + // + // Pushing the current logging state onto the state stack results + // in the current state being cleared by default (no listeners, default logging response policy). + // Set bClearState to false to copy the existing listener pointers to the new state. + // + // These functions which mutate logging state ARE thread-safe and are + // guarded by m_StateMutex. + //----------------------------------------------------------------------------- + void PushLoggingState( bool bThreadLocal = false, bool bClearState = true ); + void PopLoggingState( bool bThreadLocal = false ); + + //----------------------------------------------------------------------------- + // Registers a logging listener (a class which handles logged messages). + //----------------------------------------------------------------------------- + void RegisterLoggingListener( ILoggingListener *pListener ); + + //----------------------------------------------------------------------------- + // Removes a logging listener from the registered list + //----------------------------------------------------------------------------- + void UnregisterLoggingListener( ILoggingListener *pListener ); + + //----------------------------------------------------------------------------- + // Returns whether the specified logging listener is registered. + //----------------------------------------------------------------------------- + bool IsListenerRegistered( ILoggingListener *pListener ); + + //----------------------------------------------------------------------------- + // Clears out all of the current logging state (removes all listeners, + // sets the response policy to the default). + //----------------------------------------------------------------------------- + void ResetCurrentLoggingState(); + + //----------------------------------------------------------------------------- + // Sets a policy class to decide what should happen when messages of a + // particular severity are logged + // (e.g. exit on error, break into debugger). + // If pLoggingResponse is NULL, uses the default response policy class. + //----------------------------------------------------------------------------- + void SetLoggingResponsePolicy( ILoggingResponsePolicy *pLoggingResponse ); + + //----------------------------------------------------------------------------- + // Logs a message to the specified channel using a given severity and + // spew color. Passing in UNSPECIFIED_LOGGING_COLOR for 'color' allows + // the logging listeners to provide a default. + // NOTE: test 'IsChannelEnabled(channelID,severity)' before calling this! + //----------------------------------------------------------------------------- + LoggingResponse_t LogDirect( LoggingChannelID_t channelID, LoggingSeverity_t severity, Color color, const tchar *pMessage ); + + // Internal data to represent a logging tag + struct LoggingTag_t + { + const char *m_pTagName; + LoggingTag_t *m_pNextTag; + }; + + // Internal data to represent a logging channel. + struct LoggingChannel_t + { + bool HasTag( const char *pTag ) const + { + LoggingTag_t *pCurrentTag = m_pFirstTag; + while( pCurrentTag != NULL ) + { + if ( stricmp( pCurrentTag->m_pTagName, pTag ) == 0 ) + { + return true; + } + pCurrentTag = pCurrentTag->m_pNextTag; + } + return false; + } + bool IsEnabled( LoggingSeverity_t severity ) const { return severity >= m_MinimumSeverity; } + void SetSpewLevel( LoggingSeverity_t severity ) { m_MinimumSeverity = severity; } + + LoggingChannelID_t m_ID; + LoggingChannelFlags_t m_Flags; // an OR'd combination of LoggingChannelFlags_t + LoggingSeverity_t m_MinimumSeverity; // The minimum severity level required to activate this channel. + Color m_SpewColor; + char m_Name[MAX_LOGGING_IDENTIFIER_LENGTH]; + LoggingTag_t *m_pFirstTag; + }; + +private: + // Represents the current state of the logger (registered listeners, response policy class, etc.) and can + // vary from thread-to-thread. It can also be pushed/popped to save/restore listener/response state. + struct LoggingState_t + { + // Index of the previous entry on the listener set stack. + int m_nPreviousStackEntry; + + // Number of active listeners in this set. Cannot exceed MAX_LOGGING_LISTENER_COUNT. + // If set to -1, implies that this state structure is not in use. + int m_nListenerCount; + // Array of registered logging listener objects. + ILoggingListener *m_RegisteredListeners[MAX_LOGGING_LISTENER_COUNT]; + + // Specific policy class to determine behavior of logging system under specific message types. + ILoggingResponsePolicy *m_pLoggingResponse; + }; + + // These state functions to assume the caller has already grabbed the mutex. + LoggingState_t *GetCurrentState(); + const LoggingState_t *GetCurrentState() const; + + int FindUnusedStateIndex(); + LoggingTag_t *AllocTag( const char *pTagName ); + + int m_nChannelCount; + LoggingChannel_t m_RegisteredChannels[MAX_LOGGING_CHANNEL_COUNT]; + + int m_nChannelTagCount; + LoggingTag_t m_ChannelTags[MAX_LOGGING_TAG_COUNT]; + + // Index to first free character in name pool. + int m_nTagNamePoolIndex; + // Pool of character data used for tag names. + char m_TagNamePool[MAX_LOGGING_TAG_CHARACTER_COUNT]; + + // Protects all data in this class except the registered channels + // (which are supposed to be registered using the macros at static/global init time). + // It is assumed that this mutex is reentrant safe on all platforms. + CThreadFastMutex *m_pStateMutex; + + // The index of the current "global" state of the logging system. By default, all threads use this state + // for logging unless a given thread has pushed the logging state with bThreadLocal == true. + // If a thread-local state has been pushed, g_nThreadLocalStateIndex (a global thread-local integer) will be non-zero. + // By default, g_nThreadLocalStateIndex is 0 for all threads. + int m_nGlobalStateIndex; + + // A pool of logging states used to store a stack (potentially per-thread). + static const int MAX_LOGGING_STATE_COUNT = 16; + LoggingState_t m_LoggingStates[MAX_LOGGING_STATE_COUNT]; + + // Default policy class which determines behavior. + CDefaultLoggingResponsePolicy m_DefaultLoggingResponse; + + // Default spew function. + CSimpleLoggingListener m_DefaultLoggingListener; + +}; + +////////////////////////////////////////////////////////////////////////// +// Logging Macros +////////////////////////////////////////////////////////////////////////// + +// This macro will resolve to the most appropriate overload of LoggingSystem_Log() depending on the number of parameters passed in. +#ifdef DBGFLAG_STRINGS_STRIP +#define InternalMsg( Channel, Severity, /* [Color], Message, */ ... ) do { if ( Severity == LS_ERROR && LoggingSystem_IsChannelEnabled( Channel, Severity ) ) LoggingSystem_Log( Channel, Severity, /* [Color], Message, */ ##__VA_ARGS__ ); } while( 0 ) +#else +#define InternalMsg( Channel, Severity, /* [Color], Message, */ ... ) do { if ( LoggingSystem_IsChannelEnabled( Channel, Severity ) ) LoggingSystem_Log( Channel, Severity, /* [Color], Message, */ ##__VA_ARGS__ ); } while( 0 ) +#endif + +//----------------------------------------------------------------------------- +// New macros, use these! +// +// The macros take an optional Color parameter followed by the message +// and the message formatting. +// We rely on the variadic macro (__VA_ARGS__) operator to paste in the +// extra parameters and resolve to the appropriate overload. +//----------------------------------------------------------------------------- +#define Log_Msg( Channel, /* [Color], Message, */ ... ) InternalMsg( Channel, LS_MESSAGE, /* [Color], Message, */ ##__VA_ARGS__ ) +#define Log_Warning( Channel, /* [Color], Message, */ ... ) InternalMsg( Channel, LS_WARNING, /* [Color], Message, */ ##__VA_ARGS__ ) +#define Log_Error( Channel, /* [Color], Message, */ ... ) InternalMsg( Channel, LS_ERROR, /* [Color], Message, */ ##__VA_ARGS__ ) +#ifdef DBGFLAG_STRINGS_STRIP +#define Log_Assert( ... ) LR_CONTINUE +#else +#define Log_Assert( Message, ... ) LoggingSystem_LogAssert( Message, ##__VA_ARGS__ ) +#endif + + +#define DECLARE_LOGGING_CHANNEL( Channel ) extern LoggingChannelID_t Channel + +#define DEFINE_LOGGING_CHANNEL_NO_TAGS( Channel, ChannelName, /* [Flags], [Severity], [Color] */ ... ) \ + LoggingChannelID_t Channel = LoggingSystem_RegisterLoggingChannel( ChannelName, NULL, ##__VA_ARGS__ ) + +#define BEGIN_DEFINE_LOGGING_CHANNEL( Channel, ChannelName, /* [Flags], [Severity], [Color] */ ... ) \ + static void Register_##Channel##_Tags(); \ + LoggingChannelID_t Channel = LoggingSystem_RegisterLoggingChannel( ChannelName, Register_##Channel##_Tags, ##__VA_ARGS__ ); \ + void Register_##Channel##_Tags() \ + { + +#define ADD_LOGGING_CHANNEL_TAG( Tag ) LoggingSystem_AddTagToCurrentChannel( Tag ) + +#define END_DEFINE_LOGGING_CHANNEL() \ + } + +////////////////////////////////////////////////////////////////////////// +// DLL Exports +////////////////////////////////////////////////////////////////////////// + +// For documentation on these functions, please look at the corresponding function +// in CLoggingSystem (unless otherwise specified). +PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_RegisterLoggingChannel( const char *pName, RegisterTagsFunc registerTagsFunc, int flags = 0, LoggingSeverity_t severity = LS_MESSAGE, Color color = UNSPECIFIED_LOGGING_COLOR ); + +PLATFORM_INTERFACE void LoggingSystem_RegisterLoggingListener( ILoggingListener *pListener ); +PLATFORM_INTERFACE void LoggingSystem_UnregisterLoggingListener( ILoggingListener *pListener ); +PLATFORM_INTERFACE void LoggingSystem_ResetCurrentLoggingState(); +PLATFORM_INTERFACE void LoggingSystem_SetLoggingResponsePolicy( ILoggingResponsePolicy *pResponsePolicy ); +// NOTE: PushLoggingState() saves the current logging state on a stack and results in a new clear state +// (no listeners, default logging response policy). +PLATFORM_INTERFACE void LoggingSystem_PushLoggingState( bool bThreadLocal = false, bool bClearState = true ); +PLATFORM_INTERFACE void LoggingSystem_PopLoggingState( bool bThreadLocal = false ); + +PLATFORM_INTERFACE void LoggingSystem_AddTagToCurrentChannel( const char *pTagName ); + +// Returns INVALID_LOGGING_CHANNEL_ID if not found +PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_FindChannel( const char *pChannelName ); +PLATFORM_INTERFACE int LoggingSystem_GetChannelCount(); +PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_GetFirstChannelID(); +// Returns INVALID_LOGGING_CHANNEL_ID when there are no channels remaining. +PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_GetNextChannelID( LoggingChannelID_t channelID ); +PLATFORM_INTERFACE const CLoggingSystem::LoggingChannel_t *LoggingSystem_GetChannel( LoggingChannelID_t channelID ); + +PLATFORM_INTERFACE bool LoggingSystem_HasTag( LoggingChannelID_t channelID, const char *pTag ); + +PLATFORM_INTERFACE bool LoggingSystem_IsChannelEnabled( LoggingChannelID_t channelID, LoggingSeverity_t severity ); +PLATFORM_INTERFACE void LoggingSystem_SetChannelSpewLevel( LoggingChannelID_t channelID, LoggingSeverity_t minimumSeverity ); +PLATFORM_INTERFACE void LoggingSystem_SetChannelSpewLevelByName( const char *pName, LoggingSeverity_t minimumSeverity ); +PLATFORM_INTERFACE void LoggingSystem_SetChannelSpewLevelByTag( const char *pTag, LoggingSeverity_t minimumSeverity ); + +// Color is represented as an int32 due to C-linkage restrictions +PLATFORM_INTERFACE int32 LoggingSystem_GetChannelColor( LoggingChannelID_t channelID ); +PLATFORM_INTERFACE void LoggingSystem_SetChannelColor( LoggingChannelID_t channelID, int color ); + +PLATFORM_INTERFACE LoggingChannelFlags_t LoggingSystem_GetChannelFlags( LoggingChannelID_t channelID ); +PLATFORM_INTERFACE void LoggingSystem_SetChannelFlags( LoggingChannelID_t channelID, LoggingChannelFlags_t flags ); + +//----------------------------------------------------------------------------- +// Logs a variable-argument to a given channel with the specified severity. +// NOTE: if adding overloads to this function, remember that the Log_*** +// macros simply pass their variadic parameters through to LoggingSystem_Log(). +// Therefore, you need to ensure that the parameters are in the same general +// order and that there are no ambiguities with the overload. +//----------------------------------------------------------------------------- +PLATFORM_INTERFACE LoggingResponse_t LoggingSystem_Log( LoggingChannelID_t channelID, LoggingSeverity_t severity, const char *pMessageFormat, ... ) FMTFUNCTION( 3, 4 ); +PLATFORM_OVERLOAD LoggingResponse_t LoggingSystem_Log( LoggingChannelID_t channelID, LoggingSeverity_t severity, Color spewColor, const char *pMessageFormat, ... ) FMTFUNCTION( 4, 5 ); + +PLATFORM_INTERFACE LoggingResponse_t LoggingSystem_LogDirect( LoggingChannelID_t channelID, LoggingSeverity_t severity, Color spewColor, const char *pMessage ); +PLATFORM_INTERFACE LoggingResponse_t LoggingSystem_LogAssert( const char *pMessageFormat, ... ) FMTFUNCTION( 1, 2 ); + +#endif // LOGGING_H
\ No newline at end of file diff --git a/external/vpc/public/tier0/mem.h b/external/vpc/public/tier0/mem.h new file mode 100644 index 0000000..ffb590b --- /dev/null +++ b/external/vpc/public/tier0/mem.h @@ -0,0 +1,50 @@ +//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Memory allocation! +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TIER0_MEM_H +#define TIER0_MEM_H + +#ifdef _WIN32 +#pragma once +#endif + +#include <stddef.h> + + +#include "tier0/platform.h" + +#if !defined(STATIC_TIER0) && !defined(_STATIC_LINKED) + +#ifdef TIER0_DLL_EXPORT +# define MEM_INTERFACE DLL_EXPORT +#else +# define MEM_INTERFACE DLL_IMPORT +#endif + +#else // BUILD_AS_DLL + +#define MEM_INTERFACE extern + +#endif // BUILD_AS_DLL + + + +//----------------------------------------------------------------------------- +// DLL-exported methods for particular kinds of memory +//----------------------------------------------------------------------------- +MEM_INTERFACE void *MemAllocScratch( int nMemSize ); +MEM_INTERFACE void MemFreeScratch(); + +#if defined( POSIX ) +MEM_INTERFACE void ZeroMemory( void *mem, size_t length ); +#endif + +//Only works with USE_MEM_DEBUG and memory allocation call stack tracking enabled. +MEM_INTERFACE int GetAllocationCallStack( void *mem, void **pCallStackOut, int iMaxEntriesOut ); + + +#endif /* TIER0_MEM_H */ diff --git a/external/vpc/public/tier0/memalloc.h b/external/vpc/public/tier0/memalloc.h new file mode 100644 index 0000000..4254e74 --- /dev/null +++ b/external/vpc/public/tier0/memalloc.h @@ -0,0 +1,701 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: This header should never be used directly from leaf code!!! +// Instead, just add the file memoverride.cpp into your project and all this +// will automagically be used +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TIER0_MEMALLOC_H +#define TIER0_MEMALLOC_H + +#ifdef _WIN32 +#pragma once +#endif + +// These memory debugging switches aren't relevant under Linux builds since memoverride.cpp +// isn't built into Linux projects +#ifndef LINUX +// Define this in release to get memory tracking even in release builds +//#define USE_MEM_DEBUG 1 + +// Define this in release to get light memory debugging +//#define USE_LIGHT_MEM_DEBUG + +// Define this to require -uselmd to turn light memory debugging on +//#define LIGHT_MEM_DEBUG_REQUIRES_CMD_LINE_SWITCH +#endif + +#if defined( _MEMTEST ) +#if defined( _WIN32 ) || defined( _PS3 ) +#define USE_MEM_DEBUG 1 +#endif +#endif + + +#if defined( _PS3 ) +// Define STEAM_SHARES_GAME_ALLOCATOR to make Steam use the game's tier0 memory allocator. +// This adds some memory to the game's Small Block Heap and Medium Block Heap, to compensate. +// This configuration was disabled for Portal 2, as we could not sufficiently test it before ship. +//#define STEAM_SHARES_GAME_ALLOCATOR +#endif + +#if defined( STEAM_SHARES_GAME_ALLOCATOR ) +#define MBYTES_STEAM_SBH_USAGE 2 +#define MBYTES_STEAM_MBH_USAGE 4 +#else // STEAM_SHARES_GAME_ALLOCATOR +#define MBYTES_STEAM_SBH_USAGE 0 +#define MBYTES_STEAM_MBH_USAGE 0 +#endif // STEAM_SHARES_GAME_ALLOCATOR + +// Undefine this if using a compiler lacking threadsafe RTTI (like vc6) +#define MEM_DEBUG_CLASSNAME 1 + +#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE) + +#include <stddef.h> +#ifdef LINUX +#undef offsetof +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#endif + +#ifdef _PS3 +#define MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS 1 +#endif + +#include "tier0/mem.h" + +struct _CrtMemState; + +#define MEMALLOC_VERSION 1 + +typedef size_t (*MemAllocFailHandler_t)( size_t ); + +struct GenericMemoryStat_t +{ + const char *name; + int value; +}; + + +// Virtual memory interface +#include "tier0/memvirt.h" + + +//----------------------------------------------------------------------------- +// NOTE! This should never be called directly from leaf code +// Just use new,delete,malloc,free etc. They will call into this eventually +//----------------------------------------------------------------------------- +abstract_class IMemAlloc +{ +public: + // Release versions + virtual void *Alloc( size_t nSize ) = 0; +public: + virtual void *Realloc( void *pMem, size_t nSize ) = 0; + + virtual void Free( void *pMem ) = 0; + virtual void *Expand_NoLongerSupported( void *pMem, size_t nSize ) = 0; + + // Debug versions + virtual void *Alloc( size_t nSize, const char *pFileName, int nLine ) = 0; +public: + virtual void *Realloc( void *pMem, size_t nSize, const char *pFileName, int nLine ) = 0; + virtual void Free( void *pMem, const char *pFileName, int nLine ) = 0; + virtual void *Expand_NoLongerSupported( void *pMem, size_t nSize, const char *pFileName, int nLine ) = 0; + +#ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS + virtual void *AllocAlign( size_t nSize, size_t align ) = 0; + virtual void *AllocAlign( size_t nSize, size_t align, const char *pFileName, int nLine ) = 0; + virtual void *ReallocAlign( void *pMem, size_t nSize, size_t align ) = 0; +#endif + + inline void *IndirectAlloc( size_t nSize ) { return Alloc( nSize ); } + inline void *IndirectAlloc( size_t nSize, const char *pFileName, int nLine ) { return Alloc( nSize, pFileName, nLine ); } + + // Returns the size of a particular allocation (NOTE: may be larger than the size requested!) + virtual size_t GetSize( void *pMem ) = 0; + + // Force file + line information for an allocation + virtual void PushAllocDbgInfo( const char *pFileName, int nLine ) = 0; + virtual void PopAllocDbgInfo() = 0; + + // FIXME: Remove when we have our own allocator + // these methods of the Crt debug code is used in our codebase currently + virtual int32 CrtSetBreakAlloc( int32 lNewBreakAlloc ) = 0; + virtual int CrtSetReportMode( int nReportType, int nReportMode ) = 0; + virtual int CrtIsValidHeapPointer( const void *pMem ) = 0; + virtual int CrtIsValidPointer( const void *pMem, unsigned int size, int access ) = 0; + virtual int CrtCheckMemory( void ) = 0; + virtual int CrtSetDbgFlag( int nNewFlag ) = 0; + virtual void CrtMemCheckpoint( _CrtMemState *pState ) = 0; + + // FIXME: Make a better stats interface + virtual void DumpStats() = 0; + virtual void DumpStatsFileBase( char const *pchFileBase ) = 0; + virtual size_t ComputeMemoryUsedBy( char const *pchSubStr ) = 0; + + // FIXME: Remove when we have our own allocator + virtual void* CrtSetReportFile( int nRptType, void* hFile ) = 0; + virtual void* CrtSetReportHook( void* pfnNewHook ) = 0; + virtual int CrtDbgReport( int nRptType, const char * szFile, + int nLine, const char * szModule, const char * pMsg ) = 0; + + virtual int heapchk() = 0; + + virtual bool IsDebugHeap() = 0; + + virtual void GetActualDbgInfo( const char *&pFileName, int &nLine ) = 0; + virtual void RegisterAllocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ) = 0; + virtual void RegisterDeallocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ) = 0; + + virtual int GetVersion() = 0; + + virtual void CompactHeap() = 0; + + // Function called when malloc fails or memory limits hit to attempt to free up memory (can come in any thread) + virtual MemAllocFailHandler_t SetAllocFailHandler( MemAllocFailHandler_t pfnMemAllocFailHandler ) = 0; + + virtual void DumpBlockStats( void * ) = 0; + + virtual void SetStatsExtraInfo( const char *pMapName, const char *pComment ) = 0; + + // Returns 0 if no failure, otherwise the size_t of the last requested chunk + virtual size_t MemoryAllocFailed() = 0; + + virtual void CompactIncremental() = 0; + + virtual void OutOfMemory( size_t nBytesAttempted = 0 ) = 0; + + // Region-based allocations + virtual void *RegionAlloc( int region, size_t nSize ) = 0; + virtual void *RegionAlloc( int region, size_t nSize, const char *pFileName, int nLine ) = 0; + + // Replacement for ::GlobalMemoryStatus which accounts for unused memory in our system + virtual void GlobalMemoryStatus( size_t *pUsedMemory, size_t *pFreeMemory ) = 0; + + // Obtain virtual memory manager interface + virtual IVirtualMemorySection * AllocateVirtualMemorySection( size_t numMaxBytes ) = 0; + + // Request 'generic' memory stats (returns a list of N named values; caller should assume this list will change over time) + virtual int GetGenericMemoryStats( GenericMemoryStat_t **ppMemoryStats ) = 0; + + virtual ~IMemAlloc() { }; + + // handles storing allocation info for coroutines + virtual uint32 GetDebugInfoSize() = 0; + virtual void SaveDebugInfo( void *pvDebugInfo ) = 0; + virtual void RestoreDebugInfo( const void *pvDebugInfo ) = 0; + virtual void InitDebugInfo( void *pvDebugInfo, const char *pchRootFileName, int nLine ) = 0; +}; + +//----------------------------------------------------------------------------- +// Singleton interface +//----------------------------------------------------------------------------- +#ifdef _PS3 + +PLATFORM_INTERFACE IMemAlloc * g_pMemAllocInternalPS3; +#ifndef PLATFORM_INTERFACE_MEM_ALLOC_INTERNAL_PS3_OVERRIDE +#define g_pMemAlloc g_pMemAllocInternalPS3 +#else +#define g_pMemAlloc PLATFORM_INTERFACE_MEM_ALLOC_INTERNAL_PS3_OVERRIDE +#endif + +#else // !_PS3 + +MEM_INTERFACE IMemAlloc *g_pMemAlloc; + +#endif + +//----------------------------------------------------------------------------- + +#ifdef MEMALLOC_REGIONS +#ifndef MEMALLOC_REGION +#define MEMALLOC_REGION 0 +#endif +inline void *MemAlloc_Alloc( size_t nSize ) +{ + return g_pMemAlloc->RegionAlloc( MEMALLOC_REGION, nSize ); +} + +inline void *MemAlloc_Alloc( size_t nSize, const char *pFileName, int nLine ) +{ + return g_pMemAlloc->RegionAlloc( MEMALLOC_REGION, nSize, pFileName, nLine ); +} +#else +#undef MEMALLOC_REGION +inline void *MemAlloc_Alloc( size_t nSize ) +{ + return g_pMemAlloc->IndirectAlloc( nSize ); +} + +inline void *MemAlloc_Alloc( size_t nSize, const char *pFileName, int nLine ) +{ + return g_pMemAlloc->IndirectAlloc( nSize, pFileName, nLine ); +} +#endif + +//----------------------------------------------------------------------------- + +#ifdef MEMALLOC_REGIONS +#else +#endif + + +inline bool ValueIsPowerOfTwo( size_t value ) // don't clash with mathlib definition +{ + return (value & ( value - 1 )) == 0; +} + + +inline void *MemAlloc_AllocAlignedUnattributed( size_t size, size_t align ) +{ +#ifndef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS + + unsigned char *pAlloc, *pResult; + +#endif + + if (!ValueIsPowerOfTwo(align)) + return NULL; + +#ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS + + return g_pMemAlloc->AllocAlign( size, align ); + +#else + + align = (align > sizeof(void *) ? align : sizeof(void *)) - 1; + + if ( (pAlloc = (unsigned char*)MemAlloc_Alloc( sizeof(void *) + align + size ) ) == (unsigned char*)NULL) + return NULL; + + pResult = (unsigned char*)( (size_t)(pAlloc + sizeof(void *) + align ) & ~align ); + ((unsigned char**)(pResult))[-1] = pAlloc; + + return (void *)pResult; + +#endif +} + +inline void *MemAlloc_AllocAlignedFileLine( size_t size, size_t align, const char *pszFile, int nLine ) +{ +#ifndef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS + + unsigned char *pAlloc, *pResult; + +#endif + + if (!ValueIsPowerOfTwo(align)) + return NULL; + +#ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS + + return g_pMemAlloc->AllocAlign( size, align, pszFile, nLine ); + +#else + + align = (align > sizeof(void *) ? align : sizeof(void *)) - 1; + + if ( (pAlloc = (unsigned char*)MemAlloc_Alloc( sizeof(void *) + align + size, pszFile, nLine ) ) == (unsigned char*)NULL) + return NULL; + + pResult = (unsigned char*)( (size_t)(pAlloc + sizeof(void *) + align ) & ~align ); + ((unsigned char**)(pResult))[-1] = pAlloc; + + return (void *)pResult; + +#endif +} + +#ifdef USE_MEM_DEBUG +#define MemAlloc_AllocAligned( s, a ) MemAlloc_AllocAlignedFileLine( s, a, __FILE__, __LINE__ ) +#elif defined(USE_LIGHT_MEM_DEBUG) +extern const char *g_pszModule; +#define MemAlloc_AllocAligned( s, a ) MemAlloc_AllocAlignedFileLine( s, a, g_pszModule, 0 ) +#else +#define MemAlloc_AllocAligned( s, a ) MemAlloc_AllocAlignedUnattributed( s, a ) +#endif + + +inline void *MemAlloc_ReallocAligned( void *ptr, size_t size, size_t align ) +{ + if ( !ValueIsPowerOfTwo( align ) ) + return NULL; + + // Don't change alignment between allocation + reallocation. + if ( ( (size_t)ptr & ( align - 1 ) ) != 0 ) + return NULL; + +#ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS + + return g_pMemAlloc->ReallocAlign( ptr, size, align ); + +#else + + if ( !ptr ) + return MemAlloc_AllocAligned( size, align ); + + void *pAlloc, *pResult; + + // Figure out the actual allocation point + pAlloc = ptr; + pAlloc = (void *)(((size_t)pAlloc & ~( sizeof(void *) - 1 ) ) - sizeof(void *)); + pAlloc = *( (void **)pAlloc ); + + // See if we have enough space + size_t nOffset = (size_t)ptr - (size_t)pAlloc; + size_t nOldSize = g_pMemAlloc->GetSize( pAlloc ); + if ( nOldSize >= size + nOffset ) + return ptr; + + pResult = MemAlloc_AllocAligned( size, align ); + memcpy( pResult, ptr, nOldSize - nOffset ); + g_pMemAlloc->Free( pAlloc ); + return pResult; + +#endif +} + +inline void MemAlloc_FreeAligned( void *pMemBlock ) +{ +#ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS + + g_pMemAlloc->Free( pMemBlock ); + +#else + + void *pAlloc; + + if ( pMemBlock == NULL ) + return; + + pAlloc = pMemBlock; + + // pAlloc points to the pointer to starting of the memory block + pAlloc = (void *)(((size_t)pAlloc & ~( sizeof(void *) - 1 ) ) - sizeof(void *)); + + // pAlloc is the pointer to the start of memory block + pAlloc = *( (void **)pAlloc ); + + g_pMemAlloc->Free( pAlloc ); + +#endif +} + +inline void MemAlloc_FreeAligned( void *pMemBlock, const char *pszFile, int nLine ) +{ +#ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS + + g_pMemAlloc->Free( pMemBlock, pszFile, nLine ); + +#else + + void *pAlloc; + + if ( pMemBlock == NULL ) + return; + + pAlloc = pMemBlock; + + // pAlloc points to the pointer to starting of the memory block + pAlloc = (void *)(((size_t)pAlloc & ~( sizeof(void *) - 1 ) ) - sizeof(void *)); + + // pAlloc is the pointer to the start of memory block + pAlloc = *( (void **)pAlloc ); + g_pMemAlloc->Free( pAlloc, pszFile, nLine ); + +#endif +} + +inline size_t MemAlloc_GetSizeAligned( void *pMemBlock ) +{ +#ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS + + return g_pMemAlloc->GetSize( pMemBlock ); + +#else + + void *pAlloc; + + if ( pMemBlock == NULL ) + return 0; + + pAlloc = pMemBlock; + + // pAlloc points to the pointer to starting of the memory block + pAlloc = (void *)(((size_t)pAlloc & ~( sizeof(void *) - 1 ) ) - sizeof(void *)); + + // pAlloc is the pointer to the start of memory block + pAlloc = *((void **)pAlloc ); + return g_pMemAlloc->GetSize( pAlloc ) - ( (byte *)pMemBlock - (byte *)pAlloc ); + +#endif +} + + +struct aligned_tmp_t +{ + // empty base class +}; + +// template here to allow adding alignment at levels of hierarchy that aren't the base +template< int bytesAlignment = 16, class T = aligned_tmp_t > +class CAlignedNewDelete : public T +{ +public: + void *operator new( size_t nSize ) + { + return MemAlloc_AllocAligned( nSize, bytesAlignment ); + } + + void* operator new( size_t nSize, int nBlockUse, const char *pFileName, int nLine ) + { + return MemAlloc_AllocAlignedFileLine( nSize, bytesAlignment, pFileName, nLine ); + } + + void operator delete(void *pData) + { + if ( pData ) + { + MemAlloc_FreeAligned( pData ); + } + } + + void operator delete( void* pData, int nBlockUse, const char *pFileName, int nLine ) + { + if ( pData ) + { + MemAlloc_FreeAligned( pData, pFileName, nLine ); + } + } +}; + +//----------------------------------------------------------------------------- + +#if (defined(_DEBUG) || defined(USE_MEM_DEBUG)) +#define MEM_ALLOC_CREDIT_(tag) CMemAllocAttributeAlloction memAllocAttributeAlloction( tag, __LINE__ ) +#define MemAlloc_PushAllocDbgInfo( pszFile, line ) g_pMemAlloc->PushAllocDbgInfo( pszFile, line ) +#define MemAlloc_PopAllocDbgInfo() g_pMemAlloc->PopAllocDbgInfo() +#define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) g_pMemAlloc->RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) +#define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) g_pMemAlloc->RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) +#else +#define MEM_ALLOC_CREDIT_(tag) ((void)0) +#define MemAlloc_PushAllocDbgInfo( pszFile, line ) ((void)0) +#define MemAlloc_PopAllocDbgInfo() ((void)0) +#define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0) +#define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0) +#endif + +//----------------------------------------------------------------------------- + +class CMemAllocAttributeAlloction +{ +public: + CMemAllocAttributeAlloction( const char *pszFile, int line ) + { + MemAlloc_PushAllocDbgInfo( pszFile, line ); + } + + ~CMemAllocAttributeAlloction() + { + MemAlloc_PopAllocDbgInfo(); + } +}; + +#define MEM_ALLOC_CREDIT() MEM_ALLOC_CREDIT_(__FILE__) + +//----------------------------------------------------------------------------- + +#if defined(MSVC) && ( defined(_DEBUG) || defined(USE_MEM_DEBUG) ) + + #pragma warning(disable:4290) + #pragma warning(push) + #include <typeinfo.h> + + // MEM_DEBUG_CLASSNAME is opt-in. + // Note: typeid().name() is not threadsafe, so if the project needs to access it in multiple threads + // simultaneously, it'll need a mutex. + #if defined(_CPPRTTI) && defined(MEM_DEBUG_CLASSNAME) + + template <typename T> const char *MemAllocClassName( T *p ) + { + static const char *pszName = typeid(*p).name(); // @TODO: support having debug heap ignore certain allocations, and ignore memory allocated here [5/7/2009 tom] + return pszName; + } + + #define MEM_ALLOC_CREDIT_CLASS() MEM_ALLOC_CREDIT_( MemAllocClassName( this ) ) + #define MEM_ALLOC_CLASSNAME(type) (typeid((type*)(0)).name()) + #else + #define MEM_ALLOC_CREDIT_CLASS() MEM_ALLOC_CREDIT_( __FILE__ ) + #define MEM_ALLOC_CLASSNAME(type) (__FILE__) + #endif + + // MEM_ALLOC_CREDIT_FUNCTION is used when no this pointer is available ( inside 'new' overloads, for example ) + #ifdef _MSC_VER + #define MEM_ALLOC_CREDIT_FUNCTION() MEM_ALLOC_CREDIT_( __FUNCTION__ ) + #else + #define MEM_ALLOC_CREDIT_FUNCTION() (__FILE__) + #endif + + #pragma warning(pop) +#else + #define MEM_ALLOC_CREDIT_CLASS() + #define MEM_ALLOC_CLASSNAME(type) NULL + #define MEM_ALLOC_CREDIT_FUNCTION() +#endif + +//----------------------------------------------------------------------------- + +#if (defined(_DEBUG) || defined(USE_MEM_DEBUG)) +struct MemAllocFileLine_t +{ + const char *pszFile; + int line; +}; + +#define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag ) \ + static CUtlMap<void *, MemAllocFileLine_t, int> s_##tag##Allocs( DefLessFunc( void *) ); \ + CUtlMap<void *, MemAllocFileLine_t, int> * g_p##tag##Allocs = &s_##tag##Allocs; \ + static CThreadFastMutex s_##tag##AllocsMutex; \ + CThreadFastMutex * g_p##tag##AllocsMutex = &s_##tag##AllocsMutex; \ + const char * g_psz##tag##Alloc = strcpy( (char *)MemAlloc_Alloc( strlen( #tag "Alloc" ) + 1, "intentional leak", 0 ), #tag "Alloc" ); + +#define MEMALLOC_DECLARE_EXTERNAL_TRACKING( tag ) \ + extern CUtlMap<void *, MemAllocFileLine_t, int> * g_p##tag##Allocs; \ + extern CThreadFastMutex *g_p##tag##AllocsMutex; \ + extern const char * g_psz##tag##Alloc; + +#define MemAlloc_RegisterExternalAllocation( tag, p, size ) \ + if ( !p ) \ + ; \ + else \ + { \ + AUTO_LOCK_FM( *g_p##tag##AllocsMutex ); \ + MemAllocFileLine_t fileLine = { g_psz##tag##Alloc, 0 }; \ + g_pMemAlloc->GetActualDbgInfo( fileLine.pszFile, fileLine.line ); \ + if ( fileLine.pszFile != g_psz##tag##Alloc ) \ + { \ + g_p##tag##Allocs->Insert( p, fileLine ); \ + } \ + \ + MemAlloc_RegisterAllocation( fileLine.pszFile, fileLine.line, size, size, 0); \ + } + +#define MemAlloc_RegisterExternalDeallocation( tag, p, size ) \ + if ( !p ) \ + ; \ + else \ + { \ + AUTO_LOCK_FM( *g_p##tag##AllocsMutex ); \ + MemAllocFileLine_t fileLine = { g_psz##tag##Alloc, 0 }; \ + CUtlMap<void *, MemAllocFileLine_t, int>::IndexType_t iRecordedFileLine = g_p##tag##Allocs->Find( p ); \ + if ( iRecordedFileLine != g_p##tag##Allocs->InvalidIndex() ) \ + { \ + fileLine = (*g_p##tag##Allocs)[iRecordedFileLine]; \ + g_p##tag##Allocs->RemoveAt( iRecordedFileLine ); \ + } \ + \ + MemAlloc_RegisterDeallocation( fileLine.pszFile, fileLine.line, size, size, 0); \ + } + +#else + +#define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag ) +#define MEMALLOC_DECLARE_EXTERNAL_TRACKING( tag ) +#define MemAlloc_RegisterExternalAllocation( tag, p, size ) ((void)0) +#define MemAlloc_RegisterExternalDeallocation( tag, p, size ) ((void)0) + +#endif + +//----------------------------------------------------------------------------- + +#endif // !STEAM && !NO_MALLOC_OVERRIDE + +//----------------------------------------------------------------------------- + +#if !defined(STEAM) && defined(NO_MALLOC_OVERRIDE) +#include <malloc.h> + +#define MEM_ALLOC_CREDIT_(tag) ((void)0) +#define MEM_ALLOC_CREDIT() MEM_ALLOC_CREDIT_(__FILE__) +#define MEM_ALLOC_CREDIT_CLASS() +#define MEM_ALLOC_CLASSNAME(type) NULL + +#define MemAlloc_PushAllocDbgInfo( pszFile, line ) +#define MemAlloc_PopAllocDbgInfo() + +#define MemAlloc_RegisterAllocation( a,b,c,d,e ) ((void)0) +#define MemAlloc_RegisterDeallocation( a,b,c,d,e ) ((void)0) + +#define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag ) +#define MemAlloc_RegisterExternalAllocation( tag, p, size ) ((void)0) +#define MemAlloc_RegisterExternalDeallocation( tag, p, size ) ((void)0) + +inline void *MemAlloc_AllocAligned( size_t size, size_t align ) +{ + return (void *)_aligned_malloc( size, align ); +} +inline void *MemAlloc_AllocAligned( size_t size, size_t align, const char *pszFile, int nLine ) +{ + pszFile = pszFile; + nLine = nLine; + return (void *)_aligned_malloc( size, align ); +} + +inline void MemAlloc_FreeAligned( void *pMemBlock ) +{ + _aligned_free( pMemBlock ); +} +inline void MemAlloc_FreeAligned( void *pMemBlock, const char *pszFile, int nLine ) +{ + pszFile = pszFile; + nLine = nLine; + _aligned_free( pMemBlock ); +} + +#endif // !STEAM && NO_MALLOC_OVERRIDE + +//----------------------------------------------------------------------------- + + + +// linux memory tracking via hooks. +#if defined( POSIX ) && !defined( _PS3 ) +PLATFORM_INTERFACE void MemoryLogMessage( char const *s ); // throw a message into the memory log +PLATFORM_INTERFACE void EnableMemoryLogging( bool bOnOff ); +PLATFORM_INTERFACE void DumpMemoryLog( int nThresh ); +PLATFORM_INTERFACE void DumpMemorySummary( void ); +PLATFORM_INTERFACE void SetMemoryMark( void ); +PLATFORM_INTERFACE void DumpChangedMemory( int nThresh ); + +// ApproximateProcessMemoryUsage returns the approximate memory footprint of this process. +PLATFORM_INTERFACE size_t ApproximateProcessMemoryUsage( void ); +#else +inline void MemoryLogMessage( char const * ) +{ +} +inline void EnableMemoryLogging( bool ) +{ +} +inline void DumpMemoryLog( int ) +{ +} +inline void DumpMemorySummary( void ) +{ +} +inline void SetMemoryMark( void ) +{ +} +inline void DumpChangedMemory( int ) +{ +} +inline size_t ApproximateProcessMemoryUsage( void ) +{ + return 0; +} +#endif + + +#endif /* TIER0_MEMALLOC_H */ diff --git a/external/vpc/public/tier0/memdbgoff.h b/external/vpc/public/tier0/memdbgoff.h new file mode 100644 index 0000000..4d2c021 --- /dev/null +++ b/external/vpc/public/tier0/memdbgoff.h @@ -0,0 +1,25 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: This header, which must be the final line of a .h file, +// causes all crt methods to stop using debugging versions of the memory allocators. +// NOTE: Use memdbgon.h to re-enable memory debugging. +// +// $NoKeywords: $ +//=============================================================================// + +#ifdef MEM_OVERRIDE_ON + +#undef malloc +#undef realloc +#undef calloc +#undef free +#undef _expand +#undef _msize +#undef new +#undef _aligned_malloc +#undef _aligned_free +#undef _malloc_dbg + +#undef MEM_OVERRIDE_ON + +#endif diff --git a/external/vpc/public/tier0/memdbgon.h b/external/vpc/public/tier0/memdbgon.h new file mode 100644 index 0000000..e66664d --- /dev/null +++ b/external/vpc/public/tier0/memdbgon.h @@ -0,0 +1,281 @@ +//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: This header, which must be the final include in a .cpp (or .h) file, +// causes all crt methods to use debugging versions of the memory allocators. +// NOTE: Use memdbgoff.h to disable memory debugging. +// +// $NoKeywords: $ +//=============================================================================// + +// SPECIAL NOTE! This file must *not* use include guards; we need to be able +// to include this potentially multiple times (since we can deactivate debugging +// by including memdbgoff.h) + +#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE) + +// SPECIAL NOTE #2: This must be the final include in a .cpp or .h file!!! + +#if defined(_DEBUG) && !defined(USE_MEM_DEBUG) && !defined( _PS3 ) +#define USE_MEM_DEBUG 1 +#endif + +// If debug build or ndebug and not already included MS custom alloc files, or already included this file +#if (defined(_DEBUG) || !defined(_INC_CRTDBG)) || defined(MEMDBGON_H) + +#include "tier0/basetypes.h" + +#include "tier0/valve_off.h" + #ifdef COMPILER_MSVC + #include <tchar.h> + #else + #include <wchar.h> + #endif + #include <string.h> + #ifndef _PS3 + #include <malloc.h> + #endif +#include "tier0/valve_on.h" + +#include "commonmacros.h" +#include "memalloc.h" + +#ifdef _WIN32 +#ifndef MEMALLOC_REGION +#define MEMALLOC_REGION 0 +#endif +#else +#undef MEMALLOC_REGION +#endif + +#if defined(USE_MEM_DEBUG) + #if defined( POSIX ) || defined( _PS3 ) + #define _NORMAL_BLOCK 1 + + #include "tier0/valve_off.h" + #include <cstddef> + #include <new> + #include <sys/types.h> + #if !defined( DID_THE_OPERATOR_NEW ) + #define DID_THE_OPERATOR_NEW + // posix doesn't have a new of this form, so we impl our own + void* operator new( size_t nSize, int blah, const char *pFileName, int nLine ); + void* operator new[]( size_t nSize, int blah, const char *pFileName, int nLine ); + #endif + + #else // defined(POSIX) + + // Include crtdbg.h and make sure _DEBUG is set to 1. + #if !defined(_DEBUG) + #define _DEBUG 1 + #include <crtdbg.h> + #undef _DEBUG + #else + #include <crtdbg.h> + #endif // !defined(_DEBUG) + + #endif // defined(POSIX) +#endif + +#include "tier0/memdbgoff.h" + +// -------------------------------------------------------- +// Debug/non-debug agnostic elements + +#define MEM_OVERRIDE_ON 1 + +#undef malloc +#undef realloc +#undef calloc +#undef _expand +#undef free +#undef _msize +#undef _aligned_malloc +#undef _aligned_free + +#ifndef MEMDBGON_H +inline void *MemAlloc_InlineCallocMemset( void *pMem, size_t nCount, size_t nElementSize) +{ + memset(pMem, 0, nElementSize * nCount); + return pMem; +} +#endif + +#define calloc(c, s) MemAlloc_InlineCallocMemset(malloc(c*s), c, s) +#ifndef USE_LIGHT_MEM_DEBUG +#define free(p) g_pMemAlloc->Free( p ) +#define _aligned_free( p ) MemAlloc_FreeAligned( p ) +#else +extern const char *g_pszModule; +#define free(p) g_pMemAlloc->Free( p, g_pszModule, 0 ) +#define _aligned_free( p ) MemAlloc_FreeAligned( p, g_pszModule, 0 ) +#endif +#define _msize(p) g_pMemAlloc->GetSize( p ) +#define _expand(p, s) _expand_NoLongerSupported(p, s) + +// -------------------------------------------------------- +// Debug path +#if defined(USE_MEM_DEBUG) + +#define malloc(s) MemAlloc_Alloc( s, __FILE__, __LINE__) +#define realloc(p, s) g_pMemAlloc->Realloc( p, s, __FILE__, __LINE__ ) +#define _aligned_malloc( s, a ) MemAlloc_AllocAlignedFileLine( s, a, __FILE__, __LINE__ ) + +#define _malloc_dbg(s, t, f, l) WHYCALLINGTHISDIRECTLY(s) + +#undef new + +#if defined( _PS3 ) + #ifndef PS3_OPERATOR_NEW_WRAPPER_DEFINED + #define PS3_OPERATOR_NEW_WRAPPER_DEFINED + inline void* operator new( size_t nSize, int blah, const char *pFileName, int nLine ) { return g_pMemAlloc->IndirectAlloc( nSize, pFileName, nLine ); } + inline void* operator new[]( size_t nSize, int blah, const char *pFileName, int nLine ) { return g_pMemAlloc->IndirectAlloc( nSize, pFileName, nLine ); } + #endif + #define new new( 1, __FILE__, __LINE__ ) +#elif !defined( GNUC ) + #if defined(__AFX_H__) && defined(DEBUG_NEW) + #define new DEBUG_NEW + #else + #define MEMALL_DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) + #define new MEMALL_DEBUG_NEW + #endif +#endif + +#undef _strdup +#undef strdup +#undef _wcsdup +#undef wcsdup + +#define _strdup(s) MemAlloc_StrDup(s, __FILE__, __LINE__) +#define strdup(s) MemAlloc_StrDup(s, __FILE__, __LINE__) +#define _wcsdup(s) MemAlloc_WcStrDup(s, __FILE__, __LINE__) +#define wcsdup(s) MemAlloc_WcStrDup(s, __FILE__, __LINE__) + +// Make sure we don't define strdup twice +#if !defined(MEMDBGON_H) + +inline char *MemAlloc_StrDup(const char *pString, const char *pFileName, unsigned nLine) +{ + char *pMemory; + + if (!pString) + return NULL; + + size_t len = strlen(pString) + 1; + if ((pMemory = (char *)MemAlloc_Alloc(len, pFileName, nLine)) != NULL) + { + return strcpy( pMemory, pString ); + } + + return NULL; +} + +inline wchar_t *MemAlloc_WcStrDup(const wchar_t *pString, const char *pFileName, unsigned nLine) +{ + wchar_t *pMemory; + + if (!pString) + return NULL; + + size_t len = (wcslen(pString) + 1); + if ((pMemory = (wchar_t *)MemAlloc_Alloc(len * sizeof(wchar_t), pFileName, nLine)) != NULL) + { + return wcscpy( pMemory, pString ); + } + + return NULL; +} + +#endif // DBMEM_DEFINED_STRDUP + +#else +// -------------------------------------------------------- +// Release path + +#ifndef USE_LIGHT_MEM_DEBUG +#define malloc(s) MemAlloc_Alloc( s ) +#define realloc(p, s) g_pMemAlloc->Realloc( p, s ) +#define _aligned_malloc( s, a ) MemAlloc_AllocAligned( s, a ) +#else +#define malloc(s) MemAlloc_Alloc( s, g_pszModule, 0 ) +#define realloc(p, s) g_pMemAlloc->Realloc( p, s, g_pszModule, 0 ) +#define _aligned_malloc( s, a ) MemAlloc_AllocAlignedFileLine( s, a, g_pszModule, 0 ) +#endif + +#ifndef _malloc_dbg +#define _malloc_dbg(s, t, f, l) WHYCALLINGTHISDIRECTLY(s) +#endif + +#undef new + +#if defined( _PS3 ) && !defined( _CERT ) + #ifndef PS3_OPERATOR_NEW_WRAPPER_DEFINED + #define PS3_OPERATOR_NEW_WRAPPER_DEFINED + inline void* operator new( size_t nSize, int blah, const char *pFileName, int nLine ) { return g_pMemAlloc->IndirectAlloc( nSize, pFileName, nLine ); } + inline void* operator new[]( size_t nSize, int blah, const char *pFileName, int nLine ) { return g_pMemAlloc->IndirectAlloc( nSize, pFileName, nLine ); } + #endif + #define new new( 1, __FILE__, __LINE__ ) +#endif + +#undef _strdup +#undef strdup +#undef _wcsdup +#undef wcsdup + +#define _strdup(s) MemAlloc_StrDup(s) +#define strdup(s) MemAlloc_StrDup(s) +#define _wcsdup(s) MemAlloc_WcStrDup(s) +#define wcsdup(s) MemAlloc_WcStrDup(s) + +// Make sure we don't define strdup twice +#if !defined(MEMDBGON_H) + +inline char *MemAlloc_StrDup(const char *pString) +{ + char *pMemory; + + if (!pString) + return NULL; + + size_t len = strlen(pString) + 1; + if ((pMemory = (char *)malloc(len)) != NULL) + { + return strcpy( pMemory, pString ); + } + + return NULL; +} + +inline wchar_t *MemAlloc_WcStrDup(const wchar_t *pString) +{ + wchar_t *pMemory; + + if (!pString) + return NULL; + + size_t len = (wcslen(pString) + 1); + if ((pMemory = (wchar_t *)malloc(len * sizeof(wchar_t))) != NULL) + { + return wcscpy( pMemory, pString ); + } + + return NULL; +} + +#endif // DBMEM_DEFINED_STRDUP + +#endif // USE_MEM_DEBUG + +#define MEMDBGON_H // Defined here so can be used above + +#else + +#if defined(USE_MEM_DEBUG) +#ifndef _STATIC_LINKED +#pragma message ("Note: file includes crtdbg.h directly, therefore will cannot use memdbgon.h in non-debug build") +#else +#error "Error: file includes crtdbg.h directly, therefore will cannot use memdbgon.h in non-debug build. Not recoverable in static build" +#endif +#endif +#endif // _INC_CRTDBG + +#endif // !STEAM && !NO_MALLOC_OVERRIDE diff --git a/external/vpc/public/tier0/memvirt.h b/external/vpc/public/tier0/memvirt.h new file mode 100644 index 0000000..eeb0996 --- /dev/null +++ b/external/vpc/public/tier0/memvirt.h @@ -0,0 +1,46 @@ +//========== Copyright (C) Valve Corporation, All rights reserved. ==========// +// +// Purpose: CVirtualMemoryManager interface +// +//===========================================================================// + +#ifndef MEM_VIRT_H +#define MEM_VIRT_H +#ifdef _WIN32 +#pragma once +#endif + + +#define VMM_KB ( 1024 ) +#define VMM_MB ( 1024 * VMM_KB ) + +#ifdef _PS3 +// Total virtual address space reserved by CVirtualMemoryManager on startup: +#define VMM_VIRTUAL_SIZE ( 512 * VMM_MB ) +#define VMM_PAGE_SIZE ( 64 * VMM_KB ) +#endif + + + +// Allocate virtual sections via IMemAlloc::AllocateVirtualMemorySection +abstract_class IVirtualMemorySection +{ +public: + // Information about memory section + virtual void * GetBaseAddress() = 0; + virtual size_t GetPageSize() = 0; + virtual size_t GetTotalSize() = 0; + + // Functions to manage physical memory mapped to virtual memory + virtual bool CommitPages( void *pvBase, size_t numBytes ) = 0; + virtual void DecommitPages( void *pvBase, size_t numBytes ) = 0; + + // Release the physical memory and associated virtual address space + virtual void Release() = 0; +}; + +// Get the IVirtualMemorySection associated with a given memory address (if any): +extern IVirtualMemorySection *GetMemorySectionForAddress( void *pAddress ); + + +#endif // MEM_VIRT_H diff --git a/external/vpc/public/tier0/minidump.h b/external/vpc/public/tier0/minidump.h new file mode 100644 index 0000000..8f4b7b0 --- /dev/null +++ b/external/vpc/public/tier0/minidump.h @@ -0,0 +1,82 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef MINIDUMP_H +#define MINIDUMP_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + +// writes out a minidump of the current stack trace with a unique filename +PLATFORM_INTERFACE void WriteMiniDump(); + +typedef void (*FnWMain)( int , tchar *[] ); + +#ifdef IS_WINDOWS_PC + +// calls the passed in function pointer and catches any exceptions/crashes thrown by it, and writes a minidump +// use from wmain() to protect the whole program + +PLATFORM_INTERFACE void CatchAndWriteMiniDump( FnWMain pfn, int argc, tchar *argv[] ); + +// The ExceptionInfo_t struct is a typeless data struct +// which is OS-dependent and should never be used by external code. +// Just pass it back into MinidumpSetUnhandledExceptionFunction +struct ExceptionInfo_t; + + +// Replaces the current function pointer with the one passed in. +// Returns the previously-set function. +// The function is called internally by WriteMiniDump() and CatchAndWriteMiniDump() +// The default is the built-in function that uses DbgHlp.dll's MiniDumpWriteDump function +typedef void (*FnMiniDump)( unsigned int uStructuredExceptionCode, ExceptionInfo_t * pExceptionInfo ); +PLATFORM_INTERFACE FnMiniDump SetMiniDumpFunction( FnMiniDump pfn ); + +// Use this to write a minidump explicitly. +// Some of the tools choose to catch the minidump themselves instead of using CatchAndWriteMinidump +// so they can show their own dialog. +// +// ptchMinidumpFileNameBuffer if not-NULL should be a writable tchar buffer of length at +// least _MAX_PATH and on return will contain the name of the minidump file written. +// If ptchMinidumpFileNameBuffer is NULL the name of the minidump file written will not +// be available after the function returns. +// + + +// NOTE: Matches windows.h +enum MinidumpType_t +{ + MINIDUMP_Normal = 0x00000000, + MINIDUMP_WithDataSegs = 0x00000001, + MINIDUMP_WithFullMemory = 0x00000002, + MINIDUMP_WithHandleData = 0x00000004, + MINIDUMP_FilterMemory = 0x00000008, + MINIDUMP_ScanMemory = 0x00000010, + MINIDUMP_WithUnloadedModules = 0x00000020, + MINIDUMP_WithIndirectlyReferencedMemory = 0x00000040, + MINIDUMP_FilterModulePaths = 0x00000080, + MINIDUMP_WithProcessThreadData = 0x00000100, + MINIDUMP_WithPrivateReadWriteMemory = 0x00000200, + MINIDUMP_WithoutOptionalData = 0x00000400, + MINIDUMP_WithFullMemoryInfo = 0x00000800, + MINIDUMP_WithThreadInfo = 0x00001000, + MINIDUMP_WithCodeSegs = 0x00002000 +}; + +PLATFORM_INTERFACE bool WriteMiniDumpUsingExceptionInfo( + unsigned int uStructuredExceptionCode, + ExceptionInfo_t *pExceptionInfo, + uint32 nMinidumpTypeFlags, // OR-ed together MinidumpType_t flags + tchar *ptchMinidumpFileNameBuffer = NULL + ); + +PLATFORM_INTERFACE void MinidumpSetUnhandledExceptionFunction( FnMiniDump pfn ); + +#endif + +#endif // MINIDUMP_H diff --git a/external/vpc/public/tier0/p4performancecounters.h b/external/vpc/public/tier0/p4performancecounters.h new file mode 100644 index 0000000..d0882b9 --- /dev/null +++ b/external/vpc/public/tier0/p4performancecounters.h @@ -0,0 +1,322 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef P4PERFORMANCECOUNTERS_H +#define P4PERFORMANCECOUNTERS_H + +#pragma once +// Pentium 4 support + +/* + http://developer.intel.com/design/Pentium4/documentation.htm + + IA-32 Intel Architecture Software Developer's Manual Volume 1: Basic Architecture + + IA-32 Intel Architecture Software Developer's Manual Volume 2A: Instruction Set Reference, A-M + + IA-32 Intel Architecture Software Developer's Manual Volume 2B: Instruction Set Reference, N-Z + + IA-32 Intel Architecture Software Developer's Manual Volume 3: System Programming Guide + + + From Mikael Pettersson's perfctr: + + http://user.it.uu.se/~mikpe/linux/perfctr/ + + * Known quirks: + - OVF_PMI+FORCE_OVF counters must have an ireset value of -1. + This allows the regular overflow check to also handle FORCE_OVF + counters. Not having this restriction would lead to MAJOR + complications in the driver's "detect overflow counters" code. + There is no loss of functionality since the ireset value doesn't + affect the counter's PMI rate for FORCE_OVF counters. + + - In experiments with FORCE_OVF counters, and regular OVF_PMI + counters with small ireset values between -8 and -1, it appears + that the faulting instruction is subjected to a new PMI before + it can complete, ad infinitum. This occurs even though the driver + clears the CCCR (and in testing also the ESCR) and invokes a + user-space signal handler before restoring the CCCR and resuming + the instruction. +*/ + +#define NCOUNTERS 18 + +// The 18 counters +enum Counters +{ + MSR_BPU_COUNTER0, + MSR_BPU_COUNTER1, + MSR_BPU_COUNTER2, + MSR_BPU_COUNTER3, + MSR_MS_COUNTER0, + MSR_MS_COUNTER1, + MSR_MS_COUNTER2, + MSR_MS_COUNTER3, + MSR_FLAME_COUNTER0, + MSR_FLAME_COUNTER1, + MSR_FLAME_COUNTER2, + MSR_FLAME_COUNTER3, + MSR_IQ_COUNTER0, + MSR_IQ_COUNTER1, + MSR_IQ_COUNTER2, + MSR_IQ_COUNTER3, + MSR_IQ_COUNTER4, + MSR_IQ_COUNTER5 +}; + +// register base for counters +#define MSR_COUNTER_BASE 0x300 + +// register base for CCCR register +#define MSR_CCCR_BASE 0x360 + +#pragma pack(push, 1) +// access to these bits is through the methods +typedef union ESCR +{ + struct + { + uint64 Reserved0_1 : 2; // + uint64 USR : 1; // + uint64 OS : 1; // + uint64 TagEnable : 1; // + uint64 TagValue : 4; // + uint64 EventMask : 16; // from event select + uint64 ESCREventSelect : 6; // 31:25 class of event + uint64 Reserved31 : 1; // + + uint64 Reserved32_63 : 32; // + }; + uint64 flat; + +} ESCR; + +typedef union CCCR +{ + struct + { + uint64 Reserved0_11 : 12;// 0 -11 + uint64 Enable : 1; // 12 + uint64 CCCRSelect : 3; // 13-15 + uint64 Reserved16_17 : 2; // 16 17 + + uint64 Compare : 1; // 18 + uint64 Complement : 1; // 19 + uint64 Threshold : 4; // 20-23 + uint64 Edge : 1; // 24 + uint64 FORCE_OVF : 1; // 25 + uint64 OVF_PMI : 1; // 26 + uint64 Reserved27_29 : 3; // 27-29 + uint64 Cascade : 1; // 30 + uint64 OVF : 1; // 31 + + uint64 Reserved32_63 : 32; // + }; + uint64 flat; + +} CCCR; + +#pragma pack(pop) + +extern const unsigned short cccr_escr_map[NCOUNTERS][8]; + +enum P4TagState +{ + TagDisable, // + TagEnable, // +}; + +enum P4ForceOverflow +{ + ForceOverflowDisable, + ForceOverflowEnable, +}; + +enum P4OverflowInterrupt +{ + OverflowInterruptDisable, + OverflowInterruptEnable, +}; + +// Turn off the no return value warning in ReadCounter. +#pragma warning( disable : 4035 ) +class P4BaseEvent +{ + int m_counter; + +protected: + + void SetCounter(int counter) + { + m_counter = counter; + cccrPort = MSR_CCCR_BASE + m_counter; + counterPort = MSR_COUNTER_BASE + m_counter; + escrPort = cccr_escr_map[m_counter][cccr.CCCRSelect]; + } + +public: + + unsigned short m_eventMask; + const tchar *description; + PME *pme; + ESCR escr; + CCCR cccr; + int counterPort; + int cccrPort; + int escrPort; + + P4BaseEvent() + { + pme = PME::Instance(); + m_eventMask = 0; + description = _T(""); + escr.flat = 0; + cccr.flat = 0; + cccr.Reserved16_17 = 3; // must be set + escrPort = 0; + m_counter = -1; + } + + void StartCounter() + { + cccr.Enable = 1; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + void StopCounter() + { + cccr.Enable = 0; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + void ClearCounter() + { + pme->WriteMSR( counterPort, 0ui64 ); // clear + } + + void WriteCounter( int64 value ) + { + pme->WriteMSR( counterPort, value ); // clear + } + + int64 ReadCounter() + { +#if PME_DEBUG + if ( escr.USR == 0 && escr.OS == 0 ) + return -1; // no area to collect, use SetCaptureMode + + if ( escr.EventMask == 0 ) + return -2; // no event mask set + + if ( m_counter == -1 ) + return -3; // counter not legal +#endif + + // ReadMSR should work here too, but RDPMC should be faster + int64 value = 0; + pme->ReadMSR( counterPort, &value ); + return value; +#if 0 + // we need to copy this into a temp for some reason + int temp = m_counter; + _asm + { + mov ecx, temp + RDPMC + } +#endif + } + + void SetCaptureMode( PrivilegeCapture priv ) + { + switch ( priv ) + { + case OS_Only: + { + escr.USR = 0; + escr.OS = 1; + break; + } + case USR_Only: + { + escr.USR = 1; + escr.OS = 0; + break; + } + case OS_and_USR: + { + escr.USR = 1; + escr.OS = 1; + break; + } + } + + escr.EventMask = m_eventMask; + pme->WriteMSR( escrPort, escr.flat ); + } + + void SetTagging( P4TagState tagEnable, uint8 tagValue ) + { + escr.TagEnable = tagEnable; + escr.TagValue = tagValue; + pme->WriteMSR( escrPort, escr.flat ); + } + + void SetFiltering( CompareState compareEnable, CompareMethod compareMethod, uint8 threshold, EdgeState edgeEnable ) + { + cccr.Compare = compareEnable; + cccr.Complement = compareMethod; + cccr.Threshold = threshold; + cccr.Edge = edgeEnable; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + void SetOverflowEnables( P4ForceOverflow overflowEnable, P4OverflowInterrupt overflowInterruptEnable ) + { + cccr.FORCE_OVF = overflowEnable; + cccr.OVF_PMI = overflowInterruptEnable; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + void SetOverflow() + { + cccr.OVF = 1; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + void ClearOverflow() + { + cccr.OVF = 0; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + bool isOverflow() + { + CCCR cccr_temp; + pme->ReadMSR( cccrPort, &cccr_temp.flat ); + return cccr_temp.OVF; + } + + void SetCascade() + { + cccr.Cascade = 1; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + void ClearCascade() + { + cccr.Cascade = 0; + pme->WriteMSR( cccrPort, cccr.flat ); + } +}; +#pragma warning( default : 4035 ) + +#include "eventmasks.h" +#include "eventmodes.h" + +#endif // P4PERFORMANCECOUNTERS_H diff --git a/external/vpc/public/tier0/p5p6performancecounters.h b/external/vpc/public/tier0/p5p6performancecounters.h new file mode 100644 index 0000000..6e2d8b1 --- /dev/null +++ b/external/vpc/public/tier0/p5p6performancecounters.h @@ -0,0 +1,225 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef P5P6PERFORMANCECOUNTERS_H +#define P5P6PERFORMANCECOUNTERS_H + +// defined for < Pentium 4 + +//--------------------------------------------------------------------------- +// Format of the performance event IDs within this header file in case you +// wish to add any additional events that may not be present here. +// +// BITS 0-8 Unit Mask, Unsed on P5 processors +// BIT 9 Set if event can be set on counter 0 +// BIT 10 Set if event can be set on counter 1 +// BITS 11-15 Unused Set to zero +// BITS 16-23 Event Select ID, Only bits 16-21 used on P5 Family +// BITS 24-27 Unused set to zero +// BITS 28-32 Process family that the event belong to, as returned by +// the CPUID instruction. +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// PENTIUM PERFORMANCE COUNTERS. +//--------------------------------------------------------------------------- +#define P5_DTCRD 0x50000300 //Data Cache Reads +#define P5_DWRIT 0x50010300 //Data Cache Writes +#define P5_DTTLB 0x50020300 //Data TLB Miss +#define P5_DTRMS 0x50030300 //Data Read Misses +#define P5_DWRMS 0x50040300 //Data Write Miss +#define P5_WHLCL 0x50050300 //Write (Hit) to M- or E-state line +#define P5_DCLWB 0x50060300 //Data Cache Lines Written Back +#define P5_DCSNP 0x50070300 //External Snoops +#define P5_DCSHT 0x50080300 //Data Cache Snoop Hits +#define P5_MAIBP 0x50090300 //Memory Access in Both Pipes +#define P5_BANKS 0x500A0300 //Bank Conflicts +#define P5_MISAL 0x500B0300 //Misaligned Data Memory Reference +#define P5_COCRD 0x500C0300 //Code Cache Reads +#define P5_COTLB 0x500D0300 //Code TLB Misses +#define P5_COCMS 0x500E0300 //Code Cache Misses +#define P5_ANYSG 0x500F0300 //Any Segment Register Loaded +#define P5_BRANC 0x50120300 //Branches +#define P5_BTBHT 0x50130300 //BTB Hits +#define P5_TBRAN 0x50140300 //Taken Branch or BTB hit +#define P5_PFLSH 0x50150300 //Pipeline flushes +#define P5_INSTR 0x50160300 //Instructions Executed +#define P5_INSTV 0x50170300 //Instructions Executed in the V-Pipe (Pairing) +#define P5_CLOCL 0x50180300 //Bus active +#define P5_PSDWR 0x50190300 //Full write buffers +#define P5_PSWDR 0x501A0300 //Waiting for Data Memory Read +#define P5_NCLSW 0x501B0300 //Clocks stalled writing an E or M state line +#define P5_IORWC 0x501D0300 //I/O Read or Write Cycle +#define P5_NOCMR 0x501E0300 //Non-Cacheable Memory Reads +#define P5_PSLDA 0x501F0300 //Clocks stalled due to AGI +#define P5_FLOPS 0x50220300 //Floating Point Operations +#define P5_DBGR0 0x50230300 //Breakpoint match on DR0 +#define P5_DBGR1 0x50240300 //Breakpoint match on DR1 +#define P5_DBGR2 0x50250300 //Breakpoint match on DR2 +#define P5_DBGR3 0x50260300 //Breakpoint match on DR3 +#define P5_HWINT 0x50270300 //Hardware interrupts +#define P5_DTRWR 0x50280300 //Data reads or writes +#define P5_DTRWM 0x50290300 //Data read or write miss +#define P5_BOLAT 0x502A0100 //Bus ownership latency +#define P5_BOTFR 0x502A0200 //Bus ownership transfer +#define P5_MMXA1 0x502B0100 //MMX Instruction Executed in U-pipe +#define P5_MMXA2 0x502B0200 //MMX Instruction Executed in V-pipe +#define P5_MMXMS 0x502C0100 //Cache M state line sharing +#define P5_MMSLS 0x502C0200 //Cache line sharing +#define P5_MMXB1 0x502D0100 //EMMS Instructions Executed +#define P5_MMXB2 0x502D0200 //Transition from MMX to FP instructions +#define P5_NOCMW 0x502E0200 //Non-Cacheable Memory Writes +#define P5_MMXC1 0x502F0100 //Saturated MMX Instructions Executed +#define P5_MMXC2 0x502F0200 //Saturations Performed +#define P5_MMXHS 0x50300100 //Cycles Not in HALT State +#define P5_MMXD2 0x50310100 //MMX Data Read +#define P5_MMXFP 0x50320100 //Floating Point Stalls +#define P5_MMXTB 0x50320200 //Taken Branches +#define P5_MMXD0 0x50330100 //D1 Starvation and FIFO Empty +#define P5_MMXD1 0x50330200 //D1 Starvation and one instruction in FIFO +#define P5_MMXE1 0x50340100 //MMX Data Writes +#define P5_MMXE2 0x50340200 //MMX Data Write Misses +#define P5_MMXWB 0x50350100 //Pipeline flushes, wrong branch prediction +#define P5_MMXWJ 0x50350200 //Pipeline flushes, branch prediction WB-stage +#define P5_MMXF1 0x50360100 //Misaligned MMX Data Memory Reference +#define P5_MMXF2 0x50360200 //Pipeline Stalled Waiting for MMX data read +#define P5_MMXRI 0x50370100 //Returns Predicted Incorrectly +#define P5_MMXRP 0x50370200 //Returns Predicted +#define P5_MMXG1 0x50380100 //MMX Multiply Unit Interlock +#define P5_MMXG2 0x50380200 //MOVD/MOVQ store stall, previous operation +#define P5_MMXRT 0x50390100 //Returns +#define P5_MMXRO 0x50390200 //RSB Overflows +#define P5_MMXBF 0x503A0100 //BTB False entries +#define P5_MMXBM 0x503A0200 //BTB misprediction on a Not-Taken Branch +#define P5_PXDWR 0x503B0100 //stalled due MMX Full write buffers +#define P5_PXZWR 0x503B0200 //stalled on MMX write to E or M state line + +#define P5_CLOCK 0x503F0300 //Special value to count clocks on P5 + + +//--------------------------------------------------------------------------- +// PENTIUM PRO / PENTIUM II PERFORMANCE COUNTERS. +//--------------------------------------------------------------------------- +#define P6_STRBB 0x60030300 //Store Buffer Block +#define P6_STBDC 0x60040300 //Store Buffer Drain Cycles +#define P6_MISMM 0x60050300 //Misaligned Data Memory Reference +#define P6_SEGLD 0x60060300 //Segment register loads +#define P6_FPOPE 0x60100100 //FP Computational Op. (COUNTER 0 ONLY) +#define P6_FPEOA 0x60110200 //FP Microcode Exceptions (COUNTER 1 ONLY) +#define P6_FMULT 0x60120200 //Multiplies (COUNTER 1 ONLY) +#define P6_FPDIV 0x60130200 //Divides (COUNTER 1 ONLY) +#define P6_DBUSY 0x60140200 //Cycles Divider Busy (COUNTER 1 ONLY) +#define P6_L2STR 0x60210300 //L2 address strobes => address bus utilization +#define P6_L2BBS 0x60220300 //Cycles L2 Bus Busy +#define P6_L2BBT 0x60230300 //Cycles L2 Bus Busy transferring data to CPU +#define P6_L2ALO 0x60240300 //L2 Lines Allocated +#define P6_L2MAL 0x60250300 //L2 M-state Lines Allocated +#define P6_L2CEV 0x60260300 //L2 Lines Evicted +#define P6_L2MEV 0x60270300 //L2 M-state Lines Evicted +#define P6_L2MCF 0x60280301 //L2 Cache Instruction Fetch Misses +#define P6_L2FET 0x6028030F //L2 Cache Instruction Fetches +#define P6_L2DRM 0x60290301 //L2 Cache Read Misses +#define P6_L2DMR 0x6029030F //L2 Cache Reads +#define P6_L2DWM 0x602A0301 //L2 Cache Write Misses +#define P6_L2DMW 0x602A030F //L2 Cache Writes +#define P6_L2CMS 0x602E0301 //L2 Cache Request Misses +#define P6_L2DCR 0x602E030F //L2 Cache Requests +#define P6_DMREF 0x60430300 //Data Memory References +#define P6_DCALO 0x6045030F //L1 Lines Allocated +#define P6_DCMAL 0x60460300 //L1 M-state Data Cache Lines Allocated +#define P6_DCMEV 0x60470300 //L1 M-state Data Cache Lines Evicted +#define P6_DCOUT 0x60480300 //L1 Misses outstanding +#define P6_TSMCD 0x60520300 //Time Self-Modifiying Code Detected +#define P6_BRWRA 0x60600300 //External Bus Cycles While Receive Active +#define P6_BRDCD 0x60600300 //External Bus Request Outstanding +#define P6_BRBNR 0x60610300 //External Bus Cycles While BNR Asserted +#define P6_BUSBS 0x60620300 //External Bus Cycles-DRDY Asserted (busy) +#define P6_BLOCK 0x60630300 //External Bus Cycles-LOCK signal asserted +#define P6_BBRCV 0x60640300 //External Bus Cycles-Processor receiving data +#define P6_BURST 0x60650300 //External Bus Burst Read Operations +#define P6_BRINV 0x60660300 //External Bus Read for Ownership Transaction +#define P6_BMLEV 0x60670300 //External Bus Writeback M-state Evicted +#define P6_BBIFT 0x60680300 //External Bus Burst Instruction Fetches +#define P6_BINVL 0x60690300 //External Bus Invalidate Transactions +#define P6_BPRBT 0x606A0300 //External Bus Partial Read Transactions +#define P6_BPTMO 0x606B0300 //External Bus Partial Memory Transactions +#define P6_BUSIO 0x606C0300 //External Bus I/O Bus Transactions +#define P6_BUSDF 0x606D0300 //External Bus Deferred Transactions +#define P6_BUSTB 0x606E0300 //External Bus Burst Transactions +#define P6_BMALL 0x606F0300 //External Bus Memory Transactions +#define P6_BSALL 0x60700300 //External Bus Transactions +#define P6_CLOCK 0x60790300 //Clockticks +#define P6_BRHIT 0x607A0300 //External Bus Cycles While HIT Asserted +#define P6_BRHTM 0x607B0300 //External Bus Cycles While HITM Asserted +#define P6_BRSST 0x607E0300 //External Bus Cycles While Snoop Stalled +#define P6_CMREF 0x60800300 //Total Instruction Fetches +#define P6_TOIFM 0x60810300 //Total Instruction Fetch Misses +#define P6_INTLB 0x60850300 //Instructions TLB Misses +#define P6_CSFET 0x60860300 //Cycles Instruction Fetch Stalled +#define P6_FTSTL 0x60870300 //Cycles Instruction Fetch stalled +#define P6_RSTAL 0x60A20300 //Resource Related Stalls +#define P6_MMXIE 0x60B00300 //MMX Instructions Executed +#define P6_SAISE 0x60B10300 //Saturated Arithmetic Instructions Executed +#define P6_PORT0 0x60B20301 //MMX micro-ops executed on Port 0 +#define P6_PORT1 0x60B20302 //MMX micro-ops executed on Port 1 +#define P6_PORT2 0x60B20304 //MMX micro-ops executed on Port 2 +#define P6_PORT3 0x60B20308 //MMX micro-ops executed on Port 3 +#define P6_MMXPA 0x60B30300 //MMX Packed Arithmetic +#define P6_MMXPM 0x60B30301 //MMX Packed Multiply +#define P6_MMXPS 0x60B30302 //MMX Packed Shift +#define P6_MMXPO 0x60B30304 //MMX Packed Operations +#define P6_MMXUO 0x60B30308 //MMX Unpacked Operations +#define P6_MMXPL 0x60B30310 //MMX Packed Logical +#define P6_INSTR 0x60C00300 //Instructions Retired +#define P6_FPOPS 0x60C10100 //FP operations retired (COUNTER 0 ONLY) +#define P6_UOPSR 0x60C20300 //Micro-Ops Retired +#define P6_BRRET 0x60C40300 //Branch Instructions Retired +#define P6_BRMSR 0x60C50300 //Branch Mispredictions Retired +#define P6_MASKD 0x60C60300 //Clocks while interrupts masked +#define P6_MSKPN 0x60C70300 //Clocks while interrupt is pending +#define P6_HWINT 0x60C80300 //Hardware Interrupts Received +#define P6_BTAKR 0x60C90300 //Taken Branch Retired +#define P6_BTAKM 0x60CA0300 //Taken Branch Mispredictions +#define P6_FPMMX 0x60CC0301 //Transitions from Floating Point to MMX +#define P6_MMXFP 0x60CC0300 //Transitions from MMX to Floating Point +#define P6_SIMDA 0x60CD0300 //SIMD Assists (EMMS Instructions Executed) +#define P6_MMXIR 0x60CE0300 //MMX Instructions Retired +#define P6_SAISR 0x60CF0300 //Saturated Arithmetic Instructions Retired +#define P6_INSTD 0x60D00300 //Instructions Decoded +#define P6_NPRTL 0x60D20300 //Renaming Stalls +#define P6_SRSES 0x60D40301 //Segment Rename Stalls - ES +#define P6_SRSDS 0x60D40302 //Segment Rename Stalls - DS +#define P6_SRSFS 0x60D40304 //Segment Rename Stalls - FS +#define P6_SRSGS 0x60D40308 //Segment Rename Stalls - GS +#define P6_SRSXS 0x60D4030F //Segment Rename Stalls - ES DS FS GS +#define P6_SRNES 0x60D50301 //Segment Renames - ES +#define P6_SRNDS 0x60D50302 //Segment Renames - DS +#define P6_SRNFS 0x60D50304 //Segment Renames - FS +#define P6_SRNGS 0x60D50308 //Segment Renames - GS +#define P6_SRNXS 0x60D5030F //Segment Renames - ES DS FS GS +#define P6_BRDEC 0x60E00300 //Branch Instructions Decoded +#define P6_BTBMS 0x60E20301 //BTB Misses +#define P6_RETDC 0x60E40300 //Bogus Branches +#define P6_BACLR 0x60E60300 //BACLEARS Asserted (Testing) + + + + + + +// INTEL +#define PENTIUM_FAMILY 5 // define for pentium +#define PENTIUMPRO_FAMILY 6 // define for pentium pro +#define PENTIUM4_FAMILY 15 // define for pentium 4 + + +// AMD +#define K6_FAMILY 5 +#define K8_FAMILY 6 +#define EXTENDED_FAMILY 15 // AMD 64 and AMD Opteron + +#endif // P5P6PERFORMANCECOUNTERS_H diff --git a/external/vpc/public/tier0/platform.h b/external/vpc/public/tier0/platform.h new file mode 100644 index 0000000..4dad5df --- /dev/null +++ b/external/vpc/public/tier0/platform.h @@ -0,0 +1,2032 @@ +//===== Copyright 1997-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef PLATFORM_H +#define PLATFORM_H + + +#ifdef SN_TARGET_PS3 + +#define _PS3 1 +#define COMPILER_PS3 1 +#define PLATFORM_PS3 1 + +// There are 2 compilers for the PS3: GCC and the SN Systems compiler. +// They are mostly similar, but in a few places we need to distinguish between the two. +#if defined( __SNC__ ) +#define COMPILER_SNC 1 +#elif defined( __GCC__ ) +#define COMPILER_GCC 1 +#else +#error "Unrecognized PS3 compiler; either __SNC__ or __GCC__ must be defined" +#endif + +#endif // SN_TARGET_PS3 + +#ifdef __GCC__ +#define COMPILER_GCC 1 +#endif + +#if defined( _X360 ) || defined( _PS3 ) +#define PLATFORM_PPC 1 +#endif + + +#ifdef COMPILER_MSVC +#pragma once +#endif + +#if defined (_PS3) + #include <ppu_intrinsics.h> + + // We want to force the assert to be redefined, because the STD assert might have been + // included and redefined. ps3_assert.h will do a check for assert being redefined. + // #include "ps3/ps3_assert.h" + #ifndef COMPILER_PS3 + #error "for PS3, VPC must define COMPILER_PS3 macro just like it does for COMPILER_MSVCX360 macro" + #endif + #if !defined( COMPILER_SNC ) && !defined( COMPILER_GCC ) + #error "for PS3, VPC must define COMPILER_SNC or COMPILER_GCC macro, depending on the target compiler, just like it does for COMPILER_MSVCX360 macro" + #endif + +#elif defined( _X360 ) + #define NO_STEAM + #define NO_VOICE + // for the 360, the ppc platform and the rtos are tightly coupled + // setup the 360 environment here !once! for much less leaf module include wackiness + // these are critical order and purposely appear *before* anything else + #define _XBOX + #include <xaudio2.h> + #include <xbdm.h> + #include <xgraphics.h> + #include <xui.h> + #include <pmcpbsetup.h> + #include <xmahardwareabstraction.h> + #undef _XBOX + +#endif + +#include "wchartypes.h" +#include "tier0/valve_off.h" + +#ifdef _PS3 + + #include "ps3/ps3_platform.h" + + #define NO_STEAM_GAMECOORDINATOR + +#else + + #include <malloc.h> + #include <memory.h> + #include <limits.h> + #include <float.h> + #include <stdlib.h> + #include <string.h> +#ifdef OSX + #include <signal.h> +#endif + +#endif + +// This macro +#if defined( _PS3 ) && defined ( COMPILER_SNC ) + +// There are known bugs in the PS3 optimizer. The following macros allow us to lower optimization for a subset of a file +// If you run into build problems with optimization on, try turning off optimization for the selected file. If that +// fixes the problem, use process of elimination and the below macros to find the bare minimum that needs to be +// unoptimized and report the compiler issue to Sony as well. +// +// The correlation between optimization levels and numbers passed to the _Pragma xopt and postopt calls is as follows: +// See: Control-group reference tables / -Xshow +// .... xopt +// -O1 0 +// -O2 5 +// -O3 5 +// +// These macros MUST be used in pairs - Otherwise, the compiler will barf 'At end of source: error 67: expected a "}"' + +// xopt disables some of the miscellaneous optimizations +#if __option(xopt) +#define SN_OPT_DISABLE extern "C++" { _Pragma("control %push xopt=0") +#define SN_OPT_ENABLE _Pragma("control %pop xopt") } +#else // !__option(xopt) +#define SN_OPT_DISABLE +#define SN_OPT_ENABLE +#endif // !__option(xopt) + +// postopt disables the main optimizer +#if __option(postopt) > 0 +#define SN_MAIN_OPT_DISABLE extern "C++" { _Pragma("control %push postopt=0") +#define SN_MAIN_OPT_ENABLE _Pragma("control %pop postopt") } +#else // !__option(postopt) > 0 +#define SN_MAIN_OPT_DISABLE +#define SN_MAIN_OPT_ENABLE +#endif // !__option(postopt) > 0 + +#else // ! ( _PS3 && COMPILER_SNC ) +#define SN_OPT_DISABLE +#define SN_OPT_ENABLE +#define SN_MAIN_OPT_DISABLE +#define SN_MAIN_OPT_ENABLE +#endif // ! ( _PS3 && COMPILER_SNC ) + +#ifdef __cplusplus +#if defined( COMPILER_GCC ) || defined( COMPILER_PS3 ) + #include <new> +#else + #include <new.h> +#endif +#endif + +//----------------------------------------------------------------------------- +// Old-school defines we don't want to use moving forward +//----------------------------------------------------------------------------- +#if CROSS_PLATFORM_VERSION < 1 + +// feature enables +#define NEW_SOFTWARE_LIGHTING +#if !defined( _X360 ) +#define SUPPORT_PACKED_STORE +#endif + +#if defined( BINK_VIDEO ) && ( defined( _X360 ) || defined( _PS3 ) ) +#define BINK_ENABLED_FOR_CONSOLE +#endif + +#if !defined( PORTAL2 ) +//#define PORTAL2 +#endif + +// C functions for external declarations that call the appropriate C++ methods +#ifndef EXPORT + #ifdef _WIN32 + #define EXPORT _declspec( dllexport ) + #else + #define EXPORT /* */ + #endif +#endif + +#endif // CROSS_PLATFORM_VERSION < 1 + +#if defined(_STATIC_LINKED) +#include "staticlink/system.h" +#endif + +//----------------------------------------------------------------------------- +// NOTE: All compiler defines are set up in the base VPC scripts +// COMPILER_MSVC, COMPILER_MSVC32, COMPILER_MSVC64, COMPILER_MSVCX360 +// COMPILER_GCC +// The rationale for this is that we need COMPILER_MSVC for the pragma blocks +// #pragma once that occur at the top of all header files, therefore we can't +// place the defines for these in here. +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Set up platform defines. +//----------------------------------------------------------------------------- +#ifdef _WIN32 + #define IsPlatformLinux() 0 + #define IsPlatformPosix() 0 + #define IsPlatformOSX() 0 + #define IsOSXOpenGL() 0 + #define IsPlatformPS3() 0 + #define IsPlatformPS3_PPU() 0 + #define IsPlatformPS3_SPU() 0 + #define PLATFORM_WINDOWS 1 + #define PLATFORM_OPENGL 0 + + #ifndef _X360 + #define IsPlatformX360() 0 + #define IsPlatformWindowsPC() 1 + #define PLATFORM_WINDOWS_PC 1 + + #ifdef _WIN64 + #define IsPlatformWindowsPC64() 1 + #define IsPlatformWindowsPC32() 0 + #define PLATFORM_WINDOWS_PC64 1 + #else + #define IsPlatformWindowsPC64() 0 + #define IsPlatformWindowsPC32() 1 + #define PLATFORM_WINDOWS_PC32 1 + #endif + + #else // _X360 + + #define IsPlatformWindowsPC() 0 + #define IsPlatformWindowsPC64() 0 + #define IsPlatformWindowsPC32() 0 + #define IsPlatformX360() 1 + #define PLATFORM_X360 1 + + #endif // _X360 +#elif defined(_PS3) + + +#define IsPlatformX360() 0 +#define IsPlatformPS3() 1 +#ifdef SPU +#define IsPlatformPS3_PPU() 0 +#define IsPlatformPS3_SPU() 1 +#else +#define IsPlatformPS3_PPU() 1 +#define IsPlatformPS3_SPU() 0 +#endif +#define IsPlatformWindowsPC() 0 +#define IsPlatformWindowsPC64() 0 +#define IsPlatformWindowsPC32() 0 +#define IsPlatformPosix() 1 +#define PLATFORM_POSIX 1 +#define PLATFORM_OPENGL 0 + +#define IsPlatformLinux() 0 +#define IsPlatformOSX() 0 +#define IsOSXOpenGL() 0 + + +#elif defined(POSIX) + #define IsPlatformX360() 0 + #define IsPlatformPS3() 0 + #define IsPlatformPS3_PPU() 0 + #define IsPlatformPS3_SPU() 0 + #define IsPlatformWindowsPC() 0 + #define IsPlatformWindowsPC64() 0 + #define IsPlatformWindowsPC32() 0 + #define IsPlatformPosix() 1 + #define PLATFORM_POSIX 1 + + #if defined( LINUX ) && !defined( OSX ) // for havok we define both symbols, so don't let the osx build wander down here + #define IsPlatformLinux() 1 + #define IsPlatformOSX() 0 + #define IsOSXOpenGL() 0 + #define PLATFORM_OPENGL 0 + #define PLATFORM_LINUX 1 + #elif defined ( OSX ) + #define IsPlatformLinux() 0 + #define IsPlatformOSX() 1 + #define IsOSXOpenGL() 1 + #define PLATFORM_OSX 1 + #define PLATFORM_OPENGL 1 + #else + #define IsPlatformLinux() 0 + #define IsPlatformOSX() 0 + #define IsOSXOpenGL() 0 + #define PLATFORM_OPENGL 0 + #endif + +#else + #error +#endif + +// IsXXXX platform pseudo-functions +#if ( defined( PLATFORM_WINDOWS ) && ( PLATFORM_WINDOWS ) ) +#define IsPlatformWindows() 1 +#else +#define IsPlatformWindows() 0 +#endif + +#if ( defined( PLATFORM_OPENGL ) && PLATFORM_OPENGL ) +#define IsOpenGL() 1 +#else +#define IsOpenGL() 0 +#endif + + + +#ifndef _PS3 +//#include <malloc.h> +//#include <new.h> +#else +#include <stdlib.h> // For malloc() +#include <alloca.h> // for alloca() +#define _alloca alloca + #ifdef __cplusplus + #include <new> + #endif +#endif + + +//----------------------------------------------------------------------------- +// Old-school defines we're going to support since much code uses them +//----------------------------------------------------------------------------- +#if CROSS_PLATFORM_VERSION < 2 + +#define IsLinux() IsPlatformLinux() +#define IsOSX() IsPlatformOSX() +#define IsPosix() IsPlatformPosix() +#define IsX360() IsPlatformX360() +#define IsPS3() IsPlatformPS3() + +// Setup platform defines. +#ifdef COMPILER_MSVC +#define MSVC 1 +#endif + +#ifdef COMPILER_GCC +#define GNUC 1 +#endif + +#if defined( _WIN32 ) +#define _WINDOWS 1 +#endif + +#ifdef PLATFORM_WINDOWS_PC +#define IS_WINDOWS_PC 1 +#endif + +#endif // CROSS_PLATFORM_VERSION < 2 + +// VXConsole is enabled for... +#if defined(_X360) || defined(_PS3) +#define USE_VXCONSOLE 1 +#define HasVxConsole() 1 +#else +#define HasVxConsole() 0 +#endif + +//----------------------------------------------------------------------------- +// Set up platform type defines. +//----------------------------------------------------------------------------- +#if defined( PLATFORM_X360 ) || defined( _PS3 ) + #ifndef _GAMECONSOLE + #define _GAMECONSOLE + #endif + #define IsPC() 0 + #define IsGameConsole() 1 +#else + #define IsPC() 1 + #define IsGameConsole() 0 +#endif + + + +//----------------------------------------------------------------------------- +// Set up build configuration defines. +//----------------------------------------------------------------------------- +#ifdef _CERT +#define IsCert() 1 +#else +#define IsCert() 0 +#endif + +#ifdef _DEBUG +#define IsRelease() 0 +#define IsDebug() 1 +#else +#define IsRelease() 1 +#define IsDebug() 0 +#endif + +#ifdef _RETAIL +#define IsRetail() 1 +#else +#define IsRetail() 0 +#endif + + +//----------------------------------------------------------------------------- +// Portable data types +//----------------------------------------------------------------------------- +typedef unsigned char uint8; +typedef signed char int8; + +#if defined( COMPILER_MSVC ) + + typedef __int16 int16; + typedef unsigned __int16 uint16; + typedef __int32 int32; + typedef unsigned __int32 uint32; + typedef __int64 int64; + typedef unsigned __int64 uint64; + + // intp is an integer that can accomodate a pointer + // (ie, sizeof(intp) >= sizeof(int) && sizeof(intp) >= sizeof(void *) + typedef intptr_t intp; + typedef uintptr_t uintp; + + #if defined( COMPILER_MSVCX360 ) + #ifdef __m128 + #undef __m128 + #endif + #define __m128 __vector4 + #endif + +#else // !COMPILER_MSVC + + typedef short int16; + typedef unsigned short uint16; + typedef int int32; + typedef unsigned int uint32; + typedef long long int64; + typedef unsigned long long uint64; + #ifdef PLATFORM_64BITS + typedef long long intp; + typedef unsigned long long uintp; + #else + typedef int intp; + typedef unsigned int uintp; + #endif + typedef void *HWND; +#endif // else COMPILER_MSVC + +#if defined(_PS3) && !defined(NO_SIMD) +typedef union __attribute__ ((aligned (16))) +{ + float m128_f32[4]; +} l_m128; + +typedef __vector float __vector4; +typedef __vector4 __m128; + +const __m128 VMX_ZERO=(vector float)(0.0f); +const __m128 VMX_ONE_HALF=(vector float)(0.5f); +const __m128 VMX_ONE=(vector float)(1.0f); + +// Syntaxic sugar for multiply +inline __attribute__ ((always_inline)) __m128 __vec_mul(const __m128 a, const __m128 b) +{ + return vec_madd(a,b,VMX_ZERO); +} + +// Refined reciprocal function +inline __attribute__ ((always_inline)) __m128 __vec_rec(const __m128 a) +{ + //Get the reciprocal estimate + vector float estimate = vec_re( a ); + + //One round of Newton-Raphson refinement + return vec_madd( vec_nmsub( estimate, a, VMX_ONE ), estimate, estimate ); +} + +// refined reciprocal square root +inline __attribute__ ((always_inline)) __m128 __vec_rsqrt(const __m128 a) +{ + //Get the square root reciprocal estimate + __m128 estimate = vec_rsqrte( a ); + + //One round of Newton-Raphson refinement + __m128 estimateSquared = __vec_mul( estimate, estimate); + __m128 halfEstimate = __vec_mul( estimate, VMX_ONE_HALF); + return vec_madd( vec_nmsub( a, estimateSquared, VMX_ONE ), halfEstimate, estimate ); +} + +// refined square root +inline __attribute__ ((always_inline)) __m128 __vec_sqrt(const __m128 a) +{ + return __vec_mul( a, __vec_rsqrt( a )); +} + +// estimate square root +inline __attribute__ ((always_inline)) __m128 __vec_sqrtest(const __m128 a) +{ + return __vec_mul( a, vec_rsqrte( a )); +} + +// Syntaxic sugar for multiply +inline __attribute__ ((always_inline)) __m128 __vec_div(const __m128 a, const __m128 b) +{ + return __vec_mul( a, __vec_rec( b )); +} + +// load an unaligned array of float in a vector of floats +inline __attribute__ ((always_inline)) __m128 __vec_ld_unaligned(const float* in) +{ + return vec_perm(vec_ld(0,in), + vec_ld(sizeof(__m128),in), + vec_lvsl( 0, in )); +} + +// load an unaligned array of 3 floats in a vector of floats, last member being 0. +inline __attribute__ ((always_inline)) __m128 __vec_ld_unaligned3(const float* in) +{ + return vec_and(__vec_ld_unaligned(in),(__m128)(vector unsigned int)(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF ,0)); +} + +// stores a vector of floats in an unaligned array of float +inline __attribute__ ((always_inline)) void __vec_st_unaligned(__m128 in, float* out) +{ + __m128 temp0 = vec_ld(0,out); + __m128 temp1 = vec_ld(16,out); + vector unsigned char align = vec_lvsr(0,out); + vector unsigned char mask = vec_perm ((vector unsigned char)(0), (vector unsigned char)(0xFF), align); + + in = vec_perm ( in, in, align); + temp0 = vec_sel ( temp0, in, (vector bool)mask); + temp1 = vec_sel ( in, temp1, (vector bool)mask); + vec_st ( temp0, 0, out); + vec_st ( temp1, 16, out); +} + +// stores x,y,z from a vector of floats in an unaligned array of 3 floats +inline __attribute__ ((always_inline)) void __vec_st_unaligned3(__m128 in, float* out) +{ + __m128 temp0 = vec_ld(0,out); + __m128 temp1 = vec_ld(16,out); + vector unsigned char align = vec_lvsr(0,out); + vector unsigned char mask = vec_perm ((vector unsigned char)(0), + (vector unsigned char)(0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0,0,0,0), + align); + + in = vec_perm ( in, in, align); + temp0 = vec_sel ( temp0, in, (vector bool)mask); + temp1 = vec_sel ( in, temp1, (vector bool)mask); + vec_st ( temp0, 0, out); + vec_st ( temp1, 16, out); +} + +#endif // defined(NO_SIMD) + + +typedef float float32; +typedef double float64; + +// for when we don't care about how many bits we use +typedef unsigned int uint; + +#ifdef PLATFORM_POSIX +#ifndef _PS3 +typedef unsigned int DWORD; +typedef unsigned int *LPDWORD; +#endif +typedef unsigned short WORD; +typedef void * HINSTANCE; +#define _MAX_PATH PATH_MAX +#endif + +// MSVC CRT uses 0x7fff while gcc uses MAX_INT, leading to mismatches between platforms +// As a result, we pick the least common denominator here. This should be used anywhere +// you might typically want to use RAND_MAX +#define VALVE_RAND_MAX 0x7fff +// Maximum and minimum representable values +#ifndef PLATFORM_OSX + +#define INT8_MAX SCHAR_MAX +#define INT16_MAX SHRT_MAX +#define INT32_MAX LONG_MAX +#define INT64_MAX (((int64)~0) >> 1) + +#define INT8_MIN SCHAR_MIN +#define INT16_MIN SHRT_MIN +#define INT32_MIN LONG_MIN +#define INT64_MIN (((int64)1) << 63) + +#define UINT8_MAX ((uint8)~0) +#define UINT16_MAX ((uint16)~0) +#define UINT32_MAX ((uint32)~0) +#define UINT64_MAX ((uint64)~0) + +#define UINT8_MIN 0 +#define UINT16_MIN 0 +#define UINT32_MIN 0 +#define UINT64_MIN 0 + +#endif // PLATFORM_OSX + +#ifndef UINT_MIN +#define UINT_MIN UINT32_MIN +#endif + +#define FLOAT32_MAX FLT_MAX +#define FLOAT64_MAX DBL_MAX + +#ifdef GNUC +#undef offsetof +// Note: can't use builtin offsetof because many use cases (esp. in templates) wouldn't compile due to restrictions on the builtin offsetof +//#define offsetof( type, var ) __builtin_offsetof( type, var ) +#define offsetof(s,m) ( (size_t)&(((s *)0x1000000)->m) - 0x1000000u ) +#else +#include <stddef.h> +#undef offsetof +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#endif + + +#define FLOAT32_MIN FLT_MIN +#define FLOAT64_MIN DBL_MIN + +//----------------------------------------------------------------------------- +// Long is evil because it's treated differently by different compilers +// Preventing its use is nasty however. This #define, which should be +// turned on in individual VPC files, causes you to include tier0/valve_off.h +// before standard C + windows headers, and include tier0/valve_on.h after +// standard C + windows headers. So, there's some painful overhead to disabling long +//----------------------------------------------------------------------------- +#ifdef DISALLOW_USE_OF_LONG + #define long long_is_the_devil_stop_using_it_use_int32_or_int64 +#endif + + +//----------------------------------------------------------------------------- +// Various compiler-specific keywords +//----------------------------------------------------------------------------- +#ifdef COMPILER_MSVC + + #ifdef FORCEINLINE + #undef FORCEINLINE + #endif + #define STDCALL __stdcall + #ifndef FASTCALL + #define FASTCALL __fastcall + #endif + #define FORCEINLINE __forceinline + #define FORCEINLINE_TEMPLATE __forceinline + #define NULLTERMINATED __nullterminated + + // This can be used to ensure the size of pointers to members when declaring + // a pointer type for a class that has only been forward declared + #define SINGLE_INHERITANCE __single_inheritance + #define MULTIPLE_INHERITANCE __multiple_inheritance + #define EXPLICIT explicit + #define NO_VTABLE __declspec( novtable ) + + // gcc doesn't allow storage specifiers on explicit template instatiation, but visual studio needs them to avoid link errors. + #define TEMPLATE_STATIC static + + // Used for dll exporting and importing + #define DLL_EXPORT extern "C" __declspec( dllexport ) + #define DLL_IMPORT extern "C" __declspec( dllimport ) + + // Can't use extern "C" when DLL exporting a class + #define DLL_CLASS_EXPORT __declspec( dllexport ) + #define DLL_CLASS_IMPORT __declspec( dllimport ) + + // Can't use extern "C" when DLL exporting a global + #define DLL_GLOBAL_EXPORT extern __declspec( dllexport ) + #define DLL_GLOBAL_IMPORT extern __declspec( dllimport ) + + // Pass hints to the compiler to prevent it from generating unnessecary / stupid code + // in certain situations. Several compilers other than MSVC also have an equivilent + // construct. + // + // Essentially the 'Hint' is that the condition specified is assumed to be true at + // that point in the compilation. If '0' is passed, then the compiler assumes that + // any subsequent code in the same 'basic block' is unreachable, and thus usually + // removed. + #define HINT(THE_HINT) __assume((THE_HINT)) + + // decls for aligning data + #define DECL_ALIGN(x) __declspec( align( x ) ) + + // GCC had a few areas where it didn't construct objects in the same order + // that Windows does. So when CVProfile::CVProfile() would access g_pMemAlloc, + // it would crash because the allocator wasn't initalized yet. + #define CONSTRUCT_EARLY + + #define SELECTANY __declspec(selectany) + + #define RESTRICT __restrict + #define RESTRICT_FUNC __declspec(restrict) + #define FMTFUNCTION( a, b ) + #define NOINLINE + +#if !defined( NO_THREAD_LOCAL ) + #define DECL_THREAD_LOCAL __declspec(thread) +#endif + + #define DISABLE_VC_WARNING( x ) __pragma(warning(disable:4310) ) + #define DEFAULT_VC_WARNING( x ) __pragma(warning(default:4310) ) + + +#elif defined ( COMPILER_GCC ) || defined( COMPILER_SNC ) + + #if defined( COMPILER_SNC ) + #define STDCALL + #define __stdcall + #elif (CROSS_PLATFORM_VERSION >= 1) && !defined( PLATFORM_64BITS ) && !defined( COMPILER_PS3 ) + #define STDCALL __attribute__ ((__stdcall__)) + #else + #define STDCALL + #define __stdcall __attribute__ ((__stdcall__)) + #endif + + #define FASTCALL + #ifdef _LINUX_DEBUGGABLE + #define FORCEINLINE + #else + #ifdef _PS3 + // [IESTYN 7/29/2010] As of SDK 3.4.0, this causes bad code generation in NET_Tick::ReadFromBuffer in netmessages.cpp, + // which caused (seeming) random network packet corruption. It probably causes other bugs too. + #define FORCEINLINE inline /* __attribute__ ((always_inline)) */ + #else + #define FORCEINLINE inline __attribute__ ((always_inline)) + #endif + #endif + + // GCC 3.4.1 has a bug in supporting forced inline of templated functions + // this macro lets us not force inlining in that case + #define FORCEINLINE_TEMPLATE inline + #define SINGLE_INHERITANCE + #define MULTIPLE_INHERITANCE + #define EXPLICIT + #define NO_VTABLE + + #define NULLTERMINATED + +#if defined( COMPILER_SNC ) + #define TEMPLATE_STATIC static +#else + #define TEMPLATE_STATIC +#endif + + // Used for dll exporting and importing + #ifdef COMPILER_SNC + #define DLL_DECLARATION_DEFAULT_VISIBILITY + #else + #define DLL_DECLARATION_DEFAULT_VISIBILITY __attribute__ ((visibility("default"))) + #endif + #define DLL_EXPORT extern "C" DLL_DECLARATION_DEFAULT_VISIBILITY + #define DLL_IMPORT extern "C" + + // Can't use extern "C" when DLL exporting a class +#ifndef _PS3 + #define __stdcall __attribute__ ((__stdcall__)) +#endif + #define DLL_CLASS_EXPORT DLL_DECLARATION_DEFAULT_VISIBILITY + #define DLL_CLASS_IMPORT + + // Can't use extern "C" when DLL exporting a global + #define DLL_GLOBAL_EXPORT DLL_DECLARATION_DEFAULT_VISIBILITY + #define DLL_GLOBAL_IMPORT extern + + #define HINT(THE_HINT) __builtin_expect( THE_HINT, 1 ) + #define DECL_ALIGN(x) __attribute__( ( aligned( x ) ) ) + #define CONSTRUCT_EARLY __attribute__((init_priority(101))) + #define SELECTANY __attribute__((weak)) + #define RESTRICT __restrict__ + #define RESTRICT_FUNC RESTRICT_FUNC_NOT_YET_DEFINED_FOR_THIS_COMPILER + #define FMTFUNCTION( fmtargnumber, firstvarargnumber ) __attribute__ (( format( printf, fmtargnumber, firstvarargnumber ))) + #define NOINLINE __attribute__ ((noinline)) + +#if !defined( NO_THREAD_LOCAL ) + #define DECL_THREAD_LOCAL __thread +#endif + + #define DISABLE_VC_WARNING( x ) + #define DEFAULT_VC_WARNING( x ) + +#else + + #define DECL_ALIGN(x) /* */ + #define SELECTANY static + +#endif + +#if defined( GNUC ) && !defined( COMPILER_PS3 ) // use pre-align on PS3 +// gnuc has the align decoration at the end +#define ALIGN4 +#define ALIGN8 +#define ALIGN16 +#define ALIGN32 +#define ALIGN128 + +#undef ALIGN16_POST +#define ALIGN4_POST DECL_ALIGN(4) +#define ALIGN8_POST DECL_ALIGN(8) +#define ALIGN16_POST DECL_ALIGN(16) +#define ALIGN32_POST DECL_ALIGN(32) +#define ALIGN128_POST DECL_ALIGN(128) +#else +// MSVC has the align at the start of the struct +// PS3 SNC supports both +#define ALIGN4 DECL_ALIGN(4) +#define ALIGN8 DECL_ALIGN(8) +#define ALIGN16 DECL_ALIGN(16) +#define ALIGN32 DECL_ALIGN(32) +#define ALIGN128 DECL_ALIGN(128) + +#define ALIGN4_POST +#define ALIGN8_POST +#define ALIGN16_POST +#define ALIGN32_POST +#define ALIGN128_POST +#endif + +// This can be used to declare an abstract (interface only) class. +// Classes marked abstract should not be instantiated. If they are, and access violation will occur. +// +// Example of use: +// +// abstract_class CFoo +// { +// ... +// } +// +// MSDN __declspec(novtable) documentation: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/_langref_novtable.asp +// +// Note: NJS: This is not enabled for regular PC, due to not knowing the implications of exporting a class with no no vtable. +// It's probable that this shouldn't be an issue, but an experiment should be done to verify this. +// +#ifndef COMPILER_MSVCX360 + #define abstract_class class +#else + #define abstract_class class NO_VTABLE +#endif + + +//----------------------------------------------------------------------------- +// Why do we need this? It would be nice to make it die die die +//----------------------------------------------------------------------------- +// Alloca defined for this platform +#if defined( COMPILER_MSVC ) && !defined( WINDED ) + #if defined(_M_IX86) + #define __i386__ 1 + #endif +#endif + +#if defined __i386__ && !defined __linux__ + #define id386 1 +#else + #define id386 0 +#endif // __i386__ + + +//----------------------------------------------------------------------------- +// Disable annoying unhelpful warnings +//----------------------------------------------------------------------------- +#ifdef COMPILER_MSVC +// Remove warnings from warning level 4. +#pragma warning(disable : 4514) // warning C4514: 'acosl' : unreferenced inline function has been removed +#pragma warning(disable : 4100) // warning C4100: 'hwnd' : unreferenced formal parameter +#pragma warning(disable : 4127) // warning C4127: conditional expression is constant +#pragma warning(disable : 4512) // warning C4512: 'InFileRIFF' : assignment operator could not be generated +#pragma warning(disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable +#pragma warning(disable : 4710) // warning C4710: function 'x' not inlined +#pragma warning(disable : 4702) // warning C4702: unreachable code +#pragma warning(disable : 4505) // unreferenced local function has been removed +#pragma warning(disable : 4239) // nonstandard extension used : 'argument' ( conversion from class Vector to class Vector& ) +#pragma warning(disable : 4097) // typedef-name 'BaseClass' used as synonym for class-name 'CFlexCycler::CBaseFlex' +#pragma warning(disable : 4324) // Padding was added at the end of a structure +#pragma warning(disable : 4244) // type conversion warning. +#pragma warning(disable : 4305) // truncation from 'const double ' to 'float ' +#pragma warning(disable : 4786) // Disable warnings about long symbol names +#pragma warning(disable : 4250) // 'X' : inherits 'Y::Z' via dominance +#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union + +#if _MSC_VER >= 1300 +#pragma warning(disable : 4511) // Disable warnings about private copy constructors +#pragma warning(disable : 4121) // warning C4121: 'symbol' : alignment of a member was sensitive to packing +#pragma warning(disable : 4530) // warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc (disabled due to std headers having exception syntax) +#endif + +#if _MSC_VER >= 1400 +#pragma warning(disable : 4996) // functions declared deprecated +#endif + +// When we port to 64 bit, we'll have to resolve the int, ptr vs size_t 32/64 bit problems... +#if !defined( COMPILER_MSVC64 ) +#if ( CROSS_PLATFORM_VERSION < 1 ) +#pragma warning( disable : 4267 ) // conversion from 'size_t' to 'int', possible loss of data +#pragma warning( disable : 4311 ) // pointer truncation from 'char *' to 'int' +#pragma warning( disable : 4312 ) // conversion from 'unsigned int' to 'memhandle_t' of greater size +#endif +#endif + +#elif defined( COMPILER_SNC ) +#pragma diag_suppress=1700 // warning 1700: class "%s" has virtual functions but non-virtual destructor +// Uncomment the following line if you want to investigate a specific compiler remark without all the noise: +// #pragma diag_suppress=1700, 83, 162, 182, 192, 194, 229, 238, 262, 341, 382, 401, 402, 403, 481, 817, 828, 833, 1363, 1771, 1774, 1779, 1780, 1783, 1785, 1786, 1788 +#endif + +// Pull in the /analyze code annotations. +#include "annotations.h" + +//----------------------------------------------------------------------------- +// Convert int<-->pointer, avoiding 32/64-bit compiler warnings: +//----------------------------------------------------------------------------- +#define INT_TO_POINTER( i ) (void *)( ( i ) + (char *)NULL ) +#define POINTER_TO_INT( p ) ( (int)(uint64)( p ) ) + + +//----------------------------------------------------------------------------- +// Stack-based allocation related helpers +//----------------------------------------------------------------------------- +#if defined( COMPILER_GCC ) || defined( COMPILER_SNC ) + + #define stackalloc( _size ) alloca( ALIGN_VALUE( _size, 16 ) ) + + #ifdef PLATFORM_OSX + #define mallocsize( _p ) ( malloc_size( _p ) ) + #else + #define mallocsize( _p ) ( malloc_usable_size( _p ) ) + #endif + +#elif defined ( COMPILER_MSVC ) + + #define stackalloc( _size ) _alloca( ALIGN_VALUE( _size, 16 ) ) + #define mallocsize( _p ) ( _msize( _p ) ) + +#endif + +#define stackfree( _p ) 0 + +//----------------------------------------------------------------------------- +// Used to break into the debugger +//----------------------------------------------------------------------------- +#ifdef COMPILER_MSVC64 + #define DebuggerBreak() __debugbreak() +#elif COMPILER_MSVC32 + #define DebuggerBreak() __asm { int 3 } +#elif COMPILER_MSVCX360 + #define DebuggerBreak() DebugBreak() +#elif COMPILER_GCC + #if defined( _PS3 ) + #define DebuggerBreak() { __asm volatile ("tw 31,1,1"); } + #elif defined( OSX ) + #define DebuggerBreak() if ( Plat_IsInDebugSession() ) { __asm__ __volatile__ ( "int $3" ); } else { raise(SIGTRAP); } + #elif defined( PLATFORM_CYGWIN ) || defined( PLATFORM_POSIX ) + #define DebuggerBreak() __asm__( "int $0x3;") + #else + #define DebuggerBreak() asm( "int3" ) + #endif +#elif defined( COMPILER_SNC ) && defined( COMPILER_PS3 ) +static bool sPS3_SuppressAssertsInThisFile = false; // you can throw this in the debugger to temporarily disable asserts inside any particular .cpp module. + #define DebuggerBreak() if (!sPS3_SuppressAssertsInThisFile) __builtin_snpause(); // <sergiy> from SNC Migration Guide, tw 31,1,1 +#else +#error DebuggerBreak() is not defined for this platform! +#endif + +#if defined( _X360 ) || defined( _PS3 ) + #if defined( fsel ) + #error + #endif +#else + +FORCEINLINE float fsel(float fComparand, float fValGE, float fLT) +{ + return fComparand >= 0 ? fValGE : fLT; +} +FORCEINLINE double fsel(double fComparand, double fValGE, double fLT) +{ + return fComparand >= 0 ? fValGE : fLT; +} + +#endif + +//----------------------------------------------------------------------------- +// DLL export for platform utilities +//----------------------------------------------------------------------------- +#ifndef STATIC_TIER0 + +#ifdef TIER0_DLL_EXPORT +#define PLATFORM_INTERFACE DLL_EXPORT +#define PLATFORM_OVERLOAD DLL_GLOBAL_EXPORT +#define PLATFORM_CLASS DLL_CLASS_EXPORT +#else +#define PLATFORM_INTERFACE DLL_IMPORT +#define PLATFORM_OVERLOAD DLL_GLOBAL_IMPORT +#define PLATFORM_CLASS DLL_CLASS_IMPORT +#endif + +#else // BUILD_AS_DLL + +#define PLATFORM_INTERFACE extern +#define PLATFORM_OVERLOAD +#define PLATFORM_CLASS + +#endif // BUILD_AS_DLL + + +//----------------------------------------------------------------------------- +// Returns true if debugger attached, false otherwise +//----------------------------------------------------------------------------- +#if defined( PLATFORM_WINDOWS ) || defined( _PS3 ) +PLATFORM_INTERFACE void Plat_DebugString( const tchar * ); +#else +#define Plat_DebugString(s) ((void)0) +#endif + +PLATFORM_INTERFACE bool Plat_IsInDebugSession(); + +#define DebuggerBreakIfDebugging() if ( !Plat_IsInDebugSession() ) ; else DebuggerBreak() + + +//----------------------------------------------------------------------------- +// Message Box +//----------------------------------------------------------------------------- +#if defined( PLATFORM_WINDOWS_PC ) +PLATFORM_INTERFACE void Plat_MessageBox( const char *pTitle, const tchar *pMessage ); +#else +#define Plat_MessageBox( t, m ) ((void)0) +#endif + + +//----------------------------------------------------------------------------- +// Posix platform helpers +//----------------------------------------------------------------------------- +#ifdef PLATFORM_POSIX + +// Visual Studio likes to put an underscore in front of anything that looks like a portable function. +#define _strupr strupr +#define _getcwd getcwd +#define _open open +#define _lseek lseek +#define _read read +#define _close close +#define _vsnprintf vsnprintf +#define _stat stat +#define _O_RDONLY O_RDONLY +#define _stricmp strcasecmp +#define _finite finite +#define _unlink unlink +#define _putenv putenv +#define _chdir chdir +#define _access access + +#define strcmpi stricmp +#define stricmp strcasecmp +#define _alloca alloca +#define GetProcAddress dlsym +#define _chdir chdir +#ifndef _PS3 +#define _strnicmp strnicmp +#endif +#define strnicmp strncasecmp +#define _snwprintf swprintf +#define swprintf_s swprintf +#define wcsicmp _wcsicmp +#define _wcsicmp wcscmp +#define _tempnam tempnam +#define strtok_s strtok_r +#define _mkdir(dir) mkdir( dir, S_IRWXU | S_IRWXG | S_IRWXO ) +#define _wtoi(arg) wcstol(arg, NULL, 10) +#define _wtoi64(arg) wcstoll(arg, NULL, 10) + +#ifndef _PS3 +typedef uint32 HMODULE; +#endif +typedef void *HANDLE; +#define __cdecl + +#if !defined( _snprintf ) // some vpc's define this on the command line +#define _snprintf snprintf +#endif + +#include <alloca.h> +#include <unistd.h> // get unlink +#include <errno.h> + +#endif // PLATFORM_POSIX + +#ifdef PLATFORM_WINDOWS +#ifndef SOCKLEN_T +#define SOCKLEN_T +typedef int socklen_t; +#endif +#endif + +//----------------------------------------------------------------------------- +// Generally useful platform-independent macros (move to another file?) +//----------------------------------------------------------------------------- + +// need macro for constant expression +#define ALIGN_VALUE( val, alignment ) ( ( val + alignment - 1 ) & ~( alignment - 1 ) ) + +// Force a function call site -not- to inlined. (useful for profiling) +#define DONT_INLINE(a) (((int)(a)+1)?(a):(a)) + +// Marks the codepath from here until the next branch entry point as unreachable, +// and asserts if any attempt is made to execute it. +#define UNREACHABLE() { Assert(0); HINT(0); } + +// In cases where no default is present or appropriate, this causes MSVC to generate +// as little code as possible, and throw an assertion in debug. +#define NO_DEFAULT default: UNREACHABLE(); + +// Defines MAX_PATH +#ifndef MAX_PATH + #define MAX_PATH 260 +#endif + + +//----------------------------------------------------------------------------- +// FP exception handling +//----------------------------------------------------------------------------- +//#define CHECK_FLOAT_EXCEPTIONS 1 +//#define CHECK_FPU_CONTROL_WORD_SET 1 // x360 only + +#if defined( COMPILER_MSVC64 ) + + inline void SetupFPUControlWord() + { + } + +#elif defined ( COMPILER_MSVC32 ) + + inline void SetupFPUControlWordForceExceptions() + { + // use local to get and store control word + uint16 tmpCtrlW; + __asm + { + fnclex /* clear all current exceptions */ + fnstcw word ptr [tmpCtrlW] /* get current control word */ + and [tmpCtrlW], 0FCC0h /* Keep infinity control + rounding control */ + or [tmpCtrlW], 0230h /* set to 53-bit, mask only inexact, underflow */ + fldcw word ptr [tmpCtrlW] /* put new control word in FPU */ + } + } + + #ifdef CHECK_FLOAT_EXCEPTIONS + + inline void SetupFPUControlWord() + { + SetupFPUControlWordForceExceptions(); + } + + #else + + inline void SetupFPUControlWord() + { + // use local to get and store control word + uint16 tmpCtrlW; + __asm + { + fnstcw word ptr [tmpCtrlW] /* get current control word */ + and [tmpCtrlW], 0FCC0h /* Keep infinity control + rounding control */ + or [tmpCtrlW], 023Fh /* set to 53-bit, mask only inexact, underflow */ + fldcw word ptr [tmpCtrlW] /* put new control word in FPU */ + } + } + + #endif + +#elif defined ( COMPILER_GCC ) + +// Works for PS3 + inline void SetupFPUControlWord() + { +#ifdef _PS3 +// TODO: PS3 compiler spits out the following errors: +// C:/tmp/ccIN0aaa.s: Assembler messages: +// C:/tmp/ccIN0aaa.s(80): Error: Unrecognized opcode: `fnstcw' +// C:/tmp/ccIN0aaa.s(93): Error: Unrecognized opcode: `fldcw' +#else + __volatile unsigned short int __cw; + __asm __volatile ("fnstcw %0" : "=m" (__cw)); + __cw = __cw & 0x0FCC0; // keep infinity control, keep rounding mode + __cw = __cw | 0x023F; // set 53-bit, no exceptions + __asm __volatile ("fldcw %0" : : "m" (__cw)); +#endif + } + +#elif defined ( COMPILER_SNC ) + +// Works for PS3 + inline void SetupFPUControlWord() + { +#ifdef _PS3 +// TODO: PS3 compiler spits out the following errors: +// C:/tmp/ccIN0aaa.s: Assembler messages: +// C:/tmp/ccIN0aaa.s(80): Error: Unrecognized opcode: `fnstcw' +// C:/tmp/ccIN0aaa.s(93): Error: Unrecognized opcode: `fldcw' +#else + __volatile unsigned short int __cw; + __asm __volatile ("fnstcw %0" : "=m" (__cw)); + __cw = __cw & 0x0FCC0; // keep infinity control, keep rounding mode + __cw = __cw | 0x023F; // set 53-bit, no exceptions + __asm __volatile ("fldcw %0" : : "m" (__cw)); +#endif + } + +#elif defined( COMPILER_MSVCX360 ) + + #ifdef CHECK_FPU_CONTROL_WORD_SET + FORCEINLINE bool IsFPUControlWordSet() + { + float f = 0.996f; + union + { + double flResult; + int pResult[2]; + }; + flResult = __fctiw( f ); + return ( pResult[1] == 1 ); + } + #else + #define IsFPUControlWordSet() 1 + #endif + + inline void SetupFPUControlWord() + { + // Set round-to-nearest in FPSCR + // (cannot assemble, must use op-code form) + __emit( 0xFF80010C ); // mtfsfi 7,0 + + // Favour compatibility over speed (make sure the VPU set to Java-compliant mode) + // NOTE: the VPU *always* uses round-to-nearest + __vector4 a = { 0.0f, 0.0f, 0.0f, 0.0f }; + a; // Avoid compiler warning + __asm + { + mtvscr a; // Clear the Vector Status & Control Register to zero + } + } + +#endif // COMPILER_MSVCX360 + + + + +//----------------------------------------------------------------------------- +// Purpose: Standard functions for handling endian-ness +//----------------------------------------------------------------------------- + +//------------------------------------- +// Basic swaps +//------------------------------------- + +template <typename T> +inline T WordSwapC( T w ) +{ + uint16 temp; + + temp = ((*((uint16 *)&w) & 0xff00) >> 8); + temp |= ((*((uint16 *)&w) & 0x00ff) << 8); + + return *((T*)&temp); +} + +template <typename T> +inline T DWordSwapC( T dw ) +{ + uint32 temp; + + temp = *((uint32 *)&dw) >> 24; + temp |= ((*((uint32 *)&dw) & 0x00FF0000) >> 8); + temp |= ((*((uint32 *)&dw) & 0x0000FF00) << 8); + temp |= ((*((uint32 *)&dw) & 0x000000FF) << 24); + + return *((T*)&temp); +} + +//------------------------------------- +// Fast swaps +//------------------------------------- + +#if defined( COMPILER_MSVCX360 ) + + #define WordSwap WordSwap360Intr + #define DWordSwap DWordSwap360Intr + + template <typename T> + inline T WordSwap360Intr( T w ) + { + T output; + __storeshortbytereverse( w, 0, &output ); + return output; + } + + template <typename T> + inline T DWordSwap360Intr( T dw ) + { + T output; + __storewordbytereverse( dw, 0, &output ); + return output; + } + +#elif defined( COMPILER_MSVC32 ) + + #define WordSwap WordSwapAsm + #define DWordSwap DWordSwapAsm + + #pragma warning(push) + #pragma warning (disable:4035) // no return value + + template <typename T> + inline T WordSwapAsm( T w ) + { + __asm + { + mov ax, w + xchg al, ah + } + } + + template <typename T> + inline T DWordSwapAsm( T dw ) + { + __asm + { + mov eax, dw + bswap eax + } + } + + #pragma warning(pop) + +#else + + #define WordSwap WordSwapC + #define DWordSwap DWordSwapC + +#endif + +//------------------------------------- +// The typically used methods. +//------------------------------------- + +#if defined( _SGI_SOURCE ) || defined( PLATFORM_X360 ) || defined( _PS3 ) +#define PLAT_BIG_ENDIAN 1 +#else +#define PLAT_LITTLE_ENDIAN 1 +#endif + + +// If a swapped float passes through the fpu, the bytes may get changed. +// Prevent this by swapping floats as DWORDs. +#define SafeSwapFloat( pOut, pIn ) (*((uint*)pOut) = DWordSwap( *((uint*)pIn) )) + +#if defined(PLAT_LITTLE_ENDIAN) +#define BigShort( val ) WordSwap( val ) +#define BigWord( val ) WordSwap( val ) +#define BigLong( val ) DWordSwap( val ) +#define BigDWord( val ) DWordSwap( val ) +#define LittleShort( val ) ( val ) +#define LittleWord( val ) ( val ) +#define LittleLong( val ) ( val ) +#define LittleDWord( val ) ( val ) +#define SwapShort( val ) BigShort( val ) +#define SwapWord( val ) BigWord( val ) +#define SwapLong( val ) BigLong( val ) +#define SwapDWord( val ) BigDWord( val ) + +// Pass floats by pointer for swapping to avoid truncation in the fpu +#define BigFloat( pOut, pIn ) SafeSwapFloat( pOut, pIn ) +#define LittleFloat( pOut, pIn ) ( *pOut = *pIn ) +#define SwapFloat( pOut, pIn ) BigFloat( pOut, pIn ) + +#elif defined(PLAT_BIG_ENDIAN) + +#define BigShort( val ) ( val ) +#define BigWord( val ) ( val ) +#define BigLong( val ) ( val ) +#define BigDWord( val ) ( val ) +#define LittleShort( val ) WordSwap( val ) +#define LittleWord( val ) WordSwap( val ) +#define LittleLong( val ) DWordSwap( val ) +#define LittleDWord( val ) DWordSwap( val ) +#define SwapShort( val ) LittleShort( val ) +#define SwapWord( val ) LittleWord( val ) +#define SwapLong( val ) LittleLong( val ) +#define SwapDWord( val ) LittleDWord( val ) + +// Pass floats by pointer for swapping to avoid truncation in the fpu +#define BigFloat( pOut, pIn ) ( *pOut = *pIn ) +#define LittleFloat( pOut, pIn ) SafeSwapFloat( pOut, pIn ) +#define SwapFloat( pOut, pIn ) LittleFloat( pOut, pIn ) + +#else + +// @Note (toml 05-02-02): this technique expects the compiler to +// optimize the expression and eliminate the other path. On any new +// platform/compiler this should be tested. +inline short BigShort( short val ) { int test = 1; return ( *(char *)&test == 1 ) ? WordSwap( val ) : val; } +inline uint16 BigWord( uint16 val ) { int test = 1; return ( *(char *)&test == 1 ) ? WordSwap( val ) : val; } +inline long BigLong( long val ) { int test = 1; return ( *(char *)&test == 1 ) ? DWordSwap( val ) : val; } +inline uint32 BigDWord( uint32 val ) { int test = 1; return ( *(char *)&test == 1 ) ? DWordSwap( val ) : val; } +inline short LittleShort( short val ) { int test = 1; return ( *(char *)&test == 1 ) ? val : WordSwap( val ); } +inline uint16 LittleWord( uint16 val ) { int test = 1; return ( *(char *)&test == 1 ) ? val : WordSwap( val ); } +inline long LittleLong( long val ) { int test = 1; return ( *(char *)&test == 1 ) ? val : DWordSwap( val ); } +inline uint32 LittleDWord( uint32 val ) { int test = 1; return ( *(char *)&test == 1 ) ? val : DWordSwap( val ); } +inline short SwapShort( short val ) { return WordSwap( val ); } +inline uint16 SwapWord( uint16 val ) { return WordSwap( val ); } +inline long SwapLong( long val ) { return DWordSwap( val ); } +inline uint32 SwapDWord( uint32 val ) { return DWordSwap( val ); } + +// Pass floats by pointer for swapping to avoid truncation in the fpu +inline void BigFloat( float *pOut, const float *pIn ) { int test = 1; ( *(char *)&test == 1 ) ? SafeSwapFloat( pOut, pIn ) : ( *pOut = *pIn ); } +inline void LittleFloat( float *pOut, const float *pIn ) { int test = 1; ( *(char *)&test == 1 ) ? ( *pOut = *pIn ) : SafeSwapFloat( pOut, pIn ); } +inline void SwapFloat( float *pOut, const float *pIn ) { SafeSwapFloat( pOut, pIn ); } + +#endif + +#if PLAT_BIG_ENDIAN + #if defined( _PS3 ) + inline uint32 LoadLittleDWord( uint32 *base, unsigned int dwordIndex ) + { + return __lwbrx( base + dwordIndex ); + } + + inline void StoreLittleDWord( uint32 *base, unsigned int dwordIndex, uint32 dword ) + { + __stwbrx( base + dwordIndex, dword ); + } + inline uint64 LoadLittleInt64( uint64 *base, unsigned int nWordIndex ) + { + return __ldbrx( base + nWordIndex ); + } + + inline void StoreLittleInt64( uint64 *base, unsigned int nWordIndex, uint64 nWord ) + { + __stdbrx( base + nWordIndex, nWord ); + } + #else + inline uint32 LoadLittleDWord( uint32 *base, unsigned int dwordIndex ) + { + return __loadwordbytereverse( dwordIndex<<2, base ); + } + + inline void StoreLittleDWord( uint32 *base, unsigned int dwordIndex, uint32 dword ) + { + __storewordbytereverse( dword, dwordIndex<<2, base ); + } + inline uint64 LoadLittleInt64( uint64 *base, unsigned int nWordIndex ) + { + return __loaddoublewordbytereverse( nWordIndex<<2, base ); + } + + inline void StoreLittleInt64( uint64 *base, unsigned int nWordIndex, uint64 nWord ) + { + __storedoublewordbytereverse( nWord, nWordIndex<<2, base ); + } + #endif +#else + inline uint32 LoadLittleDWord( uint32 *base, unsigned int dwordIndex ) + { + return LittleDWord( base[dwordIndex] ); + } + + inline void StoreLittleDWord( uint32 *base, unsigned int dwordIndex, uint32 dword ) + { + base[dwordIndex] = LittleDWord(dword); + } +#endif + + +// When in benchmark mode, the timer returns a simple incremented value each time you call it. +// +// It should not be changed after startup unless you really know what you're doing. The only place +// that should do this is the benchmark code itself so it can output a legit duration. +PLATFORM_INTERFACE void Plat_SetBenchmarkMode( bool bBenchmarkMode ); +PLATFORM_INTERFACE bool Plat_IsInBenchmarkMode(); + + +PLATFORM_INTERFACE double Plat_FloatTime(); // Returns time in seconds since the module was loaded. +PLATFORM_INTERFACE uint32 Plat_MSTime(); // Time in milliseconds. +PLATFORM_INTERFACE uint64 Plat_GetClockStart(); // Snapshot of the clock when app started. +PLATFORM_INTERFACE uint64 Timer_GetTimeUS(); + +// Get the local calendar time. +// Same as time() followed by localtime(), but non-crash-prone and threadsafe. +PLATFORM_INTERFACE void Plat_GetLocalTime( struct tm *pNow ); + +// Convert a time_t (specified in nTime - seconds since Jan 1, 1970 UTC) to a local calendar time in a threadsafe and non-crash-prone way. +PLATFORM_INTERFACE void Plat_ConvertToLocalTime( uint64 nTime, struct tm *pNow ); + +// Get a time string (same as ascstring, but threadsafe). +PLATFORM_INTERFACE void Plat_GetTimeString( struct tm *pTime, char *pOut, int nMaxBytes ); + +// converts a time_t to a struct tm without the local time conversion of ConvertToLocalTime +PLATFORM_INTERFACE void Plat_gmtime( uint64 nTime, struct tm *pTime ); +PLATFORM_INTERFACE time_t Plat_timegm( struct tm *timeptr ); + +// Get the process' executable filename. +PLATFORM_INTERFACE void Plat_GetModuleFilename( char *pOut, int nMaxBytes ); + +PLATFORM_INTERFACE void Plat_ExitProcess( int nCode ); + +// b/w compatibility +#define Sys_FloatTime Plat_FloatTime + +// Protect against bad auto operator= +#define DISALLOW_OPERATOR_EQUAL( _classname ) \ + private: \ + _classname &operator=( const _classname & ); \ + public: + +// Define a reasonable operator= +#define IMPLEMENT_OPERATOR_EQUAL( _classname ) \ + public: \ + _classname &operator=( const _classname &src ) \ + { \ + memcpy( this, &src, sizeof(_classname) ); \ + return *this; \ + } + +// Processor Information: +struct CPUInformation +{ + int m_Size; // Size of this structure, for forward compatability. + + bool m_bRDTSC : 1, // Is RDTSC supported? + m_bCMOV : 1, // Is CMOV supported? + m_bFCMOV : 1, // Is FCMOV supported? + m_bSSE : 1, // Is SSE supported? + m_bSSE2 : 1, // Is SSE2 Supported? + m_b3DNow : 1, // Is 3DNow! Supported? + m_bMMX : 1, // Is MMX supported? + m_bHT : 1; // Is HyperThreading supported? + + uint8 m_nLogicalProcessors; // Number op logical processors. + uint8 m_nPhysicalProcessors; // Number of physical processors + + bool m_bSSE3 : 1, + m_bSSSE3 : 1, + m_bSSE4a : 1, + m_bSSE41 : 1, + m_bSSE42 : 1; + + int64 m_Speed; // In cycles per second. + + tchar* m_szProcessorID; // Processor vendor Identification. + + CPUInformation(): m_Size(0){} +}; + +PLATFORM_INTERFACE const CPUInformation& GetCPUInformation(); + +PLATFORM_INTERFACE void GetCurrentDate( int *pDay, int *pMonth, int *pYear ); +PLATFORM_INTERFACE void GetCurrentDayOfTheWeek( int *pDay ); // 0 = Sunday +PLATFORM_INTERFACE void GetCurrentDayOfTheYear( int *pDay ); // 0 = Jan 1 + +// ---------------------------------------------------------------------------------- // +// Performance Monitoring Events - L2 stats etc... +// ---------------------------------------------------------------------------------- // +PLATFORM_INTERFACE void InitPME(); +PLATFORM_INTERFACE void ShutdownPME(); + + +//----------------------------------------------------------------------------- +// Security related functions +//----------------------------------------------------------------------------- +// Ensure that the hardware key's drivers have been installed. +PLATFORM_INTERFACE bool Plat_VerifyHardwareKeyDriver(); + +// Ok, so this isn't a very secure way to verify the hardware key for now. It +// is primarially depending on the fact that all the binaries have been wrapped +// with the secure wrapper provided by the hardware keys vendor. +PLATFORM_INTERFACE bool Plat_VerifyHardwareKey(); + +// The same as above, but notifies user with a message box when the key isn't in +// and gives him an opportunity to correct the situation. +PLATFORM_INTERFACE bool Plat_VerifyHardwareKeyPrompt(); + +// Can be called in real time, doesn't perform the verify every frame. Mainly just +// here to allow the game to drop out quickly when the key is removed, rather than +// allowing the wrapper to pop up it's own blocking dialog, which the engine doesn't +// like much. +PLATFORM_INTERFACE bool Plat_FastVerifyHardwareKey(); + +//----------------------------------------------------------------------------- +// Just logs file and line to simple.log +//----------------------------------------------------------------------------- +PLATFORM_INTERFACE void* Plat_SimpleLog( const tchar* file, int line ); + + +#if defined( _X360 ) +#define Plat_FastMemset XMemSet +#define Plat_FastMemcpy XMemCpy +#else +#define Plat_FastMemset memset +#define Plat_FastMemcpy memcpy +#endif + +//----------------------------------------------------------------------------- +// XBOX Components valid in PC compilation space +//----------------------------------------------------------------------------- + +#define XBOX_DVD_SECTORSIZE 2048 +#define XBOX_DVD_ECC_SIZE 32768 // driver reads in quantum ECC blocks +#define XBOX_HDD_SECTORSIZE 512 + +// Custom windows messages for Xbox input +#define WM_XREMOTECOMMAND (WM_USER + 100) +#define WM_XCONTROLLER_KEY (WM_USER + 101) +#define WM_SYS_UI (WM_USER + 102) +#define WM_SYS_SIGNINCHANGED (WM_USER + 103) +#define WM_SYS_STORAGEDEVICESCHANGED (WM_USER + 104) +#define WM_SYS_PROFILESETTINGCHANGED (WM_USER + 105) +#define WM_SYS_MUTELISTCHANGED (WM_USER + 106) +#define WM_SYS_INPUTDEVICESCHANGED (WM_USER + 107) +#define WM_SYS_INPUTDEVICECONFIGCHANGED (WM_USER + 108) +#define WM_LIVE_CONNECTIONCHANGED (WM_USER + 109) +#define WM_LIVE_INVITE_ACCEPTED (WM_USER + 110) +#define WM_LIVE_LINK_STATE_CHANGED (WM_USER + 111) +#define WM_LIVE_CONTENT_INSTALLED (WM_USER + 112) +#define WM_LIVE_MEMBERSHIP_PURCHASED (WM_USER + 113) +#define WM_LIVE_VOICECHAT_AWAY (WM_USER + 114) +#define WM_LIVE_PRESENCE_CHANGED (WM_USER + 115) +#define WM_FRIENDS_PRESENCE_CHANGED (WM_USER + 116) +#define WM_FRIENDS_FRIEND_ADDED (WM_USER + 117) +#define WM_FRIENDS_FRIEND_REMOVED (WM_USER + 118) +#define WM_CUSTOM_GAMEBANNERPRESSED (WM_USER + 119) +#define WM_CUSTOM_ACTIONPRESSED (WM_USER + 120) +#define WM_XMP_STATECHANGED (WM_USER + 121) +#define WM_XMP_PLAYBACKBEHAVIORCHANGED (WM_USER + 122) +#define WM_XMP_PLAYBACKCONTROLLERCHANGED (WM_USER + 123) +#define WM_SYS_SHUTDOWNREQUEST (WM_USER + 124) + +#if defined( _PS3 ) +#define PLATFORM_EXT ".ps3" +#elif defined( PLATFORM_X360 ) +#define PLATFORM_EXT ".360" +#else +#define PLATFORM_EXT "" +#endif + +inline const char *GetPlatformExt( void ) +{ + return PLATFORM_EXT; +} + +// flat view, 6 hw threads +#define XBOX_PROCESSOR_0 ( 1<<0 ) +#define XBOX_PROCESSOR_1 ( 1<<1 ) +#define XBOX_PROCESSOR_2 ( 1<<2 ) +#define XBOX_PROCESSOR_3 ( 1<<3 ) +#define XBOX_PROCESSOR_4 ( 1<<4 ) +#define XBOX_PROCESSOR_5 ( 1<<5 ) + +// core view, 3 cores with 2 hw threads each +#define XBOX_CORE_0_HWTHREAD_0 XBOX_PROCESSOR_0 +#define XBOX_CORE_0_HWTHREAD_1 XBOX_PROCESSOR_1 +#define XBOX_CORE_1_HWTHREAD_0 XBOX_PROCESSOR_2 +#define XBOX_CORE_1_HWTHREAD_1 XBOX_PROCESSOR_3 +#define XBOX_CORE_2_HWTHREAD_0 XBOX_PROCESSOR_4 +#define XBOX_CORE_2_HWTHREAD_1 XBOX_PROCESSOR_5 + +//----------------------------------------------------------------------------- +// Include additional dependant header components. +//----------------------------------------------------------------------------- +#if defined( PLATFORM_X360 ) +#include "xbox/xbox_core.h" +#elif defined( PLATFORM_PS3 ) +#include "ps3/ps3_core.h" +#endif + +//----------------------------------------------------------------------------- +// Methods to invoke the constructor, copy constructor, and destructor +//----------------------------------------------------------------------------- + +template <class T> +inline T* Construct( T* pMemory ) +{ + return ::new( pMemory ) T; +} + +template <class T, typename ARG1> +inline T* Construct( T* pMemory, ARG1 a1 ) +{ + return ::new( pMemory ) T( a1 ); +} + +template <class T, typename ARG1, typename ARG2> +inline T* Construct( T* pMemory, ARG1 a1, ARG2 a2 ) +{ + return ::new( pMemory ) T( a1, a2 ); +} + +template <class T, typename ARG1, typename ARG2, typename ARG3> +inline T* Construct( T* pMemory, ARG1 a1, ARG2 a2, ARG3 a3 ) +{ + return ::new( pMemory ) T( a1, a2, a3 ); +} + +template <class T, typename ARG1, typename ARG2, typename ARG3, typename ARG4> +inline T* Construct( T* pMemory, ARG1 a1, ARG2 a2, ARG3 a3, ARG4 a4 ) +{ + return ::new( pMemory ) T( a1, a2, a3, a4 ); +} + +template <class T, typename ARG1, typename ARG2, typename ARG3, typename ARG4, typename ARG5> +inline T* Construct( T* pMemory, ARG1 a1, ARG2 a2, ARG3 a3, ARG4 a4, ARG5 a5 ) +{ + return ::new( pMemory ) T( a1, a2, a3, a4, a5 ); +} + +template <class T> +inline T* CopyConstruct( T* pMemory, T const& src ) +{ + return ::new( pMemory ) T(src); +} + +template <class T> +inline void Destruct( T* pMemory ) +{ + pMemory->~T(); + +#ifdef _DEBUG + memset( pMemory, 0xDD, sizeof(T) ); +#endif +} + + +// +// GET_OUTER() +// +// A platform-independent way for a contained class to get a pointer to its +// owner. If you know a class is exclusively used in the context of some +// "outer" class, this is a much more space efficient way to get at the outer +// class than having the inner class store a pointer to it. +// +// class COuter +// { +// class CInner // Note: this does not need to be a nested class to work +// { +// void PrintAddressOfOuter() +// { +// printf( "Outer is at 0x%x\n", GET_OUTER( COuter, m_Inner ) ); +// } +// }; +// +// CInner m_Inner; +// friend class CInner; +// }; + +#define GET_OUTER( OuterType, OuterMember ) \ + ( ( OuterType * ) ( (uint8 *)this - offsetof( OuterType, OuterMember ) ) ) + + +/* TEMPLATE_FUNCTION_TABLE() + + (Note added to platform.h so platforms that correctly support templated + functions can handle portions as templated functions rather than wrapped + functions) + + Helps automate the process of creating an array of function + templates that are all specialized by a single integer. + This sort of thing is often useful in optimization work. + + For example, using TEMPLATE_FUNCTION_TABLE, this: + + TEMPLATE_FUNCTION_TABLE(int, Function, ( int blah, int blah ), 10) + { + return argument * argument; + } + + is equivilent to the following: + + (NOTE: the function has to be wrapped in a class due to code + generation bugs involved with directly specializing a function + based on a constant.) + + template<int argument> + class FunctionWrapper + { + public: + int Function( int blah, int blah ) + { + return argument*argument; + } + } + + typedef int (*FunctionType)( int blah, int blah ); + + class FunctionName + { + public: + enum { count = 10 }; + FunctionType functions[10]; + }; + + FunctionType FunctionName::functions[] = + { + FunctionWrapper<0>::Function, + FunctionWrapper<1>::Function, + FunctionWrapper<2>::Function, + FunctionWrapper<3>::Function, + FunctionWrapper<4>::Function, + FunctionWrapper<5>::Function, + FunctionWrapper<6>::Function, + FunctionWrapper<7>::Function, + FunctionWrapper<8>::Function, + FunctionWrapper<9>::Function + }; +*/ + +PLATFORM_INTERFACE bool vtune( bool resume ); + + +#define TEMPLATE_FUNCTION_TABLE(RETURN_TYPE, NAME, ARGS, COUNT) \ + \ +typedef RETURN_TYPE (FASTCALL *__Type_##NAME) ARGS; \ + \ +template<const int nArgument> \ +struct __Function_##NAME \ +{ \ + static RETURN_TYPE FASTCALL Run ARGS; \ +}; \ + \ +template <const int i> \ +struct __MetaLooper_##NAME : __MetaLooper_##NAME<i-1> \ +{ \ + __Type_##NAME func; \ + inline __MetaLooper_##NAME() { func = __Function_##NAME<i>::Run; } \ +}; \ + \ +template<> \ +struct __MetaLooper_##NAME<0> \ +{ \ + __Type_##NAME func; \ + inline __MetaLooper_##NAME() { func = __Function_##NAME<0>::Run; } \ +}; \ + \ +class NAME \ +{ \ +private: \ + static const __MetaLooper_##NAME<COUNT> m; \ +public: \ + enum { count = COUNT }; \ + static const __Type_##NAME* functions; \ +}; \ +const __MetaLooper_##NAME<COUNT> NAME::m; \ +const __Type_##NAME* NAME::functions = (__Type_##NAME*)&m; \ +template<const int nArgument> \ +RETURN_TYPE FASTCALL __Function_##NAME<nArgument>::Run ARGS + + +#define LOOP_INTERCHANGE(BOOLEAN, CODE)\ + if( (BOOLEAN) )\ + {\ + CODE;\ + } else\ + {\ + CODE;\ + } + + +//----------------------------------------------------------------------------- +// Dynamic libs support +//----------------------------------------------------------------------------- +#if defined( PLATFORM_WINDOWS ) + +PLATFORM_INTERFACE void *Plat_GetProcAddress( const char *pszModule, const char *pszName ); + +template <typename FUNCPTR_TYPE> +class CDynamicFunction +{ +public: + CDynamicFunction( const char *pszModule, const char *pszName, FUNCPTR_TYPE pfnFallback = NULL ) + { + m_pfn = pfnFallback; + void *pAddr = Plat_GetProcAddress( pszModule, pszName ); + if ( pAddr ) + { + m_pfn = (FUNCPTR_TYPE)pAddr; + } + } + + operator bool() { return m_pfn != NULL; } + bool operator !() { return !m_pfn; } + operator FUNCPTR_TYPE() { return m_pfn; } + +private: + FUNCPTR_TYPE m_pfn; +}; +#endif + + +//----------------------------------------------------------------------------- +// What OS version are we? +//----------------------------------------------------------------------------- +enum PlatOSVersion_t +{ + PLAT_OS_VERSION_UNKNOWN = -1, + + // X360-specific versions + PLAT_OS_VERSION_XBOX360 = 0, + + // PC-specific OS versions + PLAT_OS_VERSION_XP = 5, + PLAT_OS_VERSION_VISTA = 6, +}; + +PLATFORM_INTERFACE PlatOSVersion_t Plat_GetOSVersion(); + + +// Watchdog timer support. Call BeginWatchdogTimer( nn ) to kick the timer off. if you don't call +// EndWatchdogTimer within nn seconds, the program will kick off an exception. This is for making +// sure that hung dedicated servers abort (and restart) instead of staying hung. Calling +// EndWatchdogTimer more than once or when there is no active watchdog is fine. Only does anything +// under linux right now. It should be possible to implement this functionality in windows via a +// thread, if desired. + +#if defined( POSIX ) && !defined( _PS3 ) + +PLATFORM_INTERFACE void BeginWatchdogTimer( int nSecs ); +PLATFORM_INTERFACE void EndWatchdogTimer( void ); +PLATFORM_INTERFACE void ResetBaseTime( void ); // reset plat_floattime to 0 for a subprocess +#else +FORCEINLINE void BeginWatchdogTimer( int nSecs ) +{ +} + +FORCEINLINE void EndWatchdogTimer( void ) +{ +} +FORCEINLINE void ResetBaseTime( void ) // reset plat_floattime to 0 for a subprocess +{ +} + +#endif + + +#ifdef COMPILER_MSVC +/* +FORCEINLINE uint8 RotateBitsLeft8( uint8 nValue, int nRotateBits ) +{ + return _rotl8( nValue, nRotateBits ); +} +FORCEINLINE uint16 RotateBitsLeft16( uint16 nValue, int nRotateBits ) +{ + return _rotl( nValue, nRotateBits ); +} +FORCEINLINE uint8 RotateBitsRight8( uint8 nValue, int nRotateBits ) +{ +return _rotr8( nValue, nRotateBits ); +} +FORCEINLINE uint16 RotateBitsRight16( uint16 nValue, int nRotateBits ) +{ +return _rotr16( nValue, nRotateBits ); +} +*/ +FORCEINLINE uint32 RotateBitsLeft32( uint32 nValue, int nRotateBits ) +{ + return _rotl( nValue, nRotateBits ); +} +FORCEINLINE uint64 RotateBitsLeft64( uint64 nValue, int nRotateBits ) +{ + return _rotl64( nValue, nRotateBits ); +} +FORCEINLINE uint32 RotateBitsRight32( uint32 nValue, int nRotateBits ) +{ + return _rotr( nValue, nRotateBits ); +} +FORCEINLINE uint64 RotateBitsRight64( uint64 nValue, int nRotateBits ) +{ + return _rotr64( nValue, nRotateBits ); +} +#else +// GCC should compile this all into single instruction +/* +FORCEINLINE uint8 RotateBitsLeft8( uint8 nValue, int nRotateBits ) +{ + return ( nValue << nRotateBits ) | ( nValue >> ( ( -nRotateBits ) & 7 ) ); +} +FORCEINLINE uint16 RotateBitsLeft16( uint16 nValue, int nRotateBits ) +{ + return ( nValue << nRotateBits ) | ( nValue >> ( ( -nRotateBits ) & 15 ) ); +} +FORCEINLINE uint8 RotateBitsRight8( uint8 nValue, int nRotateBits ) +{ + return ( nValue >> nRotateBits ) | ( nValue << ( ( -nRotateBits ) & 7 ) ); +} +FORCEINLINE uint16 RotateBitsRight16( uint16 nValue, int nRotateBits ) +{ + return ( nValue >> nRotateBits ) | ( nValue << ( ( -nRotateBits ) & 15 ) ); +} +*/ +FORCEINLINE uint32 RotateBitsLeft32( uint32 nValue, int nRotateBits ) +{ + return ( nValue << nRotateBits ) | ( nValue >> ( ( -nRotateBits ) & 31 ) ); +} +FORCEINLINE uint64 RotateBitsLeft64( uint64 nValue, int nRotateBits ) +{ + return ( nValue << nRotateBits ) | ( nValue >> ( ( - nRotateBits ) & 63 ) ); +} +FORCEINLINE uint32 RotateBitsRight32( uint32 nValue, int nRotateBits ) +{ + return ( nValue >> nRotateBits ) | ( nValue << ( ( -nRotateBits ) & 31 ) ); +} +FORCEINLINE uint64 RotateBitsRight64( uint64 nValue, int nRotateBits ) +{ + return ( nValue >> nRotateBits ) | ( nValue << ( ( - nRotateBits ) & 63 ) ); +} +#endif +PLATFORM_INTERFACE const char * GetPlatformSpecificFileName(const char * FileName); + +#include "tier0/valve_on.h" + +#if defined(TIER0_DLL_EXPORT) +extern "C" int V_tier0_stricmp(const char *s1, const char *s2 ); +#undef stricmp +#undef strcmpi +#define stricmp(s1,s2) V_tier0_stricmp( s1, s2 ) +#define strcmpi(s1,s2) V_tier0_stricmp( s1, s2 ) +#else +int _V_stricmp (const char *s1, const char *s2 ); +int V_strncasecmp (const char *s1, const char *s2, int n); + +// A special high-performance case-insensitive compare function that in +// a single call distinguishes between exactly matching strings, +// strings equal in case-insensitive way, and not equal strings: +// returns 0 if strings match exactly +// returns >0 if strings match in a case-insensitive way, but do not match exactly +// returns <0 if strings do not match even in a case-insensitive way +int _V_stricmp_NegativeForUnequal ( const char *s1, const char *s2 ); + +#undef stricmp +#undef strcmpi +#define stricmp(s1,s2) _V_stricmp(s1, s2) +#define strcmpi(s1,s2) _V_stricmp(s1, s2) +#undef strnicmp +#define strnicmp V_strncasecmp +#endif + +#endif /* PLATFORM_H */ diff --git a/external/vpc/public/tier0/pmelib.h b/external/vpc/public/tier0/pmelib.h new file mode 100644 index 0000000..dcdec5f --- /dev/null +++ b/external/vpc/public/tier0/pmelib.h @@ -0,0 +1,212 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +#ifndef PMELIB_H +#define PMELIB_H + +//#include "windows.h" + +#include "tier0/platform.h" + +// Get rid of a bunch of STL warnings! +#pragma warning( push, 3 ) +#pragma warning( disable : 4018 ) + +#define VERSION "1.0.2" + +// uncomment this list to add some runtime checks +//#define PME_DEBUG + +#include "tier0/valve_off.h" +#include <string> +#include "tier0/valve_on.h" + +using namespace std; + +// RDTSC Instruction macro +#ifdef COMPILER_MSVC64 +#define RDTSC(var) (var = __rdtsc()) +#else +#define RDTSC(var) \ +_asm RDTSC \ +_asm mov DWORD PTR var,eax \ +_asm mov DWORD PTR var+4,edx +#endif + +// RDPMC Instruction macro +#ifdef COMPILER_MSVC64 +#define RDPMC(counter, var) (var = __readpmc(counter)) +#else +#define RDPMC(counter, var) \ +_asm mov ecx, counter \ +_asm RDPMC \ +_asm mov DWORD PTR var,eax \ +_asm mov DWORD PTR var+4,edx +#endif + +// RDPMC Instruction macro, for performance counter 1 (ecx = 1) +#ifdef COMPILER_MSVC64 +#define RDPMC0(var) (var = __readpmc(0)) +#else +#define RDPMC0(var) \ +_asm mov ecx, 0 \ +_asm RDPMC \ +_asm mov DWORD PTR var,eax \ +_asm mov DWORD PTR var+4,edx +#endif + +#ifdef COMPILER_MSVC64 +#define RDPMC1(var) (var = __readpmc(1)) +#else +#define RDPMC1(var) \ +_asm mov ecx, 1 \ +_asm RDPMC \ +_asm mov DWORD PTR var,eax \ +_asm mov DWORD PTR var+4,edx +#endif + +#define EVENT_TYPE(mode) EventType##mode +#define EVENT_MASK(mode) EventMask##mode + +#include "ia32detect.h" + +enum ProcessPriority +{ + ProcessPriorityNormal, + ProcessPriorityHigh, +}; + +enum PrivilegeCapture +{ + OS_Only, // ring 0, kernel level + USR_Only, // app level + OS_and_USR, // all levels +}; + +enum CompareMethod +{ + CompareGreater, // + CompareLessEqual, // +}; + +enum EdgeState +{ + RisingEdgeDisabled, // + RisingEdgeEnabled, // +}; + +enum CompareState +{ + CompareDisable, // + CompareEnable, // +}; + +// Singletion Class +class PME : public ia32detect +{ +public: +//private: + + static PME* _singleton; + + HANDLE hFile; + bool bDriverOpen; + double m_CPUClockSpeed; + + //ia32detect detect; + HRESULT Init(); + HRESULT Close(); + +protected: + + PME() + { + hFile = NULL; + bDriverOpen = FALSE; + m_CPUClockSpeed = 0; + Init(); + } + +public: + + static PME* Instance(); // gives back a real object + + ~PME() + { + Close(); + } + + double GetCPUClockSpeedSlow( void ); + double GetCPUClockSpeedFast( void ); + + HRESULT SelectP5P6PerformanceEvent( uint32 dw_event, uint32 dw_counter, bool b_user, bool b_kernel ); + + HRESULT ReadMSR( uint32 dw_reg, int64 * pi64_value ); + HRESULT ReadMSR( uint32 dw_reg, uint64 * pi64_value ); + + HRESULT WriteMSR( uint32 dw_reg, const int64 & i64_value ); + HRESULT WriteMSR( uint32 dw_reg, const uint64 & i64_value ); + + void SetProcessPriority( ProcessPriority priority ) + { + switch( priority ) + { + case ProcessPriorityNormal: + { + SetPriorityClass (GetCurrentProcess(),NORMAL_PRIORITY_CLASS); + SetThreadPriority (GetCurrentThread(),THREAD_PRIORITY_NORMAL); + break; + } + case ProcessPriorityHigh: + { + SetPriorityClass (GetCurrentProcess(),REALTIME_PRIORITY_CLASS); + SetThreadPriority (GetCurrentThread(),THREAD_PRIORITY_HIGHEST); + break; + } + } + } + + //--------------------------------------------------------------------------- + // Return the family of the processor + //--------------------------------------------------------------------------- + CPUVendor GetVendor(void) + { + return vendor; + } + + int GetProcessorFamily(void) + { + return version.Family; + } + +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, tchar *pchName ); // Validate our internal structures +#endif // DBGFLAG_VALIDATE + +}; + +#include "p5p6performancecounters.h" +#include "p4performancecounters.h" +#include "k8performancecounters.h" + +enum PerfErrors +{ + E_UNKNOWN_CPU_VENDOR = -1, + E_BAD_COUNTER = -2, + E_UNKNOWN_CPU = -3, + E_CANT_OPEN_DRIVER = -4, + E_DRIVER_ALREADY_OPEN = -5, + E_DRIVER_NOT_OPEN = -6, + E_DISABLED = -7, + E_BAD_DATA = -8, + E_CANT_CLOSE = -9, + E_ILLEGAL_OPERATION = -10, +}; + +#pragma warning( pop ) + +#endif // PMELIB_H
\ No newline at end of file diff --git a/external/vpc/public/tier0/stackstats.h b/external/vpc/public/tier0/stackstats.h new file mode 100644 index 0000000..a14d64b --- /dev/null +++ b/external/vpc/public/tier0/stackstats.h @@ -0,0 +1,966 @@ +//========= Copyright � 1996-2008, Valve Corporation, All rights reserved. ============// +// +// Purpose: Tools for grabbing/dumping the stack at runtime +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TIER0_STACKSTATS_H +#define TIER0_STACKSTATS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/stacktools.h" +#include "tier0/threadtools.h" + +#if defined ENABLE_RUNTIME_STACK_TRANSLATION +#define ENABLE_STACK_STATS_GATHERING //uncomment to enable the gathering class +#endif + +#if defined ENABLE_STACK_STATS_GATHERING +#include "tier0/valve_off.h" +# include <map> //needed for CCallStackStatsGatherer +# include <vector> +#include "tier0/valve_on.h" +#define CDefaultStatsGathererAllocator std::allocator +#else +template<class _Ty> class CNullStatsGathererAllocator { CNullStatsGathererAllocator( void ) { } }; +#define CDefaultStatsGathererAllocator CNullStatsGathererAllocator +#endif + + +typedef size_t (*FN_DescribeStruct)( uint8 *, size_t ); + +class CCallStackStatsGatherer_Standardized_t; +struct CCallStackStatsGatherer_FunctionTable_t +{ + void (*pfn_GetDumpInfo)( void *, const char *&, size_t &, size_t &, void *&, size_t &, CCallStackStatsGatherer_Standardized_t *&, size_t & ); + void (*pfn_PushSubTree)( void *, const CCallStackStatsGatherer_Standardized_t &, const CCallStackStorage & ); + void (*pfn_PopSubTree)( void * ); + size_t (*pfn_DescribeCallStackStatStruct)( uint8 *, size_t ); + void (*pfn_SyncMutexes)( void *, bool ); + void *(*pfn_GetEntry)( void *, uint32 ); + void (*pfn_ApplyTreeAccessLock)( void *, bool ); + void (*pfn_LockEntry)( void *, uint32, bool ); +}; + +//templatized classes are fun, can't really use a base pointer effectively, so we'll have a translator struct and store pointers to instances of the translator function +class CCallStackStatsGatherer_Standardized_t +{ +public: + CCallStackStatsGatherer_Standardized_t( void ) {}; + CCallStackStatsGatherer_Standardized_t( void *pThis, const CCallStackStatsGatherer_FunctionTable_t &FnTable ) : pGatherer( pThis ), pFunctionTable( &FnTable ) {}; + + //go ahead and create some helper functions that are likely to be used by helper code + void PushSubTree( const CCallStackStatsGatherer_Standardized_t &SubTree, const CCallStackStorage &PushStack = CCallStackStorage() ) const + { + pFunctionTable->pfn_PushSubTree( pGatherer, SubTree, PushStack ); + } + + inline void PopSubTree( void ) const + { + pFunctionTable->pfn_PopSubTree( pGatherer ); + } + + void *pGatherer; + const CCallStackStatsGatherer_FunctionTable_t *pFunctionTable; +}; + +//Designed to be called by an instance of CCallStackStatsGatherer to dump it's data +PLATFORM_INTERFACE bool _CCallStackStatsGatherer_Internal_DumpStatsToFile( const char *szFileName, const CCallStackStatsGatherer_Standardized_t &StatsGatherer, bool bAllowMemoryAllocations ); + + + + + + +template <class STATSTRUCT> +class CCallStackStatsGatherer_StructAccessor_Base +{ +public: + CCallStackStatsGatherer_StructAccessor_Base( const CCallStackStatsGatherer_Standardized_t &Gatherer, int iEntryIndex ) : m_Gatherer( Gatherer ), m_iEntryIndex( iEntryIndex ) {}; +protected: + uint32 m_iEntryIndex; //index of the stat entry we want in the vector. Stored as index as the vector base address can change. + CCallStackStatsGatherer_Standardized_t m_Gatherer; //so we can lock the vector memory in place while manipulating the values +}; + + +class CCallStackStatsGatherer_StatMutexBase +{ +public: + void LockEntry( uint32 iEntryIndex, bool bLock ) {} //true to increase lock refcount, false to decrease +}; + +template <uint32 SHAREDENTRYMUTEXES> //must be a power of 2 +class CCallStackStatsGatherer_StatMutexPool +{ +public: + void LockEntry( uint32 iEntryIndex, bool bLock ) + { +#if defined( ENABLE_STACK_STATS_GATHERING ) + COMPILE_TIME_ASSERT( (SHAREDENTRYMUTEXES & (SHAREDENTRYMUTEXES - 1)) == 0 ); //must be a power of 2 + + if( bLock ) + { + m_IndividualEntryMutexes[iEntryIndex & (SHAREDENTRYMUTEXES - 1)].Lock(); + } + else + { + m_IndividualEntryMutexes[iEntryIndex & (SHAREDENTRYMUTEXES - 1)].Unlock(); + } +#endif + } +protected: + CThreadFastMutex m_IndividualEntryMutexes[SHAREDENTRYMUTEXES]; +}; + + + + +//STATSTRUCT - The structure you'll use to track whatever it is you're tracking. +//CAPTUREDCALLSTACKLENGTH - The maximum length of your stack trace that we'll use to distinguish entries +//STACKACQUISITIONFUNCTION - The function to use to gather the current call stack. GetCallStack() is safe, GetCallStack_Fast() is faster, but has special requirements +//STATMUTEXHANDLER - If you want automatic mutex management for your individual entries, supply a handler here. +// You'll need to not only call GetEntry(), but lock/unlock the entry while accessing it. +//TEMPLATIZEDMEMORYALLOCATOR - We'll need to allocate memory, supply an allocator if you want to manage that +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION = GetCallStack, typename STATMUTEXHANDLER = CCallStackStatsGatherer_StatMutexPool<4>, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR = CDefaultStatsGathererAllocator> +class CCallStackStatsGatherer : public STATMUTEXHANDLER +{ +public: +#if !defined( ENABLE_STACK_STATS_GATHERING ) + CCallStackStatsGatherer( void ) + { + for( size_t i = 0; i != CAPTUREDCALLSTACKLENGTH; ++i ) + m_SingleCallStack[i] = NULL; + } +#endif + + CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> GetEntry( void * const CallStack[CAPTUREDCALLSTACKLENGTH] ); //get the entry using some callstack grabbed a while ago. Assumes ALL invalid entries have been nullified + CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> GetEntry( void * const CallStack[CAPTUREDCALLSTACKLENGTH], uint32 iValidEntries ); //same as above, but does the work of nullifying invalid entries + CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> GetEntry( const CCallStackStorage &PushStack = CCallStackStorage( STACKACQUISITIONFUNCTION ) ); + CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> GetEntry( uint32 iEntryIndex ); + + //get the entry index for the caller's current call stack. Pre-nullified entries count as valid entries (and save re-nullification work) + uint32 GetEntryIndex( void * const CallStack[CAPTUREDCALLSTACKLENGTH], uint32 iValidEntries ); //index is unchanging, safe to keep and use later (designed for exactly that purpose) + uint32 GetEntryIndex( const CCallStackStorage &PushStack = CCallStackStorage( STACKACQUISITIONFUNCTION ) ); + + + + typedef void *(&StackReference)[CAPTUREDCALLSTACKLENGTH]; + StackReference GetCallStackForIndex( uint32 iEntryIndex ) + { +#if defined( ENABLE_STACK_STATS_GATHERING ) + return m_StatEntries[iEntryIndex].m_CallStack; +#else + return m_SingleCallStack; +#endif + } + + void GetCallStackForIndex( uint32 iEntryIndex, void *CallStackOut[CAPTUREDCALLSTACKLENGTH] ); + + size_t NumEntries( void ) const; + + bool DumpToFile( const char *szFileName, bool bAllowMemoryAllocations = true ); + + static const CCallStackStatsGatherer_FunctionTable_t &GetFunctionTable( void ); + + static void GetDumpInfo( void *pThis, const char *&szStructName, size_t &iCapturedStackLength, size_t &iEntrySizeWithStack, void *&pEntries, size_t &iEntryCount, CCallStackStatsGatherer_Standardized_t *&pSubTrees, size_t &iSubTreeCount ); + static void PushSubTree( void *pParent, const CCallStackStatsGatherer_Standardized_t &SubTree, const CCallStackStorage &PushStack ); + + void PushSubTree( CCallStackStatsGatherer_Standardized_t &Parent, const CCallStackStorage &PushStack = CCallStackStorage( STACKACQUISITIONFUNCTION ) ); + + static void PopSubTree( void *pParent ); + static void SyncMutexes( void *pParent, bool bLock ); //true for lock, false for unlock + static void *GetEntry( void *pParent, uint32 iEntryIndex ); + static void ApplyTreeAccessLock( void *pParent, bool bLock ); + static void LockEntry( void *pParent, uint32 iEntryIndex, bool bLock ); + + void Reset( void ); + + + CCallStackStatsGatherer_Standardized_t Standardized( void ); + operator CCallStackStatsGatherer_Standardized_t( void ); + + const static FN_GetCallStack StackFunction; //publish the requested acquisition function so you can easily key all your stack gathering to the class instance + const static size_t CapturedCallStackLength; +private: + +#pragma pack(push) +#pragma pack(1) + struct StackAndStats_t + { + void *m_CallStack[CAPTUREDCALLSTACKLENGTH]; + STATSTRUCT m_Stats; + }; +#pragma pack(pop) + + typedef CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR> ThisCast; + + +#if defined( ENABLE_STACK_STATS_GATHERING ) + + struct IndexMapKey_t + { + IndexMapKey_t( void * const CallStack[CAPTUREDCALLSTACKLENGTH] ) + { + m_Hash = 0; + for( int i = 0; i < CAPTUREDCALLSTACKLENGTH; ++i ) + { + m_CallStack[i] = CallStack[i]; + m_Hash += (uintp)CallStack[i]; + } + } + bool operator<( const IndexMapKey_t &key ) const + { + if( m_Hash != key.m_Hash ) + return m_Hash < key.m_Hash; + + //only here if there's a hash match. Do a full check. Extremely likely to be the exact same call stack. But not 100% guaranteed. + for( int i = 0; i < CAPTUREDCALLSTACKLENGTH; ++i ) + { + if( m_CallStack[i] == key.m_CallStack[i] ) + { + continue; + } + + return m_CallStack[i] < key.m_CallStack[i]; + } + + return false; //exact same call stack + } + + uintp m_Hash; + void *m_CallStack[CAPTUREDCALLSTACKLENGTH]; + }; + + void KeepSubTree( CCallStackStatsGatherer_Standardized_t &SubTree ) + { + AUTO_LOCK_FM( m_SubTreeMutex ); + for( StoredSubTreeVector_t::iterator treeIter = m_StoredSubTrees.begin(); treeIter != m_StoredSubTrees.end(); ++treeIter ) + { + if( SubTree.pGatherer == treeIter->pGatherer ) + return; + } + + //Warning( "Storing subtree\n" ); + + m_StoredSubTrees.push_back( SubTree ); + } + + uint32 PatchInSubTrees( void * const CallStackIn[CAPTUREDCALLSTACKLENGTH], void *CallStackOut[CAPTUREDCALLSTACKLENGTH], uint32 iValidEntries ) + { + if( iValidEntries > CAPTUREDCALLSTACKLENGTH ) + { + iValidEntries = CAPTUREDCALLSTACKLENGTH; + } + + AUTO_LOCK_FM( m_SubTreeMutex ); + if( m_PushedSubTrees.size() == 0 ) + { + memcpy( CallStackOut, CallStackIn, sizeof( void * ) * iValidEntries ); + return iValidEntries; + } + + unsigned long iThreadID = ThreadGetCurrentId(); + PushedSubTreeVector_t::reverse_iterator treeIter; + for( treeIter = m_PushedSubTrees.rbegin(); treeIter != m_PushedSubTrees.rend(); ++treeIter ) + { + if( treeIter->iThreadID == iThreadID ) + { + break; + } + } + + if( treeIter == m_PushedSubTrees.rend() ) + { + memcpy( CallStackOut, CallStackIn, sizeof( void * ) * iValidEntries ); + return iValidEntries; + } + + //char szTemp[4096]; + //TranslateStackInfo( CallStackIn, CAPTUREDCALLSTACKLENGTH, szTemp, sizeof( szTemp ), "\n\t" ); + + //Warning( "Attempting to link trees:\n=======================ONE=======================\n\t%s\n", szTemp ); + //TranslateStackInfo( treeIter->Stack, CAPTUREDCALLSTACKLENGTH, szTemp, sizeof( szTemp ), "\n\t" ); + //Warning( "=======================TWO=======================\n\t%s\n", szTemp ); + + void *pMatchAddress = treeIter->Stack[1]; //while the first entry is where the actual push was made. The second entry is the first that is matchable in most cases + + uint32 i; + for( i = 0; i < iValidEntries; ++i ) + { + if( CallStackIn[i] == pMatchAddress ) + { + //TranslateStackInfo( CallStackIn, i, szTemp, sizeof( szTemp ), "\n\t" ); + //Warning( "======================MATCH======================\n\t%s\n", szTemp ); + + CallStackOut[i] = treeIter->tree.pGatherer; //tag this entry as leading into the sub-tree + KeepSubTree( treeIter->tree ); //store the sub-tree forever + return i + 1; + } + CallStackOut[i] = CallStackIn[i]; + } + + return iValidEntries; + + //Warning( "=======================END=======================\n" ); + } + + struct StatIndex_t + { + StatIndex_t( void ) : m_Index((unsigned int)-1) {}; + unsigned int m_Index; + }; + + typedef std::vector<StackAndStats_t, TEMPLATIZEDMEMORYALLOCATOR<StackAndStats_t> > StatVector_t; + typedef std::map< IndexMapKey_t, StatIndex_t, std::less<IndexMapKey_t>, TEMPLATIZEDMEMORYALLOCATOR<std::pair<const IndexMapKey_t, StatIndex_t> > > IndexMap_t; + typedef typename IndexMap_t::iterator IndexMapIter_t; + typedef typename IndexMap_t::value_type IndexMapEntry_t; + + StatVector_t m_StatEntries; + IndexMap_t m_IndexMap; + + struct PushedSubTree_t + { + unsigned long iThreadID; + CCallStackStatsGatherer_Standardized_t tree; + void *Stack[CAPTUREDCALLSTACKLENGTH]; + }; + + typedef std::vector<PushedSubTree_t, TEMPLATIZEDMEMORYALLOCATOR<PushedSubTree_t> > PushedSubTreeVector_t; + PushedSubTreeVector_t m_PushedSubTrees; + + typedef std::vector<CCallStackStatsGatherer_Standardized_t, TEMPLATIZEDMEMORYALLOCATOR<CCallStackStatsGatherer_Standardized_t> > StoredSubTreeVector_t; + StoredSubTreeVector_t m_StoredSubTrees; + + CThreadFastMutex m_IndexMapMutex; + CThreadFastMutex m_SubTreeMutex; + + //only for locking the memory in place, locked for write when the entry addresses might change. + //Locked for read when you've claimed you're manipulating a value. + //You're on your own for making sure two threads don't access the same index simultaneously + CThreadRWLock m_StatEntryLock; + +#else //#if defined( ENABLE_STACK_STATS_GATHERING ) + + STATSTRUCT m_SingleEntry; //the class is disabled, we'll always return this same struct + void *m_SingleCallStack[CAPTUREDCALLSTACKLENGTH]; + + static size_t NULL_DescribeCallStackStatStruct( uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength ) { return 0; } + +#endif //#if defined( ENABLE_STACK_STATS_GATHERING ) +}; + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +const FN_GetCallStack CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::StackFunction = STACKACQUISITIONFUNCTION; + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +const size_t CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::CapturedCallStackLength = CAPTUREDCALLSTACKLENGTH; + +#if defined( ENABLE_STACK_STATS_GATHERING ) + +class CallStackStatStructDescFuncs; +PLATFORM_INTERFACE size_t _CCallStackStatsGatherer_Write_FieldDescriptions( CallStackStatStructDescFuncs *pFieldDescriptions, uint8 *pWriteBuffer, size_t iWriteBufferSize ); +//PLATFORM_INTERFACE size_t _CCallStackStatsGatherer_Write_FieldMergeScript( CallStackStatStructDescFuncs *pFieldDescriptions, CallStackStatStructDescFuncs::MergeScript_Language scriptMergeLanguage, uint8 *pWriteBuffer, size_t iWriteBufferSize ); + +#define DECLARE_CALLSTACKSTATSTRUCT() static const char *STATSTRUCTSTRINGNAME;\ + static size_t DescribeCallStackStatStruct( uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength ); + +#define BEGIN_STATSTRUCTDESCRIPTION( className ) const char *className::STATSTRUCTSTRINGNAME = #className;\ + size_t className::DescribeCallStackStatStruct( uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength ) {\ + size_t iWroteBytes = 0; +#define END_STATSTRUCTDESCRIPTION() return iWroteBytes; } + + +#define DECLARE_CALLSTACKSTATSTRUCT_FIELDDESCRIPTION() static CallStackStatStructDescFuncs *GetStatStructFieldDescriptions( void ); + +#define BEGIN_STATSTRUCTFIELDDESCRIPTION( className ) CallStackStatStructDescFuncs * className::GetStatStructFieldDescriptions( void ) {\ + typedef className ThisStruct;\ + CallStackStatStructDescFuncs *_pHeadLinkage = NULL;\ + CallStackStatStructDescFuncs **_pLinkageHelperVar = &_pHeadLinkage; + +#define _DEFINE_STATSTRUCTFIELD_VARNAME( varName, fieldName, fieldStruct, fieldParmsInParentheses ) static fieldStruct varName##_desc##fieldParmsInParentheses;\ + varName##_desc.m_szFieldName = #fieldName;\ + varName##_desc.m_iFieldOffset = (size_t)(&((ThisStruct *)NULL)->fieldName);\ + varName##_desc.m_pNext = NULL;\ + *_pLinkageHelperVar = &varName##_desc;\ + _pLinkageHelperVar = &varName##_desc.m_pNext; + +#define DEFINE_STATSTRUCTFIELD( fieldName, fieldStruct, fieldParmsInParentheses ) _DEFINE_STATSTRUCTFIELD_VARNAME( fieldName, fieldName, fieldStruct, fieldParmsInParentheses ) +#define DEFINE_STATSTRUCTFIELD_ARRAYENTRY( arrayName, arrayIndex, fieldStruct, fieldParmsInParentheses ) _DEFINE_STATSTRUCTFIELD_VARNAME( arrayName##_##arrayIndex, arrayName##[##arrayIndex##], fieldStruct, fieldParmsInParentheses ) + +#define END_STATSTRUCTFIELDDESCRIPTION() static CallStackStatStructDescFuncs *s_pHeadStruct = _pHeadLinkage;\ + return s_pHeadStruct; } + +#define WRITE_STATSTRUCT_FIELDDESCRIPTION() iWroteBytes += _CCallStackStatsGatherer_Write_FieldDescriptions( GetStatStructFieldDescriptions(), pDescribeWriteBuffer + iWroteBytes, iDescribeMaxLength - iWroteBytes ); +//#define WRITE_STATSTRUCT_FIELDMERGESCRIPT( scriptMergeLanguage ) iWroteBytes += _CCallStackStatsGatherer_Write_FieldMergeScript( GetStatStructFieldDescriptions(), CallStackStatStructDescFuncs::scriptMergeLanguage, pDescribeWriteBuffer + iWroteBytes, iDescribeMaxLength - iWroteBytes ); + + +#else //#if defined( ENABLE_STACK_STATS_GATHERING ) + +#define DECLARE_CALLSTACKSTATSTRUCT() +#define BEGIN_STATSTRUCTDESCRIPTION( className ) +#define END_STATSTRUCTDESCRIPTION() + +#define DECLARE_CALLSTACKSTATSTRUCT_FIELDDESCRIPTION() +#define BEGIN_STATSTRUCTFIELDDESCRIPTION( className ) +#define DEFINE_STATSTRUCTFIELD( fieldName, fieldStruct, fieldParmsInParentheses ) +#define END_STATSTRUCTFIELDDESCRIPTION() + +#define WRITE_STATSTRUCT_FIELDDESCRIPTION() +//#define WRITE_STATSTRUCT_FIELDMERGESCRIPT( scriptMergeLanguage ) + +#endif //#if defined( ENABLE_STACK_STATS_GATHERING ) + + + + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntry( void * const CallStack[CAPTUREDCALLSTACKLENGTH] ) //get the entry using some callstack grabbed a while ago. Assumes ALL invalid entries have been nullified +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + return GetEntry( GetEntryIndex( CallStack ) ); +#else + return CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( Standardized(), 0 ); +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntry( void * const CallStack[CAPTUREDCALLSTACKLENGTH], uint32 iValidEntries ) //same as above, but does the work of nullifying invalid entries +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + void *CleanedCallStack[CAPTUREDCALLSTACKLENGTH]; + size_t i; + for( i = 0; i < CAPTUREDCALLSTACKLENGTH; ++i ) + { + CleanedCallStack[i] = CallStack[i]; + } + + for( ; i < CAPTUREDCALLSTACKLENGTH; ++i ) + { + CleanedCallStack[i] = NULL; + } + return GetEntry( GetEntryIndex( CleanedCallStack ) ); +#else + return CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( Standardized(), 0 ); +#endif +} + + + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntry( const CCallStackStorage &PushStack ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + COMPILE_TIME_ASSERT( CAPTUREDCALLSTACKLENGTH <= ARRAYSIZE( PushStack.pStack ) ); + return GetEntry( GetEntryIndex( PushStack.pStack, PushStack.iValidEntries ) ); +#else + return CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( Standardized(), 0 ); +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +uint32 CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntryIndex( const CCallStackStorage &PushStack ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + COMPILE_TIME_ASSERT( CAPTUREDCALLSTACKLENGTH <= ARRAYSIZE( PushStack.pStack ) ); + return GetEntryIndex( PushStack.pStack, PushStack.iValidEntries ); +#else + return 0; +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntry( uint32 iEntryIndex ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + return CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( Standardized(), iEntryIndex ); +#else + return CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( Standardized(), 0 ); +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +uint32 CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntryIndex( void * const CallStack[CAPTUREDCALLSTACKLENGTH], uint32 iValidEntries ) //index is unchanging, safe to keep and use later (designed for exactly that purpose) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + AUTO_LOCK_FM( m_IndexMapMutex ); + std::pair<IndexMapIter_t, bool> indexMapIter; + void *PatchedStack[CAPTUREDCALLSTACKLENGTH]; + + //if we have a sub-tree. We'll be splicing it into the original call stack as if it were a return address. Then patching that when we interpret the results later + //A stack with a sub-tree along the line is treated as distinctly different than one without a sub-tree + iValidEntries = PatchInSubTrees( CallStack, PatchedStack, iValidEntries ); + + Assert( iValidEntries <= CAPTUREDCALLSTACKLENGTH ); + + for( int i = iValidEntries; i < CAPTUREDCALLSTACKLENGTH; ++i ) + { + PatchedStack[i] = NULL; + } + + indexMapIter = m_IndexMap.insert( IndexMapEntry_t( IndexMapKey_t( PatchedStack ), StatIndex_t() ) ); + + if( indexMapIter.first->second.m_Index == -1 ) + { + m_StatEntryLock.LockForWrite(); + indexMapIter.first->second.m_Index = (unsigned int)m_StatEntries.size(); + + m_StatEntries.push_back( StackAndStats_t() ); + memcpy( m_StatEntries[indexMapIter.first->second.m_Index].m_CallStack, PatchedStack, sizeof( void * ) * CAPTUREDCALLSTACKLENGTH ); + m_StatEntryLock.UnlockWrite(); + } + + return indexMapIter.first->second.m_Index; +#else + return 0; +#endif +} + + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetCallStackForIndex( uint32 iEntryIndex, void *CallStackOut[CAPTUREDCALLSTACKLENGTH] ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + m_StatEntryLock.LockForRead(); + for( size_t i = 0; i != CAPTUREDCALLSTACKLENGTH; ++i ) + { + CallStackOut[i] = m_StatEntries[iEntryIndex].m_CallStack[i]; + } + m_StatEntryLock.UnlockRead(); +#else + for( size_t i = 0; i != CAPTUREDCALLSTACKLENGTH; ++i ) + CallStackOut[i] = NULL; +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +size_t CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::NumEntries( void ) const +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + return m_StatEntries.size(); +#else + return 0; +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +bool CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::DumpToFile( const char *szFileName, bool bAllowMemoryAllocations ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + CCallStackStatsGatherer_Standardized_t StandardThis = Standardized(); + SyncMutexes( this, true ); + bool bRetVal = _CCallStackStatsGatherer_Internal_DumpStatsToFile( szFileName, StandardThis, bAllowMemoryAllocations ); + SyncMutexes( this, false ); + return bRetVal; +#else + return false; +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +const CCallStackStatsGatherer_FunctionTable_t &CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetFunctionTable( void ) +{ + static CCallStackStatsGatherer_FunctionTable_t retVal = + { GetDumpInfo, + PushSubTree, + PopSubTree, +#if defined( ENABLE_STACK_STATS_GATHERING ) + STATSTRUCT::DescribeCallStackStatStruct, +#else + NULL_DescribeCallStackStatStruct, +#endif + SyncMutexes, + GetEntry, + ApplyTreeAccessLock, + LockEntry }; + + return retVal; +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetDumpInfo( void *pThis, const char *&szStructName, size_t &iCapturedStackLength, size_t &iEntrySizeWithStack, void *&pEntries, size_t &iEntryCount, CCallStackStatsGatherer_Standardized_t *&pSubTrees, size_t &iSubTreeCount ) +{ + ThisCast *pThisCast = (ThisCast *)pThis; + iCapturedStackLength = CAPTUREDCALLSTACKLENGTH; + iEntrySizeWithStack = sizeof( CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::StackAndStats_t ); + +#if defined( ENABLE_STACK_STATS_GATHERING ) + szStructName = STATSTRUCT::STATSTRUCTSTRINGNAME; + iEntryCount = pThisCast->m_StatEntries.size(); + pEntries = iEntryCount > 0 ? &pThisCast->m_StatEntries[0] : NULL; + iSubTreeCount = pThisCast->m_StoredSubTrees.size(); + pSubTrees = iSubTreeCount > 0 ? &pThisCast->m_StoredSubTrees[0] : NULL; +#else + szStructName = ""; + iEntryCount = 0; + pEntries = NULL; + iSubTreeCount = 0; + pSubTrees = NULL; +#endif +} + + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::PushSubTree( void *pParent, const CCallStackStatsGatherer_Standardized_t &SubTree, const CCallStackStorage &PushStack ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + ThisCast *pParentCast = (ThisCast *)pParent; + PushedSubTree_t pushVal; + pushVal.iThreadID = ThreadGetCurrentId(); + pushVal.tree = SubTree; + + memcpy( pushVal.Stack, PushStack.pStack, MIN( CAPTUREDCALLSTACKLENGTH, PushStack.iValidEntries ) * sizeof( void * ) ); + + for( int i = PushStack.iValidEntries; i < CAPTUREDCALLSTACKLENGTH; ++i ) + { + pushVal.Stack[i] = NULL; + } + + pParentCast->m_SubTreeMutex.Lock(); + pParentCast->m_PushedSubTrees.push_back( pushVal ); + pParentCast->m_SubTreeMutex.Unlock(); +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::PushSubTree( CCallStackStatsGatherer_Standardized_t &Parent, const CCallStackStorage &PushStack ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + CCallStackStatsGatherer_Standardized_t StandardThis = Standardized(); + Parent.PushSubTree( StandardThis, PushStack ); +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::PopSubTree( void *pParent ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + ThisCast *pParentCast = (ThisCast *)pParent; + pParentCast->m_SubTreeMutex.Lock(); + unsigned long iThreadID = ThreadGetCurrentId(); + + for( PushedSubTreeVector_t::reverse_iterator treeIter = pParentCast->m_PushedSubTrees.rbegin(); treeIter != pParentCast->m_PushedSubTrees.rend(); ++treeIter ) + { + if( treeIter->iThreadID == iThreadID ) + { + ++treeIter; //[24.4.1/1] &*(reverse_iterator(i)) == &*(i - 1) + PushedSubTreeVector_t::iterator eraseIter = treeIter.base(); + pParentCast->m_PushedSubTrees.erase(eraseIter); + break; + } + } + + pParentCast->m_SubTreeMutex.Unlock(); +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::SyncMutexes( void *pParent, bool bLock ) //true for lock, false for unlock +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + ThisCast *pParentCast = (ThisCast *)pParent; + if( bLock ) + { + pParentCast->m_IndexMapMutex.Lock(); + pParentCast->m_SubTreeMutex.Lock(); + + for( StoredSubTreeVector_t::iterator treeIter = pParentCast->m_StoredSubTrees.begin(); treeIter != pParentCast->m_StoredSubTrees.end(); ++treeIter ) + { + treeIter->pFunctionTable->pfn_SyncMutexes( treeIter->pGatherer, true ); + } + } + else + { + for( StoredSubTreeVector_t::iterator treeIter = pParentCast->m_StoredSubTrees.begin(); treeIter != pParentCast->m_StoredSubTrees.end(); ++treeIter ) + { + treeIter->pFunctionTable->pfn_SyncMutexes( treeIter->pGatherer, false ); + } + + pParentCast->m_IndexMapMutex.Unlock(); + pParentCast->m_SubTreeMutex.Unlock(); + } +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void *CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntry( void *pParent, uint32 iEntryIndex ) +{ + ThisCast *pParentCast = (ThisCast *)pParent; +#if defined( ENABLE_STACK_STATS_GATHERING ) + return &pParentCast->m_StatEntries[iEntryIndex].m_Stats; +#else + return &pParentCast->m_SingleEntry; +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::ApplyTreeAccessLock( void *pParent, bool bLock ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + ThisCast *pParentCast = (ThisCast *)pParent; + if( bLock ) + { + pParentCast->m_StatEntryLock.LockForRead(); + } + else + { + pParentCast->m_StatEntryLock.UnlockRead(); + } +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::LockEntry( void *pParent, uint32 iEntryIndex, bool bLock ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + ThisCast *pParentCast = (ThisCast *)pParent; + pParentCast->STATMUTEXHANDLER::LockEntry( iEntryIndex, bLock ); +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::Reset( void ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + m_StatEntryLock.LockForWrite(); + m_IndexMapMutex.Lock(); + m_SubTreeMutex.Lock(); + + m_StatEntries.clear(); + m_IndexMap.clear(); + m_StoredSubTrees.clear(); + + m_SubTreeMutex.Unlock(); + m_IndexMapMutex.Unlock(); + m_StatEntryLock.UnlockWrite(); +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::operator CCallStackStatsGatherer_Standardized_t( void ) +{ + return CCallStackStatsGatherer_Standardized_t( this, GetFunctionTable() ); +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +CCallStackStatsGatherer_Standardized_t CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::Standardized( void ) +{ + return CCallStackStatsGatherer_Standardized_t( this, GetFunctionTable() ); +} + + + + + + + + + + + + + + + + + + +class PLATFORM_CLASS CallStackStatStructDescFuncs +{ +public: + //description file format + //1 byte version per entry. Assuming that the field will get more descriptive over time, reserving this now. + virtual size_t DescribeField( uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength ) = 0; + + enum MergeScript_Language + { + SSMSL_Squirrel, //Only support squirrel for now, theoretically expandable to any vscript supported language + }; + +#if 0 //embedded script handling not ready yet + //this is expected to write a piece of script code into the body of a function that will merge two values of this type + //The function will have two parameters, "mergeTo", and "mergeFrom". Both are tables with your field defined by name + //So, an example to merge an integer count defined as "foo" in the stack struct would look like this "mergeTo.foo += mergeFrom.foo\n" + virtual size_t DescribeMergeOperation( MergeScript_Language scriptLanguage, uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength ) = 0; +#endif + + //reserve your description field versions here to avoid stomping others + enum DescribeFieldVersions_t + { + DFV_BasicStatStructFieldTypes_t, //Format: 1 byte BasicStatStructFieldTypes_t type, 4 byte field offset, null terminated string field name + }; + + const char *m_szFieldName; + size_t m_iFieldOffset; + CallStackStatStructDescFuncs *m_pNext; //needed for how the description macros are laid out. Couldn't figure out a way to store the static struct instances as a static array +}; + +enum StatStructDescription_LumpID +{ + SSDLID_UNKNOWN, + SSDLID_STATICINTERPRETER, + SSDLID_FIELDDESC, + SSDLID_EMBEDDEDSCRIPT, + + + SSDLID_COUNT, + SSDLID_FORCE_UINT32 = 0xFFFFFFFF, +}; + +enum BasicStatStructFieldTypes_t +{ + BSSFT_UNKNOWN, + BSSFT_BOOL, + BSSFT_INT8, + BSSFT_UINT8, + BSSFT_INT16, + BSSFT_UINT16, + BSSFT_INT32, + BSSFT_UINT32, + BSSFT_INT64, + BSSFT_UINT64, + BSSFT_FLOAT, + BSSFT_DOUBLE, + BSSFT_VECTOR2D, + BSSFT_VECTOR3D, + BSSFT_VECTOR4D, + + BSSFT_COUNT, +}; + +#define BSSFT_INT (sizeof( int ) == sizeof( int32 ) ? BSSFT_INT32 : BSSFT_INT64) +#define BSSFT_UINT (sizeof( unsigned int ) == sizeof( uint32 ) ? BSSFT_UINT32 : BSSFT_UINT64) +#define BSSFT_SIZE_T (sizeof( size_t ) == sizeof( uint32 ) ? BSSFT_UINT32 : BSSFT_UINT64) + +enum BasicStatStructFieldCombineMethods_t +{ + BSSFCM_UNKNOWN, + BSSFCM_CUSTOM, //rely on some outside handler + BSSFCM_ADD, //add the values + //BSSFCM_SUBTRACT, //what would subtract even mean? which one from which? + BSSFCM_MAX, //keep max value + BSSFCM_MIN, //keep min value + BSSFCM_AND, // &= , Non-integer behavior undefined + BSSFCM_OR, // |= , Non-integer behavior undefined + BSSFCM_XOR, // ^= , Non-integer behavior undefined + /*BSSFCM_LIST, //keep a list of each value (probably complicated)*/ + + BSSFCM_COUNT, +}; + +class PLATFORM_CLASS BasicStatStructFieldDesc : public CallStackStatStructDescFuncs +{ +public: + BasicStatStructFieldDesc( BasicStatStructFieldTypes_t type, BasicStatStructFieldCombineMethods_t combineMethod ) : m_Type(type), m_Combine(combineMethod) {}; + size_t DescribeField( uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength ); +#if 0 //embedded script handling not ready yet + size_t DescribeMergeOperation( MergeScript_Language scriptLanguage, uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength ); +#endif + + BasicStatStructFieldTypes_t m_Type; + BasicStatStructFieldCombineMethods_t m_Combine; +}; + + + + + + + +//struct is locked in place while you're holding onto one of these. Get a base, then create one of these from it +template <class STATSTRUCT> +class CCallStackStatsGatherer_StructAccessor_AutoLock : CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> +{ +public: + CCallStackStatsGatherer_StructAccessor_AutoLock( CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> ©From ) + : CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( copyFrom ) + { + this->m_Gatherer.pFunctionTable->pfn_ApplyTreeAccessLock( this->m_Gatherer.pGatherer, true ); + this->m_Gatherer.pFunctionTable->pfn_LockEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex, true ); + this->m_pStruct = (STATSTRUCT *)this->m_Gatherer.pFunctionTable->pfn_GetEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex ); + } + + ~CCallStackStatsGatherer_StructAccessor_AutoLock( void ) + { + this->m_Gatherer.pFunctionTable->pfn_LockEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex, false ); + this->m_Gatherer.pFunctionTable->pfn_ApplyTreeAccessLock( this->m_Gatherer.pGatherer, false ); + } + + STATSTRUCT *operator->() + { + return this->m_pStruct; + } + + STATSTRUCT *GetStruct( void ) //do not hold this pointer outside the lock period + { + return this->m_pStruct; + } + +protected: + STATSTRUCT *m_pStruct; +}; + + +//struct is locked in place only between Lock() and paired Unlock() calls. Get a base, then create one of these from it. +//It's safe to hold onto this for an extended period of time. The entry index is unchanging in the gatherer tree. +template <class STATSTRUCT> +class CCallStackStatsGatherer_StructAccessor_Manual : CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> +{ +public: + CCallStackStatsGatherer_StructAccessor_Manual( CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> ©From ) + : CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( copyFrom ), m_pStruct( NULL ) + { } + + STATSTRUCT *operator->() + { + return this->m_pStruct; //NULL while entry is not locked. + } + + STATSTRUCT *GetStruct( void ) //do not hold this pointer outside the lock period + { + return this->m_pStruct; //NULL while entry is not locked. + } + + void Lock( void ) + { + this->m_Gatherer.pFunctionTable->pfn_ApplyTreeAccessLock( this->m_Gatherer.pGatherer, true ); + this->m_Gatherer.pFunctionTable->pfn_LockEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex, true ); + this->m_pStruct = (STATSTRUCT *)this->m_Gatherer.pFunctionTable->pfn_GetEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex ); + } + + void Unlock( void ) + { + this->m_pStruct = NULL; + this->m_Gatherer.pFunctionTable->pfn_LockEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex, false ); + this->m_Gatherer.pFunctionTable->pfn_ApplyTreeAccessLock( this->m_Gatherer.pGatherer, false ); + } + +protected: + STATSTRUCT *m_pStruct; +}; + + + + + +class CCallStackStats_PushSubTree_AutoPop +{ +public: + CCallStackStats_PushSubTree_AutoPop( const CCallStackStatsGatherer_Standardized_t &Parent, const CCallStackStatsGatherer_Standardized_t &Child, const CCallStackStorage &PushStack = CCallStackStorage() ) + : m_PopFrom( Parent ) + { + Parent.pFunctionTable->pfn_PushSubTree( Parent.pGatherer, Child, PushStack ); + } + ~CCallStackStats_PushSubTree_AutoPop( void ) + { + m_PopFrom.PopSubTree(); + } + + CCallStackStatsGatherer_Standardized_t m_PopFrom; +}; + + +#endif //#ifndef TIER0_STACKTOOLS_H diff --git a/external/vpc/public/tier0/stacktools.h b/external/vpc/public/tier0/stacktools.h new file mode 100644 index 0000000..c356b8c --- /dev/null +++ b/external/vpc/public/tier0/stacktools.h @@ -0,0 +1,153 @@ +//========= Copyright � 1996-2008, Valve Corporation, All rights reserved. ============// +// +// Purpose: Tools for grabbing/dumping the stack at runtime +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TIER0_STACKTOOLS_H +#define TIER0_STACKTOOLS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + +#if (defined( PLATFORM_WINDOWS ) || defined( PLATFORM_X360 )) && !defined( STEAM ) && !defined( _CERT ) && defined( TCHAR_IS_CHAR ) //designed for windows/x360, not built/tested with wide characters, not intended for release builds (but probably wouldn't damage anything) +# define ENABLE_RUNTIME_STACK_TRANSLATION //uncomment to enable runtime stack translation tools. All of which use on-demand loading of necessary dll's and pdb's +#endif + +#if defined( ENABLE_RUNTIME_STACK_TRANSLATION ) +//#define ENABLE_THREAD_PARENT_STACK_TRACING 1 //uncomment to actually enable tracking stack traces from threads and jobs to their parent thread. Must also define THREAD_PARENT_STACK_TRACE_SUPPORTED in threadtools.h +# if defined( ENABLE_THREAD_PARENT_STACK_TRACING ) +# define THREAD_PARENT_STACK_TRACE_LENGTH 32 +# endif +#endif + + + + +PLATFORM_INTERFACE int GetCallStack( void **pReturnAddressesOut, int iArrayCount, int iSkipCount ); + +//ONLY WORKS IF THE CRAWLED PORTION OF THE STACK DISABLES FRAME POINTER OMISSION (/Oy-) "vpc /nofpo" +PLATFORM_INTERFACE int GetCallStack_Fast( void **pReturnAddressesOut, int iArrayCount, int iSkipCount ); + +typedef int (*FN_GetCallStack)( void **pReturnAddressesOut, int iArrayCount, int iSkipCount ); + +//where we'll find our PDB's for win32. +PLATFORM_INTERFACE void SetStackTranslationSymbolSearchPath( const char *szSemicolonSeparatedList = NULL ); +PLATFORM_INTERFACE void StackToolsNotify_LoadedLibrary( const char *szLibName ); + +//maximum output sample "tier0.dll!TranslateStackInfo - u:\Dev\L4D\src\tier0\stacktools.cpp(162) + 4 bytes" +enum TranslateStackInfo_StyleFlags_t +{ + TSISTYLEFLAG_NONE = 0, + TSISTYLEFLAG_MODULENAME = (1<<0), //start with module Sample: "tier0.dll!" + TSISTYLEFLAG_SYMBOLNAME = (1<<1), //include the symbol name Sample: "TranslateStackInfo" + TSISTYLEFLAG_FULLPATH = (1<<2), //include full path Sample: "u:\Dev\L4D\src\tier0\stacktools.cpp" + TSISTYLEFLAG_SHORTPATH = (1<<3), //only include 2 directories Sample: "\src\tier0\stacktools.cpp" + TSISTYLEFLAG_LINE = (1<<4), //file line number Sample: "(162)" + TSISTYLEFLAG_LINEANDOFFSET = (1<<5), //file line + offset Sample: "(162) + 4 bytes" + TSISTYLEFLAG_LAST = TSISTYLEFLAG_LINEANDOFFSET, + TSISTYLEFLAG_DEFAULT = (TSISTYLEFLAG_MODULENAME | TSISTYLEFLAG_SYMBOLNAME | TSISTYLEFLAG_FULLPATH | TSISTYLEFLAG_LINEANDOFFSET), //produces sample above +}; + +//Generates a formatted list of function information, returns number of translated entries +//On 360 this generates a string that can be decoded by VXConsole in print functions. Optimal path for translation because it's one way. Other paths require multiple transactions. +PLATFORM_INTERFACE int TranslateStackInfo( const void * const *pCallStack, int iCallStackCount, tchar *szOutput, int iOutBufferSize, const tchar *szEntrySeparator, TranslateStackInfo_StyleFlags_t style = TSISTYLEFLAG_DEFAULT ); + +PLATFORM_INTERFACE void PreloadStackInformation( void * const *pAddresses, int iAddressCount ); //caches data and reduces communication with VXConsole to speed up 360 decoding when using any of the Get***FromAddress() functions. Nop on PC. +PLATFORM_INTERFACE bool GetFileAndLineFromAddress( const void *pAddress, tchar *pFileNameOut, int iMaxFileNameLength, uint32 &iLineNumberOut, uint32 *pDisplacementOut = NULL ); +PLATFORM_INTERFACE bool GetSymbolNameFromAddress( const void *pAddress, tchar *pSymbolNameOut, int iMaxSymbolNameLength, uint64 *pDisplacementOut = NULL ); +PLATFORM_INTERFACE bool GetModuleNameFromAddress( const void *pAddress, tchar *pModuleNameOut, int iMaxModuleNameLength ); + + + +class PLATFORM_CLASS CCallStackStorage //a helper class to grab a stack trace as close to the leaf code surface as possible, then pass it on to deeper functions intact with less unpredictable inlining pollution +{ +public: + CCallStackStorage( FN_GetCallStack GetStackFunction = GetCallStack, uint32 iSkipCalls = 0 ); + CCallStackStorage( const CCallStackStorage ©From ) + { + iValidEntries = copyFrom.iValidEntries; + memcpy( pStack, copyFrom.pStack, sizeof( void * ) * copyFrom.iValidEntries ); + } + + void *pStack[128]; //probably too big, possibly too small for some applications. Don't want to spend the time figuring out how to generalize this without templatizing pollution or mallocs + uint32 iValidEntries; +}; + + +//Hold onto one of these to denote the top of a functional stack trace. Also allows us to string together threads to their parents +class PLATFORM_CLASS CStackTop_Base +{ +protected: +#if defined( ENABLE_RUNTIME_STACK_TRANSLATION ) + CStackTop_Base *m_pPrevTop; + void *m_pStackBase; + void *m_pReplaceAddress; + + void * const *m_pParentStackTrace; + int m_iParentStackTraceLength; +#endif +}; + +//makes a copy of the parent stack +class PLATFORM_CLASS CStackTop_CopyParentStack : public CStackTop_Base +{ +public: + CStackTop_CopyParentStack( void * const * pParentStackTrace, int iParentStackTraceLength ); + ~CStackTop_CopyParentStack( void ); +}; + +//just references the parent stack. Assuming that you'll keep that memory around as long as you're keeping this Stack Top marker. +class PLATFORM_CLASS CStackTop_ReferenceParentStack : public CStackTop_Base +{ +public: + CStackTop_ReferenceParentStack( void * const * pParentStackTrace = NULL, int iParentStackTraceLength = 0 ); + ~CStackTop_ReferenceParentStack( void ); + void ReleaseParentStackReferences( void ); //in case you need to delete the parent stack trace before this class goes out of scope +}; + + +//Encodes data so that every byte's most significant bit is a 1. Ensuring no null terminators. +//This puts the encoded data in the 128-255 value range. Leaving all standard ascii characters for control. +//Returns string length (not including the written null terminator as is standard). +//Or if the buffer is too small. Returns negative of necessary buffer size (including room needed for null terminator) +PLATFORM_INTERFACE int EncodeBinaryToString( const void *pToEncode, int iDataLength, char *pEncodeOut, int iEncodeBufferSize ); + +//Decodes a string produced by EncodeBinaryToString(). Safe to decode in place if you don't mind trashing your string, binary byte count always less than string byte count. +//Returns: +// >= 0 is the decoded data size +// INT_MIN (most negative value possible) indicates an improperly formatted string (not our data) +// all other negative values are the negative of how much dest buffer size is necessary. +PLATFORM_INTERFACE int DecodeBinaryFromString( const char *pString, void *pDestBuffer, int iDestBufferSize, char **ppParseFinishOut = NULL ); + + + + +// 360<->VXConsole specific communication definitions +#define XBX_CALLSTACKDECODEPREFIX ":CSDECODE[" + +enum StackTranslation_BinaryHandler_Command_t +{ + ST_BHC_LOADEDLIBARY, + ST_BHC_GETTRANSLATIONINFO, +}; + +#pragma pack(push) +#pragma pack(1) +struct FullStackInfo_t +{ + const void *pAddress; + char szModuleName[24]; + char szFileName[MAX_PATH/2]; + char szSymbol[64]; + uint32 iLine; + uint32 iSymbolOffset; + +}; +#pragma pack(pop) + +#endif //#ifndef TIER0_STACKTOOLS_H diff --git a/external/vpc/public/tier0/threadtools.h b/external/vpc/public/tier0/threadtools.h new file mode 100644 index 0000000..458675a --- /dev/null +++ b/external/vpc/public/tier0/threadtools.h @@ -0,0 +1,2402 @@ +//========== Copyright 2005, Valve Corporation, All rights reserved. ======== +// +// Purpose: A collection of utility classes to simplify thread handling, and +// as much as possible contain portability problems. Here avoiding +// including windows.h. +// +//============================================================================= + +#ifndef THREADTOOLS_H +#define THREADTOOLS_H + +#include <limits.h> + +#include "tier0/platform.h" +#include "tier0/dbg.h" + +#if defined( POSIX ) && !defined( _PS3 ) && !defined( _X360 ) +#include <pthread.h> +#include <errno.h> +#define WAIT_OBJECT_0 0 +#define WAIT_TIMEOUT 0x00000102 +#define WAIT_FAILED -1 +#define THREAD_PRIORITY_HIGHEST 2 +#endif + +#if defined( _PS3 ) +#include <sys/ppu_thread.h> +#include <sys/synchronization.h> +#include <cell/atomic.h> +#include <sys/timer.h> +#endif + +#ifdef OSX +// Add some missing defines +#define PTHREAD_MUTEX_TIMED_NP PTHREAD_MUTEX_NORMAL +#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE +#define PTHREAD_MUTEX_ERRORCHECK_NP PTHREAD_MUTEX_ERRORCHECK +#define PTHREAD_MUTEX_ADAPTIVE_NP 3 +#endif + +#ifdef _PS3 +#define PS3_SYS_PPU_THREAD_COMMON_STACK_SIZE ( 256 * 1024 ) +#endif + + +#if defined( _WIN32 ) +#pragma once +#pragma warning(push) +#pragma warning(disable:4251) +#endif + +#ifdef COMPILER_MSVC64 +#include <intrin.h> +#endif + +// #define THREAD_PROFILER 1 + +#define THREAD_MUTEX_TRACING_SUPPORTED +#if defined(_WIN32) && defined(_DEBUG) +#define THREAD_MUTEX_TRACING_ENABLED +#endif + +#ifdef _WIN32 +typedef void *HANDLE; +#endif + +// maximum number of threads that can wait on one object +#define CTHREADEVENT_MAX_WAITING_THREADS 4 + +#if (defined( PLATFORM_WINDOWS_PC ) || defined( PLATFORM_X360 )) && !defined( STEAM ) && !defined( _CERT ) +//Thread parent stack trace linkage requires ALL executing binaries to disable frame pointer omission to operate speedily/successfully. (/Oy-) "vpc /nofpo" +#define THREAD_PARENT_STACK_TRACE_SUPPORTED 1 //uncomment to support joining the root of a thread's stack trace to its parent's at time of invocation. Must also set ENABLE_THREAD_PARENT_STACK_TRACING in stacktools.h +#endif + +#if defined( THREAD_PARENT_STACK_TRACE_SUPPORTED ) +#include "tier0/stacktools.h" +# if defined( ENABLE_THREAD_PARENT_STACK_TRACING ) //stacktools.h opted in +# define THREAD_PARENT_STACK_TRACE_ENABLED 1 //both threadtools.h and stacktools.h have opted into the feature, enable it +# endif +#endif + +extern bool gbCheckNotMultithreaded; + +#ifdef _PS3 + +#define USE_INTRINSIC_INTERLOCKED + +#define CHECK_NOT_MULTITHREADED() \ +{ \ + static int init = 0; \ + static sys_ppu_thread_t threadIDPrev; \ + \ + if (!init) \ + { \ + sys_ppu_thread_get_id(&threadIDPrev); \ + init = 1; \ + } \ + else if (gbCheckNotMultithreaded) \ + { \ + sys_ppu_thread_t threadID; \ + sys_ppu_thread_get_id(&threadID); \ + if (threadID != threadIDPrev) \ + { \ + printf("CHECK_NOT_MULTITHREADED: prev thread = %x, cur thread = %x\n", \ + (uint)threadIDPrev, (uint)threadID); \ + *(int*)0 = 0; \ + } \ + } \ +} + +#else + #define CHECK_NOT_MULTITHREADED() +#endif + +#if defined( _X360 ) || defined( _PS3 ) +#define MAX_THREADS_SUPPORTED 16 +#else +#define MAX_THREADS_SUPPORTED 32 +#endif + + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +const unsigned TT_INFINITE = 0xffffffff; + +#ifdef PLATFORM_64BITS +typedef uint64 ThreadId_t; +#else +typedef uint32 ThreadId_t; +#endif + +//----------------------------------------------------------------------------- +// +// Simple thread creation. Differs from VCR mode/CreateThread/_beginthreadex +// in that it accepts a standard C function rather than compiler specific one. +// +//----------------------------------------------------------------------------- +#ifdef COMPILER_SNC +typedef uint64 ThreadHandle_t; +#else // COMPILER_SNC +FORWARD_DECLARE_HANDLE( ThreadHandle_t ); +#endif // !COMPILER_SNC +typedef uintp (*ThreadFunc_t)( void *pParam ); + +#if defined( _PS3 ) +PLATFORM_OVERLOAD ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, ThreadId_t *pID, unsigned stackSize = 0x10000 /*64*/ ); +PLATFORM_INTERFACE ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, unsigned stackSize = 0x10000 /*64*/ ); +#else //_PS3 +PLATFORM_OVERLOAD ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, ThreadId_t *pID, unsigned stackSize = 0 ); +PLATFORM_INTERFACE ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, unsigned stackSize = 0 ); +#endif //_PS3 +PLATFORM_INTERFACE bool ReleaseThreadHandle( ThreadHandle_t ); + + +//----------------------------------------------------------------------------- + +PLATFORM_INTERFACE void ThreadSleep(unsigned duration = 0); +PLATFORM_INTERFACE ThreadId_t ThreadGetCurrentId(); +PLATFORM_INTERFACE ThreadHandle_t ThreadGetCurrentHandle(); +PLATFORM_INTERFACE int ThreadGetPriority( ThreadHandle_t hThread = NULL ); +PLATFORM_INTERFACE bool ThreadSetPriority( ThreadHandle_t hThread, int priority ); +inline bool ThreadSetPriority( int priority ) { return ThreadSetPriority( NULL, priority ); } +#ifndef _X360 +PLATFORM_INTERFACE bool ThreadInMainThread(); +PLATFORM_INTERFACE void DeclareCurrentThreadIsMainThread(); +#else +PLATFORM_INTERFACE byte *g_pBaseMainStack; +PLATFORM_INTERFACE byte *g_pLimitMainStack; +inline bool ThreadInMainThread() +{ + byte b; + byte *p = &b; + return ( p < g_pBaseMainStack && p >= g_pLimitMainStack ); +} +#endif + +// NOTE: ThreadedLoadLibraryFunc_t needs to return the sleep time in milliseconds or TT_INFINITE +typedef int (*ThreadedLoadLibraryFunc_t)(); +PLATFORM_INTERFACE void SetThreadedLoadLibraryFunc( ThreadedLoadLibraryFunc_t func ); +PLATFORM_INTERFACE ThreadedLoadLibraryFunc_t GetThreadedLoadLibraryFunc(); + +#if defined( PLATFORM_WINDOWS_PC32 ) +DLL_IMPORT unsigned long STDCALL GetCurrentThreadId(); +#define ThreadGetCurrentId GetCurrentThreadId +#endif + +inline void ThreadPause() +{ +#if defined( COMPILER_PS3 ) + __db16cyc(); +#elif defined( COMPILER_GCC ) + __asm __volatile( "pause" ); +#elif defined ( COMPILER_MSVC64 ) + _mm_pause(); +#elif defined( COMPILER_MSVC32 ) + __asm pause; +#elif defined( COMPILER_MSVCX360 ) + YieldProcessor(); + __asm { or r0,r0,r0 } + YieldProcessor(); + __asm { or r1,r1,r1 } +#else +#error "implement me" +#endif +} + +PLATFORM_INTERFACE bool ThreadJoin( ThreadHandle_t, unsigned timeout = TT_INFINITE ); + +PLATFORM_INTERFACE void ThreadSetDebugName( ThreadHandle_t hThread, const char *pszName ); +inline void ThreadSetDebugName( const char *pszName ) { ThreadSetDebugName( NULL, pszName ); } + +PLATFORM_INTERFACE void ThreadSetAffinity( ThreadHandle_t hThread, int nAffinityMask ); + + +//----------------------------------------------------------------------------- +// +// Interlock methods. These perform very fast atomic thread +// safe operations. These are especially relevant in a multi-core setting. +// +//----------------------------------------------------------------------------- + +#ifdef _WIN32 +#define NOINLINE +#elif defined( _PS3 ) +#define NOINLINE __attribute__ ((noinline)) +#elif defined(POSIX) +#define NOINLINE __attribute__ ((noinline)) +#endif + +#if defined( _X360 ) || defined( _PS3 ) +#define ThreadMemoryBarrier() __lwsync() +#else +#define ThreadMemoryBarrier() ((void)0) +#endif + +#if defined( _LINUX ) || defined( _OSX ) +#define USE_INTRINSIC_INTERLOCKED +// linux implementation +inline int32 ThreadInterlockedIncrement( int32 volatile *p ) +{ + Assert( (size_t)p % 4 == 0 ); + return __sync_fetch_and_add( p, 1 ) + 1; +} + +inline int32 ThreadInterlockedDecrement( int32 volatile *p ) +{ + Assert( (size_t)p % 4 == 0 ); + return __sync_fetch_and_add( p, -1 ) - 1; +} + +inline int32 ThreadInterlockedExchange( int32 volatile *p, int32 value ) +{ + Assert( (size_t)p % 4 == 0 ); + int32 nRet; + + // Note: The LOCK instruction prefix is assumed on the XCHG instruction and GCC gets very confused on the Mac when we use it. + __asm __volatile( + "xchgl %2,(%1)" + : "=r" (nRet) + : "r" (p), "0" (value) + : "memory"); + return nRet; +} + +inline int32 ThreadInterlockedExchangeAdd( int32 volatile *p, int32 value ) +{ + Assert( (size_t)p % 4 == 0 ); + return __sync_fetch_and_add( p, value ); +} +inline int32 ThreadInterlockedCompareExchange( int32 volatile *p, int32 value, int32 comperand ) +{ + Assert( (size_t)p % 4 == 0 ); + return __sync_val_compare_and_swap( p, comperand, value ); +} + + +inline bool ThreadInterlockedAssignIf( int32 volatile *p, int32 value, int32 comperand ) +{ + Assert( (size_t)p % 4 == 0 ); + return __sync_bool_compare_and_swap( p, comperand, value ); +} + +#elif ( defined( COMPILER_MSVC32 ) && ( _MSC_VER >= 1310 ) ) +// windows 32 implemnetation using compiler intrinsics +#define USE_INTRINSIC_INTERLOCKED + +extern "C" +{ + long __cdecl _InterlockedIncrement(volatile long*); + long __cdecl _InterlockedDecrement(volatile long*); + long __cdecl _InterlockedExchange(volatile long*, long); + long __cdecl _InterlockedExchangeAdd(volatile long*, long); + long __cdecl _InterlockedCompareExchange(volatile long*, long, long); +} + +#pragma intrinsic( _InterlockedCompareExchange ) +#pragma intrinsic( _InterlockedDecrement ) +#pragma intrinsic( _InterlockedExchange ) +#pragma intrinsic( _InterlockedExchangeAdd ) +#pragma intrinsic( _InterlockedIncrement ) + +inline int32 ThreadInterlockedIncrement( int32 volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedIncrement( (volatile long*)p ); } +inline int32 ThreadInterlockedDecrement( int32 volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedDecrement( (volatile long*)p ); } +inline int32 ThreadInterlockedExchange( int32 volatile *p, int32 value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchange( (volatile long*)p, value ); } +inline int32 ThreadInterlockedExchangeAdd( int32 volatile *p, int32 value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchangeAdd( (volatile long*)p, value ); } +inline int32 ThreadInterlockedCompareExchange( int32 volatile *p, int32 value, int32 comperand ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedCompareExchange( (volatile long*)p, value, comperand ); } +inline bool ThreadInterlockedAssignIf( int32 volatile *p, int32 value, int32 comperand ) { Assert( (size_t)p % 4 == 0 ); return ( _InterlockedCompareExchange( (volatile long*)p, value, comperand ) == comperand ); } +#elif defined( _PS3 ) +PLATFORM_INTERFACE inline int32 ThreadInterlockedIncrement( int32 volatile * ea ) { return cellAtomicIncr32( (uint32_t*)ea ) + 1; } +PLATFORM_INTERFACE inline int32 ThreadInterlockedDecrement( int32 volatile * ea ) { return cellAtomicDecr32( (uint32_t*)ea ) - 1; } +PLATFORM_INTERFACE inline int32 ThreadInterlockedExchange( int32 volatile * ea, int32 value ) { return cellAtomicStore32( ( uint32_t* )ea, value); } +PLATFORM_INTERFACE inline int32 ThreadInterlockedExchangeAdd( int32 volatile * ea, int32 value ) { return cellAtomicAdd32( ( uint32_t* )ea, value ); } +PLATFORM_INTERFACE inline int32 ThreadInterlockedCompareExchange( int32 volatile * ea, int32 value, int32 comperand ) { return cellAtomicCompareAndSwap32( (uint32_t*)ea, comperand, value ) ; } +PLATFORM_INTERFACE inline bool ThreadInterlockedAssignIf( int32 volatile * ea, int32 value, int32 comperand ) { return ( cellAtomicCompareAndSwap32( (uint32_t*)ea, comperand, value ) == ( uint32_t ) comperand ); } + +PLATFORM_INTERFACE inline int64 ThreadInterlockedCompareExchange64( int64 volatile *pDest, int64 value, int64 comperand ) { return cellAtomicCompareAndSwap64( ( uint64_t* ) pDest, comperand, value ); } +PLATFORM_INTERFACE inline bool ThreadInterlockedAssignIf64( volatile int64 *pDest, int64 value, int64 comperand ) { return ( cellAtomicCompareAndSwap64( ( uint64_t* ) pDest, comperand, value ) == ( uint64_t ) comperand ); } + +#elif defined( _X360 ) +#define TO_INTERLOCK_PARAM(p) ((volatile long *)p) +#define TO_INTERLOCK_PTR_PARAM(p) ((void **)p) +FORCEINLINE int32 ThreadInterlockedIncrement( int32 volatile *pDest ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedIncrement( TO_INTERLOCK_PARAM(pDest) ); } +FORCEINLINE int32 ThreadInterlockedDecrement( int32 volatile *pDest ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedDecrement( TO_INTERLOCK_PARAM(pDest) ); } +FORCEINLINE int32 ThreadInterlockedExchange( int32 volatile *pDest, int32 value ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedExchange( TO_INTERLOCK_PARAM(pDest), value ); } +FORCEINLINE int32 ThreadInterlockedExchangeAdd( int32 volatile *pDest, int32 value ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedExchangeAdd( TO_INTERLOCK_PARAM(pDest), value ); } +FORCEINLINE int32 ThreadInterlockedCompareExchange( int32 volatile *pDest, int32 value, int32 comperand ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedCompareExchange( TO_INTERLOCK_PARAM(pDest), value, comperand ); } +FORCEINLINE bool ThreadInterlockedAssignIf( int32 volatile *pDest, int32 value, int32 comperand ) { Assert( (size_t)pDest % 4 == 0 ); return ( InterlockedCompareExchange( TO_INTERLOCK_PARAM(pDest), value, comperand ) == comperand ); } +#else +// non 32-bit windows and 360 implementation +PLATFORM_INTERFACE int32 ThreadInterlockedIncrement( int32 volatile * ) NOINLINE; +PLATFORM_INTERFACE int32 ThreadInterlockedDecrement( int32 volatile * ) NOINLINE; +PLATFORM_INTERFACE int32 ThreadInterlockedExchange( int32 volatile *, int32 value ) NOINLINE; +PLATFORM_INTERFACE int32 ThreadInterlockedExchangeAdd( int32 volatile *, int32 value ) NOINLINE; +PLATFORM_INTERFACE int32 ThreadInterlockedCompareExchange( int32 volatile *, int32 value, int32 comperand ) NOINLINE; +PLATFORM_INTERFACE bool ThreadInterlockedAssignIf( int32 volatile *, int32 value, int32 comperand ) NOINLINE; +#endif + + +#if defined( USE_INTRINSIC_INTERLOCKED ) && !defined( PLATFORM_64BITS ) +#define TIPTR() +inline void *ThreadInterlockedExchangePointer( void * volatile *p, void *value ) { return (void *)( ( intp )ThreadInterlockedExchange( reinterpret_cast<intp volatile *>(p), reinterpret_cast<intp>(value) ) ); } +inline void *ThreadInterlockedCompareExchangePointer( void * volatile *p, void *value, void *comperand ) { return (void *)( ( intp )ThreadInterlockedCompareExchange( reinterpret_cast<intp volatile *>(p), reinterpret_cast<intp>(value), reinterpret_cast<intp>(comperand) ) ); } +inline bool ThreadInterlockedAssignPointerIf( void * volatile *p, void *value, void *comperand ) { return ( ThreadInterlockedCompareExchange( reinterpret_cast<intp volatile *>(p), reinterpret_cast<intp>(value), reinterpret_cast<intp>(comperand) ) == reinterpret_cast<intp>(comperand) ); } +#else +PLATFORM_INTERFACE void *ThreadInterlockedExchangePointer( void * volatile *, void *value ) NOINLINE; +PLATFORM_INTERFACE void *ThreadInterlockedCompareExchangePointer( void * volatile *, void *value, void *comperand ) NOINLINE; +PLATFORM_INTERFACE bool ThreadInterlockedAssignPointerIf( void * volatile *, void *value, void *comperand ) NOINLINE; +#endif + + +inline unsigned ThreadInterlockedExchangeSubtract( int32 volatile *p, int32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, -value ); } + +inline void const *ThreadInterlockedExchangePointerToConst( void const * volatile *p, void const *value ) { return ThreadInterlockedExchangePointer( const_cast < void * volatile * > ( p ), const_cast < void * > ( value ) ); } +inline void const *ThreadInterlockedCompareExchangePointerToConst( void const * volatile *p, void const *value, void const *comperand ) { return ThreadInterlockedCompareExchangePointer( const_cast < void * volatile * > ( p ), const_cast < void * > ( value ), const_cast < void * > ( comperand ) ); } +inline bool ThreadInterlockedAssignPointerToConstIf( void const * volatile *p, void const *value, void const *comperand ) { return ThreadInterlockedAssignPointerIf( const_cast < void * volatile * > ( p ), const_cast < void * > ( value ), const_cast < void * > ( comperand ) ); } + + +#ifndef _PS3 +PLATFORM_INTERFACE int64 ThreadInterlockedCompareExchange64( int64 volatile *, int64 value, int64 comperand ) NOINLINE; +PLATFORM_INTERFACE bool ThreadInterlockedAssignIf64( volatile int64 *pDest, int64 value, int64 comperand ) NOINLINE; +#endif + +PLATFORM_INTERFACE int64 ThreadInterlockedExchange64( int64 volatile *, int64 value ) NOINLINE; +PLATFORM_INTERFACE int64 ThreadInterlockedIncrement64( int64 volatile * ) NOINLINE; +PLATFORM_INTERFACE int64 ThreadInterlockedDecrement64( int64 volatile * ) NOINLINE; +PLATFORM_INTERFACE int64 ThreadInterlockedExchangeAdd64( int64 volatile *, int64 value ) NOINLINE; + +inline unsigned ThreadInterlockedExchangeSubtract( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); } + +inline unsigned ThreadInterlockedIncrement( uint32 volatile *p ) { return ThreadInterlockedIncrement( (int32 volatile *)p ); } +inline unsigned ThreadInterlockedDecrement( uint32 volatile *p ) { return ThreadInterlockedDecrement( (int32 volatile *)p ); } +inline unsigned ThreadInterlockedExchange( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchange( (int32 volatile *)p, value ); } +inline unsigned ThreadInterlockedExchangeAdd( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); } +inline unsigned ThreadInterlockedCompareExchange( uint32 volatile *p, uint32 value, uint32 comperand ) { return ThreadInterlockedCompareExchange( (int32 volatile *)p, value, comperand ); } +inline bool ThreadInterlockedAssignIf( uint32 volatile *p, uint32 value, uint32 comperand ) { return ThreadInterlockedAssignIf( (int32 volatile *)p, value, comperand ); } + +//inline int ThreadInterlockedExchangeSubtract( int volatile *p, int value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); } +//inline int ThreadInterlockedIncrement( int volatile *p ) { return ThreadInterlockedIncrement( (int32 volatile *)p ); } +//inline int ThreadInterlockedDecrement( int volatile *p ) { return ThreadInterlockedDecrement( (int32 volatile *)p ); } +//inline int ThreadInterlockedExchange( int volatile *p, int value ) { return ThreadInterlockedExchange( (int32 volatile *)p, value ); } +//inline int ThreadInterlockedExchangeAdd( int volatile *p, int value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); } +//inline int ThreadInterlockedCompareExchange( int volatile *p, int value, int comperand ) { return ThreadInterlockedCompareExchange( (int32 volatile *)p, value, comperand ); } +//inline bool ThreadInterlockedAssignIf( int volatile *p, int value, int comperand ) { return ThreadInterlockedAssignIf( (int32 volatile *)p, value, comperand ); } + + +//----------------------------------------------------------------------------- +// Access to VTune thread profiling +//----------------------------------------------------------------------------- +#if defined(_WIN32) && defined(THREAD_PROFILER) +PLATFORM_INTERFACE void ThreadNotifySyncPrepare(void *p); +PLATFORM_INTERFACE void ThreadNotifySyncCancel(void *p); +PLATFORM_INTERFACE void ThreadNotifySyncAcquired(void *p); +PLATFORM_INTERFACE void ThreadNotifySyncReleasing(void *p); +#else +#define ThreadNotifySyncPrepare(p) ((void)0) +#define ThreadNotifySyncCancel(p) ((void)0) +#define ThreadNotifySyncAcquired(p) ((void)0) +#define ThreadNotifySyncReleasing(p) ((void)0) +#endif + +//----------------------------------------------------------------------------- +// Encapsulation of a thread local datum (needed because THREAD_LOCAL doesn't +// work in a DLL loaded with LoadLibrary() +//----------------------------------------------------------------------------- + +#ifndef NO_THREAD_LOCAL + +#if defined( _PS3 ) +// linux totally supports compiler thread locals, even across dll's. +#define PLAT_COMPILER_SUPPORTED_THREADLOCALS 1 +#define CTHREADLOCALUSEERROR PS3_ELF_EXPORTED_THREADLOCAL PS3_ELF_EXPORTED_THREADLOCAL PS3_ELF_EXPORTED_THREADLOCAL +#define CTHREADLOCALINTEGER( typ ) CTHREADLOCALUSEERROR int +#define CTHREADLOCALINT CTHREADLOCALUSEERROR int +#define CTHREADLOCALPTR( typ ) CTHREADLOCALUSEERROR typ * +#define CTHREADLOCAL( typ ) CTHREADLOCALUSEERROR typ +#define GETLOCAL( x ) ( x ) +#endif + + +#if defined(_LINUX) && !defined(OSX) +// linux totally supports compiler thread locals, even across dll's. +#define PLAT_COMPILER_SUPPORTED_THREADLOCALS 1 +#define CTHREADLOCALINTEGER( typ ) __thread int +#define CTHREADLOCALINT __thread int +#define CTHREADLOCALPTR( typ ) __thread typ * +#define CTHREADLOCAL( typ ) __thread typ +#define GETLOCAL( x ) ( x ) +#ifndef TIER0_DLL_EXPORT +DLL_IMPORT __thread int g_nThreadID; +#endif +#endif + +#if defined(WIN32) || defined(OSX) +#ifndef __AFXTLS_H__ // not compatible with some Windows headers + +#define CTHREADLOCALINT GenericThreadLocals::CThreadLocalInt<int> +#define CTHREADLOCALINTEGER( typ ) GenericThreadLocals::CThreadLocalInt<typ> +#define CTHREADLOCALPTR( typ ) GenericThreadLocals::CThreadLocalPtr<typ> +#define CTHREADLOCAL( typ ) GenericThreadLocals::CThreadLocal<typ> +#define GETLOCAL( x ) ( x.Get() ) + + +namespace GenericThreadLocals +{ + // a (not so efficient) implementation of thread locals for compilers without full support (i.e. visual c). + // don't use this explicity - instead, use the CTHREADxxx macros above. + + class PLATFORM_CLASS CThreadLocalBase + { +public: + CThreadLocalBase(); + ~CThreadLocalBase(); + + void * Get() const; + void Set(void *); + +private: +#if defined(POSIX) && !defined( _GAMECONSOLE ) + pthread_key_t m_index; +#else + uint32 m_index; +#endif + }; + + //--------------------------------------------------------- + + template <class T> + class CThreadLocal : public CThreadLocalBase + { + public: + CThreadLocal() + { +#ifdef PLATFORM_64BITS + COMPILE_TIME_ASSERT( sizeof(T) <= sizeof(void *) ); +#else + COMPILE_TIME_ASSERT( sizeof(T) == sizeof(void *) ); +#endif + } + + void operator=( T i ) { Set( i ); } + + T Get() const + { +#ifdef PLATFORM_64BITS + void *pData = CThreadLocalBase::Get(); + return *reinterpret_cast<T*>( &pData ); +#else + #ifdef COMPILER_MSVC + #pragma warning ( disable : 4311 ) + #endif + return reinterpret_cast<T>( CThreadLocalBase::Get() ); + #ifdef COMPILER_MSVC + #pragma warning ( default : 4311 ) + #endif +#endif + } + + void Set(T val) + { +#ifdef PLATFORM_64BITS + void* pData = 0; + *reinterpret_cast<T*>( &pData ) = val; + CThreadLocalBase::Set( pData ); +#else + #ifdef COMPILER_MSVC + #pragma warning ( disable : 4312 ) + #endif + CThreadLocalBase::Set( reinterpret_cast<void *>(val) ); + #ifdef COMPILER_MSVC + #pragma warning ( default : 4312 ) + #endif +#endif + } + }; + + + //--------------------------------------------------------- + + template <class T = int32> + class CThreadLocalInt : public CThreadLocal<T> + { + public: + operator const T() const { return this->Get(); } + int operator=( T i ) { this->Set( i ); return i; } + + T operator++() { T i = this->Get(); this->Set( ++i ); return i; } + T operator++(int) { T i = this->Get(); this->Set( i + 1 ); return i; } + + T operator--() { T i = this->Get(); this->Set( --i ); return i; } + T operator--(int) { T i = this->Get(); this->Set( i - 1 ); return i; } + + inline CThreadLocalInt( ) { } + inline CThreadLocalInt( const T &initialvalue ) + { + this->Set( initialvalue ); + } + }; + + + //--------------------------------------------------------- + + template <class T> + class CThreadLocalPtr : private CThreadLocalBase + { + public: + CThreadLocalPtr() {} + + operator const void *() const { return (const T *)Get(); } + operator void *() { return (T *)Get(); } + + operator const T *() const { return (const T *)Get(); } + operator const T *() { return (const T *)Get(); } + operator T *() { return (T *)Get(); } + + T * operator=( T *p ) { Set( p ); return p; } + + bool operator !() const { return (!Get()); } + bool operator!=( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (Get() != NULL); } + bool operator==( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (Get() == NULL); } + bool operator==( const void *p ) const { return (Get() == p); } + bool operator!=( const void *p ) const { return (Get() != p); } + bool operator==( const T *p ) const { return operator==((const void*)p); } + bool operator!=( const T *p ) const { return operator!=((const void*)p); } + + T * operator->() { return (T *)Get(); } + T & operator *() { return *((T *)Get()); } + + const T * operator->() const { return (const T *)Get(); } + const T & operator *() const { return *((const T *)Get()); } + + const T & operator[]( int i ) const { return *((const T *)Get() + i); } + T & operator[]( int i ) { return *((T *)Get() + i); } + + private: + // Disallowed operations + CThreadLocalPtr( T *pFrom ); + CThreadLocalPtr( const CThreadLocalPtr<T> &from ); + T **operator &(); + T * const *operator &() const; + void operator=( const CThreadLocalPtr<T> &from ); + bool operator==( const CThreadLocalPtr<T> &p ) const; + bool operator!=( const CThreadLocalPtr<T> &p ) const; + }; +} + +#ifdef _OSX +PLATFORM_INTERFACE GenericThreadLocals::CThreadLocalInt<int> g_nThreadID; +#else // _OSX +#ifndef TIER0_DLL_EXPORT + +#ifndef _PS3 +extern GenericThreadLocals::CThreadLocalInt<int> g_nThreadID; +#endif // !_PS3 + +#endif // TIER0_DLL_EXPORT +#endif // _OSX + +#endif /// afx32 +#endif //__win32 + +#endif // NO_THREAD_LOCAL + +//----------------------------------------------------------------------------- +// +// A super-fast thread-safe integer A simple class encapsulating the notion of an +// atomic integer used across threads that uses the built in and faster +// "interlocked" functionality rather than a full-blown mutex. Useful for simple +// things like reference counts, etc. +// +//----------------------------------------------------------------------------- + +template <typename T> +class CInterlockedIntT +{ +public: + CInterlockedIntT() : m_value( 0 ) { COMPILE_TIME_ASSERT( sizeof(T) == sizeof(int32) ); } + CInterlockedIntT( T value ) : m_value( value ) {} + + T operator()( void ) const { return m_value; } + operator T() const { return m_value; } + + bool operator!() const { return ( m_value == 0 ); } + bool operator==( T rhs ) const { return ( m_value == rhs ); } + bool operator!=( T rhs ) const { return ( m_value != rhs ); } + + T operator++() { return (T)ThreadInterlockedIncrement( (int32 *)&m_value ); } + T operator++(int) { return operator++() - 1; } + + T operator--() { return (T)ThreadInterlockedDecrement( (int32 *)&m_value ); } + T operator--(int) { return operator--() + 1; } + + bool AssignIf( T conditionValue, T newValue ) { return ThreadInterlockedAssignIf( (int32 *)&m_value, (int32)newValue, (int32)conditionValue ); } + + T operator=( T newValue ) { ThreadInterlockedExchange((int32 *)&m_value, newValue); return m_value; } + + // Atomic add is like += except it returns the previous value as its return value + T AtomicAdd( T add ) { return (T)ThreadInterlockedExchangeAdd( (int32 *)&m_value, (int32)add ); } + + void operator+=( T add ) { ThreadInterlockedExchangeAdd( (int32 *)&m_value, (int32)add ); } + void operator-=( T subtract ) { operator+=( -subtract ); } + void operator*=( T multiplier ) { + T original, result; + do + { + original = m_value; + result = original * multiplier; + } while ( !AssignIf( original, result ) ); + } + void operator/=( T divisor ) { + T original, result; + do + { + original = m_value; + result = original / divisor; + } while ( !AssignIf( original, result ) ); + } + + T operator+( T rhs ) const { return m_value + rhs; } + T operator-( T rhs ) const { return m_value - rhs; } + +private: + volatile T m_value; +}; + +typedef CInterlockedIntT<int> CInterlockedInt; +typedef CInterlockedIntT<unsigned> CInterlockedUInt; + +//----------------------------------------------------------------------------- + +template <typename T> +class CInterlockedPtr +{ +public: + CInterlockedPtr() : m_value( 0 ) { COMPILE_TIME_ASSERT( sizeof(T *) == sizeof(int32) ); /* Will need to rework operator+= for 64 bit */ } + CInterlockedPtr( T *value ) : m_value( value ) {} + + operator T *() const { return m_value; } + + bool operator!() const { return ( m_value == 0 ); } + bool operator==( T *rhs ) const { return ( m_value == rhs ); } + bool operator!=( T *rhs ) const { return ( m_value != rhs ); } + + T *operator++() { return ((T *)ThreadInterlockedExchangeAdd( (int32 *)&m_value, sizeof(T) )) + 1; } + T *operator++(int) { return (T *)ThreadInterlockedExchangeAdd( (int32 *)&m_value, sizeof(T) ); } + + T *operator--() { return ((T *)ThreadInterlockedExchangeAdd( (int32 *)&m_value, -sizeof(T) )) - 1; } + T *operator--(int) { return (T *)ThreadInterlockedExchangeAdd( (int32 *)&m_value, -sizeof(T) ); } + + bool AssignIf( T *conditionValue, T *newValue ) { return ThreadInterlockedAssignPointerToConstIf( (void const **) &m_value, (void const *) newValue, (void const *) conditionValue ); } + + T *operator=( T *newValue ) { ThreadInterlockedExchangePointerToConst( (void const **) &m_value, (void const *) newValue ); return newValue; } + + void operator+=( int add ) { ThreadInterlockedExchangeAdd( (int32 *)&m_value, add * sizeof(T) ); } + void operator-=( int subtract ) { operator+=( -subtract ); } + + // Atomic add is like += except it returns the previous value as its return value + T *AtomicAdd( int add ) { return ( T * ) ThreadInterlockedExchangeAdd( (int32 *)&m_value, add * sizeof(T) ); } + + T *operator+( int rhs ) const { return m_value + rhs; } + T *operator-( int rhs ) const { return m_value - rhs; } + T *operator+( unsigned rhs ) const { return m_value + rhs; } + T *operator-( unsigned rhs ) const { return m_value - rhs; } + size_t operator-( T *p ) const { return m_value - p; } + size_t operator-( const CInterlockedPtr<T> &p ) const { return m_value - p.m_value; } + +private: + T * volatile m_value; +}; + + + +//----------------------------------------------------------------------------- +// +// Platform independent for critical sections management +// +//----------------------------------------------------------------------------- + +class PLATFORM_CLASS CThreadMutex +{ +public: + CThreadMutex(); + ~CThreadMutex(); + + //------------------------------------------------------ + // Mutex acquisition/release. Const intentionally defeated. + //------------------------------------------------------ + void Lock(); + void Lock() const { (const_cast<CThreadMutex *>(this))->Lock(); } + void Unlock(); + void Unlock() const { (const_cast<CThreadMutex *>(this))->Unlock(); } + + bool TryLock(); + bool TryLock() const { return (const_cast<CThreadMutex *>(this))->TryLock(); } + + void LockSilent(); // A Lock() operation which never spews. Required by the logging system to prevent badness. + void UnlockSilent(); // An Unlock() operation which never spews. Required by the logging system to prevent badness. + + //------------------------------------------------------ + // Use this to make deadlocks easier to track by asserting + // when it is expected that the current thread owns the mutex + //------------------------------------------------------ + bool AssertOwnedByCurrentThread(); + + //------------------------------------------------------ + // Enable tracing to track deadlock problems + //------------------------------------------------------ + void SetTrace( bool ); + +private: + // Disallow copying + CThreadMutex( const CThreadMutex & ); + CThreadMutex &operator=( const CThreadMutex & ); + +#if defined( _WIN32 ) + // Efficient solution to breaking the windows.h dependency, invariant is tested. +#ifdef _WIN64 + #define TT_SIZEOF_CRITICALSECTION 40 +#else +#ifndef _X360 + #define TT_SIZEOF_CRITICALSECTION 24 +#else + #define TT_SIZEOF_CRITICALSECTION 28 +#endif // !_X360 +#endif // _WIN64 + byte m_CriticalSection[TT_SIZEOF_CRITICALSECTION]; +#elif defined( _PS3 ) + sys_mutex_t m_Mutex; +#elif defined(POSIX) + pthread_mutex_t m_Mutex; + pthread_mutexattr_t m_Attr; +#else +#error +#endif + +#ifdef THREAD_MUTEX_TRACING_SUPPORTED + // Debugging (always herge to allow mixed debug/release builds w/o changing size) + uint m_currentOwnerID; + uint16 m_lockCount; + bool m_bTrace; +#endif +}; + +//----------------------------------------------------------------------------- +// +// An alternative mutex that is useful for cases when thread contention is +// rare, but a mutex is required. Instances should be declared volatile. +// Sleep of 0 may not be sufficient to keep high priority threads from starving +// lesser threads. This class is not a suitable replacement for a critical +// section if the resource contention is high. +// +//----------------------------------------------------------------------------- + +#if !defined(THREAD_PROFILER) + +class CThreadFastMutex +{ +public: + CThreadFastMutex() + : m_ownerID( 0 ), + m_depth( 0 ) + { + } + +private: + FORCEINLINE bool TryLockInline( const uint32 threadId ) volatile + { + if ( threadId != m_ownerID && !ThreadInterlockedAssignIf( (volatile int32 *)&m_ownerID, (int32)threadId, 0 ) ) + return false; + + ThreadMemoryBarrier(); + ++m_depth; + return true; + } + + bool TryLock( const uint32 threadId ) volatile + { + return TryLockInline( threadId ); + } + + PLATFORM_CLASS void Lock( const uint32 threadId, unsigned nSpinSleepTime ) volatile; + +public: + bool TryLock() volatile + { +#ifdef _DEBUG + if ( m_depth == INT_MAX ) + DebuggerBreak(); + + if ( m_depth < 0 ) + DebuggerBreak(); +#endif + return TryLockInline( ThreadGetCurrentId() ); + } + +#ifndef _DEBUG + FORCEINLINE +#endif + void Lock( unsigned int nSpinSleepTime = 0 ) volatile + { + const uint32 threadId = ThreadGetCurrentId(); + + if ( !TryLockInline( threadId ) ) + { + ThreadPause(); + Lock( threadId, nSpinSleepTime ); + } +#ifdef _DEBUG + if ( m_ownerID != ThreadGetCurrentId() ) + DebuggerBreak(); + + if ( m_depth == INT_MAX ) + DebuggerBreak(); + + if ( m_depth < 0 ) + DebuggerBreak(); +#endif + } + +#ifndef _DEBUG + FORCEINLINE +#endif + void Unlock() volatile + { +#ifdef _DEBUG + if ( m_ownerID != ThreadGetCurrentId() ) + DebuggerBreak(); + + if ( m_depth <= 0 ) + DebuggerBreak(); +#endif + + --m_depth; + if ( !m_depth ) + { + ThreadMemoryBarrier(); + ThreadInterlockedExchange( &m_ownerID, 0 ); + } + } + + bool TryLock() const volatile { return (const_cast<CThreadFastMutex *>(this))->TryLock(); } + void Lock(unsigned nSpinSleepTime = 0 ) const volatile { (const_cast<CThreadFastMutex *>(this))->Lock( nSpinSleepTime ); } + void Unlock() const volatile { (const_cast<CThreadFastMutex *>(this))->Unlock(); } + + // To match regular CThreadMutex: + bool AssertOwnedByCurrentThread() { return true; } + void SetTrace( bool ) {} + + uint32 GetOwnerId() const { return m_ownerID; } + int GetDepth() const { return m_depth; } +private: + volatile uint32 m_ownerID; + int m_depth; +}; + +class ALIGN128 CAlignedThreadFastMutex : public CThreadFastMutex +{ +public: + CAlignedThreadFastMutex() + { + Assert( (size_t)this % 128 == 0 && sizeof(*this) == 128 ); + } + +private: + uint8 pad[128-sizeof(CThreadFastMutex)]; +}; + +#else +#ifdef _PS3 + +class CThreadFastMutex +{ +public: + CThreadFastMutex(); + ~CThreadFastMutex(); + + //------------------------------------------------------ + // Mutex acquisition/release. Const intentionally defeated. + //------------------------------------------------------ + void Lock(); + void Lock() const { (const_cast<CThreadFastMutex *>(this))->Lock(); } + void Unlock(); + void Unlock() const { (const_cast<CThreadFastMutex *>(this))->Unlock(); } + + bool TryLock(); + bool TryLock() const { return (const_cast<CThreadFastMutex *>(this))->TryLock(); } + + //------------------------------------------------------ + // Use this to make deadlocks easier to track by asserting + // when it is expected that the current thread owns the mutex + //------------------------------------------------------ + bool AssertOwnedByCurrentThread(); + + //------------------------------------------------------ + // Enable tracing to track deadlock problems + //------------------------------------------------------ + void SetTrace( bool ); + +private: + // Disallow copying + CThreadFastMutex( const CThreadFastMutex & ); + //CThreadFastMutex &operator=( const CThreadFastMutex & ); + sys_lwmutex_t m_Mutex; + sys_mutex_t m_SlowMutex; +}; + +#else + +typedef CThreadMutex CThreadFastMutex; + +#endif + +class ALIGN128 CAlignedThreadFastMutex : public CThreadFastMutex +{ +public: + CAlignedThreadFastMutex() + { + Assert( (size_t)this % 128 == 0 && sizeof(*this) == 128 ); + } + +private: + uint8 pad[128-sizeof(CThreadFastMutex)]; +}; + +#endif + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +class CThreadNullMutex +{ +public: + static void Lock() {} + static void Unlock() {} + + static bool TryLock() { return true; } + static bool AssertOwnedByCurrentThread() { return true; } + static void SetTrace( bool b ) {} + + static uint32 GetOwnerId() { return 0; } + static int GetDepth() { return 0; } +}; + +//----------------------------------------------------------------------------- +// +// A mutex decorator class used to control the use of a mutex, to make it +// less expensive when not multithreading +// +//----------------------------------------------------------------------------- + +template <class BaseClass, bool *pCondition> +class CThreadConditionalMutex : public BaseClass +{ +public: + void Lock() { if ( *pCondition ) BaseClass::Lock(); } + void Lock() const { if ( *pCondition ) BaseClass::Lock(); } + void Unlock() { if ( *pCondition ) BaseClass::Unlock(); } + void Unlock() const { if ( *pCondition ) BaseClass::Unlock(); } + + bool TryLock() { if ( *pCondition ) return BaseClass::TryLock(); else return true; } + bool TryLock() const { if ( *pCondition ) return BaseClass::TryLock(); else return true; } + bool AssertOwnedByCurrentThread() { if ( *pCondition ) return BaseClass::AssertOwnedByCurrentThread(); else return true; } + void SetTrace( bool b ) { if ( *pCondition ) BaseClass::SetTrace( b ); } +}; + +//----------------------------------------------------------------------------- +// Mutex decorator that blows up if another thread enters +//----------------------------------------------------------------------------- + +template <class BaseClass> +class CThreadTerminalMutex : public BaseClass +{ +public: + bool TryLock() { if ( !BaseClass::TryLock() ) { DebuggerBreak(); return false; } return true; } + bool TryLock() const { if ( !BaseClass::TryLock() ) { DebuggerBreak(); return false; } return true; } + void Lock() { if ( !TryLock() ) BaseClass::Lock(); } + void Lock() const { if ( !TryLock() ) BaseClass::Lock(); } + +}; + +//----------------------------------------------------------------------------- +// +// Class to Lock a critical section, and unlock it automatically +// when the lock goes out of scope +// +//----------------------------------------------------------------------------- + +template <class MUTEX_TYPE = CThreadMutex> +class CAutoLockT +{ +public: + FORCEINLINE CAutoLockT( MUTEX_TYPE &lock) + : m_lock(lock) + { + m_lock.Lock(); + } + + FORCEINLINE CAutoLockT(const MUTEX_TYPE &lock) + : m_lock(const_cast<MUTEX_TYPE &>(lock)) + { + m_lock.Lock(); + } + + FORCEINLINE ~CAutoLockT() + { + m_lock.Unlock(); + } + + +private: + MUTEX_TYPE &m_lock; + + // Disallow copying + CAutoLockT<MUTEX_TYPE>( const CAutoLockT<MUTEX_TYPE> & ); + CAutoLockT<MUTEX_TYPE> &operator=( const CAutoLockT<MUTEX_TYPE> & ); +}; + +typedef CAutoLockT<CThreadMutex> CAutoLock; + +//--------------------------------------------------------- + +template <int size> struct CAutoLockTypeDeducer {}; +template <> struct CAutoLockTypeDeducer<sizeof(CThreadMutex)> { typedef CThreadMutex Type_t; }; +template <> struct CAutoLockTypeDeducer<sizeof(CThreadNullMutex)> { typedef CThreadNullMutex Type_t; }; +#if !defined(THREAD_PROFILER) +template <> struct CAutoLockTypeDeducer<sizeof(CThreadFastMutex)> { typedef CThreadFastMutex Type_t; }; +template <> struct CAutoLockTypeDeducer<sizeof(CAlignedThreadFastMutex)> { typedef CAlignedThreadFastMutex Type_t; }; +#else +template <> struct CAutoLockTypeDeducer<sizeof(CAlignedThreadFastMutex)> { typedef CAlignedThreadFastMutex Type_t; }; +#endif + + +#ifdef MSVC +#define AUTO_LOCK_( type, mutex ) \ + CAutoLockT< typename type > UNIQUE_ID( static_cast<const type &>( mutex ) ) +#else +// clang requires +#define AUTO_LOCK_( type, mutex ) \ + CAutoLockT< typename type > UNIQUE_ID( static_cast<const typename type &>( mutex ) ) +#endif + +#define AUTO_LOCK( mutex ) \ + AUTO_LOCK_( CAutoLockTypeDeducer<sizeof(mutex)>::Type_t, mutex ) + + +#define AUTO_LOCK_FM( mutex ) \ + AUTO_LOCK_( CAutoLockTypeDeducer<sizeof(CThreadFastMutex)>::Type_t, mutex ) + +#define LOCAL_THREAD_LOCK_( tag ) \ + ; \ + static CThreadFastMutex autoMutex_##tag; \ + AUTO_LOCK( autoMutex_##tag ) + +#define LOCAL_THREAD_LOCK() \ + LOCAL_THREAD_LOCK_(_) + +//----------------------------------------------------------------------------- +// +// Base class for event, semaphore and mutex objects. +// +//----------------------------------------------------------------------------- + +// TW_TIMEOUT must match WAIT_TIMEOUT definition +#define TW_TIMEOUT 0x00000102 +// TW_FAILED must match WAIT_FAILED definition +#define TW_FAILED 0xFFFFFFFF + +class PLATFORM_CLASS CThreadSyncObject +{ +public: + ~CThreadSyncObject(); + + //----------------------------------------------------- + // Query if object is useful + //----------------------------------------------------- + bool operator!() const; + + //----------------------------------------------------- + // Access handle + //----------------------------------------------------- +#ifdef _WIN32 + operator HANDLE() { return GetHandle(); } + const HANDLE GetHandle() const { return m_hSyncObject; } +#endif + //----------------------------------------------------- + // Wait for a signal from the object + //----------------------------------------------------- + bool Wait( uint32 dwTimeout = TT_INFINITE ); + + //----------------------------------------------------- + // Wait for a signal from any of the specified objects. + // + // Returns the index of the object that signaled the event + // or THREADSYNC_TIMEOUT if the timeout was hit before the wait condition was met. + // + // Returns TW_FAILED if an incoming object is invalid. + // + // If bWaitAll=true, then it'll return 0 if all the objects were set. + //----------------------------------------------------- + static uint32 WaitForMultiple( int nObjects, CThreadSyncObject **ppObjects, bool bWaitAll, uint32 dwTimeout = TT_INFINITE ); + + // This builds a list of pointers and calls straight through to the other WaitForMultiple. + static uint32 WaitForMultiple( int nObjects, CThreadSyncObject *ppObjects, bool bWaitAll, uint32 dwTimeout = TT_INFINITE ); + +protected: + CThreadSyncObject(); + void AssertUseable(); + +#ifdef _WIN32 + HANDLE m_hSyncObject; + bool m_bCreatedHandle; +#elif defined( _PS3 ) + static sys_lwmutex_t m_staticMutex; + static uint32_t m_bstaticMutexInitialized; + static uint32_t m_bstaticMutexInitializing; +#elif defined(POSIX) + pthread_mutex_t m_Mutex; + pthread_cond_t m_Condition; + bool m_bInitalized; + int m_cSet; + bool m_bManualReset; + bool m_bWakeForEvent; +#else +#error "Implement me" +#endif + +private: + CThreadSyncObject( const CThreadSyncObject & ); + CThreadSyncObject &operator=( const CThreadSyncObject & ); +}; + + +//----------------------------------------------------------------------------- +// +// Wrapper for unnamed event objects +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// +// CThreadSemaphore +// +//----------------------------------------------------------------------------- + +class PLATFORM_CLASS CThreadSemaphore : public CThreadSyncObject +{ +public: + CThreadSemaphore(int32 initialValue, int32 maxValue); + + //----------------------------------------------------- + // Increases the count of the semaphore object by a specified + // amount. Wait() decreases the count by one on return. + //----------------------------------------------------- + bool Release(int32 releaseCount = 1, int32 * pPreviousCount = NULL ); + bool Wait( uint32 dwTimeout = TT_INFINITE ); + +private: + CThreadSemaphore(const CThreadSemaphore &); + CThreadSemaphore &operator=(const CThreadSemaphore &); +#ifdef _PS3 + bool AddWaitingThread(); + void RemoveWaitingThread(); + sys_semaphore_t m_Semaphore; + sys_semaphore_value_t m_sema_max_val; + uint32_t m_numWaitingThread; + uint32_t m_bInitalized; + uint32_t m_semaCount; +#endif +}; + +#if defined( _WIN32 ) + +//----------------------------------------------------------------------------- +// +// A mutex suitable for out-of-process, multi-processor usage +// +//----------------------------------------------------------------------------- + +class PLATFORM_CLASS CThreadFullMutex : public CThreadSyncObject +{ +public: + CThreadFullMutex( bool bEstablishInitialOwnership = false, const char * pszName = NULL ); + + //----------------------------------------------------- + // Release ownership of the mutex + //----------------------------------------------------- + bool Release(); + + // To match regular CThreadMutex: + void Lock() { Wait(); } + void Lock( unsigned timeout ) { Wait( timeout ); } + void Unlock() { Release(); } + bool AssertOwnedByCurrentThread() { return true; } + void SetTrace( bool ) {} + +private: + CThreadFullMutex( const CThreadFullMutex & ); + CThreadFullMutex &operator=( const CThreadFullMutex & ); +}; +#endif + +enum NamedEventResult_t +{ + TT_EventDoesntExist = 0, + TT_EventNotSignaled, + TT_EventSignaled +}; +#if defined( _PS3 ) +//--------------------------------------------------------------------------- +// CThreadEventWaitObject - the purpose of this class is to help implement +// WaitForMultipleObejcts on PS3. +// +// Each event maintains a linked list of CThreadEventWaitObjects. When a +// thread wants to wait on an event it passes the event a semaphore that +// ptr to see the index of the event that triggered it +// +// The thread-specific mutex is to ensure that setting the index and setting the +// semaphore are atomic +//--------------------------------------------------------------------------- + +class CThreadEventWaitObject +{ +public: + CThreadEventWaitObject *m_pPrev, *m_pNext; + sys_semaphore_t *m_pSemaphore; + int m_index; + int *m_pFlag; + + CThreadEventWaitObject() {} + + void Init(sys_semaphore_t *pSem, int index, int *pFlag) + { + m_pSemaphore = pSem; + m_index = index; + m_pFlag = pFlag; + } + + void Set(); +}; +#endif //_PS3 + +class PLATFORM_CLASS CThreadEvent : public CThreadSyncObject +{ +public: + CThreadEvent( bool fManualReset = false ); +#ifdef PLATFORM_WINDOWS + CThreadEvent( const char *name, bool initialState = false, bool bManualReset = false ); + static NamedEventResult_t CheckNamedEvent( const char *name, uint32 dwTimeout = 0 ); + + CThreadEvent( HANDLE hHandle ); +#endif + //----------------------------------------------------- + // Set the state to signaled + //----------------------------------------------------- + bool Set(); + + //----------------------------------------------------- + // Set the state to nonsignaled + //----------------------------------------------------- + bool Reset(); + + //----------------------------------------------------- + // Check if the event is signaled + //----------------------------------------------------- + bool Check(); // Please, use for debugging only! + + bool Wait( uint32 dwTimeout = TT_INFINITE ); + + // See CThreadSyncObject for definitions of these functions. + static uint32 WaitForMultiple( int nObjects, CThreadEvent **ppObjects, bool bWaitAll, uint32 dwTimeout = TT_INFINITE ); + // To implement these, I need to check that casts are safe + static uint32 WaitForMultiple( int nObjects, CThreadEvent *ppObjects, bool bWaitAll, uint32 dwTimeout = TT_INFINITE ); + +#ifdef _PS3 + void RegisterWaitingThread(sys_semaphore_t *pSemaphore, int index, int *flag); + void UnregisterWaitingThread(sys_semaphore_t *pSemaphore); +#endif + +protected: +#ifdef _PS3 + // These virtual functions need to be inline in order for the class to be exported from tier0.prx + virtual bool AddWaitingThread() + { + //This checks if the event is already signaled and if not creates a semaphore which will be signaled + //when the event is finally signaled. + bool result; + + sys_lwmutex_lock(&m_staticMutex, 0); + + if (m_bSet) + result=false; + else + { + result=true; + + m_numWaitingThread++; + + if ( m_numWaitingThread == 1 ) + { + sys_semaphore_attribute_t semAttr; + sys_semaphore_attribute_initialize( semAttr ); + int err = sys_semaphore_create( &m_Semaphore, &semAttr, 0, 256 ); + Assert( err == CELL_OK ); + m_bInitalized = true; + } + } + + sys_lwmutex_unlock(&m_staticMutex); + return result; + } + + virtual void RemoveWaitingThread() + { + sys_lwmutex_lock(&m_staticMutex, 0); + + m_numWaitingThread--; + + if ( m_numWaitingThread == 0) + { + int err = sys_semaphore_destroy( m_Semaphore ); + Assert( err == CELL_OK ); + m_bInitalized = false; + } + + sys_lwmutex_unlock(&m_staticMutex); + } +#endif +private: + CThreadEvent( const CThreadEvent & ); + CThreadEvent &operator=( const CThreadEvent & ); +#if defined( _PS3 ) + uint32_t m_bSet; + bool m_bManualReset; + + sys_semaphore_t m_Semaphore; + uint32_t m_numWaitingThread; + uint32_t m_bInitalized; + + CThreadEventWaitObject m_waitObjects[CTHREADEVENT_MAX_WAITING_THREADS+2]; + CThreadEventWaitObject *m_pWaitObjectsPool; + CThreadEventWaitObject *m_pWaitObjectsList; + + CThreadEventWaitObject* LLUnlinkNode(CThreadEventWaitObject *node); + CThreadEventWaitObject* LLLinkNode(CThreadEventWaitObject* list, CThreadEventWaitObject *node); + +#endif +}; + +// Hard-wired manual event for use in array declarations +class CThreadManualEvent : public CThreadEvent +{ +public: + CThreadManualEvent() + : CThreadEvent( true ) + { + } +}; + +PLATFORM_INTERFACE int ThreadWaitForObjects( int nEvents, const HANDLE *pHandles, bool bWaitAll = true, unsigned timeout = TT_INFINITE ); +inline int ThreadWaitForEvents( int nEvents, const CThreadEvent *pEvents, bool bWaitAll = true, unsigned timeout = TT_INFINITE ) { return ThreadWaitForObjects( nEvents, (const HANDLE *)pEvents, bWaitAll, timeout ); } + +//----------------------------------------------------------------------------- +// +// CThreadRWLock +// +//----------------------------------------------------------------------------- + +class PLATFORM_CLASS CThreadRWLock +{ +public: + CThreadRWLock(); + + void LockForRead(); + void UnlockRead(); + void LockForWrite(); + void UnlockWrite(); + + void LockForRead() const { const_cast<CThreadRWLock *>(this)->LockForRead(); } + void UnlockRead() const { const_cast<CThreadRWLock *>(this)->UnlockRead(); } + void LockForWrite() const { const_cast<CThreadRWLock *>(this)->LockForWrite(); } + void UnlockWrite() const { const_cast<CThreadRWLock *>(this)->UnlockWrite(); } + +private: + void WaitForRead(); + +#ifdef WIN32 + CThreadFastMutex m_mutex; +#else + CThreadMutex m_mutex; +#endif + CThreadEvent m_CanWrite; + CThreadEvent m_CanRead; + + int m_nWriters; + int m_nActiveReaders; + int m_nPendingReaders; +}; + +//----------------------------------------------------------------------------- +// +// CThreadSpinRWLock +// +//----------------------------------------------------------------------------- + +#ifndef OLD_SPINRWLOCK +class ALIGN8 PLATFORM_CLASS CThreadSpinRWLock +{ +public: + CThreadSpinRWLock() + { + m_lockInfo.m_i32 = 0; + m_writerId = 0; +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + m_iWriteDepth = 0; +#endif + } + + bool IsLockedForWrite(); + bool IsLockedForRead(); + + FORCEINLINE bool TryLockForWrite(); + bool TryLockForWrite_UnforcedInline(); + + void LockForWrite(); + void SpinLockForWrite(); + + FORCEINLINE bool TryLockForRead(); + bool TryLockForRead_UnforcedInline(); + + void LockForRead(); + void SpinLockForRead(); + + void UnlockWrite(); + void UnlockRead(); + + bool TryLockForWrite() const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForWrite(); } + bool TryLockForRead() const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForRead(); } + void LockForRead() const { const_cast<CThreadSpinRWLock *>(this)->LockForRead(); } + void UnlockRead() const { const_cast<CThreadSpinRWLock *>(this)->UnlockRead(); } + void LockForWrite() const { const_cast<CThreadSpinRWLock *>(this)->LockForWrite(); } + void UnlockWrite() const { const_cast<CThreadSpinRWLock *>(this)->UnlockWrite(); } + +private: + enum + { + THREAD_SPIN = (8*1024) + }; + + union LockInfo_t + { + struct + { +#if PLAT_LITTLE_ENDIAN + uint16 m_nReaders; + uint16 m_fWriting; +#else + uint16 m_fWriting; + uint16 m_nReaders; +#endif + }; + uint32 m_i32; + }; + + LockInfo_t m_lockInfo; + uint32 m_writerId; +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + int m_iWriteDepth; + uint32 pad; +#endif +} ALIGN8_POST; + +#else + +/* (commented out to reduce distraction in colorized editor, remove entirely when new implementation settles) +class ALIGN8 PLATFORM_CLASS CThreadSpinRWLock +{ +public: + CThreadSpinRWLock() { COMPILE_TIME_ASSERT( sizeof( LockInfo_t ) == sizeof( int64 ) ); Assert( (intp)this % 8 == 0 ); memset( this, 0, sizeof( *this ) ); } + + bool TryLockForWrite(); + bool TryLockForRead(); + + void LockForRead(); + void UnlockRead(); + void LockForWrite(); + void UnlockWrite(); + + bool TryLockForWrite() const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForWrite(); } + bool TryLockForRead() const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForRead(); } + void LockForRead() const { const_cast<CThreadSpinRWLock *>(this)->LockForRead(); } + void UnlockRead() const { const_cast<CThreadSpinRWLock *>(this)->UnlockRead(); } + void LockForWrite() const { const_cast<CThreadSpinRWLock *>(this)->LockForWrite(); } + void UnlockWrite() const { const_cast<CThreadSpinRWLock *>(this)->UnlockWrite(); } + +private: + // This structure is used as an atomic & exchangeable 64-bit value. It would probably be better to just have one 64-bit value + // and accessor functions that make/break it, but at this late stage of development, I'm just wrapping it into union + // Beware of endianness: on Xbox/PowerPC m_writerId is high-word of m_i64; on PC, it's low-dword of m_i64 + union LockInfo_t + { + struct + { + uint32 m_writerId; + int m_nReaders; + }; + int64 m_i64; + }; + + bool AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand ); + bool TryLockForWrite( const uint32 threadId ); + void SpinLockForWrite( const uint32 threadId ); + + volatile LockInfo_t m_lockInfo; + CInterlockedInt m_nWriters; +} ALIGN8_POST; +*/ +#endif + +//----------------------------------------------------------------------------- +// +// A thread wrapper similar to a Java thread. +// +//----------------------------------------------------------------------------- +#ifdef _PS3 +// Everything must be inline for this to work across PRX boundaries + +class CThread; +PLATFORM_INTERFACE CThread *GetCurThreadPS3(); +PLATFORM_INTERFACE void SetCurThreadPS3( CThread * ); +PLATFORM_INTERFACE void AllocateThreadID( void ); +PLATFORM_INTERFACE void FreeThreadID( void ); +#endif + +class PLATFORM_CLASS CThread +{ +public: + CThread(); + virtual ~CThread(); + + //----------------------------------------------------- + + const char *GetName(); + void SetName( const char *pszName ); + + size_t CalcStackDepth( void *pStackVariable ) { return ((byte *)m_pStackBase - (byte *)pStackVariable); } + + //----------------------------------------------------- + // Functions for the other threads + //----------------------------------------------------- + + // Start thread running - error if already running + enum ThreadPriorityEnum_t + { +#ifdef _PS3 + PRIORITY_NORMAL = 1001, + PRIORITY_HIGH = 100, + PRIORITY_LOW = 2001, + PRIORITY_DEFAULT = 1001 +#else + PRIORITY_DEFAULT = 0,//THREAD_PRIORITY_NORMAL, + PRIORITY_NORMAL = 0,//THREAD_PRIORITY_NORMAL, + PRIORITY_HIGH = 1,//THREAD_PRIORITY_ABOVE_NORMAL, + PRIORITY_LOW = -1//THREAD_PRIORITY_BELOW_NORMAL +#endif + }; + virtual bool Start( unsigned nBytesStack = 0, ThreadPriorityEnum_t nPriority = PRIORITY_DEFAULT ); + + // Returns true if thread has been created and hasn't yet exited + bool IsAlive(); + + // This method causes the current thread to wait until this thread + // is no longer alive. + bool Join( unsigned timeout = TT_INFINITE ); + + // Access the thread handle directly + ThreadHandle_t GetThreadHandle(); + +#ifdef _WIN32 + uint GetThreadId(); +#endif + + //----------------------------------------------------- + + int GetResult(); + + //----------------------------------------------------- + // Functions for both this, and maybe, and other threads + //----------------------------------------------------- + + // Forcibly, abnormally, but relatively cleanly stop the thread + void Stop( int exitCode = 0 ); + + // Get the priority + int GetPriority() const; + + // Set the priority + bool SetPriority( int priority ); + + // Suspend a thread, can only call from the thread itself + unsigned Suspend(); + + // Resume a suspended thread + unsigned Resume(); + + // Check if thread is suspended + bool IsSuspended() { return !m_NotSuspendedEvent.Check(); } + + // Force hard-termination of thread. Used for critical failures. + bool Terminate( int exitCode = 0 ); + + //----------------------------------------------------- + // Global methods + //----------------------------------------------------- + + // Get the Thread object that represents the current thread, if any. + // Can return NULL if the current thread was not created using + // CThread + static CThread *GetCurrentCThread(); + + // Offer a context switch. Under Win32, equivalent to Sleep(0) +#ifdef Yield +#undef Yield +#endif + static void Yield(); + + // This method causes the current thread to yield and not to be + // scheduled for further execution until a certain amount of real + // time has elapsed, more or less. Duration is in milliseconds + static void Sleep( unsigned duration ); + +protected: + + // Optional pre-run call, with ability to fail-create. Note Init() + // is forced synchronous with Start() + virtual bool Init(); + + // Thread will run this function on startup, must be supplied by + // derived class, performs the intended action of the thread. + virtual int Run() = 0; + + // Called when the thread exits + virtual void OnExit(); + + // Allow for custom start waiting + virtual bool WaitForCreateComplete( CThreadEvent *pEvent ); + const ThreadId_t GetThreadID() const { return (ThreadId_t)m_threadId; } + +#ifdef PLATFORM_WINDOWS + const ThreadHandle_t GetThreadHandle() const { return (ThreadHandle_t)m_hThread; } + + static unsigned long __stdcall ThreadProc( void * pv ); + typedef unsigned long (__stdcall *ThreadProc_t)( void * ); +#else + static void* ThreadProc( void * pv ); + typedef void* (*ThreadProc_t)( void * pv ); +#endif + + virtual ThreadProc_t GetThreadProc(); + CThreadMutex m_Lock; + CThreadEvent m_ExitEvent; // Set right before the thread's function exits. + +private: + enum Flags + { + SUPPORT_STOP_PROTOCOL = 1 << 0 + }; + + // Thread initially runs this. param is actually 'this'. function + // just gets this and calls ThreadProc + struct ThreadInit_t + { + CThread * pThread; + CThreadEvent *pInitCompleteEvent; + bool * pfInitSuccess; +#if defined( THREAD_PARENT_STACK_TRACE_ENABLED ) + void * ParentStackTrace[THREAD_PARENT_STACK_TRACE_LENGTH]; +#endif + }; + + // make copy constructor and assignment operator inaccessible + CThread( const CThread & ); + CThread &operator=( const CThread & ); + +#ifdef _WIN32 + HANDLE m_hThread; + ThreadId_t m_threadId; +#elif defined( _PS3 ) + sys_ppu_thread_t m_threadId; + volatile sys_ppu_thread_t m_threadZombieId; + + // Mutex and condition variable used by the Suspend / Resume logic + sys_mutex_t m_mutexSuspend; + sys_cond_t m_condSuspend; + + //EAPS3 Event to indicate that a thread has terminated. This helps with the replacing of WaitForMultipleObjects + // on the PS3, since it waits for a thread to finish. + CThreadEvent m_threadEnd; +#elif defined(_POSIX) + pthread_t m_threadId; + volatile pthread_t m_threadZombieId; +#endif + int m_result; + char m_szName[32]; + void * m_pStackBase; + unsigned m_flags; + CThreadManualEvent m_NotSuspendedEvent; +}; + +// The CThread implementation needs to be inlined for performance on the PS3 - It makes a difference of more than 1ms/frame +// Since the dependency checker isn't smart enough to take an #ifdef _PS3 into account, all platforms will inline it. +#ifdef _PS3 +#include "threadtools.inl" +#endif + +//----------------------------------------------------------------------------- +// Simple thread class encompasses the notion of a worker thread, handing +// synchronized communication. +//----------------------------------------------------------------------------- + +// These are internal reserved error results from a call attempt +enum WTCallResult_t +{ + WTCR_FAIL = -1, + WTCR_TIMEOUT = -2, + WTCR_THREAD_GONE = -3, +}; + +class PLATFORM_CLASS CWorkerThread : public CThread +{ +public: + CWorkerThread(); + + //----------------------------------------------------- + // + // Inter-thread communication + // + // Calls in either direction take place on the same "channel." + // Seperate functions are specified to make identities obvious + // + //----------------------------------------------------- + + // Master: Signal the thread, and block for a response + int CallWorker( unsigned, unsigned timeout = TT_INFINITE, bool fBoostWorkerPriorityToMaster = true ); + + // Worker: Signal the thread, and block for a response + int CallMaster( unsigned, unsigned timeout = TT_INFINITE ); + + // Wait for the next request + bool WaitForCall( unsigned dwTimeout, unsigned *pResult = NULL ); + bool WaitForCall( unsigned *pResult = NULL ); + + // Is there a request? + bool PeekCall( unsigned *pParam = NULL ); + + // Reply to the request + void Reply( unsigned ); + + // Wait for a reply in the case when CallWorker() with timeout != TT_INFINITE + int WaitForReply( unsigned timeout = TT_INFINITE ); + + // If you want to do WaitForMultipleObjects you'll need to include + // this handle in your wait list or you won't be responsive + CThreadEvent& GetCallHandle(); // (returns m_EventSend) + + // Find out what the request was + unsigned GetCallParam() const; + + // Boost the worker thread to the master thread, if worker thread is lesser, return old priority + int BoostPriority(); + +protected: + typedef uint32 ( *WaitFunc_t)( uint32 nHandles, CThreadEvent** ppHandles, int bWaitAll, uint32 timeout ); + int Call( unsigned, unsigned timeout, bool fBoost, WaitFunc_t = NULL ); + int WaitForReply( unsigned timeout, WaitFunc_t ); + +private: + CWorkerThread( const CWorkerThread & ); + CWorkerThread &operator=( const CWorkerThread & ); + + CThreadEvent m_EventSend; + CThreadEvent m_EventComplete; + + unsigned m_Param; + int m_ReturnVal; +}; + + +// a unidirectional message queue. A queue of type T. Not especially high speed since each message +// is malloced/freed. Note that if your message class has destructors/constructors, they MUST be +// thread safe! +template<class T> class CMessageQueue +{ + CThreadEvent SignalEvent; // signals presence of data + CThreadMutex QueueAccessMutex; + + // the parts protected by the mutex + struct MsgNode + { + MsgNode *Next; + T Data; + }; + + MsgNode *Head; + MsgNode *Tail; + +public: + CMessageQueue( void ) + { + Head = Tail = NULL; + } + + // check for a message. not 100% reliable - someone could grab the message first + bool MessageWaiting( void ) + { + return ( Head != NULL ); + } + + void WaitMessage( T *pMsg ) + { + for(;;) + { + while( ! MessageWaiting() ) + SignalEvent.Wait(); + QueueAccessMutex.Lock(); + if (! Head ) + { + // multiple readers could make this null + QueueAccessMutex.Unlock(); + continue; + } + *( pMsg ) = Head->Data; + MsgNode *remove_this = Head; + Head = Head->Next; + if (! Head) // if empty, fix tail ptr + Tail = NULL; + QueueAccessMutex.Unlock(); + delete remove_this; + break; + } + } + + void QueueMessage( T const &Msg) + { + MsgNode *new1=new MsgNode; + new1->Data=Msg; + new1->Next=NULL; + QueueAccessMutex.Lock(); + if ( Tail ) + { + Tail->Next=new1; + Tail = new1; + } + else + { + Head = new1; + Tail = new1; + } + SignalEvent.Set(); + QueueAccessMutex.Unlock(); + } +}; + + +//----------------------------------------------------------------------------- +// +// CThreadMutex. Inlining to reduce overhead and to allow client code +// to decide debug status (tracing) +// +//----------------------------------------------------------------------------- + +#ifdef MSVC +typedef struct _RTL_CRITICAL_SECTION RTL_CRITICAL_SECTION; +typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; + +#ifndef _X360 +extern "C" +{ + void __declspec(dllimport) __stdcall InitializeCriticalSection(CRITICAL_SECTION *); + void __declspec(dllimport) __stdcall EnterCriticalSection(CRITICAL_SECTION *); + void __declspec(dllimport) __stdcall LeaveCriticalSection(CRITICAL_SECTION *); + void __declspec(dllimport) __stdcall DeleteCriticalSection(CRITICAL_SECTION *); +}; +#endif +#endif + +//--------------------------------------------------------- +#if !defined(POSIX) || defined( _GAMECONSOLE ) + +inline void CThreadMutex::Lock() +{ +#if defined(_PS3) + #ifndef NO_THREAD_SYNC + sys_mutex_lock( m_Mutex, 0 ); + #endif +#else + #if defined( THREAD_MUTEX_TRACING_ENABLED ) + uint thisThreadID = ThreadGetCurrentId(); + if ( m_bTrace && m_currentOwnerID && ( m_currentOwnerID != thisThreadID ) ) + Msg( _T( "Thread %u about to wait for lock %x owned by %u\n" ), ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID ); + #endif + + LockSilent(); + + #ifdef THREAD_MUTEX_TRACING_ENABLED + if (m_lockCount == 0) + { + // we now own it for the first time. Set owner information + m_currentOwnerID = thisThreadID; + if ( m_bTrace ) + Msg( _T( "Thread %u now owns lock 0x%x\n" ), m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection ); + } + m_lockCount++; + #endif +#endif +} + +//--------------------------------------------------------- + +inline void CThreadMutex::Unlock() +{ +#if defined( _PS3 ) + + #ifndef NO_THREAD_SYNC + sys_mutex_unlock( m_Mutex ); + #endif + +#else + #ifdef THREAD_MUTEX_TRACING_ENABLED + AssertMsg( m_lockCount >= 1, "Invalid unlock of thread lock" ); + m_lockCount--; + if (m_lockCount == 0) + { + if ( m_bTrace ) + Msg( _T( "Thread %u releasing lock 0x%x\n" ), m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection ); + m_currentOwnerID = 0; + } + #endif + UnlockSilent(); +#endif +} + +//--------------------------------------------------------- + +inline void CThreadMutex::LockSilent() +{ + #ifdef MSVC + EnterCriticalSection((CRITICAL_SECTION *)&m_CriticalSection); + #else + DebuggerBreak(); // should not be called - not defined for this platform/compiler!!! + #endif +} + +//--------------------------------------------------------- + +inline void CThreadMutex::UnlockSilent() +{ + #ifdef MSVC + LeaveCriticalSection((CRITICAL_SECTION *)&m_CriticalSection); + #else + DebuggerBreak(); // should not be called - not defined for this platform/compiler!!! + #endif +} + +//--------------------------------------------------------- + +inline bool CThreadMutex::AssertOwnedByCurrentThread() +{ +#ifdef THREAD_MUTEX_TRACING_ENABLED +#ifdef _WIN32 + if (ThreadGetCurrentId() == m_currentOwnerID) + return true; + AssertMsg3( 0, "Expected thread %u as owner of lock 0x%x, but %u owns", ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID ); + return false; +#elif defined( _PS3 ) + return true; +#endif +#else + return true; +#endif +} + +//--------------------------------------------------------- + +inline void CThreadMutex::SetTrace( bool bTrace ) +{ +#ifdef _WIN32 +#ifdef THREAD_MUTEX_TRACING_ENABLED + m_bTrace = bTrace; +#endif +#elif defined _PS3 + //EAPS3 +#endif + +} + +//--------------------------------------------------------- + +#elif defined(POSIX) && !defined( _GAMECONSOLE ) + +inline CThreadMutex::CThreadMutex() +{ + // enable recursive locks as we need them + pthread_mutexattr_init( &m_Attr ); + pthread_mutexattr_settype( &m_Attr, PTHREAD_MUTEX_RECURSIVE ); + pthread_mutex_init( &m_Mutex, &m_Attr ); +} + +//--------------------------------------------------------- + +inline CThreadMutex::~CThreadMutex() +{ + pthread_mutex_destroy( &m_Mutex ); +} + +//--------------------------------------------------------- + +inline void CThreadMutex::Lock() +{ + pthread_mutex_lock( &m_Mutex ); +} + +//--------------------------------------------------------- + +inline void CThreadMutex::Unlock() +{ + pthread_mutex_unlock( &m_Mutex ); +} + +//--------------------------------------------------------- + +inline void CThreadMutex::LockSilent() +{ + pthread_mutex_lock( &m_Mutex ); +} + +//--------------------------------------------------------- + +inline void CThreadMutex::UnlockSilent() +{ + pthread_mutex_unlock( &m_Mutex ); +} + +//--------------------------------------------------------- + +inline bool CThreadMutex::AssertOwnedByCurrentThread() +{ + return true; +} + +//--------------------------------------------------------- + +inline void CThreadMutex::SetTrace(bool fTrace) +{ +} + +#else +#error +#endif // POSIX + +//----------------------------------------------------------------------------- +// +// CThreadRWLock inline functions +// +//----------------------------------------------------------------------------- + +inline CThreadRWLock::CThreadRWLock() +: m_CanRead( true ), + m_nWriters( 0 ), + m_nActiveReaders( 0 ), + m_nPendingReaders( 0 ) +{ +} + +inline void CThreadRWLock::LockForRead() +{ + m_mutex.Lock(); + if ( m_nWriters) + { + WaitForRead(); + } + m_nActiveReaders++; + m_mutex.Unlock(); +} + +inline void CThreadRWLock::UnlockRead() +{ + m_mutex.Lock(); + m_nActiveReaders--; + if ( m_nActiveReaders == 0 && m_nWriters != 0 ) + { + m_CanWrite.Set(); + } + m_mutex.Unlock(); +} + + +//----------------------------------------------------------------------------- +// +// CThreadSpinRWLock inline functions +// +//----------------------------------------------------------------------------- + +#ifndef OLD_SPINRWLOCK + +#if defined(TEST_THREAD_SPIN_RW_LOCK) +#define RWLAssert( exp ) if ( exp ) ; else DebuggerBreak(); +#else +#define RWLAssert( exp ) ((void)0) +#endif + +inline bool CThreadSpinRWLock::IsLockedForWrite() +{ + return ( m_lockInfo.m_fWriting == 1 ); +} + +inline bool CThreadSpinRWLock::IsLockedForRead() +{ + return ( m_lockInfo.m_nReaders > 0 ); +} + +FORCEINLINE bool CThreadSpinRWLock::TryLockForWrite() +{ + volatile LockInfo_t &curValue = m_lockInfo; + if ( !( curValue.m_i32 & 0x00010000 ) && ThreadInterlockedAssignIf( &curValue.m_i32, 0x00010000, 0 ) ) + { + ThreadMemoryBarrier(); + RWLAssert( m_iWriteDepth == 0 && m_writerId == 0 ); + m_writerId = ThreadGetCurrentId(); +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + m_iWriteDepth++; +#endif + return true; + } + + return false; +} + +inline bool CThreadSpinRWLock::TryLockForWrite_UnforcedInline() +{ + if ( TryLockForWrite() ) + { + return true; + } + +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + if ( m_writerId != ThreadGetCurrentId() ) + { + return false; + } + m_iWriteDepth++; + return true; +#else + return false; +#endif +} + +FORCEINLINE void CThreadSpinRWLock::LockForWrite() +{ + if ( !TryLockForWrite() ) + { + SpinLockForWrite(); + } +} + +FORCEINLINE bool CThreadSpinRWLock::TryLockForRead() +{ + volatile LockInfo_t &curValue = m_lockInfo; + if ( !( curValue.m_i32 & 0x00010000 ) ) // !m_lockInfo.m_fWriting + { + LockInfo_t oldValue; + LockInfo_t newValue; + oldValue.m_i32 = ( curValue.m_i32 & 0xffff ); + newValue.m_i32 = oldValue.m_i32 + 1; + + if ( ThreadInterlockedAssignIf( &m_lockInfo.m_i32, newValue.m_i32, oldValue.m_i32 ) ) + { + ThreadMemoryBarrier(); + RWLAssert( m_lockInfo.m_fWriting == 0 ); + return true; + } + } + return false; +} + +inline bool CThreadSpinRWLock::TryLockForRead_UnforcedInline() +{ +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + if ( m_lockInfo.m_i32 & 0x00010000 ) // m_lockInfo.m_fWriting + { + if ( m_writerId == ThreadGetCurrentId() ) + { + m_lockInfo.m_nReaders++; + return true; + } + + return false; + } +#endif + return TryLockForRead(); +} + +FORCEINLINE void CThreadSpinRWLock::LockForRead() +{ + if ( !TryLockForRead() ) + { + SpinLockForRead(); + } +} + +FORCEINLINE void CThreadSpinRWLock::UnlockWrite() +{ + RWLAssert( m_writerId == ThreadGetCurrentId() ); +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + if ( --m_iWriteDepth == 0 ) +#endif + { + m_writerId = 0; + ThreadMemoryBarrier(); + m_lockInfo.m_i32 = 0; + } +} + +#ifndef REENTRANT_THREAD_SPIN_RW_LOCK +FORCEINLINE +#else +inline +#endif +void CThreadSpinRWLock::UnlockRead() +{ + RWLAssert( m_writerId == 0 || ( m_writerId == ThreadGetCurrentId() && m_lockInfo.m_fWriting ) ); +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + if ( !( m_lockInfo.m_i32 & 0x00010000 ) ) // !m_lockInfo.m_fWriting +#endif + { + ThreadMemoryBarrier(); + ThreadInterlockedDecrement( &m_lockInfo.m_i32 ); + RWLAssert( m_writerId == 0 && !m_lockInfo.m_fWriting ); + } +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + else if ( m_writerId == ThreadGetCurrentId() ) + { + m_lockInfo.m_nReaders--; + } + else + { + RWLAssert( 0 ); + } +#endif +} + +#else +/* (commented out to reduce distraction in colorized editor, remove entirely when new implementation settles) +inline bool CThreadSpinRWLock::AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand ) +{ + // Note: using unions guarantees no aliasing bugs. Casting structures through *(int64*)& + // may create hard-to-catch bugs because when you do that, compiler doesn't know that the newly computed pointer + // is actually aliased with LockInfo_t structure. It's rarely a problem in practice, but when it is, it's a royal pain to debug. + return ThreadInterlockedAssignIf64( &m_lockInfo.m_i64, newValue.m_i64, comperand.m_i64 ); +} + +FORCEINLINE bool CThreadSpinRWLock::TryLockForWrite( const uint32 threadId ) +{ + // In order to grab a write lock, there can be no readers and no owners of the write lock + if ( m_lockInfo.m_nReaders > 0 || ( m_lockInfo.m_writerId && m_lockInfo.m_writerId != threadId ) ) + { + return false; + } + + static const LockInfo_t oldValue = { {0, 0} }; + LockInfo_t newValue = { { threadId, 0 } }; + if ( AssignIf( newValue, oldValue ) ) + { + ThreadMemoryBarrier(); + return true; + } + return false; +} + +inline bool CThreadSpinRWLock::TryLockForWrite() +{ + m_nWriters++; + if ( !TryLockForWrite( ThreadGetCurrentId() ) ) + { + m_nWriters--; + return false; + } + return true; +} + +FORCEINLINE bool CThreadSpinRWLock::TryLockForRead() +{ + if ( m_nWriters != 0 ) + { + return false; + } + // In order to grab a write lock, the number of readers must not change and no thread can own the write + LockInfo_t oldValue; + LockInfo_t newValue; + + if( IsX360() || IsPS3() ) + { + // this is the code equivalent to original code (see below) that doesn't cause LHS on Xbox360 + // WARNING: This code assumes BIG Endian CPU + oldValue.m_i64 = uint32( m_lockInfo.m_nReaders ); + newValue.m_i64 = oldValue.m_i64 + 1; // NOTE: when we have -1 (or 0xFFFFFFFF) readers, this will result in non-equivalent code + } + else + { + // this is the original code that worked here for a while + oldValue.m_nReaders = m_lockInfo.m_nReaders; + oldValue.m_writerId = 0; + newValue.m_nReaders = oldValue.m_nReaders + 1; + newValue.m_writerId = 0; + } + + if ( AssignIf( newValue, oldValue ) ) + { + ThreadMemoryBarrier(); + return true; + } + return false; +} + +inline void CThreadSpinRWLock::LockForWrite() +{ + const uint32 threadId = ThreadGetCurrentId(); + + m_nWriters++; + + if ( !TryLockForWrite( threadId ) ) + { + ThreadPause(); + SpinLockForWrite( threadId ); + } +} +*/ +#endif + +// read data from a memory address +template<class T> FORCEINLINE T ReadVolatileMemory( T const *pPtr ) +{ + volatile const T * pVolatilePtr = ( volatile const T * ) pPtr; + return *pVolatilePtr; +} + + +//----------------------------------------------------------------------------- + +#if defined( _WIN32 ) +#pragma warning(pop) +#endif + +#if defined( _PS3 ) +BOOL SetEvent( CThreadEvent *pEvent ); +BOOL ResetEvent( CThreadEvent *pEvent ); +DWORD WaitForMultipleObjects(DWORD nCount, CThreadEvent **lppHandles, BOOL bWaitAll, DWORD dwMilliseconds ); +#endif // _PS3 +#endif // THREADTOOLS_H diff --git a/external/vpc/public/tier0/threadtools.inl b/external/vpc/public/tier0/threadtools.inl new file mode 100644 index 0000000..0afe97a --- /dev/null +++ b/external/vpc/public/tier0/threadtools.inl @@ -0,0 +1,629 @@ +#ifndef THREADTOOLS_INL +#define THREADTOOLS_INL + +// This file is included in threadtools.h for PS3 and threadtools.cpp for all other platforms +// +// Do not #include other files here + +#ifndef _PS3 +// this is defined in the .cpp for the PS3 to avoid introducing a dependency for files including the header +CTHREADLOCALPTR(CThread) g_pCurThread; + +#define INLINE_ON_PS3 +#else +// Inlining these functions on PS3 (which are called across PRX boundaries) saves us over 1ms per frame +#define INLINE_ON_PS3 inline +#endif + +INLINE_ON_PS3 CThread::CThread() : +#ifdef _WIN32 +m_hThread( NULL ), +m_threadId( 0 ), +#elif defined( _PS3 ) || defined(_POSIX) +m_threadId( 0 ), +m_threadZombieId( 0 ) , +#endif +m_result( 0 ), +m_flags( 0 ) +{ + m_szName[0] = 0; + m_NotSuspendedEvent.Set(); +} + +//--------------------------------------------------------- + +INLINE_ON_PS3 CThread::~CThread() +{ +#ifdef MSVC + if (m_hThread) +#elif defined(POSIX) && !defined( _PS3 ) + if ( m_threadId ) +#endif + { + if ( IsAlive() ) + { + Msg( "Illegal termination of worker thread! Threads must negotiate an end to the thread before the CThread object is destroyed.\n" ); +#ifdef _WIN32 + + DoNewAssertDialog( __FILE__, __LINE__, "Illegal termination of worker thread! Threads must negotiate an end to the thread before the CThread object is destroyed.\n" ); +#endif + if ( GetCurrentCThread() == this ) + { + Stop(); // BUGBUG: Alfred - this doesn't make sense, this destructor fires from the hosting thread not the thread itself!! + } + } + } +#if defined(POSIX) || defined( _PS3 ) + if ( m_threadZombieId ) + { + // just clean up zombie threads immediately (the destructor is fired from the hosting thread) + Join(); + } +#endif +} + + +//--------------------------------------------------------- + +INLINE_ON_PS3 const char *CThread::GetName() +{ + AUTO_LOCK( m_Lock ); + if ( !m_szName[0] ) + { +#if defined( _WIN32 ) + _snprintf( m_szName, sizeof(m_szName) - 1, "Thread(%p/%p)", this, m_hThread ); +#elif defined( _PS3 ) + snprintf( m_szName, sizeof(m_szName) - 1, "Thread(%p)", this ); +#elif defined( POSIX ) + _snprintf( m_szName, sizeof(m_szName) - 1, "Thread(%p/0x%x)", this, (uint)m_threadId ); +#endif + m_szName[sizeof(m_szName) - 1] = 0; + } + return m_szName; +} + +//--------------------------------------------------------- + +INLINE_ON_PS3 void CThread::SetName(const char *pszName) +{ + AUTO_LOCK( m_Lock ); + strncpy( m_szName, pszName, sizeof(m_szName) - 1 ); + m_szName[sizeof(m_szName) - 1] = 0; +} + +//----------------------------------------------------- +// Functions for the other threads +//----------------------------------------------------- + +// Start thread running - error if already running +INLINE_ON_PS3 bool CThread::Start( unsigned nBytesStack, ThreadPriorityEnum_t nPriority ) +{ + AUTO_LOCK( m_Lock ); + + if ( IsAlive() ) + { + AssertMsg( 0, "Tried to create a thread that has already been created!" ); + return false; + } + + bool bInitSuccess = false; + CThreadEvent createComplete; + ThreadInit_t init = { this, &createComplete, &bInitSuccess }; + +#if defined( THREAD_PARENT_STACK_TRACE_ENABLED ) + { + int iValidEntries = GetCallStack_Fast( init.ParentStackTrace, ARRAYSIZE( init.ParentStackTrace ), 0 ); + for( int i = iValidEntries; i < ARRAYSIZE( init.ParentStackTrace ); ++i ) + { + init.ParentStackTrace[i] = NULL; + } + } +#endif + +#ifdef PLATFORM_WINDOWS + m_hThread = (HANDLE)CreateThread( NULL, + nBytesStack, + (LPTHREAD_START_ROUTINE)GetThreadProc(), + new ThreadInit_t(init), + 0, + (LPDWORD)&m_threadId ); + + if( nPriority != PRIORITY_DEFAULT ) + { + SetThreadPriority( m_hThread, nPriority ); + } + + if ( !m_hThread ) + { + AssertMsg1( 0, "Failed to create thread (error 0x%x)", GetLastError() ); + return false; + } +#elif PLATFORM_PS3 + // On the PS3, a stack size of 0 doesn't imply a default stack size, so we need to force it to our + // own default size. + if ( nBytesStack == 0 ) + { + nBytesStack = PS3_SYS_PPU_THREAD_COMMON_STACK_SIZE; + } + + //The thread is about to begin + m_threadEnd.Reset(); + + // sony documentation: + // "If the PPU thread is not joined by sys_ppu_thread_join() after exit, + // it should always be created as non-joinable (not specifying + // SYS_PPU_THREAD_CREATE_JOINABLE). Otherwise, some resources are left + // allocated after termination of the PPU thread as if memory leaks." + const char* threadName=m_szName; + if ( sys_ppu_thread_create( &m_threadId, + (void(*)(uint64_t))GetThreadProc(), + (uint64_t)(new ThreadInit_t( init )), + nPriority, + nBytesStack, + SYS_PPU_THREAD_CREATE_JOINABLE , + threadName ) != CELL_OK ) + { + AssertMsg1( 0, "Failed to create thread (error 0x%x)", errno ); + return false; + } + + bInitSuccess = true; +#elif PLATFORM_POSIX + pthread_attr_t attr; + pthread_attr_init( &attr ); + pthread_attr_setstacksize( &attr, MAX( nBytesStack, 1024u*1024 ) ); + if ( pthread_create( &m_threadId, &attr, (void *(*)(void *))GetThreadProc(), new ThreadInit_t( init ) ) != 0 ) + { + AssertMsg1( 0, "Failed to create thread (error 0x%x)", GetLastError() ); + return false; + } + bInitSuccess = true; +#endif + + + + if ( !WaitForCreateComplete( &createComplete ) ) + { + Msg( "Thread failed to initialize\n" ); +#ifdef _WIN32 + CloseHandle( m_hThread ); + m_hThread = NULL; +#elif defined( _PS3 ) + m_threadEnd.Set(); + m_threadId = NULL; + m_threadZombieId = 0; +#endif + + return false; + } + + if ( !bInitSuccess ) + { + Msg( "Thread failed to initialize\n" ); +#ifdef _WIN32 + CloseHandle( m_hThread ); + m_hThread = NULL; +#elif defined(POSIX) && !defined( _PS3 ) + m_threadId = 0; + m_threadZombieId = 0; +#endif + return false; + } + +#ifdef _WIN32 + if ( !m_hThread ) + { + Msg( "Thread exited immediately\n" ); + } +#endif + +#ifdef _WIN32 + AddThreadHandleToIDMap( m_hThread, m_threadId ); + return !!m_hThread; +#elif defined(POSIX) + return !!m_threadId; +#endif +} + +//--------------------------------------------------------- +// +// Return true if the thread has been created and hasn't yet exited +// + +INLINE_ON_PS3 bool CThread::IsAlive() +{ +#ifdef PLATFORM_WINDOWS + DWORD dwExitCode; + return ( + m_hThread + && GetExitCodeThread(m_hThread, &dwExitCode) + && dwExitCode == STILL_ACTIVE ); +#elif defined(POSIX) + return !!m_threadId; +#endif +} + +// This method causes the current thread to wait until this thread +// is no longer alive. +INLINE_ON_PS3 bool CThread::Join( unsigned timeout ) +{ +#ifdef _WIN32 + if ( m_hThread ) +#elif defined(POSIX) + if ( m_threadId || m_threadZombieId ) +#endif + { + AssertMsg(GetCurrentCThread() != this, _T("Thread cannot be joined with self")); + +#ifdef _WIN32 + return ThreadJoin( (ThreadHandle_t)m_hThread, timeout ); +#elif defined(POSIX) + bool ret = ThreadJoin( (ThreadHandle_t)(m_threadId ? m_threadId : m_threadZombieId), timeout ); + m_threadZombieId = 0; + return ret; +#endif + } + return true; +} + +//--------------------------------------------------------- + +INLINE_ON_PS3 ThreadHandle_t CThread::GetThreadHandle() +{ +#ifdef _WIN32 + return (ThreadHandle_t)m_hThread; +#else + return (ThreadHandle_t)m_threadId; +#endif +} + + +//--------------------------------------------------------- + +INLINE_ON_PS3 int CThread::GetResult() +{ + return m_result; +} + +//----------------------------------------------------- +// Functions for both this, and maybe, and other threads +//----------------------------------------------------- + +// Forcibly, abnormally, but relatively cleanly stop the thread +// + +INLINE_ON_PS3 void CThread::Stop(int exitCode) +{ + if ( !IsAlive() ) + return; + + if ( GetCurrentCThread() == this ) + { +#if !defined( _PS3 ) + m_result = exitCode; + if ( !( m_flags & SUPPORT_STOP_PROTOCOL ) ) + { + OnExit(); + g_pCurThread = NULL; + +#ifdef _WIN32 + CloseHandle( m_hThread ); + RemoveThreadHandleToIDMap( m_hThread ); + m_hThread = NULL; +#else + m_threadId = 0; + m_threadZombieId = 0; +#endif + } + else + { + throw exitCode; + } +#else + AssertMsg( false, "Called CThread::Stop() for a platform that doesn't have it!\n"); +#endif + } + else + AssertMsg( 0, "Only thread can stop self: Use a higher-level protocol"); +} + +//--------------------------------------------------------- + +// Get the priority +INLINE_ON_PS3 int CThread::GetPriority() const +{ +#ifdef _WIN32 + return GetThreadPriority(m_hThread); +#elif defined( _PS3 ) + return ThreadGetPriority( (ThreadHandle_t) m_threadId ); +#elif defined(POSIX) + struct sched_param thread_param; + int policy; + pthread_getschedparam( m_threadId, &policy, &thread_param ); + return thread_param.sched_priority; +#endif +} + +//--------------------------------------------------------- + +// Set the priority +INLINE_ON_PS3 bool CThread::SetPriority(int priority) +{ +#ifdef WIN32 + return ThreadSetPriority( (ThreadHandle_t)m_hThread, priority ); +#else + return ThreadSetPriority( (ThreadHandle_t)m_threadId, priority ); +#endif +} + +//--------------------------------------------------------- + +// Suspend a thread +INLINE_ON_PS3 unsigned CThread::Suspend() +{ + AssertMsg( ThreadGetCurrentId() == (ThreadId_t)m_threadId, "Cannot call CThread::Suspend from outside thread" ); + + if ( ThreadGetCurrentId() != (ThreadId_t)m_threadId ) + { + DebuggerBreakIfDebugging(); + } + + m_NotSuspendedEvent.Reset(); + m_NotSuspendedEvent.Wait(); + + return 0; +} + + +//--------------------------------------------------------- + +INLINE_ON_PS3 unsigned CThread::Resume() +{ + if ( m_NotSuspendedEvent.Check() ) + { + DevWarning( "Called Resume() on a thread that is not suspended!\n" ); + } + m_NotSuspendedEvent.Set(); + return 0; +} + +//--------------------------------------------------------- + +// Force hard-termination of thread. Used for critical failures. +INLINE_ON_PS3 bool CThread::Terminate(int exitCode) +{ +#if defined( _X360 ) + AssertMsg( 0, "Cannot terminate a thread on the Xbox!" ); + return false; +#elif defined( _WIN32 ) + // I hope you know what you're doing! + if (!TerminateThread(m_hThread, exitCode)) + return false; + CloseHandle( m_hThread ); + RemoveThreadHandleToIDMap( m_hThread ); + m_hThread = NULL; +#elif defined( _PS3 ) + m_threadEnd.Set(); + m_threadId = NULL; +#elif defined(POSIX) + pthread_kill( m_threadId, SIGKILL ); + m_threadId = 0; +#endif + return true; +} + +//----------------------------------------------------- +// Global methods +//----------------------------------------------------- + +// Get the Thread object that represents the current thread, if any. +// Can return NULL if the current thread was not created using +// CThread +// + +INLINE_ON_PS3 CThread *CThread::GetCurrentCThread() +{ +#ifdef _PS3 + return GetCurThreadPS3(); +#else + return g_pCurThread; +#endif +} + +//--------------------------------------------------------- +// +// Offer a context switch. Under Win32, equivalent to Sleep(0) +// + +#ifdef Yield +#undef Yield +#endif +INLINE_ON_PS3 void CThread::Yield() +{ +#ifdef _WIN32 + ::Sleep(0); +#elif defined( _PS3 ) + // sys_ppu_thread_yield doesn't seem to function properly, so sleep instead. + sys_timer_usleep( 60 ); +#elif defined(POSIX) + pthread_yield(); +#endif +} + +//--------------------------------------------------------- +// +// This method causes the current thread to yield and not to be +// scheduled for further execution until a certain amount of real +// time has elapsed, more or less. Duration is in milliseconds + +INLINE_ON_PS3 void CThread::Sleep( unsigned duration ) +{ +#ifdef _WIN32 + ::Sleep(duration); +#elif defined (_PS3) + sys_timer_usleep( duration * 1000 ); +#elif defined(POSIX) + usleep( duration * 1000 ); +#endif +} + +//--------------------------------------------------------- + +// Optional pre-run call, with ability to fail-create. Note Init() +// is forced synchronous with Start() +INLINE_ON_PS3 bool CThread::Init() +{ + return true; +} + +//--------------------------------------------------------- + +#if defined( _PS3 ) +INLINE_ON_PS3 int CThread::Run() +{ + return -1; +} +#endif // _PS3 + +// Called when the thread exits +INLINE_ON_PS3 void CThread::OnExit() { } + +// Allow for custom start waiting +INLINE_ON_PS3 bool CThread::WaitForCreateComplete( CThreadEvent *pEvent ) +{ + // Force serialized thread creation... + if (!pEvent->Wait(60000)) + { + AssertMsg( 0, "Probably deadlock or failure waiting for thread to initialize." ); + return false; + } + return true; +} + +//--------------------------------------------------------- +INLINE_ON_PS3 CThread::ThreadProc_t CThread::GetThreadProc() +{ + return ThreadProc; +} + +#ifdef PLATFORM_WINDOWS +unsigned long STDCALL CThread::ThreadProc(LPVOID pv) +#else +INLINE_ON_PS3 void* CThread::ThreadProc(LPVOID pv) +#endif +{ +#if defined( POSIX ) || defined( _PS3 ) + ThreadInit_t *pInit = reinterpret_cast<ThreadInit_t*>(pv); +#else + std::auto_ptr<ThreadInit_t> pInit((ThreadInit_t *)pv); +#endif + +#ifdef _X360 + // Make sure all threads are consistent w.r.t floating-point math + SetupFPUControlWord(); +#endif + AllocateThreadID(); + + CThread *pThread = pInit->pThread; +#ifdef _PS3 + SetCurThreadPS3( pThread ); +#else + g_pCurThread = pThread; +#endif + + pThread->m_pStackBase = AlignValue( &pThread, 4096 ); + + pInit->pThread->m_result = -1; + +#if defined( THREAD_PARENT_STACK_TRACE_ENABLED ) + CStackTop_ReferenceParentStack stackTop( pInit->ParentStackTrace, ARRAYSIZE( pInit->ParentStackTrace ) ); +#endif + + bool bInitSuccess = true; + if ( pInit->pfInitSuccess ) + *(pInit->pfInitSuccess) = false; + +#ifdef _PS3 + *(pInit->pfInitSuccess) = pInit->pThread->Init(); +#else + try + { + bInitSuccess = pInit->pThread->Init(); + } + + catch (...) + { + pInit->pInitCompleteEvent->Set(); + throw; + } +#endif // _PS3 + + if ( pInit->pfInitSuccess ) + *(pInit->pfInitSuccess) = bInitSuccess; + pInit->pInitCompleteEvent->Set(); + if (!bInitSuccess) + return 0; + + if ( !Plat_IsInDebugSession() && (pInit->pThread->m_flags & SUPPORT_STOP_PROTOCOL) ) + { +#ifndef _PS3 + try +#endif + { + pInit->pThread->m_result = pInit->pThread->Run(); + } + +#ifndef _PS3 + catch (...) + { + } +#endif + } + else + { + pInit->pThread->m_result = pInit->pThread->Run(); + } + + pInit->pThread->OnExit(); +#ifdef _PS3 + SetCurThreadPS3( NULL ); +#else + g_pCurThread = NULL; +#endif + FreeThreadID(); + + AUTO_LOCK( pThread->m_Lock ); +#ifdef _WIN32 + CloseHandle( pThread->m_hThread ); + RemoveThreadHandleToIDMap( pThread->m_hThread ); + pThread->m_hThread = NULL; +#elif defined( _PS3 ) + pThread->m_threadZombieId = pThread->m_threadId; + pThread->m_threadEnd.Set(); + pThread->m_threadId = 0; +#elif defined(POSIX) + pThread->m_threadZombieId = pThread->m_threadId; + pThread->m_threadId = 0; +#else +#error +#endif + + pThread->m_ExitEvent.Set(); +#ifdef _PS3 + { + pThread->m_Lock.Unlock(); + sys_ppu_thread_exit( pInit->pThread->m_result ); + // reacquire the lock in case thread exit didn't actually exit the thread, so that + // AUTO_LOCK won't double-unlock the lock (to keep it paired) + pThread->m_Lock.Lock(); + } +#endif + +#if defined( POSIX )|| defined( _PS3 ) + return (void*)pInit->pThread->m_result; +#else + return pInit->pThread->m_result; +#endif +} + +#endif // THREADTOOLS_INL diff --git a/external/vpc/public/tier0/tslist.h b/external/vpc/public/tier0/tslist.h new file mode 100644 index 0000000..d8bc55e --- /dev/null +++ b/external/vpc/public/tier0/tslist.h @@ -0,0 +1,858 @@ +//========== Copyright � 2005, Valve Corporation, All rights reserved. ======== +// +// Purpose: +// +// LIFO from disassembly of Windows API and http://perso.wanadoo.fr/gmem/evenements/jim2002/articles/L17_Fober.pdf +// FIFO from http://perso.wanadoo.fr/gmem/evenements/jim2002/articles/L17_Fober.pdf +// +//============================================================================= + +#ifndef TSLIST_H +#define TSLIST_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#if ( defined( PLATFORM_X360 ) || defined( PLATFORM_WINDOWS_PC64 ) ) +#define USE_NATIVE_SLIST +#endif + +#if defined( USE_NATIVE_SLIST ) && !defined( _X360 ) && !defined( _PS3 ) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + +#include "tier0/dbg.h" +#include "tier0/threadtools.h" + +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- + +#if defined(PLATFORM_WINDOWS_PC64) + +#define TSLIST_HEAD_ALIGNMENT 16 //MEMORY_ALLOCATION_ALIGNMENT +#define TSLIST_NODE_ALIGNMENT 16 //MEMORY_ALLOCATION_ALIGNMENT + +#define TSLIST_HEAD_ALIGN ALIGN16 +#define TSLIST_NODE_ALIGN ALIGN16 +#define TSLIST_HEAD_ALIGN_POST ALIGN16_POST +#define TSLIST_NODE_ALIGN_POST ALIGN16_POST + +#else + +#define TSLIST_HEAD_ALIGNMENT 8 +#define TSLIST_NODE_ALIGNMENT 8 + +#define TSLIST_HEAD_ALIGN ALIGN8 +#define TSLIST_NODE_ALIGN ALIGN8 +#define TSLIST_HEAD_ALIGN_POST ALIGN8_POST +#define TSLIST_NODE_ALIGN_POST ALIGN8_POST + +#endif + + +//----------------------------------------------------------------------------- + +PLATFORM_INTERFACE bool RunTSQueueTests( int nListSize = 10000, int nTests = 1 ); +PLATFORM_INTERFACE bool RunTSListTests( int nListSize = 10000, int nTests = 1 ); + +//----------------------------------------------------------------------------- +// Lock free list. +//----------------------------------------------------------------------------- +//#define USE_NATIVE_SLIST + +#ifdef USE_NATIVE_SLIST +typedef SLIST_ENTRY TSLNodeBase_t; +typedef SLIST_HEADER TSLHead_t; +#else +struct TSLIST_NODE_ALIGN TSLNodeBase_t +{ + TSLNodeBase_t *Next; // name to match Windows +} +TSLIST_NODE_ALIGN_POST; + +union TSLHead_t +{ + struct Value_t + { + TSLNodeBase_t *Next; + // <sergiy> Depth must be in the least significant halfword when atomically loading into register, + // to avoid carrying digits from Sequence. Carrying digits from Depth to Sequence is ok, + // because Sequence can be pretty much random. We could operate on both of them separately, + // but it could perhaps (?) lead to problems with store forwarding. I don't know 'cause I didn't + // performance-test or design original code, I'm just making it work on PowerPC. + #ifdef PLAT_BIG_ENDIAN + int16 Sequence; + int16 Depth; + #else + int16 Depth; + int16 Sequence; + #endif + } value; + + struct Value32_t + { + TSLNodeBase_t *Next_do_not_use_me; + int32 DepthAndSequence; + } value32; + + int64 value64; +}; +#endif + +//------------------------------------- + +class TSLIST_HEAD_ALIGN CTSListBase +{ +public: + CTSListBase() + { + if ( ((size_t)&m_Head) % TSLIST_HEAD_ALIGNMENT != 0 ) + { + Error( _T( "CTSListBase: Misaligned list\n" ) ); + DebuggerBreak(); + } + +#ifdef USE_NATIVE_SLIST + InitializeSListHead( &m_Head ); +#else + m_Head.value64 = (int64)0; +#endif + } + + ~CTSListBase() + { + Detach(); + } + + TSLNodeBase_t *Push( TSLNodeBase_t *pNode ) + { +#ifdef _DEBUG + if ( (size_t)pNode % TSLIST_NODE_ALIGNMENT != 0 ) + { + Error( _T( "CTSListBase: Misaligned node\n" ) ); + DebuggerBreak(); + } +#endif + +#ifdef USE_NATIVE_SLIST +#ifdef _X360 + // integrated write-release barrier + return (TSLNodeBase_t *)InterlockedPushEntrySListRelease( &m_Head, pNode ); +#else + return (TSLNodeBase_t *)InterlockedPushEntrySList( &m_Head, pNode ); +#endif +#else + TSLHead_t oldHead; + TSLHead_t newHead; + + #if defined( PLATFORM_PS3 ) || defined( PLATFORM_X360 ) + __lwsync(); // write-release barrier + #endif + + for (;;) + { + oldHead.value64 = m_Head.value64; + pNode->Next = oldHead.value.Next; + newHead.value.Next = pNode; + + newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence + 0x10001; + + + if ( ThreadInterlockedAssignIf64( &m_Head.value64, newHead.value64, oldHead.value64 ) ) + { + break; + } + ThreadPause(); + }; + + return (TSLNodeBase_t *)oldHead.value.Next; +#endif + } + + TSLNodeBase_t *Pop() + { +#ifdef USE_NATIVE_SLIST +#ifdef _X360 + // integrated read-acquire barrier + TSLNodeBase_t *pNode = (TSLNodeBase_t *)InterlockedPopEntrySListAcquire( &m_Head ); +#else + TSLNodeBase_t *pNode = (TSLNodeBase_t *)InterlockedPopEntrySList( &m_Head ); +#endif + return pNode; +#else + TSLHead_t oldHead; + TSLHead_t newHead; + + for (;;) + { + oldHead.value64 = m_Head.value64; + if ( !oldHead.value.Next ) + return NULL; + + newHead.value.Next = oldHead.value.Next->Next; + newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence - 1; + + + if ( ThreadInterlockedAssignIf64( &m_Head.value64, newHead.value64, oldHead.value64 ) ) + { + #if defined( PLATFORM_PS3 ) || defined( PLATFORM_X360 ) + __lwsync(); // read-acquire barrier + #endif + break; + } + ThreadPause(); + }; + + return (TSLNodeBase_t *)oldHead.value.Next; +#endif + } + + TSLNodeBase_t *Detach() + { +#ifdef USE_NATIVE_SLIST + TSLNodeBase_t *pBase = (TSLNodeBase_t *)InterlockedFlushSList( &m_Head ); +#if defined( _X360 ) || defined( _PS3 ) + __lwsync(); // read-acquire barrier +#endif + return pBase; +#else + TSLHead_t oldHead; + TSLHead_t newHead; + + do + { + ThreadPause(); + + oldHead.value64 = m_Head.value64; + if ( !oldHead.value.Next ) + return NULL; + + newHead.value.Next = NULL; + // <sergiy> the reason for AND'ing it instead of poking a short into memory + // is probably to avoid store forward issues, but I'm not sure because + // I didn't construct this code. In any case, leaving it as is on big-endian + newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence & 0xffff0000; + + } while( !ThreadInterlockedAssignIf64( &m_Head.value64, newHead.value64, oldHead.value64 ) ); + + return (TSLNodeBase_t *)oldHead.value.Next; +#endif + } + + TSLHead_t *AccessUnprotected() + { + return &m_Head; + } + + int Count() const + { +#ifdef USE_NATIVE_SLIST + return QueryDepthSList( const_cast<TSLHead_t*>( &m_Head ) ); +#else + return m_Head.value.Depth; +#endif + } + +private: + TSLHead_t m_Head; +} +TSLIST_HEAD_ALIGN_POST; + +//------------------------------------- + +template <typename T> +class TSLIST_HEAD_ALIGN CTSSimpleList : public CTSListBase +{ +public: + void Push( T *pNode ) + { + Assert( sizeof(T) >= sizeof(TSLNodeBase_t) ); + CTSListBase::Push( (TSLNodeBase_t *)pNode ); + } + + T *Pop() + { + return (T *)CTSListBase::Pop(); + } +} +TSLIST_HEAD_ALIGN_POST; + +//------------------------------------- +// this is a replacement for CTSList<> and CObjectPool<> that does not +// have a per-item, per-alloc new/delete overhead +// similar to CTSSimpleList except that it allocates it's own pool objects +// and frees them on destruct. Also it does not overlay the TSNodeBase_t memory +// on T's memory +template< class T > +class TSLIST_HEAD_ALIGN CTSPool : public CTSListBase +{ + // packs the node and the item (T) into a single struct and pools those + struct TSLIST_NODE_ALIGN simpleTSPoolStruct_t : public TSLNodeBase_t + { + T elem; + } TSLIST_NODE_ALIGN_POST; + +public: + + ~CTSPool() + { + simpleTSPoolStruct_t *pNode = NULL; + while ( 1 ) + { + pNode = (simpleTSPoolStruct_t *)CTSListBase::Pop(); + if ( !pNode ) + break; + delete pNode; + } + } + + void PutObject( T *pInfo ) + { + char *pElem = (char *)pInfo; + pElem -= offsetof(simpleTSPoolStruct_t,elem); + simpleTSPoolStruct_t *pNode = (simpleTSPoolStruct_t *)pElem; + + CTSListBase::Push( pNode ); + } + + T *GetObject() + { + simpleTSPoolStruct_t *pNode = (simpleTSPoolStruct_t *)CTSListBase::Pop(); + if ( !pNode ) + { + pNode = new simpleTSPoolStruct_t; + } + return &pNode->elem; + } + + // omg windows sdk - why do you #define GetObject()? + FORCEINLINE T *Get() + { + return GetObject(); + } + +} TSLIST_HEAD_ALIGN_POST; +//------------------------------------- + +template <typename T> +class TSLIST_HEAD_ALIGN CTSList : public CTSListBase +{ +public: + struct TSLIST_NODE_ALIGN Node_t : public TSLNodeBase_t + { + Node_t() {} + Node_t( const T &init ) : elem( init ) {} + + T elem; + + } TSLIST_NODE_ALIGN_POST; + + ~CTSList() + { + Purge(); + } + + void Purge() + { + Node_t *pCurrent = Detach(); + Node_t *pNext; + while ( pCurrent ) + { + pNext = (Node_t *)pCurrent->Next; + delete pCurrent; + pCurrent = pNext; + } + } + + void RemoveAll() + { + Purge(); + } + + Node_t *Push( Node_t *pNode ) + { + return (Node_t *)CTSListBase::Push( pNode ); + } + + Node_t *Pop() + { + return (Node_t *)CTSListBase::Pop(); + } + + void PushItem( const T &init ) + { + Push( new Node_t( init ) ); + } + + bool PopItem( T *pResult) + { + Node_t *pNode = Pop(); + if ( !pNode ) + return false; + *pResult = pNode->elem; + delete pNode; + return true; + } + + Node_t *Detach() + { + return (Node_t *)CTSListBase::Detach(); + } + +} TSLIST_HEAD_ALIGN_POST; + +//------------------------------------- + +template <typename T> +class TSLIST_HEAD_ALIGN CTSListWithFreeList : public CTSListBase +{ +public: + struct TSLIST_NODE_ALIGN Node_t : public TSLNodeBase_t + { + Node_t() {} + Node_t( const T &init ) : elem( init ) {} + + T elem; + } TSLIST_NODE_ALIGN_POST; + + ~CTSListWithFreeList() + { + Purge(); + } + + void Purge() + { + Node_t *pCurrent = Detach(); + Node_t *pNext; + while ( pCurrent ) + { + pNext = (Node_t *)pCurrent->Next; + delete pCurrent; + pCurrent = pNext; + } + pCurrent = (Node_t *)m_FreeList.Detach(); + while ( pCurrent ) + { + pNext = (Node_t *)pCurrent->Next; + delete pCurrent; + pCurrent = pNext; + } + } + + void RemoveAll() + { + Node_t *pCurrent = Detach(); + Node_t *pNext; + while ( pCurrent ) + { + pNext = (Node_t *)pCurrent->Next; + m_FreeList.Push( pCurrent ); + pCurrent = pNext; + } + } + + Node_t *Push( Node_t *pNode ) + { + return (Node_t *)CTSListBase::Push( pNode ); + } + + Node_t *Pop() + { + return (Node_t *)CTSListBase::Pop(); + } + + void PushItem( const T &init ) + { + Node_t *pNode = (Node_t *)m_FreeList.Pop(); + if ( !pNode ) + { + pNode = new Node_t; + } + pNode->elem = init; + Push( pNode ); + } + + bool PopItem( T *pResult) + { + Node_t *pNode = Pop(); + if ( !pNode ) + return false; + *pResult = pNode->elem; + m_FreeList.Push( pNode ); + return true; + } + + Node_t *Detach() + { + return (Node_t *)CTSListBase::Detach(); + } + + void FreeNode( Node_t *pNode ) + { + m_FreeList.Push( pNode ); + } + +private: + CTSListBase m_FreeList; +} TSLIST_HEAD_ALIGN_POST; + +//----------------------------------------------------------------------------- +// Lock free queue +// +// A special consideration: the element type should be simple. This code +// actually dereferences freed nodes as part of pop, but later detects +// that. If the item in the queue is a complex type, only bad things can +// come of that. Also, therefore, if you're using Push/Pop instead of +// push item, be aware that the node memory cannot be freed until +// all threads that might have been popping have completed the pop. +// The PushItem()/PopItem() for handles this by keeping a persistent +// free list. Dont mix Push/PushItem. Note also nodes will be freed at the end, +// and are expected to have been allocated with operator new. +//----------------------------------------------------------------------------- + +template <typename T, bool bTestOptimizer = false, bool bFreeList = true> +class TSLIST_HEAD_ALIGN CTSQueue +{ +public: + struct TSLIST_NODE_ALIGN Node_t + { + Node_t() {} + Node_t( const T &init ) : elem( init ) {} + + Node_t *pNext; + T elem; + } TSLIST_NODE_ALIGN_POST; + + union TSLIST_HEAD_ALIGN NodeLink_t + { + struct Value_t + { + Node_t *pNode; + int32 sequence; + } value; + + int64 value64; + } TSLIST_HEAD_ALIGN_POST; + + CTSQueue() + { + COMPILE_TIME_ASSERT( sizeof(Node_t) >= sizeof(TSLNodeBase_t) ); + if ( ((size_t)&m_Head) % TSLIST_HEAD_ALIGNMENT != 0 ) + { + Error( "CTSQueue: Misaligned queue\n" ); + DebuggerBreak(); + } + if ( ((size_t)&m_Tail) % TSLIST_HEAD_ALIGNMENT != 0 ) + { + Error( "CTSQueue: Misaligned queue\n" ); + DebuggerBreak(); + } + m_Count = 0; + m_Head.value.sequence = m_Tail.value.sequence = 0; + m_Head.value.pNode = m_Tail.value.pNode = new Node_t; // list always contains a dummy node + m_Head.value.pNode->pNext = End(); + } + + ~CTSQueue() + { + Purge(); + Assert( m_Count == 0 ); + Assert( m_Head.value.pNode == m_Tail.value.pNode ); + Assert( m_Head.value.pNode->pNext == End() ); + delete m_Head.value.pNode; + } + + // Note: Purge, RemoveAll, and Validate are *not* threadsafe + void Purge() + { + if ( IsDebug() ) + { + Validate(); + } + + Node_t *pNode; + while ( ( pNode = Pop() ) != NULL ) + { + delete pNode; + } + + while ( bFreeList && ( pNode = (Node_t *)m_FreeNodes.Pop() ) != NULL ) + { + delete pNode; + } + + Assert( m_Count == 0 ); + Assert( m_Head.value.pNode == m_Tail.value.pNode ); + Assert( m_Head.value.pNode->pNext == End() ); + + m_Head.value.sequence = m_Tail.value.sequence = 0; + } + + void RemoveAll() + { + if ( IsDebug() ) + { + Validate(); + } + + Node_t *pNode; + while ( bFreeList && ( pNode = Pop() ) != NULL ) + { + m_FreeNodes.Push( (TSLNodeBase_t *)pNode ); + } + } + + bool Validate() + { + bool bResult = true; + int nNodes = 0; + + if ( m_Count == 0 ) + { + if ( m_Head.value.pNode != m_Tail.value.pNode ) + { + DebuggerBreakIfDebugging(); + bResult = false; + } + } + + Node_t *pNode = m_Head.value.pNode; + while ( pNode != End() ) + { + nNodes++; + pNode = pNode->pNext; + } + + nNodes--;// skip dummy node + + if ( nNodes != m_Count ) + { + DebuggerBreakIfDebugging(); + bResult = false; + } + + if ( !bResult ) + { + Msg( "Corrupt CTSQueueDetected" ); + } + + return bResult; + } + + void FinishPush( Node_t *pNode, const NodeLink_t &oldTail ) + { + NodeLink_t newTail; + + newTail.value.pNode = pNode; + newTail.value.sequence = oldTail.value.sequence + 1; + + ThreadMemoryBarrier(); + + InterlockedCompareExchangeNodeLink( &m_Tail, newTail, oldTail ); + } + + Node_t *Push( Node_t *pNode ) + { +#ifdef _DEBUG + if ( (size_t)pNode % TSLIST_NODE_ALIGNMENT != 0 ) + { + Error( "CTSListBase: Misaligned node\n" ); + DebuggerBreak(); + } +#endif + + NodeLink_t oldTail; + + pNode->pNext = End(); + + for (;;) + { + oldTail.value.sequence = m_Tail.value.sequence; + oldTail.value.pNode = m_Tail.value.pNode; + if ( InterlockedCompareExchangeNode( &(oldTail.value.pNode->pNext), pNode, End() ) == End() ) + { + break; + } + else + { + // Another thread is trying to push, help it along + FinishPush( oldTail.value.pNode->pNext, oldTail ); + } + } + + FinishPush( pNode, oldTail ); // This can fail if another thread pushed between the sequence and node grabs above. Later pushes or pops corrects + + m_Count++; + + return oldTail.value.pNode; + } + + Node_t *Pop() + { + #define TSQUEUE_BAD_NODE_LINK ( (Node_t *)INT_TO_POINTER( 0xdeadbeef ) ) + NodeLink_t * volatile pHead = &m_Head; + NodeLink_t * volatile pTail = &m_Tail; + Node_t * volatile * pHeadNode = &m_Head.value.pNode; + volatile int * volatile pHeadSequence = &m_Head.value.sequence; + Node_t * volatile * pTailNode = &pTail->value.pNode; + + NodeLink_t head; + NodeLink_t newHead; + Node_t *pNext; + int tailSequence; + T elem; + + for (;;) + { + head.value.sequence = *pHeadSequence; // must grab sequence first, which allows condition below to ensure pNext is valid + ThreadMemoryBarrier(); // need a barrier to prevent reordering of these assignments + head.value.pNode = *pHeadNode; + tailSequence = pTail->value.sequence; + pNext = head.value.pNode->pNext; + + if ( pNext && head.value.sequence == *pHeadSequence ) // Checking pNext only to force optimizer to not reorder the assignment to pNext and the compare of the sequence + { + if ( bTestOptimizer ) + { + if ( pNext == TSQUEUE_BAD_NODE_LINK ) + { + Msg( "Bad node link detected\n" ); + continue; + } + } + if ( head.value.pNode == *pTailNode ) + { + if ( pNext == End() ) + { + return NULL; + } + + // Another thread is trying to push, help it along + NodeLink_t &oldTail = head; // just reuse local memory for head to build old tail + oldTail.value.sequence = tailSequence; // reuse head pNode + FinishPush( pNext, oldTail ); + } + else if ( pNext != End() ) + { + elem = pNext->elem; // NOTE: next could be a freed node here, by design + newHead.value.pNode = pNext; + newHead.value.sequence = head.value.sequence + 1; + if ( InterlockedCompareExchangeNodeLink( pHead, newHead, head ) ) + { + ThreadMemoryBarrier(); + + if ( bTestOptimizer ) + { + head.value.pNode->pNext = TSQUEUE_BAD_NODE_LINK; + } + break; + } + } + } + } + + m_Count--; + head.value.pNode->elem = elem; + return head.value.pNode; + } + + void FreeNode( Node_t *pNode ) + { + if ( bFreeList ) + { + m_FreeNodes.Push( (TSLNodeBase_t *)pNode ); + } + else + { + delete pNode; + } + } + + void PushItem( const T &init ) + { + Node_t *pNode; + if ( bFreeList && ( pNode = (Node_t *)m_FreeNodes.Pop() ) != NULL ) + { + pNode->elem = init; + } + else + { + pNode = new Node_t( init ); + } + Push( pNode ); + } + + bool PopItem( T *pResult) + { + Node_t *pNode = Pop(); + if ( !pNode ) + return false; + *pResult = pNode->elem; + if ( bFreeList ) + { + m_FreeNodes.Push( (TSLNodeBase_t *)pNode ); + } + else + { + delete pNode; + } + return true; + } + + int Count() + { + return m_Count; + } + +private: + Node_t *End() { return (Node_t *)this; } // just need a unique signifier + +#ifndef _WIN64 + Node_t *InterlockedCompareExchangeNode( Node_t * volatile *ppNode, Node_t *value, Node_t *comperand ) + { + return (Node_t *)::ThreadInterlockedCompareExchangePointer( (void **)ppNode, value, comperand ); + } + + bool InterlockedCompareExchangeNodeLink( NodeLink_t volatile *pLink, const NodeLink_t &value, const NodeLink_t &comperand ) + { + return ThreadInterlockedAssignIf64( (int64 *)pLink, value.value64, comperand.value64 ); + } + +#else + Node_t *InterlockedCompareExchangeNode( Node_t * volatile *ppNode, Node_t *value, Node_t *comperand ) + { + AUTO_LOCK( m_ExchangeMutex ); + Node_t *retVal = *ppNode; + if ( *ppNode == comperand ) + *ppNode = value; + return retVal; + } + + bool InterlockedCompareExchangeNodeLink( NodeLink_t volatile *pLink, const NodeLink_t &value, const NodeLink_t &comperand ) + { + AUTO_LOCK( m_ExchangeMutex ); + if ( pLink->value64 == comperand.value64 ) + { + pLink->value64 = value.value64; + return true; + } + return false; + } + + CThreadFastMutex m_ExchangeMutex; +#endif + + NodeLink_t m_Head; + NodeLink_t m_Tail; + + CInterlockedInt m_Count; + + CTSListBase m_FreeNodes; +} TSLIST_HEAD_ALIGN_POST; + +#include "tier0/memdbgoff.h" + +#endif // TSLIST_H diff --git a/external/vpc/public/tier0/validator.h b/external/vpc/public/tier0/validator.h new file mode 100644 index 0000000..a3b336e --- /dev/null +++ b/external/vpc/public/tier0/validator.h @@ -0,0 +1,73 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + + +#include "valobject.h" + +#ifndef VALIDATOR_H +#define VALIDATOR_H + +#ifdef _WIN32 +#pragma once +#endif + + +#ifdef DBGFLAG_VALIDATE + + +class CValidator +{ +public: + // Constructors & destructors + CValidator( void ); + ~CValidator( void ); + + // Call this each time we enter a new Validate function + void Push( tchar *pchType, void *pvObj, tchar *pchName ); + + // Call this each time we exit a Validate function + void Pop( void ); + + // Claim ownership of a memory block + void ClaimMemory( void *pvMem ); + + // Finish performing a check and perform necessary computations + void Finalize( void ); + + // Render our results to the console + void RenderObjects( int cubThreshold ); // Render all reported objects + void RenderLeaks( void ); // Render all memory leaks + + // List manipulation functions: + CValObject *FindObject( void *pvObj ); // Returns CValObject containing pvObj, or NULL. + void DiffAgainst( CValidator *pOtherValidator ); // Removes any entries from this validator that are also present in the other. + + // Accessors + bool BMemLeaks( void ) { return m_bMemLeaks; }; + CValObject *PValObjectFirst( void ) { return m_pValObjectFirst; }; + + void Validate( CValidator &validator, tchar *pchName ); // Validate our internal structures + + +private: + CValObject *m_pValObjectFirst; // Linked list of all ValObjects + CValObject *m_pValObjectLast; // Last ValObject on the linked list + + CValObject *m_pValObjectCur; // Object we're current processing + + int m_cpvOwned; // Total # of blocks owned + + int m_cpubLeaked; // # of leaked memory blocks + int m_cubLeaked; // Amount of leaked memory + bool m_bMemLeaks; // Has any memory leaked? +}; + + +#endif // DBGFLAG_VALIDATE + + +#endif // VALIDATOR_H diff --git a/external/vpc/public/tier0/valobject.h b/external/vpc/public/tier0/valobject.h new file mode 100644 index 0000000..8a2cbf0 --- /dev/null +++ b/external/vpc/public/tier0/valobject.h @@ -0,0 +1,72 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: CValObject is used for tracking individual objects that report +// in to CValidator. Whenever a new object reports in (via CValidator::Push), +// we create a new CValObject to aggregate stats for it. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VALOBJECT_H +#define VALOBJECT_H +#ifdef _WIN32 +#pragma once +#endif + + +#ifdef DBGFLAG_VALIDATE +class CValObject +{ +public: + // Constructors & destructors + CValObject( void ) { }; + ~CValObject( void ); + + void Init( tchar *pchType, void *pvObj, tchar *pchName, CValObject *pValObjectParent, + CValObject *pValObjectPrev ); + + // Our object has claimed ownership of a memory block + void ClaimMemoryBlock( void *pvMem ); + + // A child of ours has claimed ownership of a memory block + void ClaimChildMemoryBlock( int cubUser ); + + // Accessors + tchar *PchType( void ) { return m_rgchType; }; + void *PvObj( void ) { return m_pvObj; }; + tchar *PchName( void ) { return m_rgchName; }; + CValObject *PValObjectParent( void ) { return m_pValObjectParent; }; + int NLevel( void ) { return m_nLevel; }; + CValObject *PValObjectNext( void ) { return m_pValObjectNext; }; + int CpubMemSelf( void ) { return m_cpubMemSelf; }; + int CubMemSelf( void ) { return m_cubMemSelf; }; + int CpubMemTree( void ) { return m_cpubMemTree; }; + int CubMemTree( void ) { return m_cubMemTree; }; + int NUser( void ) { return m_nUser; }; + void SetNUser( int nUser ) { m_nUser = nUser; }; + void SetBNewSinceSnapshot( bool bNewSinceSnapshot ) { m_bNewSinceSnapshot = bNewSinceSnapshot; } + bool BNewSinceSnapshot( void ) { return m_bNewSinceSnapshot; } + +private: + bool m_bNewSinceSnapshot; // If this block is new since the snapshot. + tchar m_rgchType[64]; // Type of the object we represent + tchar m_rgchName[64]; // Name of this particular object + void *m_pvObj; // Pointer to the object we represent + + CValObject *m_pValObjectParent; // Our parent object in the tree. + int m_nLevel; // Our depth in the tree + + CValObject *m_pValObjectNext; // Next ValObject in the linked list + + int m_cpubMemSelf; // # of memory blocks we own directly + int m_cubMemSelf; // Total size of the memory blocks we own directly + + int m_cpubMemTree; // # of memory blocks owned by us and our children + int m_cubMemTree; // Total size of the memory blocks owned by us and our children + + int m_nUser; // Field provided for use by our users +}; +#endif // DBGFLAG_VALIDATE + + +#endif // VALOBJECT_H diff --git a/external/vpc/public/tier0/valve_off.h b/external/vpc/public/tier0/valve_off.h new file mode 100644 index 0000000..954a140 --- /dev/null +++ b/external/vpc/public/tier0/valve_off.h @@ -0,0 +1,33 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: This turns off all Valve-specific #defines. Because we sometimes +// call external include files from inside .cpp files, we need to +// wrap those includes like this: +// #include "tier0/valve_off.h" +// #include <external.h> +// #include "tier0/valve_on.h" +// +// $NoKeywords: $ +//=============================================================================// + + +#ifdef STEAM + +//----------------------------------------------------------------------------- +// Unicode-related #defines (see wchartypes.h) +//----------------------------------------------------------------------------- +#undef char + + +//----------------------------------------------------------------------------- +// Memory-related #defines +//----------------------------------------------------------------------------- +#undef malloc +#undef realloc +#undef _expand +#undef free + +#endif // STEAM + +// Allow long to be used in 3rd-party headers +#undef long
\ No newline at end of file diff --git a/external/vpc/public/tier0/valve_on.h b/external/vpc/public/tier0/valve_on.h new file mode 100644 index 0000000..03ab0a7 --- /dev/null +++ b/external/vpc/public/tier0/valve_on.h @@ -0,0 +1,37 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: This turns on all Valve-specific #defines. Because we sometimes +// call external include files from inside .cpp files, we need to +// wrap those includes like this: +// #include "tier0/valve_off.h" +// #include <external.h> +// #include "tier0/valve_on.h" +// +// $NoKeywords: $ +//=============================================================================// + + +#ifdef STEAM +//----------------------------------------------------------------------------- +// Unicode-related #defines (see wchartypes.h) +//----------------------------------------------------------------------------- +#ifdef ENFORCE_WCHAR +#define char DontUseChar_SeeWcharOn.h +#endif + + +//----------------------------------------------------------------------------- +// Memory-related #defines +//----------------------------------------------------------------------------- +#define malloc( cub ) HEY_DONT_USE_MALLOC_USE_PVALLOC +#define realloc( pvOld, cub ) HEY_DONT_USE_REALLOC_USE_PVREALLOC +#define _expand( pvOld, cub ) HEY_DONT_USE_EXPAND_USE_PVEXPAND +#define free( pv ) HEY_DONT_USE_FREE_USE_FREEPV + +#endif + + +// Long is evil because it's treated differently by different compilers +#ifdef DISALLOW_USE_OF_LONG + #define long long_is_the_devil_stop_using_it_use_int32_or_int64 +#endif diff --git a/external/vpc/public/tier0/vprof.h b/external/vpc/public/tier0/vprof.h new file mode 100644 index 0000000..5208e21 --- /dev/null +++ b/external/vpc/public/tier0/vprof.h @@ -0,0 +1,1510 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Real-Time Hierarchical Profiling +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VPROF_H +#define VPROF_H + +#include "tier0/dbg.h" +#include "tier0/fasttimer.h" +#include "tier0/l2cache.h" +#include "tier0/threadtools.h" +#include "tier0/vprof_sn.h" + +// VProf is enabled by default in all configurations -except- X360 Retail. +#if !( defined( _GAMECONSOLE ) && defined( _CERT ) ) +#define VPROF_ENABLED +#endif + +#if defined(_X360) && defined(VPROF_ENABLED) + +// PIX is always enabled in PROFILE build on X360 +#ifdef PROFILE +#define VPROF_PIX 1 +#endif + +#include "tier0/pmc360.h" +#ifndef USE_PIX +#define VPROF_UNDO_PIX +#undef _PIX_H_ +#undef PIXBeginNamedEvent +#undef PIXEndNamedEvent +#undef PIXSetMarker +#undef PIXNameThread +#define USE_PIX +#include <pix.h> +#undef USE_PIX +#else +#include <pix.h> +#endif +#endif + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4251) +#endif + +// enable this to get detailed nodes beneath budget +//#define VPROF_LEVEL 1 + +#if defined(_X360) || defined(_PS3) +#define VPROF_VXCONSOLE_EXISTS 1 +#endif + +#if defined(_X360) && defined(VPROF_PIX) +#pragma comment( lib, "Xapilibi" ) +#endif + +//----------------------------------------------------------------------------- +// +// Profiling instrumentation macros +// + +#define MAXCOUNTERS 256 + + +#ifdef VPROF_ENABLED + +#define VPROF_VTUNE_GROUP + +#define VPROF( name ) VPROF_(name, 1, VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, false, 0) +#define VPROF_ASSERT_ACCOUNTED( name ) VPROF_(name, 1, VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, true, 0) +#define VPROF_( name, detail, group, bAssertAccounted, budgetFlags ) VPROF_##detail(name,group, bAssertAccounted, budgetFlags) + +#define VPROF_BUDGET( name, group ) VPROF_BUDGET_FLAGS(name, group, BUDGETFLAG_OTHER) +#define VPROF_BUDGET_FLAGS( name, group, flags ) VPROF_(name, 0, group, false, flags) + +#define VPROF_SCOPE_BEGIN( tag ) do { VPROF( tag ) +#define VPROF_SCOPE_END() } while (0) + +#define VPROF_ONLY( expression ) ( expression ) + +#define VPROF_ENTER_SCOPE( name ) g_VProfCurrentProfile.EnterScope( name, 1, VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, false, 0 ) +#define VPROF_EXIT_SCOPE() g_VProfCurrentProfile.ExitScope() + +#define VPROF_BUDGET_GROUP_ID_UNACCOUNTED 0 + + +// Budgetgroup flags. These are used with VPROF_BUDGET_FLAGS. +// These control which budget panels the groups show up in. +// If a budget group uses VPROF_BUDGET, it gets the default +// which is BUDGETFLAG_OTHER. +#define BUDGETFLAG_CLIENT (1<<0) // Shows up in the client panel. +#define BUDGETFLAG_SERVER (1<<1) // Shows up in the server panel. +#define BUDGETFLAG_OTHER (1<<2) // Unclassified (the client shows these but the dedicated server doesn't). +#define BUDGETFLAG_HIDDEN (1<<15) +#define BUDGETFLAG_ALL 0xFFFF + + +// NOTE: You can use strings instead of these defines. . they are defined here and added +// in vprof.cpp so that they are always in the same order. +#define VPROF_BUDGETGROUP_OTHER_UNACCOUNTED _T("Unaccounted") +#define VPROF_BUDGETGROUP_WORLD_RENDERING _T("World Rendering") +#define VPROF_BUDGETGROUP_DISPLACEMENT_RENDERING _T("Displacement_Rendering") +#define VPROF_BUDGETGROUP_GAME _T("Game") +#define VPROF_BUDGETGROUP_NPCS _T("NPCs") +#define VPROF_BUDGETGROUP_SERVER_ANIM _T("Server Animation") +#define VPROF_BUDGETGROUP_PHYSICS _T("Physics") +#define VPROF_BUDGETGROUP_STATICPROP_RENDERING _T("Static_Prop_Rendering") +#define VPROF_BUDGETGROUP_MODEL_RENDERING _T("Other_Model_Rendering") +#define VPROF_BUDGETGROUP_MODEL_FAST_PATH_RENDERING _T("Fast Path Model Rendering") +#define VPROF_BUDGETGROUP_BRUSH_FAST_PATH_RENDERING _T("Fast Path Brush Rendering") +#define VPROF_BUDGETGROUP_BRUSHMODEL_RENDERING _T("Brush_Model_Rendering") +#define VPROF_BUDGETGROUP_SHADOW_RENDERING _T("Shadow_Rendering") +#define VPROF_BUDGETGROUP_DETAILPROP_RENDERING _T("Detail_Prop_Rendering") +#define VPROF_BUDGETGROUP_PARTICLE_RENDERING _T("Particle/Effect_Rendering") +#define VPROF_BUDGETGROUP_ROPES _T("Ropes") +#define VPROF_BUDGETGROUP_DLIGHT_RENDERING _T("Dynamic_Light_Rendering") +#define VPROF_BUDGETGROUP_OTHER_NETWORKING _T("Networking") +#define VPROF_BUDGETGROUP_CLIENT_ANIMATION _T("Client_Animation") +#define VPROF_BUDGETGROUP_OTHER_SOUND _T("Sound") +#define VPROF_BUDGETGROUP_OTHER_VGUI _T("VGUI") +#define VPROF_BUDGETGROUP_OTHER_FILESYSTEM _T("FileSystem") +#define VPROF_BUDGETGROUP_PREDICTION _T("Prediction") +#define VPROF_BUDGETGROUP_INTERPOLATION _T("Interpolation") +#define VPROF_BUDGETGROUP_SWAP_BUFFERS _T("Swap_Buffers") +#define VPROF_BUDGETGROUP_PLAYER _T("Player") +#define VPROF_BUDGETGROUP_OCCLUSION _T("Occlusion") +#define VPROF_BUDGETGROUP_OVERLAYS _T("Overlays") +#define VPROF_BUDGETGROUP_TOOLS _T("Tools") +#define VPROF_BUDGETGROUP_LIGHTCACHE _T("Light_Cache") +#define VPROF_BUDGETGROUP_DISP_HULLTRACES _T("Displacement_Hull_Traces") +#define VPROF_BUDGETGROUP_TEXTURE_CACHE _T("Texture_Cache") +#define VPROF_BUDGETGROUP_REPLAY _T("Replay") +#define VPROF_BUDGETGROUP_PARTICLE_SIMULATION _T("Particle Simulation") +#define VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING _T("Flashlight Shadows") +#define VPROF_BUDGETGROUP_CLIENT_SIM _T("Client Simulation") // think functions, tempents, etc. +#define VPROF_BUDGETGROUP_STEAM _T("Steam") +#define VPROF_BUDGETGROUP_CVAR_FIND _T("Cvar_Find") +#define VPROF_BUDGETGROUP_CLIENTLEAFSYSTEM _T("ClientLeafSystem") +#define VPROF_BUDGETGROUP_JOBS_COROUTINES _T("Jobs/Coroutines") + +#ifdef VPROF_VXCONSOLE_EXISTS +// update flags +#define VPROF_UPDATE_BUDGET 0x01 // send budget data every frame +#define VPROF_UPDATE_TEXTURE_GLOBAL 0x02 // send global texture data every frame +#define VPROF_UPDATE_TEXTURE_PERFRAME 0x04 // send perframe texture data every frame +#endif + +//------------------------------------- + +#ifndef VPROF_LEVEL +#define VPROF_LEVEL 0 +#endif + +#if !defined( VPROF_SN_LEVEL ) && !defined( _CERT ) +#define VPROF_SN_LEVEL 0 +#endif + +#define VPROF_0(name,group,assertAccounted,budgetFlags) CVProfScope VProf_(name, 0, group, assertAccounted, budgetFlags); + +#if VPROF_LEVEL > 0 +# define VPROF_1(name,group,assertAccounted,budgetFlags) CVProfScope VProf_(name, 1, group, assertAccounted, budgetFlags); +#else +# if VPROF_SN_LEVEL > 0 && defined( _PS3 ) +# define VPROF_1(name,group,assertAccounted,budgetFlags) CVProfSnMarkerScope VProfSn_( name ) +# else +# define VPROF_1(name,group,assertAccounted,budgetFlags) ((void)0) +# endif +#endif + +#if VPROF_LEVEL > 1 +#define VPROF_2(name,group,assertAccounted,budgetFlags) CVProfScope VProf_(name, 2, group, assertAccounted, budgetFlags); +#else +# if VPROF_SN_LEVEL > 1 && defined( _PS3 ) +# define VPROF_2(name,group,assertAccounted,budgetFlags) CVProfSnMarkerScope VProfSn_( name ) +# else +# define VPROF_2(name,group,assertAccounted,budgetFlags) ((void)0) +# endif +#endif + +#if VPROF_LEVEL > 2 +#define VPROF_3(name,group,assertAccounted,budgetFlags) CVProfScope VProf_(name, 3, group, assertAccounted, budgetFlags); +#else +# if VPROF_SN_LEVEL > 2 && defined( _PS3 ) +# define VPROF_3(name,group,assertAccounted,budgetFlags) CVProfSnMarkerScope VProfSn_( name ) +# else +# define VPROF_3(name,group,assertAccounted,budgetFlags) ((void)0) +# endif +#endif + +#if VPROF_LEVEL > 3 +#define VPROF_4(name,group,assertAccounted,budgetFlags) CVProfScope VProf_(name, 4, group, assertAccounted, budgetFlags); +#else +# if VPROF_SN_LEVEL > 3 && defined( _PS3 ) +# define VPROF_4(name,group,assertAccounted,budgetFlags) CVProfSnMarkerScope VProfSn_( name ) +# else +# define VPROF_4(name,group,assertAccounted,budgetFlags) ((void)0) +# endif +#endif + +//------------------------------------- + +#ifdef _MSC_VER +#define VProfCode( code ) \ + if ( 0 ) \ + ; \ + else \ + { \ + VPROF( __FUNCTION__ ": " #code ); \ + code; \ + } +#else +#define VProfCode( code ) \ + if ( 0 ) \ + ; \ + else \ + { \ + VPROF( #code ); \ + code; \ + } +#endif + + +//------------------------------------- + +#define VPROF_INCREMENT_COUNTER(name,amount) do { static CVProfCounter _counter( name ); _counter.Increment( amount ); } while( 0 ) +#define VPROF_INCREMENT_GROUP_COUNTER(name,group,amount) do { static CVProfCounter _counter( name, group ); _counter.Increment( amount ); } while( 0 ) +#define VPROF_SET_COUNTER(name,amount) do { static CVProfCounter _counter( name ); _counter.Set( amount ); } while( 0 ) +#define VPROF_SET_GROUP_COUNTER(name,group,amount) do { static CVProfCounter _counter( name, group ); _counter.Set( amount ); } while( 0 ) + +#else + +# if defined( VPROF_SN_LEVEL ) && ( VPROF_SN_LEVEL >= 0 ) +# define VPROF( name ) CVProfSnMarkerScope VProfSn_( name ) +# define VPROF_ASSERT_ACCOUNTED( name ) VPROF( name ) +# define VPROF_( name, detail, group, bAssertAccounted, budgetFlags ) VPROF_##detail( name, group, bAssertAccounted, budgetFlags ) +# define VPROF_0(name,group,assertAccounted,budgetFlags) VPROF( name ) +# define VPROF_BUDGET( name, group ) VPROF( name ) +# define VPROF_BUDGET_FLAGS( name, group, flags ) VPROF( name ) + +# define VPROF_SCOPE_BEGIN( tag ) do { VPROF( tag ) +# define VPROF_SCOPE_END() } while (0) + +# define VPROF_ONLY( expression ) ( expression ) + +# define VPROF_ENTER_SCOPE( name ) g_pfnPushMarker( name ) +# define VPROF_EXIT_SCOPE() g_pfnPopMarker() +# else +# define VPROF( name ) ((void)0) +# define VPROF_ASSERT_ACCOUNTED( name ) ((void)0) +# define VPROF_( name, detail, group, bAssertAccounted, budgetFlags ) ((void)0) +# define VPROF_0(name,group,assertAccounted,budgetFlags) ((void)0) +# define VPROF_BUDGET( name, group ) ((void)0) +# define VPROF_BUDGET_FLAGS( name, group, flags ) ((void)0) + +# define VPROF_SCOPE_BEGIN( tag ) do { +# define VPROF_SCOPE_END() } while (0) + +# define VPROF_ONLY( expression ) ((void)0) + +# define VPROF_ENTER_SCOPE( name ) +# define VPROF_EXIT_SCOPE() +# endif + +# if defined( VPROF_SN_LEVEL ) && ( VPROF_SN_LEVEL >= 1 ) +# define VPROF_1(name,group,assertAccounted,budgetFlags) VPROF( name ) +# else +# define VPROF_1(name,group,assertAccounted,budgetFlags) ((void)0) +# endif + +# if defined( VPROF_SN_LEVEL ) && ( VPROF_SN_LEVEL >= 2 ) +# define VPROF_2(name,group,assertAccounted,budgetFlags) VPROF( name ) +# else +# define VPROF_2(name,group,assertAccounted,budgetFlags) ((void)0) +# endif + +# if defined( VPROF_SN_LEVEL ) && ( VPROF_SN_LEVEL >= 3 ) +# define VPROF_3(name,group,assertAccounted,budgetFlags) VPROF( name ) +# else +# define VPROF_3(name,group,assertAccounted,budgetFlags) ((void)0) +# endif + +# if defined( VPROF_SN_LEVEL ) && ( VPROF_SN_LEVEL >= 4 ) +# define VPROF_4(name,group,assertAccounted,budgetFlags) VPROF( name ) +# else +# define VPROF_4(name,group,assertAccounted,budgetFlags) ((void)0) +# endif + + + +#define VPROF_INCREMENT_COUNTER(name,amount) ((void)0) +#define VPROF_INCREMENT_GROUP_COUNTER(name,group,amount) ((void)0) +#define VPROF_SET_COUNTER(name,amount) ((void)0) +#define VPROF_SET_GROUP_COUNTER(name,group,amount) ((void)0) + +#define VPROF_TEST_SPIKE( msec ) ((void)0) + +#define VProfCode( code ) code + +#endif + +//----------------------------------------------------------------------------- + +#ifdef VPROF_ENABLED + +//----------------------------------------------------------------------------- +// +// A node in the call graph hierarchy +// + +class PLATFORM_CLASS CVProfNode +{ +friend class CVProfRecorder; +friend class CVProfile; + +public: + CVProfNode( const tchar * pszName, int detailLevel, CVProfNode *pParent, const tchar *pBudgetGroupName, int budgetFlags ); + ~CVProfNode(); + + CVProfNode *GetSubNode( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName, int budgetFlags ); + CVProfNode *GetSubNode( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName ); + CVProfNode *GetParent(); + CVProfNode *GetSibling(); + CVProfNode *GetPrevSibling(); + CVProfNode *GetChild(); + + void MarkFrame(); + void ResetPeak(); + + void Pause(); + void Resume(); + void Reset(); + + void EnterScope(); + bool ExitScope(); + + const tchar *GetName(); + + int GetBudgetGroupID() + { + return m_BudgetGroupID; + } + + // Only used by the record/playback stuff. + void SetBudgetGroupID( int id ) + { + m_BudgetGroupID = id; + } + + int GetCurCalls(); + double GetCurTime(); + int GetPrevCalls(); + double GetPrevTime(); + int GetTotalCalls(); + double GetTotalTime(); + double GetPeakTime(); + + double GetCurTimeLessChildren(); + double GetPrevTimeLessChildren(); + double GetTotalTimeLessChildren(); + + int GetPrevL2CacheMissLessChildren(); + int GetPrevLoadHitStoreLessChildren(); + + void ClearPrevTime(); + + int GetL2CacheMisses(); + + // Not used in the common case... + void SetCurFrameTime( unsigned long milliseconds ); + + void SetClientData( int iClientData ) { m_iClientData = iClientData; } + int GetClientData() const { return m_iClientData; } + +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, tchar *pchName ); // Validate our internal structures +#endif // DBGFLAG_VALIDATE + + +// Used by vprof record/playback. +private: + + void SetUniqueNodeID( int id ) + { + m_iUniqueNodeID = id; + } + + int GetUniqueNodeID() const + { + return m_iUniqueNodeID; + } + + static int s_iCurrentUniqueNodeID; + + +private: + const tchar *m_pszName; + CFastTimer m_Timer; + + // L2 Cache data. + int m_iPrevL2CacheMiss; + int m_iCurL2CacheMiss; + int m_iTotalL2CacheMiss; + +#ifndef _X360 + // L2 Cache data. + CL2Cache m_L2Cache; +#else // 360: + + unsigned int m_iBitFlags; // see enum below for settings + CPMCData m_PMCData; + int m_iPrevLoadHitStores; + int m_iCurLoadHitStores; + int m_iTotalLoadHitStores; + + public: + enum FlagBits + { + kRecordL2 = 0x01, + kCPUTrace = 0x02, ///< cause a PIX trace inside this node. + }; + // call w/ true to enable L2 and LHS recording; false to turn it off + inline void EnableL2andLHS(bool enable) + { + if (enable) + m_iBitFlags |= kRecordL2; + else + m_iBitFlags &= (~kRecordL2); + } + + inline bool IsL2andLHSEnabled( void ) + { + return (m_iBitFlags & kRecordL2) != 0; + } + + int GetLoadHitStores(); + + private: + +#endif + + int m_nRecursions; + + unsigned m_nCurFrameCalls; + CCycleCount m_CurFrameTime; + + unsigned m_nPrevFrameCalls; + CCycleCount m_PrevFrameTime; + + unsigned m_nTotalCalls; + CCycleCount m_TotalTime; + + CCycleCount m_PeakTime; + + CVProfNode *m_pParent; + CVProfNode *m_pChild; + CVProfNode *m_pSibling; + + int m_BudgetGroupID; + + int m_iClientData; + int m_iUniqueNodeID; +}; + +//----------------------------------------------------------------------------- +// +// Coordinator and root node of the profile hierarchy tree +// + +enum VProfReportType_t +{ + VPRT_SUMMARY = ( 1 << 0 ), + VPRT_HIERARCHY = ( 1 << 1 ), + VPRT_HIERARCHY_TIME_PER_FRAME_AND_COUNT_ONLY = ( 1 << 2 ), + VPRT_LIST_BY_TIME = ( 1 << 3 ), + VPRT_LIST_BY_TIME_LESS_CHILDREN = ( 1 << 4 ), + VPRT_LIST_BY_AVG_TIME = ( 1 << 5 ), + VPRT_LIST_BY_AVG_TIME_LESS_CHILDREN = ( 1 << 6 ), + VPRT_LIST_BY_PEAK_TIME = ( 1 << 7 ), + VPRT_LIST_BY_PEAK_OVER_AVERAGE = ( 1 << 8 ), + VPRT_LIST_TOP_ITEMS_ONLY = ( 1 << 9 ), + + VPRT_FULL = (0xffffffff & ~(VPRT_HIERARCHY_TIME_PER_FRAME_AND_COUNT_ONLY|VPRT_LIST_TOP_ITEMS_ONLY)), +}; + +enum CounterGroup_t +{ + COUNTER_GROUP_DEFAULT=0, + COUNTER_GROUP_NO_RESET, // The engine doesn't reset these counters. Usually, they are used + // like global variables that can be accessed across modules. + COUNTER_GROUP_TEXTURE_GLOBAL, // Global texture usage counters (totals for what is currently in memory). + COUNTER_GROUP_TEXTURE_PER_FRAME, // Per-frame texture usage counters. + COUNTER_GROUP_GRAPHICS_PER_FRAME, // Misc graphics counters that are reset each frame +}; + +class PLATFORM_CLASS CVProfile +{ +public: + CVProfile(); + ~CVProfile(); + + void Term(); + + // + // Runtime operations + // + + void Start(); + void Stop(); + + void SetTargetThreadId( unsigned id ) { m_TargetThreadId = id; } + unsigned GetTargetThreadId() { return m_TargetThreadId; } + bool InTargetThread() { return ( m_TargetThreadId == ThreadGetCurrentId() ); } + +#ifdef VPROF_VXCONSOLE_EXISTS + enum VXConsoleReportMode_t + { + VXCONSOLE_REPORT_TIME = 0, + VXCONSOLE_REPORT_L2CACHE_MISSES, + VXCONSOLE_REPORT_LOAD_HIT_STORE, + VXCONSOLE_REPORT_COUNT, + }; + + void VXProfileStart(); + void VXProfileUpdate(); + void VXEnableUpdateMode( int event, bool bEnable ); + void VXSendNodes( void ); + + void PMCDisableAllNodes(CVProfNode *pStartNode = NULL); ///< turn off l2 and lhs recording for everywhere + bool PMCEnableL2Upon(const tchar *pszNodeName, bool bRecursive = false); ///< enable l2 and lhs recording for one given node + bool PMCDisableL2Upon(const tchar *pszNodeName, bool bRecursive = false); ///< enable l2 and lhs recording for one given node + + void DumpEnabledPMCNodes( void ); + + void VXConsoleReportMode( VXConsoleReportMode_t mode ); + void VXConsoleReportScale( VXConsoleReportMode_t mode, float flScale ); +#endif + +#ifdef _X360 + + + // the CPU trace mode is actually a small state machine; it can be off, primed for + // single capture, primed for everything-in-a-frame capture, or currently in everything-in-a-frame + // capture. + enum CPUTraceState + { + kDisabled, + kFirstHitNode, // record from the first time we hit the node until that node ends + kAllNodesInFrame_WaitingForMark, // we're going to record all the times a node is hit in a frame, but are waiting for the frame to start + kAllNodesInFrame_Recording, // we're recording all hits on a node this frame. + + // Same as above, but going to record for > 1 frame + kAllNodesInFrame_WaitingForMarkMultiFrame, // we're going to record all the times a node is hit in a frame, but are waiting for the frame to start + kAllNodesInFrame_RecordingMultiFrame, + }; + + // Global switch to turn CPU tracing on or off at all. The idea is you set up a node first, + // then trigger tracing by throwing this to true. It'll reset back to false after the trace + // happens. + inline CPUTraceState GetCPUTraceMode(); + inline void SetCPUTraceEnabled( CPUTraceState enabled, bool bTraceCompleteEvent = false, int nNumFrames = -1 ); + inline void IncrementMultiTraceIndex(); // tick up the counter that gets appended to the multi-per-frame traces + inline unsigned int GetMultiTraceIndex(); // return the counter + void CPUTraceDisableAllNodes( CVProfNode *pStartNode = NULL ); // disable the cpu trace flag wherever it may be + CVProfNode *CPUTraceEnableForNode( const tchar *pszNodeName ); // enable cpu trace on this node only, disabling it wherever else it may be on. + CVProfNode *CPUTraceGetEnabledNode( CVProfNode *pStartNode = NULL ); // return the node enabled for CPU tracing, or NULL. + const char *GetCPUTraceFilename(); // get the filename the trace should write into. + const char *SetCPUTraceFilename( const char *filename ); // set the filename the trace should write into. (don't specify the extension; I'll do that.) + inline bool TraceCompleteEvent( void ); + +#ifdef _X360 + void LatchMultiFrame( int64 cycles ); + void SpewWorstMultiFrame(); +#endif + +#endif + + void EnterScope( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName, bool bAssertAccounted ); + void EnterScope( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName, bool bAssertAccounted, int budgetFlags ); + void ExitScope(); + + void MarkFrame(); + void ResetPeaks(); + + void Pause(); + void Resume(); + void Reset(); + + bool IsEnabled() const; + int GetDetailLevel() const; + + bool AtRoot() const; + + // + // Queries + // + +#ifdef VPROF_VTUNE_GROUP +# define MAX_GROUP_STACK_DEPTH 1024 + + void EnableVTuneGroup( const tchar *pGroupName ) + { + m_nVTuneGroupID = BudgetGroupNameToBudgetGroupID( pGroupName ); + m_bVTuneGroupEnabled = true; + } + void DisableVTuneGroup( void ) + { + m_bVTuneGroupEnabled = false; + } + + inline void PushGroup( int nGroupID ); + inline void PopGroup( void ); +#endif + + int NumFramesSampled() { return m_nFrames; } + double GetPeakFrameTime(); + double GetTotalTimeSampled(); + double GetTimeLastFrame(); + + CVProfNode *GetRoot(); + CVProfNode *FindNode( CVProfNode *pStartNode, const tchar *pszNode ); + CVProfNode *GetCurrentNode(); + + void OutputReport( int type = VPRT_FULL, const tchar *pszStartNode = NULL, int budgetGroupID = -1 ); + + const tchar *GetBudgetGroupName( int budgetGroupID ); + int GetBudgetGroupFlags( int budgetGroupID ) const; // Returns a combination of BUDGETFLAG_ defines. + int GetNumBudgetGroups( void ); + void GetBudgetGroupColor( int budgetGroupID, int &r, int &g, int &b, int &a ); + int BudgetGroupNameToBudgetGroupID( const tchar *pBudgetGroupName ); + int BudgetGroupNameToBudgetGroupID( const tchar *pBudgetGroupName, int budgetFlagsToORIn ); + void RegisterNumBudgetGroupsChangedCallBack( void (*pCallBack)(void) ); + + int BudgetGroupNameToBudgetGroupIDNoCreate( const tchar *pBudgetGroupName ) { return FindBudgetGroupName( pBudgetGroupName ); } + + void HideBudgetGroup( int budgetGroupID, bool bHide = true ); + void HideBudgetGroup( const tchar *pszName, bool bHide = true ) { HideBudgetGroup( BudgetGroupNameToBudgetGroupID( pszName), bHide ); } + + int *FindOrCreateCounter( const tchar *pName, CounterGroup_t eCounterGroup=COUNTER_GROUP_DEFAULT ); + void ResetCounters( CounterGroup_t eCounterGroup ); + + int GetNumCounters( void ) const; + + const tchar *GetCounterName( int index ) const; + int GetCounterValue( int index ) const; + const tchar *GetCounterNameAndValue( int index, int &val ) const; + CounterGroup_t GetCounterGroup( int index ) const; + + // Performance monitoring events. + void PMEInitialized( bool bInit ) { m_bPMEInit = bInit; } + void PMEEnable( bool bEnable ) { m_bPMEEnabled = bEnable; } + +#ifdef _X360 + bool UsePME( void ) { return ( CPMCData::IsInitialized() && m_bPMEEnabled ); } +#elif defined( _PS3 ) + inline bool UsePME( void ) { return false; } +#else + bool UsePME( void ) { return ( m_bPMEInit && m_bPMEEnabled ); } +#endif + +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, tchar *pchName ); // Validate our internal structures +#endif // DBGFLAG_VALIDATE + +protected: + + void FreeNodes_R( CVProfNode *pNode ); + +#ifdef VPROF_VTUNE_GROUP + bool VTuneGroupEnabled() + { + return m_bVTuneGroupEnabled; + } + int VTuneGroupID() + { + return m_nVTuneGroupID; + } +#endif + + void SumTimes( const tchar *pszStartNode, int budgetGroupID ); + void SumTimes( CVProfNode *pNode, int budgetGroupID ); + void DumpNodes( CVProfNode *pNode, int indent, bool bAverageAndCountOnly ); + int FindBudgetGroupName( const tchar *pBudgetGroupName ); + int AddBudgetGroupName( const tchar *pBudgetGroupName, int budgetFlags ); + +#ifdef VPROF_VTUNE_GROUP + bool m_bVTuneGroupEnabled; + int m_nVTuneGroupID; + int m_GroupIDStack[MAX_GROUP_STACK_DEPTH]; + int m_GroupIDStackDepth; +#endif + int m_enabled; + bool m_fAtRoot; // tracked for efficiency of the "not profiling" case + CVProfNode *m_pCurNode; + CVProfNode m_Root; + int m_nFrames; + int m_ProfileDetailLevel; + int m_pausedEnabledDepth; + + class CBudgetGroup + { + public: + tchar *m_pName; + int m_BudgetFlags; + }; + + CBudgetGroup *m_pBudgetGroups; + int m_nBudgetGroupNamesAllocated; + int m_nBudgetGroupNames; + void (*m_pNumBudgetGroupsChangedCallBack)(void); + + // Performance monitoring events. + bool m_bPMEInit; + bool m_bPMEEnabled; + + int m_Counters[MAXCOUNTERS]; + char m_CounterGroups[MAXCOUNTERS]; // (These are CounterGroup_t's). + tchar *m_CounterNames[MAXCOUNTERS]; + int m_NumCounters; + +#ifdef VPROF_VXCONSOLE_EXISTS + int m_UpdateMode; + int m_nFramesRemaining; + int m_nFrameCount; + int64 m_WorstCycles; + char m_WorstTraceFilename[128]; + char m_CPUTraceFilename[128]; + unsigned int m_iSuccessiveTraceIndex; + VXConsoleReportMode_t m_ReportMode; + float m_pReportScale[VXCONSOLE_REPORT_COUNT]; + bool m_bTraceCompleteEvent; +#endif +#ifdef _X360 + CPUTraceState m_iCPUTraceEnabled; +#endif + + unsigned m_TargetThreadId; +}; + +//------------------------------------- + +PLATFORM_INTERFACE CVProfile g_VProfCurrentProfile; + +//----------------------------------------------------------------------------- + +PLATFORM_INTERFACE bool g_VProfSignalSpike; + +class CVProfSpikeDetector +{ +public: + CVProfSpikeDetector( float spike ) : + m_timeLast( GetTimeLast() ) + { + m_spike = spike; + m_Timer.Start(); + } + + ~CVProfSpikeDetector() + { + m_Timer.End(); + if ( Plat_FloatTime() - m_timeLast > 2.0 ) + { + m_timeLast = Plat_FloatTime(); + if ( m_Timer.GetDuration().GetMillisecondsF() > m_spike ) + { + g_VProfSignalSpike = true; + } + } + } + +private: + static float &GetTimeLast() { static float timeLast = 0; return timeLast; } + CFastTimer m_Timer; + float m_spike; + float &m_timeLast; +}; + + +// Macro to signal a local spike. Meant as temporary instrumentation, do not leave in code +#define VPROF_TEST_SPIKE( msec ) CVProfSpikeDetector UNIQUE_ID( msec ) + +//----------------------------------------------------------------------------- + +#ifdef VPROF_VTUNE_GROUP +inline void CVProfile::PushGroup( int nGroupID ) +{ + // There is always at least one item on the stack since we force + // the first element to be VPROF_BUDGETGROUP_OTHER_UNACCOUNTED. + Assert( m_GroupIDStackDepth > 0 ); + Assert( m_GroupIDStackDepth < MAX_GROUP_STACK_DEPTH ); + m_GroupIDStack[m_GroupIDStackDepth] = nGroupID; + m_GroupIDStackDepth++; + if( m_GroupIDStack[m_GroupIDStackDepth-2] != nGroupID && + VTuneGroupEnabled() && + nGroupID == VTuneGroupID() ) + { + vtune( true ); + } +} +#endif // VPROF_VTUNE_GROUP + +#ifdef VPROF_VTUNE_GROUP +inline void CVProfile::PopGroup( void ) +{ + m_GroupIDStackDepth--; + // There is always at least one item on the stack since we force + // the first element to be VPROF_BUDGETGROUP_OTHER_UNACCOUNTED. + Assert( m_GroupIDStackDepth > 0 ); + if( m_GroupIDStack[m_GroupIDStackDepth] != m_GroupIDStack[m_GroupIDStackDepth+1] && + VTuneGroupEnabled() && + m_GroupIDStack[m_GroupIDStackDepth+1] == VTuneGroupID() ) + { + vtune( false ); + } +} +#endif // VPROF_VTUNE_GROUP + +//----------------------------------------------------------------------------- + + +class CVProfScope: public CVProfSnMarkerScope +{ +public: + CVProfScope( const tchar * pszName, int detailLevel, const tchar *pBudgetGroupName, bool bAssertAccounted, int budgetFlags ); + ~CVProfScope(); + +private: + bool m_bEnabled; +}; + +//----------------------------------------------------------------------------- +// +// CVProfNode, inline methods +// + +inline CVProfNode::CVProfNode( const tchar * pszName, int detailLevel, CVProfNode *pParent, const tchar *pBudgetGroupName, int budgetFlags ) + : m_pszName( pszName ), + m_nCurFrameCalls( 0 ), + m_nPrevFrameCalls( 0 ), + m_nRecursions( 0 ), + m_pParent( pParent ), + m_pChild( NULL ), + m_pSibling( NULL ), + m_iClientData( -1 ) +#ifdef _X360 + , m_iBitFlags( 0 ) +#endif +{ + m_iUniqueNodeID = s_iCurrentUniqueNodeID++; + + if ( m_iUniqueNodeID > 0 ) + { + m_BudgetGroupID = g_VProfCurrentProfile.BudgetGroupNameToBudgetGroupID( pBudgetGroupName, budgetFlags ); + } + else + { + m_BudgetGroupID = 0; // "m_Root" can't call BudgetGroupNameToBudgetGroupID because g_VProfCurrentProfile not yet initialized + } + + Reset(); + + if( m_pParent && ( m_BudgetGroupID == VPROF_BUDGET_GROUP_ID_UNACCOUNTED ) ) + { + m_BudgetGroupID = m_pParent->GetBudgetGroupID(); + } +} + + +//------------------------------------- + +inline CVProfNode *CVProfNode::GetParent() +{ + Assert( m_pParent ); + return m_pParent; +} + +//------------------------------------- + +inline CVProfNode *CVProfNode::GetSibling() +{ + return m_pSibling; +} + +//------------------------------------- +// Hacky way to the previous sibling, only used from vprof panel at the moment, +// so it didn't seem like it was worth the memory waste to add the reverse +// link per node. + +inline CVProfNode *CVProfNode::GetPrevSibling() +{ + CVProfNode* p = GetParent(); + + if(!p) + return NULL; + + CVProfNode* s; + for( s = p->GetChild(); + s && ( s->GetSibling() != this ); + s = s->GetSibling() ) + ; + + return s; +} + +//------------------------------------- + +inline CVProfNode *CVProfNode::GetChild() +{ + return m_pChild; +} + +//------------------------------------- + +inline const tchar *CVProfNode::GetName() +{ + return m_pszName; +} + +//------------------------------------- + +inline int CVProfNode::GetTotalCalls() +{ + return m_nTotalCalls; +} + +//------------------------------------- + +inline double CVProfNode::GetTotalTime() +{ + return m_TotalTime.GetMillisecondsF(); +} + +//------------------------------------- + +inline int CVProfNode::GetCurCalls() +{ + return m_nCurFrameCalls; +} + +//------------------------------------- + +inline double CVProfNode::GetCurTime() +{ + return m_CurFrameTime.GetMillisecondsF(); +} + +//------------------------------------- + +inline int CVProfNode::GetPrevCalls() +{ + return m_nPrevFrameCalls; +} + +//------------------------------------- + +inline double CVProfNode::GetPrevTime() +{ + return m_PrevFrameTime.GetMillisecondsF(); +} + +//------------------------------------- + +inline double CVProfNode::GetPeakTime() +{ + return m_PeakTime.GetMillisecondsF(); +} + +//------------------------------------- + +inline double CVProfNode::GetTotalTimeLessChildren() +{ + double result = GetTotalTime(); + CVProfNode *pChild = GetChild(); + while ( pChild ) + { + result -= pChild->GetTotalTime(); + pChild = pChild->GetSibling(); + } + return result; +} + +//------------------------------------- + +inline double CVProfNode::GetCurTimeLessChildren() +{ + double result = GetCurTime(); + CVProfNode *pChild = GetChild(); + while ( pChild ) + { + result -= pChild->GetCurTime(); + pChild = pChild->GetSibling(); + } + return result; +} + +inline double CVProfNode::GetPrevTimeLessChildren() +{ + double result = GetPrevTime(); + CVProfNode *pChild = GetChild(); + while ( pChild ) + { + result -= pChild->GetPrevTime(); + pChild = pChild->GetSibling(); + } + return result; +} + +//----------------------------------------------------------------------------- +inline int CVProfNode::GetPrevL2CacheMissLessChildren() +{ + int result = m_iPrevL2CacheMiss; + CVProfNode *pChild = GetChild(); + while ( pChild ) + { + result -= pChild->m_iPrevL2CacheMiss; + pChild = pChild->GetSibling(); + } + return result; +} + +//----------------------------------------------------------------------------- +inline int CVProfNode::GetPrevLoadHitStoreLessChildren() +{ +#ifndef _X360 + return 0; +#else + int result = m_iPrevLoadHitStores; + CVProfNode *pChild = GetChild(); + while ( pChild ) + { + result -= pChild->m_iPrevLoadHitStores; + pChild = pChild->GetSibling(); + } + return result; +#endif +} + + +//----------------------------------------------------------------------------- +inline void CVProfNode::ClearPrevTime() +{ + m_PrevFrameTime.Init(); +} + +//----------------------------------------------------------------------------- +inline int CVProfNode::GetL2CacheMisses( void ) +{ +#ifndef _X360 + return m_L2Cache.GetL2CacheMisses(); +#else + return m_iTotalL2CacheMiss; +#endif +} + +#ifdef _X360 +inline int CVProfNode::GetLoadHitStores( void ) +{ + return m_iTotalLoadHitStores; +} +#endif + +//----------------------------------------------------------------------------- +// +// CVProfile, inline methods +// + +//------------------------------------- + +inline bool CVProfile::IsEnabled() const +{ + return ( m_enabled != 0 ); +} + +//------------------------------------- + +inline int CVProfile::GetDetailLevel() const +{ + return m_ProfileDetailLevel; +} + + +//------------------------------------- + +inline bool CVProfile::AtRoot() const +{ + return m_fAtRoot; +} + +//------------------------------------- + +inline void CVProfile::Start() +{ + if ( ++m_enabled == 1 ) + { + m_Root.EnterScope(); +#ifdef VPROF_VXCONSOLE_EXISTS + VXProfileStart(); +#endif +#ifdef _X360 + CPMCData::InitializeOnceProgramWide(); +#endif + } +} + +//------------------------------------- + +inline void CVProfile::Stop() +{ + if ( --m_enabled == 0 ) + m_Root.ExitScope(); +} + +//------------------------------------- + +inline void CVProfile::EnterScope( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName, bool bAssertAccounted, int budgetFlags ) +{ + if ( ( m_enabled != 0 || !m_fAtRoot ) && InTargetThread() ) // if became disabled, need to unwind back to root before stopping + { + // Only account for vprof stuff on the primary thread. + //if( !Plat_IsPrimaryThread() ) + // return; + + if ( pszName != m_pCurNode->GetName() ) + { + m_pCurNode = m_pCurNode->GetSubNode( pszName, detailLevel, pBudgetGroupName, budgetFlags ); + } + m_pBudgetGroups[m_pCurNode->GetBudgetGroupID()].m_BudgetFlags |= budgetFlags; + +#if defined( _DEBUG ) && !defined( _X360 ) + // 360 doesn't want this to allow tier0 debug/release .def files to match + if ( bAssertAccounted ) + { + // FIXME + AssertOnce( m_pCurNode->GetBudgetGroupID() != 0 ); + } +#endif + m_pCurNode->EnterScope(); + m_fAtRoot = false; + } +#if defined(_X360) && defined(VPROF_PIX) + if ( m_pCurNode->GetBudgetGroupID() != VPROF_BUDGET_GROUP_ID_UNACCOUNTED ) + PIXBeginNamedEvent( 0, pszName ); +#endif +} + +inline void CVProfile::EnterScope( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName, bool bAssertAccounted ) +{ + EnterScope( pszName, detailLevel, pBudgetGroupName, bAssertAccounted, BUDGETFLAG_OTHER ); +} + +//------------------------------------- + +inline void CVProfile::ExitScope() +{ +#if defined(_X360) && defined(VPROF_PIX) +/* +#ifdef PIXBeginNamedEvent +#error +#endif +*/ + if ( m_pCurNode->GetBudgetGroupID() != VPROF_BUDGET_GROUP_ID_UNACCOUNTED ) + PIXEndNamedEvent(); +#endif + if ( ( !m_fAtRoot || m_enabled != 0 ) && InTargetThread() ) + { + // Only account for vprof stuff on the primary thread. + //if( !Plat_IsPrimaryThread() ) + // return; + + // ExitScope will indicate whether we should back up to our parent (we may + // be profiling a recursive function) + if (m_pCurNode->ExitScope()) + { + m_pCurNode = m_pCurNode->GetParent(); + } + m_fAtRoot = ( m_pCurNode == &m_Root ); + } +} + +//------------------------------------- + +inline void CVProfile::Pause() +{ + m_pausedEnabledDepth = m_enabled; + m_enabled = 0; + if ( !AtRoot() ) + m_Root.Pause(); +} + +//------------------------------------- + +inline void CVProfile::Resume() +{ + m_enabled = m_pausedEnabledDepth; + if ( !AtRoot() ) + m_Root.Resume(); +} + +//------------------------------------- + +inline void CVProfile::Reset() +{ + m_Root.Reset(); + m_nFrames = 0; +} + +//------------------------------------- + +inline void CVProfile::ResetPeaks() +{ + m_Root.ResetPeak(); +} + +//------------------------------------- + +inline void CVProfile::MarkFrame() +{ + if ( m_enabled ) + { + ++m_nFrames; + m_Root.ExitScope(); + m_Root.MarkFrame(); + m_Root.EnterScope(); + +#ifdef _X360 + // update the CPU trace state machine if enabled + switch ( GetCPUTraceMode() ) + { + case kAllNodesInFrame_WaitingForMark: + // mark! Start recording a zillion traces. + m_iCPUTraceEnabled = kAllNodesInFrame_Recording; + break; + case kAllNodesInFrame_WaitingForMarkMultiFrame: + m_iCPUTraceEnabled = kAllNodesInFrame_RecordingMultiFrame; + break; + case kAllNodesInFrame_Recording: + // end of frame. stop recording if no more frames needed + m_iCPUTraceEnabled = kDisabled; + Msg("Frame ended. Recording no more CPU traces\n"); + + break; + case kAllNodesInFrame_RecordingMultiFrame: + // end of frame. stop recording if no more frames needed + if ( --m_nFramesRemaining == 0 ) + { + m_iCPUTraceEnabled = kDisabled; + Msg("Frames ended. Recording no more CPU traces\n"); + + SpewWorstMultiFrame(); + } + + ++m_nFrameCount; + + break; + default: + // no default + break; + } +#endif + } +} + +//------------------------------------- + +inline double CVProfile::GetTotalTimeSampled() +{ + return m_Root.GetTotalTime(); +} + +//------------------------------------- + +inline double CVProfile::GetPeakFrameTime() +{ + return m_Root.GetPeakTime(); +} + +//------------------------------------- + +inline double CVProfile::GetTimeLastFrame() +{ + return m_Root.GetCurTime(); +} + +//------------------------------------- + +inline CVProfNode *CVProfile::GetRoot() +{ + return &m_Root; +} + +//------------------------------------- + +inline CVProfNode *CVProfile::GetCurrentNode() +{ + return m_pCurNode; +} + + +inline const tchar *CVProfile::GetBudgetGroupName( int budgetGroupID ) +{ + Assert( budgetGroupID >= 0 && budgetGroupID < m_nBudgetGroupNames ); + return m_pBudgetGroups[budgetGroupID].m_pName; +} + +inline int CVProfile::GetBudgetGroupFlags( int budgetGroupID ) const +{ + Assert( budgetGroupID >= 0 && budgetGroupID < m_nBudgetGroupNames ); + return m_pBudgetGroups[budgetGroupID].m_BudgetFlags; +} + +#ifdef _X360 + +inline CVProfile::CPUTraceState CVProfile::GetCPUTraceMode() +{ + return m_iCPUTraceEnabled; +} + +inline void CVProfile::SetCPUTraceEnabled( CPUTraceState enabled, bool bTraceCompleteEvent /*=true*/, int nNumFrames /*= -1*/ ) +{ + m_iCPUTraceEnabled = enabled; + m_bTraceCompleteEvent = bTraceCompleteEvent; + if ( nNumFrames != -1 ) + { + m_nFramesRemaining = nNumFrames; + m_nFrameCount = 0; + m_WorstCycles = 0; + m_WorstTraceFilename[ 0 ] = 0; + } +} + +inline void CVProfile::IncrementMultiTraceIndex() +{ + ++m_iSuccessiveTraceIndex; +} + +inline unsigned int CVProfile::GetMultiTraceIndex() +{ + return m_iSuccessiveTraceIndex; +} + +#endif + + +//----------------------------------------------------------------------------- + +inline CVProfScope::CVProfScope( const tchar * pszName, int detailLevel, const tchar *pBudgetGroupName, bool bAssertAccounted, int budgetFlags ): + CVProfSnMarkerScope( pszName ), + m_bEnabled( g_VProfCurrentProfile.IsEnabled() ) +{ + if ( m_bEnabled ) + { + g_VProfCurrentProfile.EnterScope( pszName, detailLevel, pBudgetGroupName, bAssertAccounted, budgetFlags ); + } +} + +//------------------------------------- + +inline CVProfScope::~CVProfScope() +{ + if ( m_bEnabled ) + { + g_VProfCurrentProfile.ExitScope(); + } +} + +class CVProfCounter +{ +public: + CVProfCounter( const tchar *pName, CounterGroup_t group=COUNTER_GROUP_DEFAULT ) + { + m_pCounter = g_VProfCurrentProfile.FindOrCreateCounter( pName, group ); + Assert( m_pCounter ); + } + ~CVProfCounter() + { + } + void Increment( int val ) + { + Assert( m_pCounter ); + *m_pCounter += val; + } + void Set( int val ) + { + Assert( m_pCounter ); + *m_pCounter = val; + } +private: + int *m_pCounter; +}; + +#endif + +#ifdef _X360 + +#include "xbox/xbox_console.h" +#include "tracerecording.h" +#include "tier1/fmtstr.h" +#pragma comment( lib, "tracerecording.lib" ) +#pragma comment( lib, "xbdm.lib" ) + +class CPIXRecorder +{ +public: + CPIXRecorder() : m_bActive( false ) {} + ~CPIXRecorder() { Stop(); } + + void Start( const char *pszFilename = "capture" ) + { + if ( !m_bActive ) + { + if ( !XTraceStartRecording( CFmtStr( "e:\\%s.pix2", pszFilename ) ) ) + { + Msg( "XTraceStartRecording failed, error code %d\n", GetLastError() ); + } + else + { + m_bActive = true; + } + } + } + + void Stop() + { + if ( m_bActive ) + { + m_bActive = false; + if ( XTraceStopRecording() ) + { + Msg( "CPU trace finished.\n" ); + // signal VXConsole that trace is completed + XBX_rTraceComplete(); + } + } + } + +private: + bool m_bActive; +}; + +#define VPROF_BEGIN_PIX_BLOCK( convar ) \ + { \ + bool bRunPix = 0; \ + static CFastTimer PIXTimer; \ + extern ConVar convar; \ + ConVar &PIXConvar = convar; \ + CPIXRecorder PIXRecorder; \ + { \ + PIXLabel: \ + if ( bRunPix ) \ + { \ + PIXRecorder.Start(); \ + } \ + else \ + { \ + if ( PIXConvar.GetBool() ) \ + { \ + PIXTimer.Start(); \ + } \ + } \ + { + + +#define VPROF_END_PIX_BLOCK() \ + } \ + \ + if ( !bRunPix ) \ + { \ + if ( PIXConvar.GetBool() ) \ + { \ + PIXTimer.End(); \ + if ( PIXTimer.GetDuration().GetMillisecondsF() > PIXConvar.GetFloat() ) \ + { \ + PIXConvar.SetValue( 0 ); \ + bRunPix = true; \ + goto PIXLabel; \ + } \ + } \ + } \ + else \ + { \ + PIXRecorder.Stop(); \ + } \ + } \ + } +#else +#define VPROF_BEGIN_PIX_BLOCK( PIXConvar ) { +#define VPROF_END_PIX_BLOCK() } +#endif + + +#ifdef VPROF_UNDO_PIX +#undef USE_PIX +#undef _PIX_H_ +#undef PIXBeginNamedEvent +#undef PIXEndNamedEvent +#undef PIXSetMarker +#undef PIXNameThread +#include <pix.h> +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif + +//============================================================================= diff --git a/external/vpc/public/tier0/vprof_sn.h b/external/vpc/public/tier0/vprof_sn.h new file mode 100644 index 0000000..ecf776f --- /dev/null +++ b/external/vpc/public/tier0/vprof_sn.h @@ -0,0 +1,31 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +#ifndef TIER_V0PROF_SN_HDR +#define TIER_V0PROF_SN_HDR + +// enable this to get detailed SN Tuner markers. PS3 specific +#if defined( SN_TARGET_PS3 ) && !defined(_CERT) +#define VPROF_SN_LEVEL 0 + +extern "C" void(*g_pfnPushMarker)( const char * pName ); +extern "C" void(*g_pfnPopMarker)(); + +class CVProfSnMarkerScope +{ +public: + CVProfSnMarkerScope( const char * pszName ) + { + g_pfnPushMarker( pszName ); + } + ~CVProfSnMarkerScope() + { + g_pfnPopMarker( ); + } +}; + +#else + +class CVProfSnMarkerScope { public: CVProfSnMarkerScope( const char * ) {} }; + +#endif + +#endif
\ No newline at end of file diff --git a/external/vpc/public/tier0/wchartypes.h b/external/vpc/public/tier0/wchartypes.h new file mode 100644 index 0000000..8446b68 --- /dev/null +++ b/external/vpc/public/tier0/wchartypes.h @@ -0,0 +1,101 @@ +//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: All of our code is completely Unicode. Instead of char, you should +// use wchar, uint8, or char8, as explained below. +// +// $NoKeywords: $ +//=============================================================================// + + +#ifndef WCHARTYPES_H +#define WCHARTYPES_H +#ifdef _WIN32 +#pragma once +#endif +#include "stddef.h" +#ifdef _INC_TCHAR +#error ("Must include tier0 type headers before tchar.h") +#endif + +// Temporarily turn off Valve defines +#include "tier0/valve_off.h" + +#if !defined(_WCHAR_T_DEFINED) && !defined( __WCHAR_TYPE__ ) && !defined(GNUC) +typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif + +// char8 +// char8 is equivalent to char, and should be used when you really need a char +// (for example, when calling an external function that's declared to take +// chars). +typedef char char8; + +// uint8 +// uint8 is equivalent to byte (but is preferred over byte for clarity). Use this +// whenever you mean a byte (for example, one byte of a network packet). +// uint8 itself is defined in platform.h +typedef unsigned char BYTE; +typedef unsigned char byte; + +// wchar +// wchar is a single character of text (currently 16 bits, as all of our text is +// Unicode). Use this whenever you mean a piece of text (for example, in a string). +typedef wchar_t wchar; +//typedef char wchar; + +// __WFILE__ +// This is a Unicode version of __FILE__ +#define WIDEN2(x) L ## x +#define WIDEN(x) WIDEN2(x) +#define __WFILE__ WIDEN(__FILE__) + +#ifdef STEAM +#ifndef _UNICODE +#define FORCED_UNICODE +#endif +#define _UNICODE +#endif + +#if defined( POSIX ) || defined( _PS3 ) +#define _tcsstr strstr +#define _tcsicmp stricmp +#define _tcscmp strcmp +#define _tcscpy strcpy +#define _tcsncpy strncpy +#define _tcsrchr strrchr +#define _tcslen strlen +#define _tfopen fopen +#define _stprintf sprintf +#define _ftprintf fprintf +#define _vsntprintf _vsnprintf +#define _tprintf printf +#define _sntprintf _snprintf +#define _T(s) s +#else +#include <tchar.h> +#endif + +#if defined(_UNICODE) +typedef wchar tchar; +#define tstring wstring +#define __TFILE__ __WFILE__ +#define TCHAR_IS_WCHAR +#else +typedef char tchar; +#define tstring string +#define __TFILE__ __FILE__ +#define TCHAR_IS_CHAR +#endif + +#ifdef FORCED_UNICODE +#undef _UNICODE +#endif + +// Turn valve defines back on +#include "tier0/valve_on.h" + + +#endif // WCHARTYPES + + diff --git a/external/vpc/public/tier0/win32consoleio.h b/external/vpc/public/tier0/win32consoleio.h new file mode 100644 index 0000000..92b3914 --- /dev/null +++ b/external/vpc/public/tier0/win32consoleio.h @@ -0,0 +1,32 @@ +//======= Copyright � 1996-2006, Valve Corporation, All rights reserved. ====== +// +// Purpose: Win32 Console API helpers +// +//============================================================================= +#ifndef WIN32_CONSOLE_IO_H +#define WIN32_CONSOLE_IO_H + +#if defined( COMPILER_MSVC ) +#pragma once +#endif + +// Function to attach a console for I/O to a Win32 GUI application in a reasonably smart fashion. +PLATFORM_INTERFACE bool SetupWin32ConsoleIO(); + +// Win32 Console Color API Helpers, originally from cmdlib. + +struct Win32ConsoleColorContext_t +{ + int m_InitialColor; + uint16 m_LastColor; + uint16 m_BadColor; + uint16 m_BackgroundFlags; +}; + +PLATFORM_INTERFACE void InitWin32ConsoleColorContext( Win32ConsoleColorContext_t *pContext ); + +PLATFORM_INTERFACE uint16 SetWin32ConsoleColor( Win32ConsoleColorContext_t *pContext, int nRed, int nGreen, int nBlue, int nIntensity ); + +PLATFORM_INTERFACE void RestoreWin32ConsoleColor( Win32ConsoleColorContext_t *pContext, uint16 prevColor ); + +#endif diff --git a/external/vpc/public/tier0/xbox_codeline_defines.h b/external/vpc/public/tier0/xbox_codeline_defines.h new file mode 100644 index 0000000..3f7b544 --- /dev/null +++ b/external/vpc/public/tier0/xbox_codeline_defines.h @@ -0,0 +1,16 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef XBOX_CODELINE_DEFINES_H +#define XBOX_CODELINE_DEFINES_H + + +// In the regular src_main codeline, we leave this out. +//#define IN_XBOX_CODELINE + + +#endif // XBOX_CODELINE_DEFINES_H |