-
Notifications
You must be signed in to change notification settings - Fork 270
/
Copy pathmemstd.h
296 lines (241 loc) · 8.47 KB
/
memstd.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
//========= Copyright Valve Corporation, All rights reserved. ============//
//-----------------------------------------------------------------------------
// NOTE! This should never be called directly from leaf code
// Just use new,delete,malloc,free etc. They will call into this eventually
//-----------------------------------------------------------------------------
#include "pch_tier0.h"
#if defined(_WIN32)
#if !defined(_X360)
#define WIN_32_LEAN_AND_MEAN
#include <windows.h>
#else
#undef Verify
#define _XBOX
#include <xtl.h>
#undef _XBOX
#include "xbox/xbox_win32stubs.h"
#endif
#endif
#ifdef OSX
#include <malloc/malloc.h>
#else
#include <malloc.h>
#endif
#include <algorithm>
#include "tier0/dbg.h"
#include "tier0/memalloc.h"
#include "tier0/threadtools.h"
#include "tier0/tslist.h"
#include "mem_helpers.h"
#pragma pack(4)
#ifdef _X360
#define USE_PHYSICAL_SMALL_BLOCK_HEAP 1
#endif
// #define NO_SBH 1
#define MIN_SBH_BLOCK 8
#define MIN_SBH_ALIGN 8
#define MAX_SBH_BLOCK 2048
#define MAX_POOL_REGION (4*1024*1024)
#if !defined(_X360)
#define SBH_PAGE_SIZE (4*1024)
#define COMMIT_SIZE (16*SBH_PAGE_SIZE)
#else
#define SBH_PAGE_SIZE (64*1024)
#define COMMIT_SIZE (SBH_PAGE_SIZE)
#endif
#if _M_X64
#define NUM_POOLS 34
#else
#define NUM_POOLS 42
#endif
// SBH not enabled for LINUX right now. Unlike on Windows, we can't globally hook malloc. Well,
// we can and did in override_init_hook(), but that unfortunately causes all malloc functions
// to get hooked - including the nVidia driver, etc. And these hooks appear to happen after
// nVidia has alloc'd some memory and it crashes when they try to free that.
// So we need things to work without this global hook - which means we rely on memdbgon.h / memdbgoff.h.
// Unfortunately, that stuff always comes in source files after the headers are included, and
// that means any alloc calls in the header files call the real libc functions. It's a mess.
// I believe I've cleaned most of it up, and it appears to be working. However right now we are totally
// gated on other performance issues, and the SBH doesn't give us any win, so I've disabled it for now.
// Once those perf issues are worked out, it might make sense to do perf tests with SBH, libc, and tcmalloc.
//
//$ #if defined( _WIN32 ) || defined( _PS3 ) || defined( LINUX )
#if defined( _WIN32 ) || defined( _PS3 )
#define MEM_SBH_ENABLED 1
#endif
class ALIGN16 CSmallBlockPool
{
public:
void Init( unsigned nBlockSize, byte *pBase, unsigned initialCommit = 0 );
size_t GetBlockSize();
bool IsOwner( void *p );
void *Alloc();
void Free( void *p );
int CountFreeBlocks();
int GetCommittedSize();
int CountCommittedBlocks();
int CountAllocatedBlocks();
int Compact();
private:
typedef TSLNodeBase_t FreeBlock_t;
class CFreeList : public CTSListBase
{
public:
void Push( void *p ) { CTSListBase::Push( (TSLNodeBase_t *)p ); }
};
CFreeList m_FreeList;
unsigned m_nBlockSize;
CInterlockedPtr<byte> m_pNextAlloc;
byte * m_pCommitLimit;
byte * m_pAllocLimit;
byte * m_pBase;
CThreadFastMutex m_CommitMutex;
} ALIGN16_POST;
class ALIGN16 CSmallBlockHeap
{
public:
CSmallBlockHeap();
bool ShouldUse( size_t nBytes );
bool IsOwner( void * p );
void *Alloc( size_t nBytes );
void *Realloc( void *p, size_t nBytes );
void Free( void *p );
size_t GetSize( void *p );
void DumpStats( FILE *pFile = NULL );
int Compact();
private:
CSmallBlockPool *FindPool( size_t nBytes );
CSmallBlockPool *FindPool( void *p );
CSmallBlockPool *m_PoolLookup[MAX_SBH_BLOCK >> 2];
CSmallBlockPool m_Pools[NUM_POOLS];
byte *m_pBase;
byte *m_pLimit;
} ALIGN16_POST;
#ifdef USE_PHYSICAL_SMALL_BLOCK_HEAP
#define BYTES_X360_SBH (32*1024*1024)
#define PAGESIZE_X360_SBH (64*1024)
class CX360SmallBlockPool
{
public:
void Init( unsigned nBlockSize );
size_t GetBlockSize();
bool IsOwner( void *p );
void *Alloc();
void Free( void *p );
int CountFreeBlocks();
int GetCommittedSize();
int CountCommittedBlocks();
int CountAllocatedBlocks();
static CX360SmallBlockPool *FindPool( void *p )
{
int index = (size_t)((byte *)p - gm_pPhysicalBase) / PAGESIZE_X360_SBH;
if ( index < 0 || index >= ARRAYSIZE(gm_AddressToPool) )
return NULL;
return gm_AddressToPool[ index ];
}
private:
friend class CX360SmallBlockHeap;
typedef TSLNodeBase_t FreeBlock_t;
class CFreeList : public CTSListBase
{
public:
void Push( void *p ) { CTSListBase::Push( (TSLNodeBase_t *)p ); }
};
CFreeList m_FreeList;
unsigned m_nBlockSize;
unsigned m_CommittedSize;
CInterlockedPtr<byte> m_pNextAlloc;
byte * m_pCurBlockEnd;
CThreadFastMutex m_CommitMutex;
static CX360SmallBlockPool *gm_AddressToPool[BYTES_X360_SBH/PAGESIZE_X360_SBH];
static byte *gm_pPhysicalBlock;
static byte *gm_pPhysicalBase;
static byte *gm_pPhysicalLimit;
};
class CX360SmallBlockHeap
{
public:
CX360SmallBlockHeap();
bool ShouldUse( size_t nBytes );
bool IsOwner( void * p );
void *Alloc( size_t nBytes );
void *Realloc( void *p, size_t nBytes );
void Free( void *p );
size_t GetSize( void *p );
void DumpStats( FILE *pFile = NULL );
CSmallBlockHeap *GetStandardSBH();
private:
CX360SmallBlockPool *FindPool( size_t nBytes );
CX360SmallBlockPool *FindPool( void *p );
CX360SmallBlockPool *m_PoolLookup[MAX_SBH_BLOCK >> 2];
CX360SmallBlockPool m_Pools[NUM_POOLS];
};
#endif
class ALIGN16 CStdMemAlloc : public IMemAlloc
{
public:
CStdMemAlloc()
: m_pfnFailHandler( DefaultFailHandler ),
m_sMemoryAllocFailed( (size_t)0 )
{
// Make sure that we return 64-bit addresses in 64-bit builds.
ReserveBottomMemory();
}
// Release versions
virtual void *Alloc( size_t nSize );
virtual void *Realloc( void *pMem, size_t nSize );
virtual void Free( void *pMem );
virtual void *Expand_NoLongerSupported( void *pMem, size_t nSize );
// Debug versions
virtual void *Alloc( size_t nSize, const char *pFileName, int nLine );
virtual void *Realloc( void *pMem, size_t nSize, const char *pFileName, int nLine );
virtual void Free( void *pMem, const char *pFileName, int nLine );
virtual void *Expand_NoLongerSupported( void *pMem, size_t nSize, const char *pFileName, int nLine );
// Returns size of a particular allocation
virtual size_t GetSize( void *pMem );
// Force file + line information for an allocation
virtual void PushAllocDbgInfo( const char *pFileName, int nLine );
virtual void PopAllocDbgInfo();
virtual long CrtSetBreakAlloc( long lNewBreakAlloc );
virtual int CrtSetReportMode( int nReportType, int nReportMode );
virtual int CrtIsValidHeapPointer( const void *pMem );
virtual int CrtIsValidPointer( const void *pMem, unsigned int size, int access );
virtual int CrtCheckMemory( void );
virtual int CrtSetDbgFlag( int nNewFlag );
virtual void CrtMemCheckpoint( _CrtMemState *pState );
void* CrtSetReportFile( int nRptType, void* hFile );
void* CrtSetReportHook( void* pfnNewHook );
int CrtDbgReport( int nRptType, const char * szFile,
int nLine, const char * szModule, const char * pMsg );
virtual int heapchk();
virtual void DumpStats();
virtual void DumpStatsFileBase( char const *pchFileBase );
virtual void GlobalMemoryStatus( size_t *pUsedMemory, size_t *pFreeMemory );
virtual bool IsDebugHeap() { return false; }
virtual void GetActualDbgInfo( const char *&pFileName, int &nLine ) {}
virtual void RegisterAllocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ) {}
virtual void RegisterDeallocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ) {}
virtual int GetVersion() { return MEMALLOC_VERSION; }
virtual void CompactHeap();
virtual MemAllocFailHandler_t SetAllocFailHandler( MemAllocFailHandler_t pfnMemAllocFailHandler );
size_t CallAllocFailHandler( size_t nBytes ) { return (*m_pfnFailHandler)( nBytes); }
virtual uint32 GetDebugInfoSize() { return 0; }
virtual void SaveDebugInfo( void *pvDebugInfo ) { }
virtual void RestoreDebugInfo( const void *pvDebugInfo ) {}
virtual void InitDebugInfo( void *pvDebugInfo, const char *pchRootFileName, int nLine ) {}
static size_t DefaultFailHandler( size_t );
void DumpBlockStats( void *p ) {}
#ifdef MEM_SBH_ENABLED
CSmallBlockHeap m_SmallBlockHeap;
#ifdef USE_PHYSICAL_SMALL_BLOCK_HEAP
CX360SmallBlockHeap m_LargePageSmallBlockHeap;
#endif
#endif
#if defined( _MEMTEST )
virtual void SetStatsExtraInfo( const char *pMapName, const char *pComment );
#endif
virtual size_t MemoryAllocFailed();
void SetCRTAllocFailed( size_t nMemSize );
MemAllocFailHandler_t m_pfnFailHandler;
size_t m_sMemoryAllocFailed;
} ALIGN16_POST;