This commit is contained in:
nephacks
2025-06-04 03:22:50 +02:00
parent f234f23848
commit f12416cffd
14243 changed files with 6446499 additions and 26 deletions

480
public/tier0/EventMasks.h Normal file
View File

@@ -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);

1787
public/tier0/EventModes.h Normal file

File diff suppressed because it is too large Load Diff

29
public/tier0/IOCTLCodes.h Normal file
View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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

212
public/tier0/PMELib.h Normal file
View File

@@ -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

View File

@@ -0,0 +1,456 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
// File extracted from MFC due to symbol conflicts
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#ifdef AFX_CORE1_SEG
#pragma code_seg(AFX_CORE1_SEG)
#endif
/////////////////////////////////////////////////////////////////////////////
// Debug memory globals and implementation helpers
#ifdef _DEBUG // most of this file is for debugging
void* __cdecl operator new(size_t nSize, int nType, LPCSTR lpszFileName, int nLine);
#if _MSC_VER >= 1210
void* __cdecl operator new[](size_t nSize, int nType, LPCSTR lpszFileName, int nLine);
#endif
/////////////////////////////////////////////////////////////////////////////
// test allocation routines
void* PASCAL CObject::operator new(size_t nSize)
{
#ifdef _AFX_NO_DEBUG_CRT
return ::operator new(nSize);
#else
return ::operator new(nSize, _AFX_CLIENT_BLOCK, NULL, 0);
#endif // _AFX_NO_DEBUG_CRT
}
void PASCAL CObject::operator delete(void* p)
{
#ifdef _AFX_NO_DEBUG_CRT
free(p);
#else
_free_dbg(p, _AFX_CLIENT_BLOCK);
#endif
}
#if _MSC_VER >= 1200
void PASCAL CObject::operator delete(void* p, void*)
{
#ifdef _AFX_NO_DEBUG_CRT
free(p);
#else
_free_dbg(p, _AFX_CLIENT_BLOCK);
#endif
}
#endif
#ifndef _AFX_NO_DEBUG_CRT
void* __cdecl operator new(size_t nSize, LPCSTR lpszFileName, int nLine)
{
return ::operator new(nSize, _NORMAL_BLOCK, lpszFileName, nLine);
}
#if _MSC_VER >= 1210
void* __cdecl operator new[](size_t nSize, LPCSTR lpszFileName, int nLine)
{
return ::operator new[](nSize, _NORMAL_BLOCK, lpszFileName, nLine);
}
#endif
#if _MSC_VER >= 1200
void __cdecl operator delete(void* pData, LPCSTR /* lpszFileName */,
int /* nLine */)
{
::operator delete(pData);
}
#endif
#if _MSC_VER >= 1210
void __cdecl operator delete[](void* pData, LPCSTR /* lpszFileName */,
int /* nLine */)
{
::operator delete(pData);
}
#endif
void* PASCAL
CObject::operator new(size_t nSize, LPCSTR lpszFileName, int nLine)
{
return ::operator new(nSize, _AFX_CLIENT_BLOCK, lpszFileName, nLine);
}
#if _MSC_VER >= 1200
void PASCAL
CObject::operator delete(void *pObject, LPCSTR /* lpszFileName */,
int /* nLine */)
{
#ifdef _AFX_NO_DEBUG_CRT
free(pObject);
#else
_free_dbg(pObject, _AFX_CLIENT_BLOCK);
#endif
}
#endif
void* AFXAPI AfxAllocMemoryDebug(size_t nSize, BOOL bIsObject, LPCSTR lpszFileName, int nLine)
{
return _malloc_dbg(nSize, bIsObject ? _AFX_CLIENT_BLOCK : _NORMAL_BLOCK,
lpszFileName, nLine);
}
void AFXAPI AfxFreeMemoryDebug(void* pbData, BOOL bIsObject)
{
_free_dbg(pbData, bIsObject ? _AFX_CLIENT_BLOCK : _NORMAL_BLOCK);
}
/////////////////////////////////////////////////////////////////////////////
// allocation failure hook, tracking turn on
BOOL AFXAPI _AfxDefaultAllocHook(size_t, BOOL, LONG)
{ return TRUE; }
AFX_STATIC_DATA AFX_ALLOC_HOOK pfnAllocHook = _AfxDefaultAllocHook;
AFX_STATIC_DATA _CRT_ALLOC_HOOK pfnCrtAllocHook = NULL;
#if _MSC_VER >= 1200
int __cdecl _AfxAllocHookProxy(int nAllocType, void * pvData, size_t nSize,
int nBlockUse, long lRequest, const unsigned char * szFilename, int nLine)
#else
int __cdecl _AfxAllocHookProxy(int nAllocType, void * pvData, size_t nSize,
int nBlockUse, long lRequest, const char * szFilename, int nLine)
#endif
{
#if _MSC_VER >= 1200
if (nAllocType != _HOOK_ALLOC)
return (pfnCrtAllocHook)(nAllocType, pvData, nSize,
nBlockUse, lRequest, (const unsigned char*) szFilename, nLine);
if ((pfnAllocHook)(nSize, _BLOCK_TYPE(nBlockUse) == _AFX_CLIENT_BLOCK, lRequest))
return (pfnCrtAllocHook)(nAllocType, pvData, nSize,
nBlockUse, lRequest, (const unsigned char*) szFilename, nLine);
#else
if (nAllocType != _HOOK_ALLOC)
return (pfnCrtAllocHook)(nAllocType, pvData, nSize,
nBlockUse, lRequest, szFilename, nLine);
if ((pfnAllocHook)(nSize, _BLOCK_TYPE(nBlockUse) == _AFX_CLIENT_BLOCK, lRequest))
return (pfnCrtAllocHook)(nAllocType, pvData, nSize,
nBlockUse, lRequest, szFilename, nLine);
#endif
return FALSE;
}
AFX_ALLOC_HOOK AFXAPI AfxSetAllocHook(AFX_ALLOC_HOOK pfnNewHook)
{
if (pfnCrtAllocHook == NULL)
pfnCrtAllocHook = _CrtSetAllocHook(_AfxAllocHookProxy);
AFX_ALLOC_HOOK pfnOldHook = pfnAllocHook;
pfnAllocHook = pfnNewHook;
return pfnOldHook;
}
// This can be set to TRUE to override all AfxEnableMemoryTracking calls,
// allowing all allocations, even MFC internal allocations to be tracked.
BOOL _afxMemoryLeakOverride = FALSE;
BOOL AFXAPI AfxEnableMemoryTracking(BOOL bTrack)
{
if (_afxMemoryLeakOverride)
return TRUE;
int nOldState = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
if (bTrack)
_CrtSetDbgFlag(nOldState | _CRTDBG_ALLOC_MEM_DF);
else
_CrtSetDbgFlag(nOldState & ~_CRTDBG_ALLOC_MEM_DF);
return nOldState & _CRTDBG_ALLOC_MEM_DF;
}
/////////////////////////////////////////////////////////////////////////////
// stop on a specific memory request
// Obsolete API
void AFXAPI AfxSetAllocStop(LONG lRequestNumber)
{
_CrtSetBreakAlloc(lRequestNumber);
}
BOOL AFXAPI AfxCheckMemory()
// check all of memory (look for memory tromps)
{
return _CrtCheckMemory();
}
// -- true if block of exact size, allocated on the heap
// -- set *plRequestNumber to request number (or 0)
BOOL AFXAPI AfxIsMemoryBlock(const void* pData, UINT nBytes,
LONG* plRequestNumber)
{
return _CrtIsMemoryBlock(pData, nBytes, plRequestNumber, NULL, NULL);
}
/////////////////////////////////////////////////////////////////////////////
// CMemoryState
CMemoryState::CMemoryState()
{
memset(this, 0, sizeof(*this));
}
void CMemoryState::UpdateData()
{
for(int i = 0; i < nBlockUseMax; i++)
{
m_lCounts[i] = m_memState.lCounts[i];
m_lSizes[i] = m_memState.lSizes[i];
}
m_lHighWaterCount = m_memState.lHighWaterCount;
m_lTotalCount = m_memState.lTotalCount;
}
// fills 'this' with the difference, returns TRUE if significant
BOOL CMemoryState::Difference(const CMemoryState& oldState,
const CMemoryState& newState)
{
int nResult = _CrtMemDifference(&m_memState, &oldState.m_memState, &newState.m_memState);
UpdateData();
return nResult != 0;
}
void CMemoryState::DumpStatistics() const
{
_CrtMemDumpStatistics(&m_memState);
}
// -- fill with current memory state
void CMemoryState::Checkpoint()
{
_CrtMemCheckpoint(&m_memState);
UpdateData();
}
// Dump objects created after this memory state was checkpointed
// Will dump all objects if this memory state wasn't checkpointed
// Dump all objects, report about non-objects also
// List request number in {}
void CMemoryState::DumpAllObjectsSince() const
{
_CrtMemDumpAllObjectsSince(&m_memState);
}
/////////////////////////////////////////////////////////////////////////////
// Enumerate all objects allocated in the diagnostic memory heap
struct _AFX_ENUM_CONTEXT
{
void (*m_pfn)(CObject*,void*);
void* m_pContext;
};
AFX_STATIC void _AfxDoForAllObjectsProxy(void* pObject, void* pContext)
{
_AFX_ENUM_CONTEXT* p = (_AFX_ENUM_CONTEXT*)pContext;
(*p->m_pfn)((CObject*)pObject, p->m_pContext);
}
void AFXAPI
AfxDoForAllObjects(void (AFX_CDECL *pfn)(CObject*, void*), void* pContext)
{
if (pfn == NULL)
{
AfxThrowInvalidArgException();
}
_AFX_ENUM_CONTEXT context;
context.m_pfn = pfn;
context.m_pContext = pContext;
_CrtDoForAllClientObjects(_AfxDoForAllObjectsProxy, &context);
}
/////////////////////////////////////////////////////////////////////////////
// Automatic debug memory diagnostics
BOOL AFXAPI AfxDumpMemoryLeaks()
{
return _CrtDumpMemoryLeaks();
}
#endif // _AFX_NO_DEBUG_CRT
#endif // _DEBUG
/////////////////////////////////////////////////////////////////////////////
// Non-diagnostic memory routines
int AFX_CDECL AfxNewHandler(size_t /* nSize */)
{
AfxThrowMemoryException();
}
#pragma warning(disable: 4273)
#ifndef _AFXDLL
_PNH _afxNewHandler = &AfxNewHandler;
#endif
_PNH AFXAPI AfxGetNewHandler(void)
{
#ifdef _AFXDLL
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
return pState->m_pfnNewHandler;
#else
return _afxNewHandler;
#endif
}
_PNH AFXAPI AfxSetNewHandler(_PNH pfnNewHandler)
{
#ifdef _AFXDLL
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
_PNH pfnOldHandler = pState->m_pfnNewHandler;
pState->m_pfnNewHandler = pfnNewHandler;
return pfnOldHandler;
#else
_PNH pfnOldHandler = _afxNewHandler;
_afxNewHandler = pfnNewHandler;
return pfnOldHandler;
#endif
}
AFX_STATIC_DATA const _PNH _pfnUninitialized = (_PNH)-1;
void* __cdecl operator new(size_t nSize)
{
void* pResult;
#ifdef _AFXDLL
_PNH pfnNewHandler = _pfnUninitialized;
#endif
for (;;)
{
#if !defined(_AFX_NO_DEBUG_CRT) && defined(_DEBUG)
pResult = _malloc_dbg(nSize, _NORMAL_BLOCK, NULL, 0);
#else
pResult = malloc(nSize);
#endif
if (pResult != NULL)
return pResult;
#ifdef _AFXDLL
if (pfnNewHandler == _pfnUninitialized)
{
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
pfnNewHandler = pState->m_pfnNewHandler;
}
if (pfnNewHandler == NULL || (*pfnNewHandler)(nSize) == 0)
break;
#else
if (_afxNewHandler == NULL || (*_afxNewHandler)(nSize) == 0)
break;
#endif
}
return pResult;
}
void __cdecl operator delete(void* p)
{
#if !defined(_AFX_NO_DEBUG_CRT) && defined(_DEBUG)
_free_dbg(p, _NORMAL_BLOCK);
#else
free(p);
#endif
}
#if _MSC_VER >= 1210
void* __cdecl operator new[](size_t nSize)
{
return ::operator new(nSize);
}
void __cdecl operator delete[](void* p)
{
::operator delete(p);
}
#endif
#ifdef _DEBUG
void* __cdecl operator new(size_t nSize, int nType, LPCSTR lpszFileName, int nLine)
{
#ifdef _AFX_NO_DEBUG_CRT
UNUSED_ALWAYS(nType);
UNUSED_ALWAYS(lpszFileName);
UNUSED_ALWAYS(nLine);
return ::operator new(nSize);
#else
void* pResult;
#ifdef _AFXDLL
_PNH pfnNewHandler = _pfnUninitialized;
#endif
for (;;)
{
pResult = _malloc_dbg(nSize, nType, lpszFileName, nLine);
if (pResult != NULL)
return pResult;
#ifdef _AFXDLL
if (pfnNewHandler == _pfnUninitialized)
{
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
pfnNewHandler = pState->m_pfnNewHandler;
}
if (pfnNewHandler == NULL || (*pfnNewHandler)(nSize) == 0)
break;
#else
if (_afxNewHandler == NULL || (*_afxNewHandler)(nSize) == 0)
break;
#endif
}
return pResult;
#endif
}
#if _MSC_VER >= 1700
void __cdecl operator delete(void* p, int nType, LPCSTR /* lpszFileName */, int /* nLine */)
{
#if !defined(_AFX_NO_DEBUG_CRT) && defined(_DEBUG)
_free_dbg(p, nType);
#else
free(p);
#endif
}
#endif // _MSC_VER >= 1200
#if _MSC_VER >= 1700
void* __cdecl operator new[](size_t nSize, int nType, LPCSTR lpszFileName, int nLine)
{
return ::operator new(nSize, nType, lpszFileName, nLine);
}
void __cdecl operator delete[](void* p, int nType, LPCSTR lpszFileName, int nLine)
{
::operator delete(p, nType, lpszFileName, nLine);
}
#endif // _MSC_VER >= 1210
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////

116
public/tier0/annotations.h Normal file
View File

@@ -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

700
public/tier0/basetypes.h Normal file
View File

@@ -0,0 +1,700 @@
//========= 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
#define noschema
#define schema_pragma( ... )
#define META( ... )
#define TYPEMETA( ... )
#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)
#if defined( __SPU__ )
#include <spu_intrinsics.h>
#else
#include <ppu_intrinsics.h>
#include <sys/fs.h>
#endif
#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;
}
// This is the preferred clamp operator. Using the clamp macro can lead to
// unexpected side-effects or more expensive code. Even the clamp (all
// lower-case) function can generate more expensive code because of the
// mixed types involved.
template< class T >
T Clamp( T const &val, T const &minVal, T const &maxVal )
{
if( val < minVal )
return minVal;
else if( val > maxVal )
return maxVal;
else
return val;
}
// This is the preferred Min operator. Using the MIN macro can lead to unexpected
// side-effects or more expensive code.
template< class T >
T Min( T const &val1, T const &val2 )
{
return val1 < val2 ? val1 : val2;
}
// This is the preferred Max operator. Using the MAX macro can lead to unexpected
// side-effects or more expensive code.
template< class T >
T Max( T const &val1, T const &val2 )
{
return val1 > val2 ? val1 : val2;
}
template <typename T>
void Swap( T &a, T &b )
{
T temp = a;
a = b;
b = temp;
}
#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
#if defined(__SPU__)
#define fsel(c,x,y) ( (c) >= 0 ? (x) : (y) )
#define __fsel fsel
#define __fsels fsel
#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
#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 unsigned long& FloatBits( vec_t& f )
{
return *reinterpret_cast<unsigned long*>(&f);
}
inline unsigned long const& FloatBits( vec_t const& f )
{
return *reinterpret_cast<unsigned long const*>(&f);
}
inline vec_t BitsToFloat( unsigned long i )
{
return *reinterpret_cast<vec_t*>(&i);
}
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 void EnsureValidValue( color32_s &x ) { x.r = x.g = x.b = x.a = 0; }
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(x) (void)(x) // 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

View File

@@ -0,0 +1,57 @@
#ifndef TIER0_CACHE_HINTS_HDR
#define TIER0_CACHE_HINTS_HDR
#if defined(_X360)
#define PREFETCH_128(POINTER,OFFSET) { __dcbt((OFFSET), (POINTER)); }
#define PREZERO_128(POINTER, OFFSET) { __dcbz128((OFFSET), (POINTER)); }
#elif defined( _PS3 ) && !defined( SPU )
#define PREFETCH_128(POINTER,OFFSET) { __dcbt( ( char * )( POINTER ) + ( size_t )( OFFSET ) ); }
#define PREZERO_128(POINTER,OFFSET) { __dcbz( ( char * )( POINTER ) + ( size_t )( OFFSET ) ); }
#elif defined(WIN32)
// NOTE: In every case I've tested so far using this prefetch on PC is actually slower. Changing it actually
// prefetch 128-bytes (tested on a PC with 64-byte cache lines) makes it even slower
// It is much more difficult to improve performance with prefetch on the PC. I suggest trying to make your data
// linear and let the hardware prefetch do the work for you. Otherwise you can prefetch in 64-byte chunks with this:
#define PREFETCH_64_PC(POINTER,OFFSET) { _mm_prefetch((const char*)(POINTER) + (OFFSET), _MM_HINT_T0); }
// leave this empty because we can't improve perf of any existing cases by defining it
#define PREFETCH_128(POINTER,OFFSET) { /* Nothing to do here */ }
// The concept of zeroing the cache does not exist the same way on PC. Nevertheless, simulate the same behavior.
#define PREZERO_128(POINTER,OFFSET) \
{ \
intptr_t __tempPtr__ = (intptr_t)((char *)(POINTER) + (OFFSET)); \
__tempPtr__ &= -128; \
memset((void*)__tempPtr__, 0, 128); \
}
#else
// Same for other platforms.
#define PREFETCH_128(POINTER,OFFSET) { /* Nothing to do here */ }
#define PREZERO_128(POINTER,OFFSET) \
{ \
intptr_t __tempPtr__ = (intptr_t)((char *)(POINTER) + (OFFSET)); \
__tempPtr__ &= -128; \
memset((void*)__tempPtr__, 0, 128); \
}
#endif
// This exists for backward compatibility until a massive search and replace is done
#define PREFETCH_CACHE_LINE PREFETCH_128
// Indicate that the cache line is 128. It is not correct on PC, but this will have no side effects related to the macros above.
#define CACHE_LINE_SIZE 128
#ifdef IVP_VECTOR_INCLUDED
template<class T>
inline void UnsafePrefetchLastElementOf(IVP_U_Vector<T>&array)
{
PREFETCH_128(array.element_at(array.len()-1),0);
}
template<class T>
inline void PrefetchLastElementOf(IVP_U_Vector<T>&array)
{
if(array.len() > 0)
PREFETCH_128(array.element_at(array.len()-1),0);
}
#endif
#endif

174
public/tier0/commonmacros.h Normal file
View File

@@ -0,0 +1,174 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef COMMONMACROS_H
#define COMMONMACROS_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/platform.h"
// -------------------------------------------------------
//
// 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 SETBITS(iBitVector, bits) ((iBitVector) |= (bits))
#define CLEARBITS(iBitVector, bits) ((iBitVector) &= ~(bits))
#define FBitSet(iBitVector, bits) ((iBitVector) & (bits))
template <typename T>
inline bool IsPowerOfTwo( T value )
{
return (value & ( value - (T)1 )) == (T)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) && \
(_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];
#ifdef _PREFAST_
// The +0 is so that we can go:
// size = ARRAYSIZE(array) * sizeof(array[0]) without triggering a /analyze
// warning about multiplying sizeof.
#define RTL_NUMBER_OF_V2(A) (sizeof(*RtlpNumberOf(A))+0)
#else
#define RTL_NUMBER_OF_V2(A) (sizeof(*RtlpNumberOf(A)))
#endif
// 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)
#define Q_ARRAYSIZE(p) ARRAYSIZE(p)
#define V_ARRAYSIZE(p) ARRAYSIZE(p)
template< typename IndexType, typename T, unsigned int N >
IndexType ClampedArrayIndex( const T (&buffer)[N], IndexType index )
{
NOTE_UNUSED( buffer );
return clamp( index, 0, (IndexType)N - 1 );
}
template< typename T, unsigned int N >
T ClampedArrayElement( const T (&buffer)[N], unsigned int uIndex )
{
// Put index in an unsigned type to halve the clamping.
if ( uIndex >= N )
uIndex = N - 1;
return buffer[ uIndex ];
}
#endif // COMMONMACROS_H

View File

@@ -0,0 +1,33 @@
#ifndef CPU_MONITORING_H
#define CPU_MONITORING_H
/*
This header defines functions and structures for controlling the measurement of CPU frequency
in order to detect thermal throttling. For details see the associated source file.
*/
struct CPUFrequencyResults
{
double m_timeStamp; // Time (from Plat_FloatTime) when the measurements were made.
float m_GHz;
float m_percentage;
float m_lowestPercentage;
};
// Call this to get results.
// When CPU monitoring is 'disabled' it may still be running at a low frequency,
// for OGS purposes or for proactively warning users of problems. If fGetDisabledResults
// is true then results will be returned when disabled (if available).
PLATFORM_INTERFACE CPUFrequencyResults GetCPUFrequencyResults( bool fGetDisabledResults = false );
// Call this to set the monitoring frequency. Intervals of 2-5 seconds (2,000 to 5,000 ms)
// are recommended. An interval of zero will disable CPU monitoring. Short delays (below
// about 300 ms) will be rounded up.
PLATFORM_INTERFACE void SetCPUMonitoringInterval( unsigned nDelayMilliseconds );
// Warn with increasing strident colors when CPU percentages go below these levels.
// They are const int instead of float because const float in C++ is stupid.
const int kCPUMonitoringWarning1 = 80;
const int kCPUMonitoringWarning2 = 50;
#endif

852
public/tier0/dbg.h Normal file
View File

@@ -0,0 +1,852 @@
//===== Copyright (c) Valve Corporation, All rights reserved. ========//
//
// Purpose:
//
// $NoKeywords: $
//
//====================================================================//
#ifndef DBG_H
#define DBG_H
#if !defined(__SPU__)
#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
//-----------------------------------------------------------------------------
#ifdef TIER0_DLL_EXPORT
#define DBG_INTERFACE DLL_EXPORT
#define DBG_OVERLOAD DLL_GLOBAL_EXPORT
#define DBG_CLASS DLL_CLASS_EXPORT
#else
#define DBG_INTERFACE DLL_IMPORT
#define DBG_OVERLOAD DLL_GLOBAL_IMPORT
#define DBG_CLASS DLL_CLASS_IMPORT
#endif
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
// Allows the assert dialogs to be turned off from code
PLATFORM_INTERFACE bool AreAllAssertsDisabled();
PLATFORM_INTERFACE void SetAllAssertsDisabled( bool bAssertsEnabled );
PLATFORM_INTERFACE bool IsAssertDialogDisabled();
PLATFORM_INTERFACE void SetAssertDialogDisabled( bool bAssertDialogDisabled );
// Provides a callback that is called on asserts regardless of spew levels
typedef void (*AssertFailedNotifyFunc_t)( const char *pchFile, int nLine, const char *pchMessage );
PLATFORM_INTERFACE void SetAssertFailedNotifyFunc( AssertFailedNotifyFunc_t func );
PLATFORM_INTERFACE void CallAssertFailedNotifyFunc( const char *pchFile, int nLine, const char *pchMessage );
#if defined( LINUX )
PLATFORM_INTERFACE void SetAssertDialogParent( struct SDL_Window *window );
PLATFORM_INTERFACE struct SDL_Window * GetAssertDialogParent();
#endif
/* Used to define macros, never use these directly. */
#ifdef _PREFAST_
// When doing /analyze builds define _AssertMsg 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.
// The unfortunate !! is necessary because otherwise /analyze is incapable of evaluating
// all of the logical expressions that the regular compiler can handle.
// Include _msg in the macro so that format errors in it are detected.
#define _AssertMsg( _exp, _msg, _executeExp, _bFatal ) do { __analysis_assume( !!(_exp) ); _msg; } while (0)
#define _AssertMsgOnce( _exp, _msg, _bFatal ) do { __analysis_assume( !!(_exp) ); _msg; } while (0)
// Force asserts on for /analyze so that we get a __analysis_assume of all of the constraints.
#define DBGFLAG_ASSERT
#define DBGFLAG_ASSERTFATAL
#define DBGFLAG_ASSERTDEBUG
// Define the Q_ASSERT macro to override the QT assert macro so that its asserts
// suppress warnings instead of causing them.
#define Q_ASSERT( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), false )
#else
#define _AssertMsg( _exp, _msg, _executeExp, _bFatal ) \
do { \
if (!(_exp)) \
{ \
LoggingResponse_t ret = Log_Assert( "%s (%d) : %s\n", __TFILE__, __LINE__, static_cast<const char*>( _msg ) ); \
CallAssertFailedNotifyFunc( __TFILE__, __LINE__, _msg ); \
_executeExp; \
if ( ret == LR_DEBUGGER ) \
{ \
if ( ShouldUseNewAssertDialog() ) \
{ \
if ( 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 DbgVerifyFatal( _exp ) AssertFatal( _exp )
#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 DbgVerifyFatal( _exp ) (_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)
#define AssertAlignedWidth(PTR, width)
#define AssertAlignedConsole(PTR)
#else
# if defined( _X360 )
# define AssertAlignedWidth( PTR, width ) __twnei( intp(PTR) & ( width - 1 ), 0 ) // trap if not equal to immediate value (from width mask); unsigned comparison
# define AssertAligned( PTR ) AssertAlignedWidth( PTR, 16 ) // Call above with 16 width defined
# define AssertAlignedConsole( PTR ) AssertAlignedWidth( PTR, 4 ) // Call above with 4 width defined (xbox only for now)
# elif defined( DBGFLAG_ASSERT )
# define AssertAlignedWidth( adr, width ) Assert( ( ( ( intp ) ( adr ) ) & ( width - 1 ) ) == 0 )
# define AssertAligned( adr ) AssertAlignedWidth( adr, 16 )
# define AssertAlignedConsole(adr) // XBox only for now.
# else
# define AssertAlignedWidth(PTR, width)
# define AssertAligned(PTR)
# define AssertAlignedConsole(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 ) ( _exp )
#define VerifyEquals( _exp, _expectedValue ) AssertEquals( _exp, _expectedValue )
#ifndef DbgVerify
#define DbgVerify( _exp ) Assert( _exp )
#endif
#ifdef _DEBUG
#define DbgAssert( _exp ) Assert( _exp )
#else
#define DbgAssert( _exp ) ((void)0)
#endif
#ifdef _DEBUG
#define DbgAssert( _exp ) Assert( _exp )
#else
#define DbgAssert( _exp ) ((void)0)
#endif
#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)
#ifndef DbgVerify
#define DbgVerify( _exp ) (_exp)
#endif
#define DbgAssert( _exp ) ((void)0)
#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
// Source2 compatibility macro
#define AssertDbg( X ) DbgAssert( X )
// Use AssertAnalyze when the main purpose is to work around /analyze bugs by
// telling the compiler that a condition is impossible. If DBGFLAG_ASSERT is set
// then these will still be Asserts (just in case). The use of a different macro
// is in order to indicate their purpose.
#define AssertAnalyze( _exp ) Assert( _exp )
#define STRINGIFY_INTERNAL(x) #x
#define STRINGIFY(x) STRINGIFY_INTERNAL(x)
// The Always version of the assert macros are defined even when DBGFLAG_ASSERT is not,
// so they will be available even in release.
#define AssertAlways( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), false )
#define AssertMsgAlways( _exp, _msg ) _AssertMsg( _exp, _msg, ((void)0), false )
#define FILE_LINE_FUNCTION_STRING __FILE__ "(" STRINGIFY(__LINE__) "):" __FUNCTION__ ":"
#define FILE_LINE_STRING __FILE__ "(" STRINGIFY(__LINE__) "):"
#define FUNCTION_LINE_STRING __FUNCTION__ "(" STRINGIFY(__LINE__) "): "
// Handy define for inserting clickable messages into the build output.
// Use like this:
// #pragma MESSAGE("Some message")
#define MESSAGE(msg) message(__FILE__ "(" FUNCTION_LINE_TOSTRING(__LINE__) "): " msg)
//////////////////////////////////////////////////////////////////////////
// Legacy Logging System
//////////////////////////////////////////////////////////////////////////
// Channels which map the legacy logging system to the new system.
// Channel for all default Msg/Warning/Error commands.
PLATFORM_INTERFACE LoggingChannelID_t 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
// These functions do not return.
PLATFORM_INTERFACE void Error( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 );
PLATFORM_INTERFACE void Error_SpewCallStack( int iMaxCallStackLength, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 );
#define Plat_FatalError( ... ) do { Log_Error( LOG_GENERAL, ##__VA_ARGS__ ); Plat_ExitProcess( EXIT_FAILURE ); } while( 0 )
#if defined( DBGFLAG_STRINGS_STRIP )
#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 // DBGFLAG_STRINGS_STRIP
PLATFORM_INTERFACE void Msg( PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 );
PLATFORM_INTERFACE void Warning( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 );
PLATFORM_INTERFACE void Warning_SpewCallStack( int iMaxCallStackLength, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 );
#ifdef _PS3
PLATFORM_OVERLOAD void DevMsg( int level, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 );
PLATFORM_OVERLOAD void DevWarning( int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 );
PLATFORM_INTERFACE void DevMsg( PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 );
PLATFORM_INTERFACE void DevWarning( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 );
PLATFORM_INTERFACE void ConColorMsg( const Color& clr, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 );
PLATFORM_INTERFACE void ConMsg( PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 );
#else // !_PS3
PLATFORM_INTERFACE void DevMsg( int level, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 );
PLATFORM_INTERFACE void DevWarning( int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 );
PLATFORM_OVERLOAD void DevMsg( PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 );
PLATFORM_OVERLOAD void DevWarning( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 );
PLATFORM_OVERLOAD void ConColorMsg( const Color& clr, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 );
PLATFORM_OVERLOAD void ConMsg( PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 );
#endif // _PS3
PLATFORM_INTERFACE void ConDMsg( PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 );
PLATFORM_INTERFACE void COM_TimestampedLog( PRINTF_FORMAT_STRING char const *fmt, ... ) FMTFUNCTION( 1, 2 );
#endif // DBGFLAG_STRINGS_STRIP
// 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 */
#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(PRINTF_FORMAT_STRING 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
//-----------------------------------------------------------------------------
#else //#if !defined(__SPU__)
// void these for now
#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)
#define COMPILE_TIME_ASSERT( pred )
#define ASSERT_INVARIANT( pred )
#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)
#define AssertAligned(PTR)
#endif
#endif /* DBG_H */

68
public/tier0/dbgflag.h Normal file
View File

@@ -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

136
public/tier0/dynfunction.h Normal file
View File

@@ -0,0 +1,136 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
// This makes it easy to dynamically load a shared library and lookup a
// function in that library.
//
// Usage:
// CDynamicFunction<void (*)(const char *)> MyPuts(libname, "puts");
// if (MyPuts)
// MyPuts("Hello world!");
//
// Please note that this interface does not distinguish between functions and
// data. If you look up a global variable in your shared library, or simply
// mess up the function signature, you'll get a valid pointer and a crash
// if you call it as a function.
#ifndef DYNFUNCTION_H
#define DYNFUNCTION_H
#pragma once
#include "tier0/platform.h"
// The heavy lifting isn't template-specific, so we move it out of the header.
DLL_EXPORT void *VoidFnPtrLookup_Tier0(const char *libname, const char *fn, void *fallback);
template < class FunctionType >
class CDynamicFunction
{
public:
// Construct with a NULL function pointer. You must manually call
// Lookup() before you can call a dynamic function through this interface.
CDynamicFunction() : m_pFn(NULL) {}
// Construct and do a lookup right away. You will need to make sure that
// the lookup actually succeeded, as (libname) might have failed to load
// or (fn) might not exist in it.
CDynamicFunction(const char *libname, const char *fn, FunctionType fallback=NULL) : m_pFn(NULL)
{
Lookup(libname, fn, fallback);
}
// Construct and do a lookup right away. See comments in Lookup() about what (okay) does.
CDynamicFunction(const char *libname, const char *fn, bool &okay, FunctionType fallback=NULL) : m_pFn(NULL)
{
Lookup(libname, fn, okay, fallback);
}
// Load library if necessary, look up symbol. Returns true and sets
// m_pFn on successful lookup, returns false otherwise. If the
// function pointer is already looked up, this return true immediately.
// Use Reset() first if you want to look up the symbol again.
// This function will return false immediately unless (okay) is true.
// This allows you to chain lookups like this:
// bool okay = true;
// x.Lookup(lib, "x", okay);
// y.Lookup(lib, "y", okay);
// z.Lookup(lib, "z", okay);
// if (okay) { printf("All functions were loaded successfully!\n"); }
// If you supply a fallback, it'll be used if the lookup fails (and if
// non-NULL, means this will always return (okay)).
bool Lookup(const char *libname, const char *fn, bool &okay, FunctionType fallback=NULL)
{
if (!okay)
return false;
else if (m_pFn == NULL)
m_pFn = (FunctionType) VoidFnPtrLookup_Tier0(libname, fn, (void *) fallback);
okay = m_pFn != NULL;
return okay;
}
// Load library if necessary, look up symbol. Returns true and sets
// m_pFn on successful lookup, returns false otherwise. If the
// function pointer is already looked up, this return true immediately.
// Use Reset() first if you want to look up the symbol again.
// This function will return false immediately unless (okay) is true.
// If you supply a fallback, it'll be used if the lookup fails (and if
// non-NULL, means this will always return true).
bool Lookup(const char *libname, const char *fn, FunctionType fallback=NULL)
{
bool okay = true;
return Lookup(libname, fn, okay, fallback);
}
// Invalidates the current lookup. Makes the function pointer NULL. You
// will need to call Lookup() before you can call a dynamic function
// through this interface again.
void Reset() { m_pFn = NULL; }
// Force this to be a specific function pointer.
void Force(FunctionType ptr) { m_pFn = ptr; }
// Retrieve the actual function pointer.
FunctionType Pointer() const { return m_pFn; }
operator FunctionType() const { return m_pFn; }
// Can be used to verify that we have an actual function looked up and
// ready to call: if (!MyDynFunc) { printf("Function not found!\n"); }
operator bool () const { return m_pFn != NULL; }
bool operator !() const { return m_pFn == NULL; }
protected:
FunctionType m_pFn;
};
// This is the same as CDynamicFunction, but we made the default constructor
// private, forcing you to do loading/lookup during construction.
// The usage pattern is to have a list of dynamic functions that are
// constructed en masse as part of another class's constructor, with the
// possibility of human error removed (the compiler will complain if you
// forget to initialize one).
template < class FunctionType >
class CDynamicFunctionMustInit : public CDynamicFunction < FunctionType >
{
private: // forbid default constructor.
CDynamicFunctionMustInit() {}
public:
CDynamicFunctionMustInit(const char *libname, const char *fn, FunctionType fallback=NULL)
: CDynamicFunction< FunctionType >(libname, fn, fallback)
{
}
CDynamicFunctionMustInit(const char *libname, const char *fn, bool &okay, FunctionType fallback=NULL)
: CDynamicFunction< FunctionType >(libname, fn, okay, fallback)
{
}
};
#endif // DYNFUNCTION_H

162
public/tier0/etwprof.h Normal file
View File

@@ -0,0 +1,162 @@
//============ 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.
#define ETW_MARKS_ENABLED
#endif
#ifdef ETW_MARKS_ENABLED
// This returns true if VTrace is running and tracing is enabled.
// More exactly it returns true if the VALVE_MAIN provider is enabled.
PLATFORM_INTERFACE bool ETWIsTracingEnabled();
// 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 void 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 synchronizing
// 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 ETWMouseMove( int nX, int nY );
PLATFORM_INTERFACE void ETWMouseWheel( int nWheelDelta, 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 bool ETWIsTracingEnabled() { return false; }
inline int64 ETWMark( const char* ) { return 0; }
inline void ETWMarkPrintf( const char *, ... ) { return; }
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 ETWMouseMove( int nX, int nY ) {}
inline void ETWMouseWheel( int nWheelDelta, 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

596
public/tier0/fasttimer.h Normal file
View File

@@ -0,0 +1,596 @@
//========= Copyright <20> 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;
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;
}
inline void CCycleCount::Sample()
{
m_Int64 = Plat_Rdtsc();
}
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. NOTE: CMicroSecOverage() and CMicroSecLeft() are not as fast to check.
class CLimitTimer
{
public:
CLimitTimer() {}
CLimitTimer( uint64 cMicroSecDuration ) { SetLimit( cMicroSecDuration ); }
void SetLimit( uint64 m_cMicroSecDuration );
bool BLimitReached() const;
int CMicroSecOverage() const;
uint64 CMicroSecLeft() const;
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 cMicroSecDuration )
{
uint64 dlCycles = ( ( uint64 ) 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() const
{
CCycleCount cycleCount;
cycleCount.Sample();
return ( cycleCount.GetLongCycles() >= m_lCycleLimit );
}
//-----------------------------------------------------------------------------
// Purpose: If we're over our specified time period, return the amount of the overage.
// Output: # of microseconds since we reached our specified time period.
//-----------------------------------------------------------------------------
inline int CLimitTimer::CMicroSecOverage() const
{
CCycleCount cycleCount;
cycleCount.Sample();
uint64 lcCycles = cycleCount.GetLongCycles();
if ( lcCycles < m_lCycleLimit )
return 0;
return( ( int ) ( ( lcCycles - m_lCycleLimit ) * ( uint64 ) 1000000L / g_dwClockSpeed ) );
}
//-----------------------------------------------------------------------------
// Purpose: If we're under our specified time period, return the amount under.
// Output: # of microseconds until we reached our specified time period, 0 if we've passed it
//-----------------------------------------------------------------------------
inline uint64 CLimitTimer::CMicroSecLeft() const
{
CCycleCount cycleCount;
cycleCount.Sample();
uint64 lcCycles = cycleCount.GetLongCycles();
if ( lcCycles >= m_lCycleLimit )
return 0;
return( ( uint64 ) ( ( m_lCycleLimit - lcCycles ) * ( uint64 ) 1000000L / g_dwClockSpeed ) );
}
#endif // FASTTIMER_H

View File

@@ -0,0 +1,49 @@
//========= Copyright c Valve Corporation, All rights reserved. ============//
#ifndef TIER0_HARDWARE_TIMER
#define TIER0_HARDWARE_TIMER
#include "tier0/platform.h"
#ifdef GNUC
inline int GetHardwareClockFast( void )
{
unsigned long long int nRet;
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (nRet)); // rdtsc
return ( int ) nRet;
}
#else
#ifdef _X360
inline /*__declspec(naked)*/ int GetHardwareClockFast()
{
/*__asm
{
lis r3,08FFFh
ld r3,011E0h(r3)
rldicl r3,r3,32,32
blr
} */
return __mftb32() << 6;
}
#elif defined( _PS3 )
inline int GetHardwareClockFast()
{
// The timebase frequency on PS/3 is 79.8 MHz, see sys_time_get_timebase_frequency()
// this works out to 40.10025 clock ticks per timebase tick
return __mftb() * 40;
}
#else
#include <intrin.h>
inline int GetHardwareClockFast()
{
return __rdtsc();
}
#endif
#endif
#endif

377
public/tier0/ia32detect.h Normal file
View File

@@ -0,0 +1,377 @@
//===== 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;
int data[4 + 1];
tchar * s1;
s1 = (tchar *) &data[1];
__cpuid(data, 0);
data[4] = 0;
// Returns something like this:
// data[0] = 0x0000000b
// data[1] = 0x756e6547 Genu
// data[2] = 0x6c65746e ntel
// data[3] = 0x49656e69 ineI
// data[4] = 0x00000000
m = data[0];
int t = data[2];
data[2] = data[3];
data[3] = t;
vendor_name = s1;
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

View File

@@ -0,0 +1,69 @@
//===== 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;
// A bool return of whether param exists, useful for just checking if param that is just a flag is set
virtual bool HasParm( const char *psz ) 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;
virtual const char **GetParms() const = 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

47
public/tier0/l2cache.h Normal file
View File

@@ -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

768
public/tier0/logging.h Normal file
View File

@@ -0,0 +1,768 @@
//============ 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(__SPU__)
#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 );
void SetGlobalSpewLevel( 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 );
//-----------------------------------------------------------------------------
// 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 );
PLATFORM_INTERFACE void LoggingSystem_SetGlobalSpewLevel( 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, PRINTF_FORMAT_STRING const char *pMessageFormat, ... ) FMTFUNCTION( 3, 4 );
PLATFORM_OVERLOAD LoggingResponse_t LoggingSystem_Log( LoggingChannelID_t channelID, LoggingSeverity_t severity, Color spewColor, PRINTF_FORMAT_STRING 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( PRINTF_FORMAT_STRING const char *pMessageFormat, ... ) FMTFUNCTION( 1, 2 );
#endif //#if !defined(__SPU__)
#endif // LOGGING_H

View File

@@ -0,0 +1,29 @@
//===== Copyright © 1996-2008, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#ifndef MATH_TABLES_H
#define MATH_TABLES_H
#define SIN_TABLE_SIZE 256
#ifdef BUILD_TABLES
DLL_EXPORT float SinCosTable[SIN_TABLE_SIZE];
DLL_EXPORT float g_Mathlib_power2_n[256];
DLL_EXPORT float g_Mathlib_lineartovertex[4096];
DLL_EXPORT unsigned char g_Mathlib_lineartolightmap[4096];
#else
DLL_IMPORT float SinCosTable[SIN_TABLE_SIZE];
DLL_IMPORT float g_Mathlib_power2_n[256];
DLL_IMPORT float g_Mathlib_lineartovertex[4096];
DLL_IMPORT unsigned char g_Mathlib_lineartolightmap[4096];
#endif
#endif // MATH_TABLES_H

51
public/tier0/mem.h Normal file
View File

@@ -0,0 +1,51 @@
//========= 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 );
MEM_INTERFACE void MemOutOfMemory( size_t nBytesAttempted );
#endif /* TIER0_MEM_H */

763
public/tier0/memalloc.h Normal file
View File

@@ -0,0 +1,763 @@
//========= Copyright <20> 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
// [will] - Temporarily disabling for OSX until I can fix memory issues.
#if !defined( LINUX ) && !defined( _OSX )
// 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"
/// This interface class is used to let the mem_dump command retrieve
/// information about memory allocations outside of the heap. It is currently
/// used by CMemoryStack to report on its allocations.
abstract_class IMemoryInfo
{
public:
virtual const char* GetMemoryName() const = 0; // User friendly name for this stack or pool
virtual size_t GetAllocatedBytes() const = 0; // Number of bytes currently allocated
virtual size_t GetCommittedBytes() const = 0; // Bytes committed -- may be greater than allocated.
virtual size_t GetReservedBytes() const = 0; // Bytes reserved -- may be greater than committed.
virtual size_t GetHighestBytes() const = 0; // The maximum number of bytes allocated or committed.
};
// Add and remove callbacks used to get statistics on non-heap memory allocations.
PLATFORM_INTERFACE void AddMemoryInfoCallback( IMemoryInfo* pMemoryInfo );
PLATFORM_INTERFACE void RemoveMemoryInfoCallback( IMemoryInfo* pMemoryInfo );
// Display the memory statistics from the callbacks controlled by the above functions.
PLATFORM_INTERFACE void DumpMemoryInfoStats();
//-----------------------------------------------------------------------------
// NOTE! This should never be called directly from leaf code
// Just use new,delete,malloc,free etc. They will call into this eventually
//-----------------------------------------------------------------------------
#define ASSERT_MEMALLOC_WILL_ALIGN( T ) COMPILE_TIME_ASSERT( __alignof( T ) <= 16 )
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;
enum DumpStatsFormat_t
{
FORMAT_TEXT,
FORMAT_HTML
};
virtual void DumpStatsFileBase( char const *pchFileBase, DumpStatsFormat_t nFormat = FORMAT_TEXT ) = 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 void MemAlloc_Free(void *pMemBlock)
{
g_pMemAlloc->Free(pMemBlock);
}
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
//-----------------------------------------------------------------------------
#elif defined( POSIX )
#if defined( OSX )
inline void *memalign(size_t alignment, size_t size) {void *pTmp=NULL; posix_memalign(&pTmp, alignment, size); return pTmp;}
#endif
inline void *_aligned_malloc( size_t nSize, size_t align ) { return memalign( align, nSize ); }
inline void _aligned_free( void *ptr ) { free( ptr ); }
inline void *MemAlloc_Alloc( size_t nSize, const char *pFileName = NULL, int nLine = 0 ) { return malloc( nSize ); }
inline void MemAlloc_Free( void *ptr, const char *pFileName = NULL, int nLine = 0 ) { free( ptr ); }
inline void *MemAlloc_AllocAligned( size_t size, size_t align ) { return memalign( align, size ); }
inline void *MemAlloc_AllocAlignedFileLine( size_t size, size_t align, const char *pszFile = NULL, int nLine = 0 ) { return memalign( align, size ); }
inline void MemAlloc_FreeAligned( void *pMemBlock, const char *pszFile = NULL, int nLine = 0 ) { free( pMemBlock ); }
#if defined( OSX )
inline size_t _msize( void *ptr ) { return malloc_size( ptr ); }
#else
inline size_t _msize( void *ptr ) { return malloc_usable_size( ptr ); }
#endif
inline void *MemAlloc_ReallocAligned( void *ptr, size_t size, size_t align )
{
void *ptr_new_aligned = memalign( align, size );
if( ptr_new_aligned )
{
size_t old_size = _msize( ptr );
size_t copy_size = ( size < old_size ) ? size : old_size;
memcpy( ptr_new_aligned, ptr, copy_size );
free( ptr );
}
return ptr_new_aligned;
}
#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_FUNCTION()
#define MEM_ALLOC_CREDIT_CLASS()
#define MEM_ALLOC_CLASSNAME(type) NULL
#define MemAlloc_PushAllocDbgInfo( pszFile, line )
#define MemAlloc_PopAllocDbgInfo()
#define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0)
#define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0)
#define MemAlloc_DumpStats() ((void)0)
#define MemAlloc_CompactHeap() ((void)0)
#define MemAlloc_OutOfMemory() ((void)0)
#define MemAlloc_CompactIncremental() ((void)0)
#define MemAlloc_DumpStatsFileBase( _filename ) ((void)0)
inline bool MemAlloc_CrtCheckMemory() { return true; }
inline void MemAlloc_GlobalMemoryStatus( size_t *pusedMemory, size_t *pfreeMemory )
{
*pusedMemory = 0;
*pfreeMemory = 0;
}
#define MemAlloc_MemoryAllocFailed() 1
#define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag )
#define MemAlloc_RegisterExternalAllocation( tag, p, size ) ((void)0)
#define MemAlloc_RegisterExternalDeallocation( tag, p, size ) ((void)0)
#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 */

25
public/tier0/memdbgoff.h Normal file
View File

@@ -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

281
public/tier0/memdbgon.h Normal file
View File

@@ -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) && !defined(__SPU__)
// 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

1940
public/tier0/memoverride.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Insert this file into all projects using the memory system
// It will cause that project to use the shader memory allocator
//
// $NoKeywords: $
//=============================================================================//
#ifdef SN_TARGET_PS3
struct MemOverrideRawCrtFunctions_t
{
void * (*pfn_malloc)( size_t size );
void * (*pfn_calloc)( size_t nelem, size_t size );
void * (*pfn_memalign)(size_t boundary, size_t size_arg);
void * (*pfn_realloc)( void *p, size_t size_arg );
void * (*pfn_reallocalign)( void *p, size_t size_arg, size_t boundary );
size_t (*pfn_malloc_usable_size)( void *p );
int (*pfn_malloc_stats)( struct malloc_managed_size *mms );
void (*pfn_free)( void *p );
};
#endif

46
public/tier0/memvirt.h Normal file
View File

@@ -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

View File

@@ -0,0 +1,345 @@
//========= Copyright (c) Valve Corporation, All rights reserved. ============
//
// this is even smaller profiler than miniprofiler: there is no linking or bookkeeping
// of any kind, it's just to throw in quick profilers that don't mess with code speed
// even in CERT builds
//
#ifndef TIER0MICROPROFILERHDR
#define TIER0MICROPROFILERHDR
#include "platform.h"
// define this to 1 to enable microprofiler; 2 to enable miniprofiler
#ifndef ENABLE_MICRO_PROFILER
#define ENABLE_MICRO_PROFILER 1
#endif
class CMicroProfiler;
PLATFORM_INTERFACE void MicroProfilerAddTS( CMicroProfiler *pProfiler, uint64 numTimeBaseTicks );
PLATFORM_INTERFACE int64 GetHardwareClockReliably();
#ifdef IS_WINDOWS_PC
#include <intrin.h> // get __rdtsc
#endif
#if defined(_LINUX) || defined( OSX )
inline unsigned long long GetTimebaseRegister( void )
{
#ifdef PLATFORM_64BITS
unsigned long long Low, High;
__asm__ __volatile__ ( "rdtsc" : "=a" (Low), "=d" (High) );
return ( High << 32 ) | ( Low & 0xffffffff );
#else
unsigned long long Val;
__asm__ __volatile__ ( "rdtsc" : "=A" (Val) );
return Val;
#endif
}
#else
// Warning: THere's a hardware bug with 64-bit MFTB on PS3 (not sure about X360): sometimes it returns incorrect results (when low word overflows, the high word doesn't increment for some time)
inline int64 GetTimebaseRegister()
{
#if defined( _X360 )
return __mftb32(); // X360: ~64 CPU ticks resolution
#elif defined( _PS3 )
// The timebase frequency on PS/3 is 79.8 MHz, see sys_time_get_timebase_frequency()
// this works out to 40.10025 clock ticks per timebase tick
return __mftb();
#elif defined( OSX )
return GetTimebaseRegister();
#else
return __rdtsc();
#endif
}
#endif
#if ENABLE_MICRO_PROFILER > 0
class CMicroProfilerSample
{
int64 m_nTimeBaseBegin; // time base is kept here instead of using -= and += for better reliability and to avoid a cache miss at the beginning of the profiled section
public:
CMicroProfilerSample()
{
m_nTimeBaseBegin = GetTimebaseRegister();
}
int64 GetElapsed()const
{
return GetTimebaseRegister() - m_nTimeBaseBegin;
}
};
#ifdef IS_WINDOWS_PC
class CMicroProfilerQpcSample
{
int64 m_nTimeBaseBegin; // time base is kept here instead of using -= and += for better reliability and to avoid a cache miss at the beginning of the profiled section
public:
CMicroProfilerQpcSample()
{
m_nTimeBaseBegin = GetHardwareClockReliably();
}
int64 GetElapsed()const
{
return GetHardwareClockReliably() - m_nTimeBaseBegin;
}
};
#else
typedef CMicroProfilerSample CMicroProfilerQpcSample;
#endif
class CMicroProfiler
{
public:
uint64 m_numTimeBaseTicks; // this will be totally screwed between Begin() and End()
uint64 m_numCalls;
public:
CMicroProfiler()
{
Reset();
}
CMicroProfiler( const CMicroProfiler &other )
{
m_numTimeBaseTicks = other.m_numTimeBaseTicks;
m_numCalls = other.m_numCalls;
}
CMicroProfiler &operator=( const CMicroProfiler &other )
{
m_numTimeBaseTicks = other.m_numTimeBaseTicks;
m_numCalls = other.m_numCalls;
return *this;
}
void Begin()
{
m_numTimeBaseTicks -= GetTimebaseRegister();
}
void End()
{
m_numTimeBaseTicks += GetTimebaseRegister();
m_numCalls ++;
}
void End( uint64 nCalls )
{
m_numTimeBaseTicks += GetTimebaseRegister();
m_numCalls += nCalls;
}
void Add( uint64 numTimeBaseTicks, uint64 numCalls = 1)
{
m_numTimeBaseTicks += numTimeBaseTicks;
m_numCalls += numCalls;
}
void AddTS( uint64 numTimeBaseTicks )
{
MicroProfilerAddTS( this, numTimeBaseTicks );
}
void Add(const CMicroProfilerSample &sample)
{
Add( sample.GetElapsed() );
}
void Add( const CMicroProfiler& profiler)
{
Add( profiler.m_numTimeBaseTicks, profiler.m_numCalls );
}
void Reset()
{
m_numTimeBaseTicks = 0;
m_numCalls = 0;
}
void Damp( int shift = 1 )
{
m_numTimeBaseTicks >>= shift;
m_numCalls >>= shift;
}
uint64 GetNumCalls() const
{
return m_numCalls;
}
uint64 GetNumTimeBaseTicks() const
{
return m_numTimeBaseTicks;
}
float GetAverageMilliseconds() const
{
return m_numCalls ? GetTotalMilliseconds() / m_numCalls : 0;
}
float GetTotalMilliseconds() const
{
return TimeBaseTicksToMilliseconds( m_numTimeBaseTicks );
}
static float TimeBaseTicksToMilliseconds( uint64 numTimeBaseTicks )
{
#if defined( _X360 ) || defined( _PS3 )
return numTimeBaseTicks / 79800.0 ;
#else
return numTimeBaseTicks / ( GetCPUInformation().m_Speed * 0.001f );
#endif
}
float GetAverageTicks() const
{
#if defined( _X360 ) || defined( _PS3 )
return m_numTimeBaseTicks * 40.1f / m_numCalls; // timebase register is 79.8 MHz on these platforms
#else
return float( m_numTimeBaseTicks / m_numCalls );
#endif
}
friend const CMicroProfiler operator + ( const CMicroProfiler &left, const CMicroProfiler &right );
void Accumulate( const CMicroProfiler &other )
{
m_numCalls += other.m_numCalls;
m_numTimeBaseTicks += other.m_numTimeBaseTicks;
}
};
inline const CMicroProfiler operator + ( const CMicroProfiler &left, const CMicroProfiler &right )
{
CMicroProfiler result;
result.m_numCalls = left.m_numCalls + right.m_numCalls;
result.m_numTimeBaseTicks = left.m_numTimeBaseTicks + right.m_numTimeBaseTicks;
return result;
}
class CMicroProfilerGuard: public CMicroProfilerSample
{
CMicroProfiler *m_pProfiler;
public:
CMicroProfilerGuard( CMicroProfiler *pProfiler )
{
m_pProfiler = pProfiler;
}
~CMicroProfilerGuard()
{
m_pProfiler->Add( GetElapsed() );
}
};
class CMicroProfilerGuardWithCount: public CMicroProfilerSample
{
CMicroProfiler *m_pProfiler;
uint m_nCount;
public:
CMicroProfilerGuardWithCount( CMicroProfiler *pProfiler, uint nCount )
{
m_nCount = nCount;
m_pProfiler = pProfiler;
}
void OverrideCount( uint nCount ) { m_nCount = nCount; }
~CMicroProfilerGuardWithCount( )
{
m_pProfiler->Add( GetElapsed( ), m_nCount );
}
};
// thread-safe variant of the same profiler
class CMicroProfilerGuardTS: public CMicroProfilerSample
{
CMicroProfiler *m_pProfiler;
public:
CMicroProfilerGuardTS( CMicroProfiler *pProfiler )
{
m_pProfiler = pProfiler;
}
~CMicroProfilerGuardTS()
{
m_pProfiler->AddTS( GetElapsed() );
}
};
#define MICRO_PROFILER_NAME_0(LINE) localAutoMpg##LINE
#define MICRO_PROFILER_NAME(LINE) MICRO_PROFILER_NAME_0(LINE)
#define MICRO_PROFILE( MP ) CMicroProfilerGuard MICRO_PROFILER_NAME(__LINE__)( &( MP ) )
#define MICRO_PROFILE_TS( MP ) CMicroProfilerGuardTS MICRO_PROFILER_NAME(__LINE__)( &( MP ) )
#else
class CMicroProfilerSample
{public:
CMicroProfilerSample(){}
int GetElapsed()const{ return 0;}
};
typedef CMicroProfilerSample CMicroProfilerQpcSample;
class CMicroProfiler
{ public:
CMicroProfiler(){}
CMicroProfiler &operator=( const CMicroProfiler &other ) { return *this; }
void Begin(){}
void End(){}
void End( uint32 ){}
void Add( uint64 numTimeBaseTicks, int numCalls = 1){}
void AddTS( uint64 numTimeBaseTicks ) {}
void Add( const CMicroProfilerSample &sample){}
void Add( const CMicroProfiler& profiler) {}
void Reset(){}
void Damp(int shift = 1){}
uint64 GetNumCalls() const { return 0; }
uint64 GetNumTimeBaseTicks() const { return 0; }
int64 GetNumTimeBaseTicksExclusive() const { return 0; }
float GetAverageMilliseconds()const { return 0; }
float GetTotalMilliseconds()const { return 0; }
static float TimeBaseTicksToMilliseconds( uint64 numTimeBaseTicks ) { return 0; }
float GetAverageTicks() const { return 0; }
friend const CMicroProfiler operator + ( const CMicroProfiler &left, const CMicroProfiler &right );
};
inline const CMicroProfiler operator + ( const CMicroProfiler &left, const CMicroProfiler &right ) { return left; }
class CMicroProfilerGuard: public CMicroProfilerSample
{
public:
CMicroProfilerGuard( CMicroProfiler *pProfiler ){}
~CMicroProfilerGuard(){}
};
class CMicroProfilerGuardTS: public CMicroProfilerSample
{
public:
CMicroProfilerGuardTS( CMicroProfiler *pProfiler ){}
~CMicroProfilerGuardTS(){}
};
#define MICRO_PROFILE( MP )
#endif
#endif

109
public/tier0/minidump.h Normal file
View File

@@ -0,0 +1,109 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef MINIDUMP_H
#define MINIDUMP_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/platform.h"
// Set prefix to use for minidump files. If you don't set one, it is defaulted for you,
// using the current module name
PLATFORM_INTERFACE void SetMinidumpFilenamePrefix( const char *pszPrefix );
// Set comment to put into minidump file upon next call of WriteMiniDump. (Most common use is the assert text.)
PLATFORM_INTERFACE void SetMinidumpComment( const char *pszComment );
// writes out a minidump of the current stack trace with a unique filename
PLATFORM_INTERFACE void WriteMiniDump( const char *pszFilenameSuffix = NULL );
typedef void( *FnWMain )(int, tchar *[]);
typedef void( *FnVoidPtrFn )(void *);
#if defined(_WIN32) && !defined(_X360)
// 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
typedef void( *FnWMain )(int, tchar *[]);
typedef int( *FnWMainIntRet )(int, tchar *[]);
typedef void( *FnVoidPtrFn )(void *);
enum ECatchAndWriteMinidumpAction
{
k_ECatchAndWriteMiniDumpAbort = 0,
k_ECatchAndWriteMiniDumpReThrow = 1,
k_ECatchAndWriteMiniDumpIgnore = 2,
};
PLATFORM_INTERFACE void CatchAndWriteMiniDump( FnWMain pfn, int argc, tchar *argv[] ); // action = Abort
PLATFORM_INTERFACE void CatchAndWriteMiniDumpForVoidPtrFn( FnVoidPtrFn pfn, void *pv, bool bExitQuietly ); // action = abort if bExitQuietly, Rethrow otherwise
PLATFORM_INTERFACE void CatchAndWriteMiniDumpEx( FnWMain pfn, int argc, tchar *argv[], ECatchAndWriteMinidumpAction eAction );
PLATFORM_INTERFACE int CatchAndWriteMiniDumpExReturnsInt( FnWMainIntRet pfn, int argc, tchar *argv[], ECatchAndWriteMinidumpAction eAction );
PLATFORM_INTERFACE void CatchAndWriteMiniDumpExForVoidPtrFn( FnVoidPtrFn pfn, void *pv, ECatchAndWriteMinidumpAction eAction );
// Let's not include this. We'll use forwards instead.
//#include <dbghelp.h>
struct _EXCEPTION_POINTERS;
typedef _EXCEPTION_POINTERS 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, _EXCEPTION_POINTERS * pExceptionInfo, const char *pszFilenameSuffix);
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,
_EXCEPTION_POINTERS * pExceptionInfo,
int /* MINIDUMP_TYPE */ minidumpType,
const char *pszFilenameSuffix = NULL,
tchar *ptchMinidumpFileNameBuffer = NULL
);
// Call this to enable a handler for unhandled exceptions.
PLATFORM_INTERFACE void MinidumpSetUnhandledExceptionFunction( FnMiniDump pfn );
// Call this to prevent crashes in kernel callbacks such as window procs from
// being silently swallowed. We should always call this at startup.
PLATFORM_INTERFACE void EnableCrashingOnCrashes();
#endif
#endif // MINIDUMP_H

369
public/tier0/miniprofiler.h Normal file
View File

@@ -0,0 +1,369 @@
//========= Copyright c 1996-2008, Valve Corporation, All rights reserved. ============
// This will contain things like helper functions to measure tick count of small pieces
// of code precisely; or measure performance counters (L2 misses, mispredictions etc.)
// on different hardware.
//=====================================================================================
// this class defines a section of code to measure
#ifndef TIER0_MINIPROFILER_HDR
#define TIER0_MINIPROFILER_HDR
#include "microprofiler.h"
#define ENABLE_MINI_PROFILER 0 // ENABLE_MICRO_PROFILER
class CMiniProfiler;
class CLinkedMiniProfiler;
extern "C"
{
#if defined( STATIC_LINK )
#define MINIPROFILER_DLL_LINKAGE extern
#elif defined( TIER0_DLL_EXPORT )
#define MINIPROFILER_DLL_LINKAGE DLL_EXPORT
#else
#define MINIPROFILER_DLL_LINKAGE DLL_IMPORT
#endif
MINIPROFILER_DLL_LINKAGE CMiniProfiler *g_pLastMiniProfiler;
MINIPROFILER_DLL_LINKAGE CMiniProfiler *g_pRootMiniProfiler;
MINIPROFILER_DLL_LINKAGE CLinkedMiniProfiler *g_pGlobalMiniProfilers;
MINIPROFILER_DLL_LINKAGE CLinkedMiniProfiler *g_pAssertMiniProfilers;
MINIPROFILER_DLL_LINKAGE uint32 g_nMiniProfilerFrame;
MINIPROFILER_DLL_LINKAGE void PublishAll( CLinkedMiniProfiler * pList, uint32 nHistoryMax );
MINIPROFILER_DLL_LINKAGE CMiniProfiler* PushMiniProfilerTS( CMiniProfiler *pProfiler );
MINIPROFILER_DLL_LINKAGE void PopMiniProfilerTS( CMiniProfiler *pProfiler );
MINIPROFILER_DLL_LINKAGE void AppendMiniProfilerToList( CLinkedMiniProfiler *pProfiler, CLinkedMiniProfiler **ppList );
MINIPROFILER_DLL_LINKAGE void RemoveMiniProfilerFromList( CLinkedMiniProfiler *pProfiler );
}
#if ENABLE_MINI_PROFILER
typedef CMicroProfilerSample CMiniProfilerSample;
class CMiniProfiler: public CMicroProfiler
{
protected:
uint64 m_numTimeBaseTicksInCallees; // this is the time to subtract from m_numTimeBaseTicks to get the "exclusive" time in this block
public:
CMiniProfiler()
{
Reset();
}
explicit CMiniProfiler( const CMicroProfiler &profiler ):
CMicroProfiler( profiler ),
m_numTimeBaseTicksInCallees( 0 )
{
}
CMiniProfiler &operator=( const CMiniProfiler &other )
{
*(CMicroProfiler *)this = (const CMicroProfiler &)other;
m_numTimeBaseTicksInCallees = other.m_numTimeBaseTicksInCallees;
return *this;
}
void SubCallee( int64 numTimeBaseTicks )
{
m_numTimeBaseTicksInCallees += numTimeBaseTicks;
}
void Reset()
{
CMicroProfiler::Reset();
m_numTimeBaseTicksInCallees = 0;
}
uint64 GetNumTimeBaseTicksInCallees() const
{
return m_numTimeBaseTicksInCallees;
}
int64 GetNumTimeBaseTicksExclusive( ) const
{
return m_numTimeBaseTicks - m_numTimeBaseTicksInCallees;
}
void Accumulate( const CMiniProfiler &other )
{
CMicroProfiler::Accumulate( other );
m_numTimeBaseTicksInCallees += other.m_numTimeBaseTicksInCallees;
}
DLL_CLASS_EXPORT void Publish( const char *szMessage, ... );
};
#else
class CMiniProfilerSample
{
public:
int GetElapsed()const
{
return 0;
}
};
class CMiniProfiler: public CMicroProfiler
{
public:
CMiniProfiler() {}
explicit CMiniProfiler( const CMicroProfiler &profiler ) :
CMicroProfiler( profiler ){}
CMiniProfiler &operator=( const CMiniProfiler &other ) { return *this; }
void SubCallee( int64 numTimeBaseTicks ) {}
uint64 GetNumTimeBaseTicksInCallees() const { return 0; }
int64 GetNumTimeBaseTicksExclusive() const { return 0; }
void Accumulate( const CMiniProfiler &other ) {}
void Reset() {}
void Damp( int shift = 1 ) {}
void Publish( const char *szMessage, ... ) {}
};
#endif
class CLinkedMiniProfiler: public CMiniProfiler
{
public:
#if ENABLE_MINI_PROFILER
CLinkedMiniProfiler *m_pNext, **m_ppPrev;
const char *m_pName;
const char *m_pLocation;
CMiniProfiler *m_pLastParent; // for dynamic tracking of an approximate call tree
CMiniProfiler *m_pDeclaredParent; // for static tracking of the logical dependency tree
//uint32 m_nId;
#endif
public:
CLinkedMiniProfiler( const char *pName, CLinkedMiniProfiler**ppList = &g_pGlobalMiniProfilers, CMiniProfiler *pDeclaredParent = NULL )
{
#if ENABLE_MINI_PROFILER
m_pName = pName;
m_pLocation = NULL;
// NOTE: m_pNext and m_ppPrev have to be NULLs the first time around. This constructor can be called multiple times
// from multiple threads, and there's no way to ensure the constructor isn't called twice. CNetworkGameServerBase::SV_PackEntity()
// is an example of the function that enters from 2 threads and collides with itself in this constructor
AppendMiniProfilerToList( this, ppList );
m_pLastParent = NULL;
m_pDeclaredParent = pDeclaredParent;
#endif
}
CLinkedMiniProfiler( const char *pName, const char *pLocation )
{
#if ENABLE_MINI_PROFILER
m_pName = pName;
m_pLocation = pLocation;
// NOTE: m_pNext and m_ppPrev have to be NULLs the first time around. This constructor can be called multiple times
// from multiple threads, and there's no way to ensure the constructor isn't called twice. CNetworkGameServerBase::SV_PackEntity()
// is an example of the function that enters from 2 threads and collides with itself in this constructor
AppendMiniProfilerToList( this, &g_pGlobalMiniProfilers );
m_pLastParent = NULL;
m_pDeclaredParent = NULL;
#endif
}
#if ENABLE_MINI_PROFILER
CLinkedMiniProfiler *GetNext() { return m_pNext; }
const char *GetName() const { return m_pName; }
const char *GetLocation( )const { return m_pLocation; }
#else
CLinkedMiniProfiler *GetNext() { return NULL; }
const char *GetName() const { return "DISABLED"; }
const char *GetLocation( )const { return NULL; }
#endif
~CLinkedMiniProfiler()
{
#if ENABLE_MINI_PROFILER
RemoveMiniProfilerFromList( this );
#endif
}
void Publish( uint nHistoryMax );
void PurgeHistory();
};
class CAssertMiniProfiler: public CLinkedMiniProfiler
{
public:
CAssertMiniProfiler( const char *pFunction, const char *pFile, int nLine ): CLinkedMiniProfiler( pFunction, &g_pAssertMiniProfilers )
{
m_pFile = pFile;
m_nLine = nLine;
m_bAsserted = false;
}
~CAssertMiniProfiler()
{
}
operator bool& () { return m_bAsserted; }
void operator = ( bool bAsserted ){ m_bAsserted = bAsserted; }
void operator = ( int bAsserted ) { m_bAsserted = (bAsserted != 0); }
public:
const char *m_pFile;
int m_nLine;
public:
bool m_bAsserted;
};
template < class Sampler, bool bThreadSafe >
class TMiniProfilerGuard: public Sampler
{
#if ENABLE_MINI_PROFILER
CMiniProfiler *m_pProfiler, *m_pLastProfiler;
int m_numCallsToAdd;
#endif
public:
void Begin( CMiniProfiler *pProfiler, int numCallsToAdd )
{
#if ENABLE_MINI_PROFILER
m_numCallsToAdd = numCallsToAdd;
m_pProfiler = pProfiler;
if ( bThreadSafe )
{
m_pLastProfiler = PushMiniProfilerTS( pProfiler );
}
else
{
m_pLastProfiler = g_pLastMiniProfiler;
g_pLastMiniProfiler = pProfiler;
}
#endif
}
void SetCallCount( int numCalls )
{
#if ENABLE_MINI_PROFILER
m_numCallsToAdd = numCalls;
#endif
}
void AddCallCount( int addCalls )
{
#if ENABLE_MINI_PROFILER
m_numCallsToAdd += addCalls;
#endif
}
TMiniProfilerGuard( CLinkedMiniProfiler *pProfiler, int numCallsToAdd = 1 )
{
Begin( pProfiler, numCallsToAdd );
#if ENABLE_MINI_PROFILER
pProfiler->m_pLastParent = m_pLastProfiler;
#endif
}
TMiniProfilerGuard( CMiniProfiler *pProfiler, int numCallsToAdd = 1 )
{
Begin( pProfiler, numCallsToAdd );
}
~TMiniProfilerGuard( )
{
#if ENABLE_MINI_PROFILER
int64 nElapsed = GetElapsed( );
m_pProfiler->Add( nElapsed, m_numCallsToAdd );
m_pLastProfiler->SubCallee( nElapsed );
if ( bThreadSafe )
{
PopMiniProfilerTS( m_pLastProfiler );
}
else
{
g_pLastMiniProfiler = m_pLastProfiler;
}
#endif
}
};
typedef TMiniProfilerGuard<CMiniProfilerSample, false> CMiniProfilerGuardFast; // default guard uses rdtsc
typedef TMiniProfilerGuard<CMiniProfilerSample, true> CMiniProfilerGuard, CMiniProfilerGuardTS; // default guard uses rdtsc
class CMiniProfilerGuardSimple: public CMiniProfilerSample
{
#if ENABLE_MINI_PROFILER
CMiniProfiler *m_pProfiler, *m_pLastProfiler;
#endif
public:
CMiniProfilerGuardSimple( CLinkedMiniProfiler *pProfiler )
{
#if ENABLE_MINI_PROFILER
m_pProfiler = pProfiler;
pProfiler->m_pLastParent = m_pLastProfiler = PushMiniProfilerTS( pProfiler ); // = g_pLastMiniProfiler; g_pLastMiniProfiler = pProfiler;
#endif
}
~CMiniProfilerGuardSimple()
{
#if ENABLE_MINI_PROFILER
// Note: we measure both push and pop as if they belonged to the measured function
PopMiniProfilerTS( m_pLastProfiler ); // g_pLastMiniProfiler = m_pLastProfiler;
int64 nElapsed = GetElapsed( );
m_pProfiler->Add( nElapsed );
m_pLastProfiler->SubCallee( nElapsed );
#endif
}
};
class CMiniProfilerAntiGuard: public CMiniProfilerSample
{
#if ENABLE_MINI_PROFILER
CMiniProfiler *m_pProfiler;
#endif
public:
CMiniProfilerAntiGuard( CMiniProfiler *pProfiler )
{
#if ENABLE_MINI_PROFILER
m_pProfiler = pProfiler;
#endif
}
~CMiniProfilerAntiGuard( )
{
#if ENABLE_MINI_PROFILER
m_pProfiler->Add( -GetElapsed( ) );
#endif
}
};
#define MPROF_VAR_NAME_INTERNAL_CAT(a, b) a##b
#define MPROF_VAR_NAME_INTERNAL( a, b ) MPROF_VAR_NAME_INTERNAL_CAT( a, b )
#define MPROF_VAR_NAME( a ) MPROF_VAR_NAME_INTERNAL( a, __LINE__ )
#define MPROF_TO_STRING_0( a ) #a
#define MPROF_TO_STRING( a ) MPROF_TO_STRING_0(a)
#ifdef PROJECTNAME
#define MPROF_PROJECTNAME_STRING MPROF_TO_STRING(PROJECTNAME)
#else
#define MPROF_PROJECTNAME_STRING ""
#endif
#if ENABLE_MINI_PROFILER
#define MPROF_GR( item, group ) static CLinkedMiniProfiler MPROF_VAR_NAME(miniProfilerNode)( ( item ), group "\n" __FUNCTION__ "\n" __FILE__ "\n" MPROF_TO_STRING( __LINE__ ) "\n" MPROF_PROJECTNAME_STRING ); CMiniProfilerGuardSimple MPROF_VAR_NAME( miniProfilerGuard )( &MPROF_VAR_NAME( miniProfilerNode ) )
#else
#define MPROF_GR( item, group )
#endif
#define MPROF_NODE( name, item, group ) CLinkedMiniProfiler miniprofiler_##name( ( item ), group "\n\n" __FILE__ "\n" MPROF_TO_STRING( __LINE__ ) "\n" MPROF_PROJECTNAME_STRING );
#define MPROF_AUTO( name ) CMiniProfilerGuardSimple MPROF_VAR_NAME(miniProfiler_##name##_auto)( &miniprofiler_##name )
#define MPROF_AUTO_FAST( name ) CMicroProfilerGuard MPROF_VAR_NAME(microProfiler_##name##_auto)( &miniprofiler_##name )
#define MPROF_AUTO_FAST_COUNT( NAME, COUNT ) CMicroProfilerGuardWithCount MPROF_VAR_NAME(microProfiler_##NAME##_auto)( &miniprofiler_##NAME, COUNT )
#define MPROF( item ) MPROF_GR( item, "" )
#define MPROF_FN() MPROF( __FUNCTION__ )
#endif

127
public/tier0/perfstats.h Normal file
View File

@@ -0,0 +1,127 @@
//===== Copyright © 1996-2007, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// Simple data structure keeping track
//
// $NoKeywords: $
//
//===========================================================================//
#ifndef PERFSTATS_H
#define PERFSTATS_H
#include "tier0/fasttimer.h"
//-----------------------------------------------------------------------------
//
// Slot ID for which we will be collecting performance stats
//
enum PerfStatsSlot_t
{
PERF_STATS_SLOT_MAINTHREAD, // stats collected in CPerfStatsData::Tick()
PERF_STATS_SLOT_MAINTHREAD_NOWAIT, // time spent in the main thread - time spent in EndFrame
PERF_STATS_SLOT_RENDERTHREAD,
PERF_STATS_SLOT_END_FRAME,
PERF_STATS_SLOT_FORCE_HARDWARE_SYNC,
PERF_STATS_SLOT_MAX
};
//-----------------------------------------------------------------------------
//
// PerfStatsSlotData struct
// Contains performance stats for a single slot
//
class CPerfStatsSlotData
{
public:
void Reset()
{
m_pszName = NULL;
m_CurrFrameTime.Init();
m_PrevFrameTime.Init();
m_AccTotalTime.Init();
}
void ResetFrameStats()
{
m_CurrFrameTime.Init();
}
void StartTimer( const char* pszName )
{
m_pszName = pszName;
m_Timer.Start();
}
void EndTimer( void )
{
m_Timer.End();
const CCycleCount& duration = m_Timer.GetDuration();
m_CurrFrameTime += duration;
m_AccTotalTime += duration;
}
const char* m_pszName;
CFastTimer m_Timer;
CCycleCount m_CurrFrameTime; // Accumulated time over a single frame
CCycleCount m_PrevFrameTime; // This is used to display cl_showfps
CCycleCount m_AccTotalTime; // Total accumulated time
};
//-----------------------------------------------------------------------------
//
// PerfStatsData struct
//
class PLATFORM_CLASS CPerfStatsData
{
public:
CPerfStatsData();
void Tick();
void Reset();
uint64 m_nFrames;
CPerfStatsSlotData m_Slots[PERF_STATS_SLOT_MAX];
};
PLATFORM_INTERFACE CPerfStatsData g_PerfStats;
//-----------------------------------------------------------------------------
//
// Helper class that times whatever block of code it's in
// and collect data for the given slot
//
class CPerfStatsScope
{
public:
CPerfStatsScope( const char* pszName, PerfStatsSlot_t slotId ) : m_SlotData( NULL )
{
if ( slotId < PERF_STATS_SLOT_MAX )
{
m_SlotData = &g_PerfStats.m_Slots[slotId];
m_SlotData->StartTimer( pszName );
}
}
~CPerfStatsScope()
{
if ( m_SlotData )
{
m_SlotData->EndTimer();
}
}
private:
CPerfStatsSlotData* m_SlotData;
};
#define PERF_STATS_BLOCK( name, slot ) CPerfStatsScope _perfStatsScope##__LINE__( name, slot );
#endif // PERFSTATS_H

2568
public/tier0/platform.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
// This file is a force-include override
#ifdef PLATFORM_OVERRIDE_MATERIALSYSTEM
#define PLATFORM_OVERRIDE_MEM_ALLOC_INTERNAL_PS3 g_pMemAllocInternalPS3Override_MaterialSystem
#endif
#ifdef PLATFORM_OVERRIDE_TIER0
#define PLATFORM_OVERRIDE_MEM_ALLOC_INTERNAL_PS3 g_pMemAllocInternalPS3Override_Tier0
#endif
#ifdef PLATFORM_OVERRIDE_MEM_ALLOC_INTERNAL_PS3
class IMemAlloc;
struct IMemAlloc_CachedInterface_t
{
IMemAlloc_CachedInterface_t();
IMemAlloc *m_pMemAllocCached;
};
extern IMemAlloc_CachedInterface_t PLATFORM_OVERRIDE_MEM_ALLOC_INTERNAL_PS3;
#define PLATFORM_INTERFACE_MEM_ALLOC_INTERNAL_PS3_OVERRIDE PLATFORM_OVERRIDE_MEM_ALLOC_INTERNAL_PS3.m_pMemAllocCached
#define PLATFORM_OVERRIDE_MEM_ALLOC_INTERNAL_PS3_IMPL \
IMemAlloc_CachedInterface_t PLATFORM_OVERRIDE_MEM_ALLOC_INTERNAL_PS3 CONSTRUCT_EARLY; \
IMemAlloc_CachedInterface_t::IMemAlloc_CachedInterface_t() \
{ \
m_pMemAllocCached = g_pMemAllocInternalPS3; \
}
#endif
// Force-include delegation to platform.h
#include "platform.h"

82
public/tier0/platwindow.h Normal file
View File

@@ -0,0 +1,82 @@
//===== Copyright © 1996-2009, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $NoKeywords: $
//
//===========================================================================//
#ifndef PLATWINDOW_H
#define PLATWINDOW_H
#ifdef COMPILER_MSVC32
#pragma once
#endif
#include "tier0/platform.h"
#include "tier0/basetypes.h"
//-----------------------------------------------------------------------------
// Window handle
//-----------------------------------------------------------------------------
DECLARE_POINTER_HANDLE( PlatWindow_t );
#define PLAT_WINDOW_INVALID ( (PlatWindow_t)0 )
//-----------------------------------------------------------------------------
// Window creation
//-----------------------------------------------------------------------------
enum WindowCreateFlags_t
{
WINDOW_CREATE_FULLSCREEN = 0x1,
WINDOW_CREATE_RESIZING = 0x2,
};
PLATFORM_INTERFACE PlatWindow_t Plat_CreateWindow( void *hInstance, const char *pTitle, int nWidth, int nHeight, int nFlags );
//-----------------------------------------------------------------------------
// Window title
//-----------------------------------------------------------------------------
PLATFORM_INTERFACE void Plat_SetWindowTitle( PlatWindow_t hWindow, const char *pTitle );
//-----------------------------------------------------------------------------
// Window movement
//-----------------------------------------------------------------------------
PLATFORM_INTERFACE void Plat_SetWindowPos( PlatWindow_t hWindow, int x, int y );
//-----------------------------------------------------------------------------
// Gets the desktop resolution
//-----------------------------------------------------------------------------
PLATFORM_INTERFACE void Plat_GetDesktopResolution( int *pWidth, int *pHeight );
//-----------------------------------------------------------------------------
// Gets a window size
//-----------------------------------------------------------------------------
PLATFORM_INTERFACE void Plat_GetWindowClientSize( PlatWindow_t hWindow, int *pWidth, int *pHeight );
//-----------------------------------------------------------------------------
// Is the window minimized?
//-----------------------------------------------------------------------------
PLATFORM_INTERFACE bool Plat_IsWindowMinimized( PlatWindow_t hWindow );
//-----------------------------------------------------------------------------
// Gets the shell window in a console app
//-----------------------------------------------------------------------------
PLATFORM_INTERFACE PlatWindow_t Plat_GetShellWindow( );
//-----------------------------------------------------------------------------
// Convert window -> Screen coordinates and back
//-----------------------------------------------------------------------------
PLATFORM_INTERFACE void Plat_WindowToScreenCoords( PlatWindow_t hWnd, int &x, int &y );
PLATFORM_INTERFACE void Plat_ScreenToWindowCoords( PlatWindow_t hWnd, int &x, int &y );
#endif // PLATWINDOW_H

73
public/tier0/pmc360.h Normal file
View File

@@ -0,0 +1,73 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Analogous to l2cache.h, this class represents information gleaned
// from the 360's Performance Monitor Counters. In particular we
// are interested in l2 cache misses and load-hit-stores.
//
//=============================================================================//
#ifndef CPMCDATA_H
#define CPMCDATA_H
#ifdef _WIN32
#pragma once
#endif
#ifndef _X360
#error This file must only be compiled for XBOX360!
#endif
// Warning:
// As written, this class only supports profiling thread 0, processor 0.
class CPMCData
{
public:
CPMCData();
~CPMCData() {};
void Start( void );
void End( void );
/// This function should be called exactly once during the lifespan of the program;
/// it will set up the counters to record the information we are interested in.
/// This will stomp on whoever else might have set the performance counters elsewhere
/// in the game.
static void InitializeOnceProgramWide( void );
static bool IsInitialized();
//-------------------------------------------------------------------------
// GetL2CacheMisses
//-------------------------------------------------------------------------
uint64 GetL2CacheMisses( void ) const
{
return m_Delta.L2CacheMiss;
}
uint64 GetLHS( void ) const
{
return m_Delta.LHS;
}
/*
#ifdef DBGFLAG_VALIDATE
void Validate( CValidator &validator, tchar *pchName ); // Validate our internal structures
#endif // DBGFLAG_VALIDATE
*/
private:
/// represents saved numbers from the counters we are interested in
struct PMCounters
{
uint64 L2CacheMiss;
uint64 LHS; ///< load hit store
PMCounters(int64 _l2cm, int64 _lhs ) : L2CacheMiss(_l2cm), LHS(_lhs) {};
PMCounters() : L2CacheMiss(0), LHS(0) {};
};
PMCounters m_OnStart; ///< values when we began the timer
PMCounters m_Delta ; ///< computed total delta between start/stop
};
#endif // CPMCDATA_H

View File

@@ -0,0 +1,23 @@
//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============//
//
// Purpose: Provide a shared place for library fucntions to report progress % for display
//
//=============================================================================//
#ifndef PROGRESSBAR_H
#define PROGRESSBAR_H
#ifdef _WIN32
#pragma once
#endif
PLATFORM_INTERFACE void ReportProgress(char const *job_name, int total_units_to_do,
int n_units_completed);
typedef void (*ProgressReportHandler_t)( char const*, int, int );
// install your own handler. returns previous handler
PLATFORM_INTERFACE ProgressReportHandler_t InstallProgressReportHandler( ProgressReportHandler_t pfn);
#endif

View File

@@ -0,0 +1,266 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#ifndef PROTECTED_THINGS_H
#define PROTECTED_THINGS_H
#ifdef _WIN32
#pragma once
#endif
// This header tries to prevent people from using potentially dangerous functions
// (like the notorious non-null-terminating strncpy) and functions that will break
// VCR mode (like time, input, registry, etc).
//
// This header should be included by ALL of our source code.
// Eventually, ALL of these should be protected, but one man can only accomplish so much in
// one day AND work on features too!
#if defined( PROTECTED_STRINGS_ENABLE )
#if defined( printf )
#undef printf
#endif
#define printf printf__HEY_YOU__USE_VSTDLIB
#if defined( wprintf )
#undef wprintf
#endif
#define wprintf wprintf__HEY_YOU__USE_VSTDLIB
#if defined( strcmp )
#undef strcmp
#endif
#define strcmp strcmp__HEY_YOU__USE_VSTDLIB
#if defined( wcscmp )
#undef wcscmp
#endif
#define wcscmp wcscmp__HEY_YOU__USE_VSTDLIB
#if defined( strncpy )
#undef strncpy
#endif
#define strncpy strncpy__HEY_YOU__USE_VSTDLIB
#if defined( wcsncpy )
#undef wcsncpy
#endif
#define wcsncpy wcsncpy__HEY_YOU__USE_VSTDLIB
#if defined( strlen )
#undef strlen
#endif
#define strlen strlen__HEY_YOU__USE_VSTDLIB
#if defined( wcslen )
#undef wcslen
#endif
#define wcslen wcslen__HEY_YOU__USE_VSTDLIB
#if defined( Q_strlen )
#undef Q_strlen
#endif
#define Q_strlen Q_strlen__HEY_YOU__USE_VSTDLIB
#if defined( _snprintf )
#undef _snprintf
#endif
#define _snprintf snprintf__HEY_YOU__USE_VSTDLIB
#if defined( _snwprintf )
#undef _snwprintf
#endif
#define _snwprintf snwprintf__HEY_YOU__USE_VSTDLIB
#if defined( sprintf )
#undef sprintf
#endif
#define sprintf sprintf__HEY_YOU__USE_VSTDLIB
#if defined( swprintf )
#undef swprintf
#endif
#define swprintf swprintf__HEY_YOU__USE_VSTDLIB
#if defined( vsprintf )
#undef vsprintf
#endif
#define vsprintf vsprintf__HEY_YOU__USE_VSTDLIB
#if defined( vswprintf )
#undef vswprintf
#endif
#define vswprintf vswprintf__HEY_YOU__USE_VSTDLIB
#if defined( _vsnprintf )
#undef _vsnprintf
#endif
#define _vsnprintf vsnprintf__HEY_YOU__USE_VSTDLIB
#if defined( _vsnwprintf )
#undef _vsnwprintf
#endif
#define _vsnwprintf vsnwprintf__HEY_YOU__USE_VSTDLIB
#if defined( strcat )
#undef strcat
#endif
#define strcat strcat__HEY_YOU__USE_VSTDLIB
#if defined( wcscat )
#undef wcscat
#endif
#define wcscat wcscat__HEY_YOU__USE_VSTDLIB
#if defined( strncat )
#undef strncat
#endif
#define strncat strncat__HEY_YOU__USE_VSTDLIB
#if defined( wcsncat )
#undef wcsncat
#endif
#define wcsncat wcsncat__HEY_YOU__USE_VSTDLIB
#endif
#if defined( PROTECTED_THINGS_ENABLE ) && !defined( _X360 )
#if defined( GetTickCount )
#undef GetTickCount
#endif
#define GetTickCount Use__Plat_MSTime__Instead_of_GetTickCount
#if defined( timeGetTime )
#undef timeGetTime
#endif
#define timeGetTime Use__Plat_MSTime__Instead_of_timeGetTime
#if defined( clock )
#undef clock
#endif
#if defined( GetCursorPos )
#undef GetCursorPos
#endif
#define GetCursorPos GetCursorPos__USE_VCR_MODE
#if defined( ScreenToClient )
#undef ScreenToClient
#endif
#define ScreenToClient ScreenToClient__USE_VCR_MODE
// JAY64: Revisit this, but squelch the warnings for now
#ifndef _WIN64
#if defined( GetCommandLine )
#undef GetCommandLine
#endif
#define GetCommandLine GetCommandLine__USE_VCR_MODE
#if defined( RegOpenKeyEx )
#undef RegOpenKeyEx
#endif
#define RegOpenKeyEx RegOpenKeyEx__USE_VCR_MODE
#if defined( RegOpenKey )
#undef RegOpenKey
#endif
#define RegOpenKey RegOpenKey__USE_VCR_MODE
#if defined( RegSetValueEx )
#undef RegSetValueEx
#endif
#define RegSetValueEx RegSetValueEx__USE_VCR_MODE
#if defined( RegSetValue )
#undef RegSetValue
#endif
#define RegSetValue RegSetValue__USE_VCR_MODE
#if defined( RegQueryValueEx )
#undef RegQueryValueEx
#endif
#define RegQueryValueEx RegQueryValueEx__USE_VCR_MODE
#if defined( RegQueryValue )
#undef RegQueryValue
#endif
#define RegQueryValue RegQueryValue__USE_VCR_MODE
#if defined( RegCreateKeyEx )
#undef RegCreateKeyEx
#endif
#define RegCreateKeyEx RegCreateKeyEx__USE_VCR_MODE
#if defined( RegCreateKey )
#undef RegCreateKey
#endif
#define RegCreateKey RegCreateKey__USE_VCR_MODE
#if defined( RegCloseKey )
#undef RegCloseKey
#endif
#define RegCloseKey RegCloseKey__USE_VCR_MODE
#if defined( GetNumberOfConsoleInputEvents )
#undef GetNumberOfConsoleInputEvents
#endif
#define GetNumberOfConsoleInputEvents GetNumberOfConsoleInputEvents__USE_VCR_MODE
#if defined( ReadConsoleInput )
#undef ReadConsoleInput
#endif
#define ReadConsoleInput ReadConsoleInput__USE_VCR_MODE
#if defined( GetAsyncKeyState )
#undef GetAsyncKeyState
#endif
#define GetAsyncKeyState GetAsyncKeyState__USE_VCR_MODE
#if defined( GetKeyState )
#undef GetKeyState
#endif
#define GetKeyState GetKeyState__USE_VCR_MODE
#endif
#if defined( CreateThread )
#undef CreateThread
#endif
#define CreateThread use__ThreadTools__for_thread_functions
#if defined( WaitForSingleObject )
#undef WaitForSingleObject
#endif
#define WaitForSingleObject use__ThreadTools__for_thread_functions
#if defined( EnterCriticalSection )
#undef EnterCriticalSection
#endif
#define EnterCriticalSection use__ThreadTools__for_thread_functions
#endif
#endif // PROTECTED_THINGS_H

966
public/tier0/stackstats.h Normal file
View File

@@ -0,0 +1,966 @@
//========= Copyright <20> 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> &copyFrom )
: 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> &copyFrom )
: 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

155
public/tier0/stacktools.h Normal file
View File

@@ -0,0 +1,155 @@
//========= Copyright <20> 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 &copyFrom )
{
iValidEntries = copyFrom.iValidEntries;
// warning C6204: Possible buffer overrun in call to 'memcpy': use of unchecked parameter 'src'
ANALYZE_SUPPRESS( 6204 )
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

View File

@@ -0,0 +1,58 @@
//====== Copyright c 1996-2007, Valve Corporation, All rights reserved. =======//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef SYSTEMINFORMATION_H
#define SYSTEMINFORMATION_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/platform.h"
#ifndef PLATFORM_INTERFACE
#define PLATFORM_INTERFACE
#endif
//
// Defines a possible outcome of a system call
//
enum SYSTEM_CALL_RESULT_t
{
SYSCALL_SUCCESS = 0, // System call succeeded
SYSCALL_FAILED = 1, // System call failed
SYSCALL_NOPROC = 2, // Failed to find required system procedure
SYSCALL_NODLL = 3, // Failed to find or load required system module
SYSCALL_UNSUPPORTED = 4, // System call unsupported on the OS
};
//
// Information about paged pool memory
//
struct PAGED_POOL_INFO_t
{
uint32 numPagesUsed; // Number of Paged Pool pages used
uint32 numPagesFree; // Number of Paged Pool pages free
};
//
// Plat_GetMemPageSize
// Returns the size of a memory page in kilobytes.
//
PLATFORM_INTERFACE uint32 Plat_GetMemPageSize();
//
// Plat_GetPagedPoolInfo
// Fills in the paged pool info structure if successful.
//
PLATFORM_INTERFACE SYSTEM_CALL_RESULT_t Plat_GetPagedPoolInfo( PAGED_POOL_INFO_t *pPPI );
#endif // #ifndef SYSTEMINFORMATION_H

View File

@@ -0,0 +1,36 @@
//========= Copyright ©, Valve LLC, All rights reserved. ============
//
// Purpose: declares a variety of constants
//
// $NoKeywords: $
//=============================================================================
#ifndef T0CONSTANTS_H
#define T0CONSTANTS_H
#ifdef _WIN32
#pragma once
#endif
//-----------------------------------------------------------------------------
// numeric constants to avoid typos with wrong number of zeros
//-----------------------------------------------------------------------------
const int64 k_nMillion = 1000000;
const int64 k_nThousand = 1000;
const int64 k_nKiloByte = 1024;
const int64 k_nMegabyte = k_nKiloByte * k_nKiloByte;
const int64 k_nGigabyte = k_nMegabyte * k_nKiloByte;
//-----------------------------------------------------------------------------
// Timing constants
//-----------------------------------------------------------------------------
const unsigned int k_nSecondsPerHour = 60*60;
const unsigned int k_nSecondsPerDay = k_nSecondsPerHour * 24;
const int k_cSecondsPerMinute = 60;
const int k_cSecondsPerHour = k_cSecondsPerMinute * 60;
const int k_cSecondsPerDay = k_cSecondsPerHour * 24;
const int k_cSecondsPerWeek = k_cSecondsPerDay * 7;
const int k_cSecondsPerYear = k_cSecondsPerDay * 365;
#endif // T0CONSTANTS_H

60
public/tier0/testthread.h Normal file
View File

@@ -0,0 +1,60 @@
//====== Copyright © 1996-2004, Valve Corporation, All rights reserved. =======
//
// Purpose: exposes testing thread functions
//
//=============================================================================
#ifndef TESTTHREAD_H
#define TESTTHREAD_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/dbg.h"
// test callback
typedef void (STDCALL *TestFunc)(void *pv);
// runs the test function
PLATFORM_INTERFACE void Test_RunTest(TestFunc func, void *pvArg);
// call to give the test thread a chance to run
// calling thread will block until the test thread yields
// doesn't do anything if no tests are running
PLATFORM_INTERFACE void Test_RunFrame();
// true if any tests are running, or have ran
PLATFORM_INTERFACE bool Test_IsActive();
// sets that the test has failed
PLATFORM_INTERFACE void Test_SetFailed();
// true if any tests have failed, due to an assert, warning, or explicit fail
PLATFORM_INTERFACE bool Test_HasFailed();
// true if any tests have completed
PLATFORM_INTERFACE bool Test_HasFinished();
// terminates the test thread
PLATFORM_INTERFACE void Test_TerminateThread();
// the following functions should only be called from the test thread
// yields to the main thread for a single frame
// passing in is a count of the number of frames that have been yielded by this yield macro
// can be used to assert if a test thread is blocked foor
PLATFORM_INTERFACE void TestThread_Yield();
// utility functions to pause the test frame until the selected condition is true
#define YIELD_UNTIL(x) { int iYieldCount = 0; while (!(x)) { TestThread_Yield(); iYieldCount++; if ( iYieldCount >= 100 ) { AssertMsg( false, #x ); break; } } }
// use this like a while(1) loop, with break; to stop yielding
#define YIELD_UNTIL_BREAK() for (; true; TestThread_Yield())
// yields for a single frame
#define YIELD_FRAME() { TestThread_Yield(); }
#define YIELD_TWO_FRAMES() { TestThread_Yield(); TestThread_Yield(); }
#endif // TESTTHREAD_H

2636
public/tier0/threadtools.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,649 @@
#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%p)", this, 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),
nBytesStack ? STACK_SIZE_PARAM_IS_A_RESERVATION : 0,
(LPDWORD)&m_threadId );
if( nPriority != TP_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 bool CThread::IsThreadRunning()
{
#ifdef _PS3
// ThreadIsThreadIdRunning() doesn't work on PS3 if the thread is in a zombie state
return m_eventTheadExit.Check();
#else
return ThreadIsThreadIdRunning( (ThreadId_t)m_threadId );
#endif
}
//---------------------------------------------------------
INLINE_ON_PS3 CThread::ThreadProc_t CThread::GetThreadProc()
{
return ThreadProc;
}
INLINE_ON_PS3 void CThread::ThreadProcRunWithMinidumpHandler( void *pv )
{
ThreadInit_t *pInit = reinterpret_cast<ThreadInit_t*>(pv);
pInit->pThread->m_result = pInit->pThread->Run();
}
#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
{
#if defined( _WIN32 )
CatchAndWriteMiniDumpForVoidPtrFn( ThreadProcRunWithMinidumpHandler, pv, false );
#else
pInit->pThread->m_result = pInit->pThread->Run();
#endif
}
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*)(uintp)pInit->pThread->m_result;
#else
return pInit->pThread->m_result;
#endif
}
#endif // THREADTOOLS_INL

1027
public/tier0/tslist.h Normal file

File diff suppressed because it is too large Load Diff

73
public/tier0/validator.h Normal file
View File

@@ -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

72
public/tier0/valobject.h Normal file
View File

@@ -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

View File

@@ -0,0 +1,8 @@
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif

View File

@@ -0,0 +1,8 @@
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif

33
public/tier0/valve_off.h Normal file
View File

@@ -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

37
public/tier0/valve_on.h Normal file
View File

@@ -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

25
public/tier0/vatoms.h Normal file
View File

@@ -0,0 +1,25 @@
// This is the interface to Valve atoms, a simple global table of pointers
// that does not change when we reload a game system. Its purpose is to facilitate
// on-the-fly unloading and reloading of AppSystems. The intended use is this:
// Appsystem allocates its interfaces on global heap (managed by tier0) and
// places pointers to those interfaces into the atom table. Then, when
// somebody unloads and reloads this system, the system will see that the atom
// is not NULL and reconnect so that the old pointers remain valid.
////////////////////////////////////////////////////////////////////////////////
#ifndef TIER0_ATOMS_HDR
#define TIER0_ATOMS_HDR
enum VAtomEnum
{
VATOM_VJOBS, // vjobs.prx system
VATOM_COUNT
};
// Do NOT cache these pointers to pointers, they may change
// the *GetVAtom() doesn't change, though
PLATFORM_INTERFACE void** GetVAtom( int nAtomIndex );
#endif

1546
public/tier0/vprof.h Normal file

File diff suppressed because it is too large Load Diff

38
public/tier0/vprof_sn.h Normal file
View File

@@ -0,0 +1,38 @@
//========= 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 // PB: Vprof markers to tuner turned off
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( );
}
};
#define SNPROF(name) ((void)0)//CVProfSnMarkerScope v_snprof##__LINE__(name);
#define SNPROF_ANIM(name) ((void)0)//SNPROF(name)
#else
class CVProfSnMarkerScope { public: CVProfSnMarkerScope( const char * ) {} };
#define SNPROF(name) TM_ZONE( TELEMETRY_LEVEL1, TMZF_NONE, "%s", name );
#define SNPROF_ANIM(name) TM_ZONE( TELEMETRY_LEVEL1, TMZF_NONE, "anim %s", name );
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,70 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Real-Time Hierarchical Profiling
//
// $NoKeywords: $
//=============================================================================//
#ifndef VTUNEINTERFACE_H
#define VTUNEINTERFACE_H
//#define VTUNE_ENABLED
#ifdef VTUNE_ENABLED
#include "platform.h"
#include "..\thirdparty\vtune\include\ittnotify.h"
class VTuneInterface
{
public:
virtual void Init() = 0;
virtual void StartFrame() = 0;
virtual void EndFrame() = 0;
virtual __itt_event CreateEvent( const char *name ) = 0;
};
// VTuneEvent implements user events. By default starts when created, stops
// when out of scope. To change start behaviour set bStart = false in constructor
// and call Start(). To change stop behaviour call Stop().
class VTuneAutoEvent
{
public:
VTuneAutoEvent( __itt_event vtuneEvent )
{
m_event = vtuneEvent;
Start();
}
~VTuneAutoEvent()
{
End();
}
PLATFORM_CLASS void Start();
PLATFORM_CLASS void End();
private:
__itt_event m_event;
};
PLATFORM_INTERFACE VTuneInterface *g_pVTuneInterface;
#define VTUNE_AUTO_EVENT( name ) \
static __itt_event event_ ## name = 0; \
if ( ! (event_ ## name) ) \
{ \
event_ ## name = g_pVTuneInterface->CreateEvent( #name ); \
} \
VTuneAutoEvent autoEvent_ ## name ( event_ ## name );
#endif
#endif // VTUNEINTERFACE_H

115
public/tier0/wchartypes.h Normal file
View File

@@ -0,0 +1,115 @@
//========= 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
#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).
typedef unsigned char uint8;
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 )
#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
#if defined( _MSC_VER ) || defined( WIN32 )
typedef wchar_t uchar16;
typedef unsigned int uchar32;
#else
typedef unsigned short uchar16;
typedef wchar_t uchar32;
#endif
#ifdef GNUC
typedef unsigned short ucs2; // wchar_t is 4 bytes on sane os's, specially define a ucs2 type so we can read out localization files and the list saved as 2 byte wchar (or ucs16 Matt tells me)
#elif defined(_MSC_VER)
typedef wchar_t ucs2; // under windows wchar_t is ucs2
#endif
// Turn valve defines back on
#include "tier0/valve_on.h"
#endif // WCHARTYPES

View File

@@ -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

View File

@@ -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