initial
This commit is contained in:
480
public/tier0/EventMasks.h
Normal file
480
public/tier0/EventMasks.h
Normal 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
1787
public/tier0/EventModes.h
Normal file
File diff suppressed because it is too large
Load Diff
29
public/tier0/IOCTLCodes.h
Normal file
29
public/tier0/IOCTLCodes.h
Normal 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
|
||||
2040
public/tier0/K8PerformanceCounters.h
Normal file
2040
public/tier0/K8PerformanceCounters.h
Normal file
File diff suppressed because it is too large
Load Diff
322
public/tier0/P4PerformanceCounters.h
Normal file
322
public/tier0/P4PerformanceCounters.h
Normal 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
|
||||
225
public/tier0/P5P6PerformanceCounters.h
Normal file
225
public/tier0/P5P6PerformanceCounters.h
Normal 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
212
public/tier0/PMELib.h
Normal 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
|
||||
456
public/tier0/afxmem_override.cpp
Normal file
456
public/tier0/afxmem_override.cpp
Normal 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
116
public/tier0/annotations.h
Normal 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
700
public/tier0/basetypes.h
Normal 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
|
||||
57
public/tier0/cache_hints.h
Normal file
57
public/tier0/cache_hints.h
Normal 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
174
public/tier0/commonmacros.h
Normal 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
|
||||
33
public/tier0/cpumonitoring.h
Normal file
33
public/tier0/cpumonitoring.h
Normal 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
852
public/tier0/dbg.h
Normal 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
68
public/tier0/dbgflag.h
Normal 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
136
public/tier0/dynfunction.h
Normal 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
162
public/tier0/etwprof.h
Normal 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
596
public/tier0/fasttimer.h
Normal 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
|
||||
49
public/tier0/hardware_clock_fast.h
Normal file
49
public/tier0/hardware_clock_fast.h
Normal 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
377
public/tier0/ia32detect.h
Normal 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
|
||||
69
public/tier0/icommandline.h
Normal file
69
public/tier0/icommandline.h
Normal 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
47
public/tier0/l2cache.h
Normal 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
768
public/tier0/logging.h
Normal 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
|
||||
29
public/tier0/math_tables.h
Normal file
29
public/tier0/math_tables.h
Normal 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
51
public/tier0/mem.h
Normal 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
763
public/tier0/memalloc.h
Normal 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
25
public/tier0/memdbgoff.h
Normal 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
281
public/tier0/memdbgon.h
Normal 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
1940
public/tier0/memoverride.cpp
Normal file
File diff suppressed because it is too large
Load Diff
23
public/tier0/memoverride_ps3.h
Normal file
23
public/tier0/memoverride_ps3.h
Normal 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
46
public/tier0/memvirt.h
Normal 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
|
||||
345
public/tier0/microprofiler.h
Normal file
345
public/tier0/microprofiler.h
Normal 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
109
public/tier0/minidump.h
Normal 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
369
public/tier0/miniprofiler.h
Normal 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
127
public/tier0/perfstats.h
Normal 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
2568
public/tier0/platform.h
Normal file
File diff suppressed because it is too large
Load Diff
33
public/tier0/platform_override.h
Normal file
33
public/tier0/platform_override.h
Normal 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
82
public/tier0/platwindow.h
Normal 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
73
public/tier0/pmc360.h
Normal 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
|
||||
23
public/tier0/progressbar.h
Normal file
23
public/tier0/progressbar.h
Normal 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
|
||||
266
public/tier0/protected_things.h
Normal file
266
public/tier0/protected_things.h
Normal 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
966
public/tier0/stackstats.h
Normal 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> ©From )
|
||||
: CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( copyFrom )
|
||||
{
|
||||
this->m_Gatherer.pFunctionTable->pfn_ApplyTreeAccessLock( this->m_Gatherer.pGatherer, true );
|
||||
this->m_Gatherer.pFunctionTable->pfn_LockEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex, true );
|
||||
this->m_pStruct = (STATSTRUCT *)this->m_Gatherer.pFunctionTable->pfn_GetEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex );
|
||||
}
|
||||
|
||||
~CCallStackStatsGatherer_StructAccessor_AutoLock( void )
|
||||
{
|
||||
this->m_Gatherer.pFunctionTable->pfn_LockEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex, false );
|
||||
this->m_Gatherer.pFunctionTable->pfn_ApplyTreeAccessLock( this->m_Gatherer.pGatherer, false );
|
||||
}
|
||||
|
||||
STATSTRUCT *operator->()
|
||||
{
|
||||
return this->m_pStruct;
|
||||
}
|
||||
|
||||
STATSTRUCT *GetStruct( void ) //do not hold this pointer outside the lock period
|
||||
{
|
||||
return this->m_pStruct;
|
||||
}
|
||||
|
||||
protected:
|
||||
STATSTRUCT *m_pStruct;
|
||||
};
|
||||
|
||||
|
||||
//struct is locked in place only between Lock() and paired Unlock() calls. Get a base, then create one of these from it.
|
||||
//It's safe to hold onto this for an extended period of time. The entry index is unchanging in the gatherer tree.
|
||||
template <class STATSTRUCT>
|
||||
class CCallStackStatsGatherer_StructAccessor_Manual : CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>
|
||||
{
|
||||
public:
|
||||
CCallStackStatsGatherer_StructAccessor_Manual( CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> ©From )
|
||||
: CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( copyFrom ), m_pStruct( NULL )
|
||||
{ }
|
||||
|
||||
STATSTRUCT *operator->()
|
||||
{
|
||||
return this->m_pStruct; //NULL while entry is not locked.
|
||||
}
|
||||
|
||||
STATSTRUCT *GetStruct( void ) //do not hold this pointer outside the lock period
|
||||
{
|
||||
return this->m_pStruct; //NULL while entry is not locked.
|
||||
}
|
||||
|
||||
void Lock( void )
|
||||
{
|
||||
this->m_Gatherer.pFunctionTable->pfn_ApplyTreeAccessLock( this->m_Gatherer.pGatherer, true );
|
||||
this->m_Gatherer.pFunctionTable->pfn_LockEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex, true );
|
||||
this->m_pStruct = (STATSTRUCT *)this->m_Gatherer.pFunctionTable->pfn_GetEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex );
|
||||
}
|
||||
|
||||
void Unlock( void )
|
||||
{
|
||||
this->m_pStruct = NULL;
|
||||
this->m_Gatherer.pFunctionTable->pfn_LockEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex, false );
|
||||
this->m_Gatherer.pFunctionTable->pfn_ApplyTreeAccessLock( this->m_Gatherer.pGatherer, false );
|
||||
}
|
||||
|
||||
protected:
|
||||
STATSTRUCT *m_pStruct;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class CCallStackStats_PushSubTree_AutoPop
|
||||
{
|
||||
public:
|
||||
CCallStackStats_PushSubTree_AutoPop( const CCallStackStatsGatherer_Standardized_t &Parent, const CCallStackStatsGatherer_Standardized_t &Child, const CCallStackStorage &PushStack = CCallStackStorage() )
|
||||
: m_PopFrom( Parent )
|
||||
{
|
||||
Parent.pFunctionTable->pfn_PushSubTree( Parent.pGatherer, Child, PushStack );
|
||||
}
|
||||
~CCallStackStats_PushSubTree_AutoPop( void )
|
||||
{
|
||||
m_PopFrom.PopSubTree();
|
||||
}
|
||||
|
||||
CCallStackStatsGatherer_Standardized_t m_PopFrom;
|
||||
};
|
||||
|
||||
|
||||
#endif //#ifndef TIER0_STACKTOOLS_H
|
||||
155
public/tier0/stacktools.h
Normal file
155
public/tier0/stacktools.h
Normal 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 ©From )
|
||||
{
|
||||
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
|
||||
58
public/tier0/systeminformation.h
Normal file
58
public/tier0/systeminformation.h
Normal 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
|
||||
36
public/tier0/t0constants.h
Normal file
36
public/tier0/t0constants.h
Normal 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
60
public/tier0/testthread.h
Normal 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
2636
public/tier0/threadtools.h
Normal file
File diff suppressed because it is too large
Load Diff
649
public/tier0/threadtools.inl
Normal file
649
public/tier0/threadtools.inl
Normal 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
1027
public/tier0/tslist.h
Normal file
File diff suppressed because it is too large
Load Diff
73
public/tier0/validator.h
Normal file
73
public/tier0/validator.h
Normal 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
72
public/tier0/valobject.h
Normal 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
|
||||
8
public/tier0/valve_minmax_off.h
Normal file
8
public/tier0/valve_minmax_off.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
8
public/tier0/valve_minmax_on.h
Normal file
8
public/tier0/valve_minmax_on.h
Normal 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
33
public/tier0/valve_off.h
Normal 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
37
public/tier0/valve_on.h
Normal 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
25
public/tier0/vatoms.h
Normal 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
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
38
public/tier0/vprof_sn.h
Normal 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
|
||||
1143
public/tier0/vprof_telemetry.h
Normal file
1143
public/tier0/vprof_telemetry.h
Normal file
File diff suppressed because it is too large
Load Diff
70
public/tier0/vtuneinterface.h
Normal file
70
public/tier0/vtuneinterface.h
Normal 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
115
public/tier0/wchartypes.h
Normal 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
|
||||
|
||||
|
||||
32
public/tier0/win32consoleio.h
Normal file
32
public/tier0/win32consoleio.h
Normal 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
|
||||
16
public/tier0/xbox_codeline_defines.h
Normal file
16
public/tier0/xbox_codeline_defines.h
Normal 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
|
||||
Reference in New Issue
Block a user