1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
4 #include "MementoMemoryManager.h"
6 #include <CrySystem/ITextModeConsole.h>
7 #include <CryRenderer/IRenderAuxGeom.h>
9 #define PREVENT_ZERO_ALLOCS(x) x = std::max((size_t)x, (size_t)1)
11 #if MMM_USE_BUCKET_ALLOCATOR
12 #include <CryMemory/BucketAllocatorImpl.h>
13 CMementoMemoryManager::CMementoMemoryManagerAllocator::MMMBuckets
CMementoMemoryManager::CMementoMemoryManagerAllocator::m_bucketAllocator(NULL
, false);
19 #if MMM_SAVE || MMM_PLAY
20 #define MMM_TYPE_ALLOC 0
21 #define MMM_TYPE_FREE 1
22 #define MMM_TYPE_TICK 2
24 #define MMM_SAVE_DATA_ALLOC_SIZE (32 * 1024)
25 static uint32 s_MMMSaveDataSize
= MMM_SAVE_DATA_ALLOC_SIZE
;
30 static MMMSaveData
* s_pMMMSaveData
;
32 static FILE* s_pMMMSaveFile
= NULL
;
34 #define MMM_SAVE_DATA_FILE_CACHE_SIZE (32 * 1024)
35 struct MMMSaveDataFileCache
37 MMMSaveDataFileCache()
41 MMMSaveDataFileCache(uint16 t
, uint16 s
, uint32 i
)
52 static MMMSaveDataFileCache s_mmmSaveDataFileCache
[MMM_SAVE_DATA_FILE_CACHE_SIZE
];
53 static uint32 s_mmmSaveDataFileCacheSize
= 0;
54 static uint32 s_mmmSaveDataFileCacheIndex
= 0;
58 static void WriteMMMDataCache()
60 if (gEnv
->pSystem
->GetApplicationInstance() == 0)
62 s_pMMMSaveFile
= fxopen("mmm.dat", "ab");
64 for (uint32 i
= 0; i
< s_mmmSaveDataFileCacheIndex
; i
++)
66 s_mmmSaveDataFileCache
[i
].index
= htonl(s_mmmSaveDataFileCache
[i
].index
);
67 s_mmmSaveDataFileCache
[i
].size
= htons(s_mmmSaveDataFileCache
[i
].size
);
68 s_mmmSaveDataFileCache
[i
].type
= htons(s_mmmSaveDataFileCache
[i
].type
);
69 fwrite(&s_mmmSaveDataFileCache
[i
], 1, sizeof(s_mmmSaveDataFileCache
[i
]), s_pMMMSaveFile
);
72 fclose(s_pMMMSaveFile
);
75 s_mmmSaveDataFileCacheIndex
= 0;
78 static void WriteMMMData(uint32 type
, void* p
, uint32 size
)
80 if (gEnv
->pSystem
->GetApplicationInstance() == 0)
87 for (index
= 0; index
< s_MMMSaveDataSize
; index
++)
89 if (!s_pMMMSaveData
[index
].p
)
95 if (index
== s_MMMSaveDataSize
)
97 MMMSaveData
* pOldPtr
= s_pMMMSaveData
;
98 uint32 oldSize
= s_MMMSaveDataSize
;
100 s_MMMSaveDataSize
+= MMM_SAVE_DATA_ALLOC_SIZE
;
101 s_pMMMSaveData
= new MMMSaveData
[s_MMMSaveDataSize
];
102 memset(s_pMMMSaveData
, 0, s_MMMSaveDataSize
* sizeof(s_pMMMSaveData
[0]));
103 memcpy(s_pMMMSaveData
, pOldPtr
, oldSize
* sizeof(s_pMMMSaveData
[0]));
108 s_pMMMSaveData
[index
].p
= p
;
113 for (index
= 0; index
< s_MMMSaveDataSize
; index
++)
115 if (s_pMMMSaveData
[index
].p
== p
)
117 s_pMMMSaveData
[index
].p
= NULL
;
122 if (index
== s_MMMSaveDataSize
)
124 NetLog("WriteMMMData: Error freeing pointer %p that hasn't been allocated", p
);
134 s_mmmSaveDataFileCache
[s_mmmSaveDataFileCacheIndex
].type
= type
;
135 s_mmmSaveDataFileCache
[s_mmmSaveDataFileCacheIndex
].size
= size
;
136 s_mmmSaveDataFileCache
[s_mmmSaveDataFileCacheIndex
].index
= index
;
137 s_mmmSaveDataFileCacheIndex
++;
139 if (s_mmmSaveDataFileCacheIndex
== MMM_SAVE_DATA_FILE_CACHE_SIZE
)
146 #define WriteMMMDataCache()
147 #define WriteMMMData(type, p, size)
151 static CTimeValue s_readDataTime
;
152 static void ReadMMMDataCache()
154 if (gEnv
->pSystem
->GetApplicationInstance() == 0)
156 CTimeValue start
= gEnv
->pTimer
->GetAsyncTime();
157 s_mmmSaveDataFileCacheIndex
= 0;
158 s_mmmSaveDataFileCacheSize
= MMM_SAVE_DATA_FILE_CACHE_SIZE
;
160 for (uint32 i
= 0; i
< MMM_SAVE_DATA_FILE_CACHE_SIZE
; i
++)
162 fread(&s_mmmSaveDataFileCache
[i
], 1, sizeof(s_mmmSaveDataFileCache
[i
]), s_pMMMSaveFile
);
163 s_mmmSaveDataFileCache
[i
].index
= ntohl(s_mmmSaveDataFileCache
[i
].index
);
164 s_mmmSaveDataFileCache
[i
].size
= ntohs(s_mmmSaveDataFileCache
[i
].size
);
165 s_mmmSaveDataFileCache
[i
].type
= ntohs(s_mmmSaveDataFileCache
[i
].type
);
167 if (feof(s_pMMMSaveFile
))
169 s_mmmSaveDataFileCacheSize
= i
;
174 CTimeValue end
= gEnv
->pTimer
->GetAsyncTime();
175 s_readDataTime
+= (end
- start
);
179 static bool ReadMMMData(MMMSaveDataFileCache
& entry
)
181 if (s_mmmSaveDataFileCacheIndex
>= s_mmmSaveDataFileCacheSize
)
186 if (s_mmmSaveDataFileCacheIndex
< s_mmmSaveDataFileCacheSize
)
188 entry
= s_mmmSaveDataFileCache
[s_mmmSaveDataFileCacheIndex
];
189 s_mmmSaveDataFileCacheIndex
++;
197 #define ENABLE_MMM_DEBUG ENABLE_NETWORK_MEM_INFO
199 CMementoMemoryManager
* CMementoMemoryRegion::m_pMMM
= 0;
200 CMementoMemoryManager::CMementoMemoryManagerAllocator
* CMementoMemoryManager::CMementoMemoryManagerAllocator::m_allocator
= NULL
;
201 int CMementoMemoryManager::CMementoMemoryManagerAllocator::m_numCMementoMemoryManagers
= 0;
203 CryLockT
<CRYLOCK_RECURSIVE
> CMementoMemoryManager::CMementoMemoryManagerAllocator::m_mutex
;
206 #if ENABLE_NETWORK_MEM_INFO
207 CMementoMemoryManager::TManagers
* CMementoMemoryManager::m_pManagers
;
210 static void DrawDebugLine(int x
, int y
, const char* fmt
, ...)
216 cry_vsprintf(buffer
, fmt
, args
);
219 float white
[] = { 1, 1, 1, 1 };
221 IRenderAuxText::Draw2dLabel((float)(x
* 12 + 12), (float)(y
* 12 + 12), 1.2f
, white
, false, "%s", buffer
);
223 if (ITextModeConsole
* pC
= gEnv
->pSystem
->GetITextModeConsole())
225 pC
->PutText(x
, y
, buffer
);
230 // pool sizes are 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096
231 static const int MMMDEBUG_FIRST_POOL
= 3; // == 8bytes
232 static const int MMMDEBUG_LAST_POOL
= 12; // == 4096bytes
233 static const int MMMDEBUG_NPOOLS
= MMMDEBUG_LAST_POOL
- MMMDEBUG_FIRST_POOL
+ 1;
236 #if !MMM_USE_BUCKET_ALLOCATOR
237 int m_numAllocs
[MMMDEBUG_NPOOLS
];
238 int m_numFrees
[MMMDEBUG_NPOOLS
];
240 int m_totalNumAllocs
;
243 int m_currentNumAllocs
;
246 static MMMDebugData s_MMMDebug
;
248 static void MMMDebugClearFrameData()
250 #if !MMM_USE_BUCKET_ALLOCATOR
251 memset(s_MMMDebug
.m_numAllocs
, 0, sizeof(s_MMMDebug
.m_numAllocs
));
252 memset(s_MMMDebug
.m_numFrees
, 0, sizeof(s_MMMDebug
.m_numFrees
));
254 s_MMMDebug
.m_totalNumAllocs
= 0;
255 s_MMMDebug
.m_totalNumFrees
= 0;
258 static void MMMDebugInit()
260 MMMDebugClearFrameData();
262 s_MMMDebug
.m_currentNumAllocs
= 0;
264 #if MMM_SAVE || MMM_PLAY
265 s_pMMMSaveData
= new MMMSaveData
[s_MMMSaveDataSize
];
266 memset(s_pMMMSaveData
, 0, s_MMMSaveDataSize
* sizeof(s_pMMMSaveData
[0]));
270 if (gEnv
->pSystem
->GetApplicationInstance() == 0)
272 s_pMMMSaveFile
= fxopen("mmm.dat", "wb");
273 fclose(s_pMMMSaveFile
);
278 static void MMMDebugAddAlloc(void* p
, size_t sz
)
280 PREVENT_ZERO_ALLOCS(sz
);
281 #if !MMM_USE_BUCKET_ALLOCATOR
282 int pool
= std::max((int)IntegerLog2_RoundUp(sz
) - MMMDEBUG_FIRST_POOL
, 0);
284 if (pool
< MMMDEBUG_NPOOLS
)
286 s_MMMDebug
.m_numAllocs
[pool
]++;
290 s_MMMDebug
.m_totalNumAllocs
++;
291 s_MMMDebug
.m_currentNumAllocs
++;
293 WriteMMMData(MMM_TYPE_ALLOC
, p
, sz
);
296 static void MMMDebugRemoveAlloc(void* p
, size_t sz
)
298 PREVENT_ZERO_ALLOCS(sz
);
299 #if !MMM_USE_BUCKET_ALLOCATOR
300 int pool
= std::max((int)IntegerLog2_RoundUp(sz
) - MMMDEBUG_FIRST_POOL
, 0);
302 if (pool
< MMMDEBUG_NPOOLS
)
304 s_MMMDebug
.m_numFrees
[pool
]++;
308 s_MMMDebug
.m_totalNumFrees
++;
309 s_MMMDebug
.m_currentNumAllocs
--;
311 WriteMMMData(MMM_TYPE_FREE
, p
, sz
);
314 static void MMMDebugDraw(int x
, int& y
)
316 #if !MMM_USE_BUCKET_ALLOCATOR
317 for (int i
= 0; i
< MMMDEBUG_NPOOLS
; i
++)
319 DrawDebugLine(x
, y
++, "Pool %d (%4d byte blocks): Frame Allocs %4d Frame Frees %4d", i
, 1 << (i
+ MMMDEBUG_FIRST_POOL
), s_MMMDebug
.m_numAllocs
[i
], s_MMMDebug
.m_numFrees
[i
]);
323 DrawDebugLine(x
, y
++, "Total: Frame Allocs %4d Frame Frees %4d", s_MMMDebug
.m_totalNumAllocs
, s_MMMDebug
.m_totalNumFrees
);
325 DrawDebugLine(x
, y
++, "Current Num Allocations %4d", s_MMMDebug
.m_currentNumAllocs
);
327 MMMDebugClearFrameData();
330 #define MMMDebugInit()
331 #define MMMDebugRemoveAlloc(p, sz)
332 #define MMMDebugAddAlloc(p, sz)
333 #define MMMDebugDraw(x, y)
336 CMementoMemoryManager::CMementoMemoryManagerAllocator::CMementoMemoryManagerAllocator()
338 #if MMM_USE_BUCKET_ALLOCATOR
339 m_bucketAllocator
.EnableExpandCleanups(false);
340 m_bucketTotalRequested
= 0;
341 m_bucketTotalAllocated
= 0;
342 #if LOG_BUCKET_ALLOCATOR_HIGH_WATERMARK
343 m_bucketHighWaterMark
= 0;
344 m_generalHeapHighWaterMark
= 0;
345 #endif // LOG_BUCKET_ALLOCATOR_HIGH_WATERMARK
347 memset(m_freeList
, 0, sizeof(m_freeList
));
348 memset(m_numAllocated
, 0, sizeof(m_numAllocated
));
349 memset(m_numFree
, 0, sizeof(m_numFree
));
352 #if !defined(PURE_CLIENT)
353 m_pGeneralHeap
= CryGetIMemoryManager()->CreateGeneralExpandingMemoryHeap(MMM_GENERAL_HEAP_SIZE
, MMM_GENERAL_HEAP_SIZE
, "Memento General");
354 m_generalHeapTotalRequested
= 0;
355 m_generalHeapTotalAllocated
= 0;
361 CMementoMemoryManager::CMementoMemoryManagerAllocator::~CMementoMemoryManagerAllocator()
363 NET_ASSERT(m_handles
.size() == m_freeHandles
.size());
365 #if !defined(PURE_CLIENT)
368 m_pGeneralHeap
->Release();
373 void CMementoMemoryManager::CMementoMemoryManagerAllocator::AddCMementoMemoryManager()
379 if (m_numCMementoMemoryManagers
== 0)
381 m_allocator
= new CMementoMemoryManagerAllocator();
384 m_numCMementoMemoryManagers
++;
391 void CMementoMemoryManager::CMementoMemoryManagerAllocator::RemoveCMementoMemoryManager()
397 m_numCMementoMemoryManagers
--;
399 if (m_numCMementoMemoryManagers
== 0)
401 #if LOG_BUCKET_ALLOCATOR_HIGH_WATERMARK
402 CryLogAlways("[CMementoMemoryManager] high water marks: bucket = %d, general heap = %d", m_allocator
->m_bucketHighWaterMark
, m_allocator
->m_generalHeapHighWaterMark
);
403 #endif // LOG_BUCKET_ALLOCATOR_HIGH_WATERMARK
415 #define MMM_MUTEX_DEBUG (1)
417 #define MMM_MUTEX_DEBUG (0)
422 #define MMM_CRASH_ON_MUTEX_FAILURE (0)
424 void MMM_ASSERT_GLOBAL_LOCK(void)
426 NetFastMutex
& nfm
= CNetwork::Get()->GetMutex();
427 if (CNetwork::Get()->IsMultithreaded() && !nfm
.IsLocked())
429 CryLogAlways("USE OF MEMENTO WHEN WE HAVEN'T ACQUIRED THE NETWORK THREAD LOCK!");
430 #if MMM_CRASH_ON_MUTEX_FAILURE
437 #define MMM_ASSERT_GLOBAL_LOCK()
440 CMementoMemoryManager::Hdl
CMementoMemoryManager::CMementoMemoryManagerAllocator::AllocHdl(size_t sz
)
442 MMM_ASSERT_GLOBAL_LOCK();
444 PREVENT_ZERO_ALLOCS(sz
);
450 if (m_freeHandles
.empty())
452 hdl
= m_handles
.size();
453 m_handles
.push_back(SHandleData());
457 hdl
= m_freeHandles
.back();
458 m_freeHandles
.pop_back();
461 InitHandleData(m_handles
[hdl
], sz
);
463 hdl
= ProtectHdl(hdl
);
472 void CMementoMemoryManager::CMementoMemoryManagerAllocator::ResizeHdl(Hdl hdl
, size_t sz
)
474 MMM_ASSERT_GLOBAL_LOCK();
475 PREVENT_ZERO_ALLOCS(sz
);
480 hdl
= UnprotectHdl(hdl
);
482 NET_ASSERT(hdl
!= InvalidHdl
);
484 SHandleData
& hd
= m_handles
[hdl
];
486 #if MMM_USE_BUCKET_ALLOCATOR
491 InitHandleData(hdp
, sz
);
495 memcpy(hdp
.p
, hd
.p
, sz
);
499 memcpy(hdp
.p
, hd
.p
, hd
.size
);
502 FreePtr(hd
.p
, hd
.size
);
507 if (sz
> hd
.size
) // growing
509 if (sz
> hd
.capacity
) // growing and changing pools
512 InitHandleData(hdp
, sz
);
513 memcpy(hdp
.p
, hd
.p
, hd
.size
);
514 FreePtr(hd
.p
, hd
.size
);
522 else if (sz
< hd
.size
) // shrinking
524 if (sz
<= hd
.capacity
/ 2) // shrinking and changing pools
527 InitHandleData(hdp
, sz
);
528 memcpy(hdp
.p
, hd
.p
, sz
);
529 FreePtr(hd
.p
, hd
.size
);
544 void CMementoMemoryManager::CMementoMemoryManagerAllocator::FreeHdl(Hdl hdl
)
546 MMM_ASSERT_GLOBAL_LOCK();
551 hdl
= UnprotectHdl(hdl
);
553 if (hdl
!= InvalidHdl
)
555 SHandleData
& hd
= m_handles
[hdl
];
557 FreePtr(hd
.p
, hd
.size
);
558 m_freeHandles
.push_back(hdl
);
566 void* CMementoMemoryManager::CMementoMemoryManagerAllocator::AllocPtr(size_t sz
)
568 MMM_ASSERT_GLOBAL_LOCK();
570 PREVENT_ZERO_ALLOCS(sz
);
576 InitHandleData(hd
, sz
);
585 void CMementoMemoryManager::CMementoMemoryManagerAllocator::FreePtr(void* p
, size_t sz
)
587 MMM_ASSERT_GLOBAL_LOCK();
588 PREVENT_ZERO_ALLOCS(sz
);
593 MMMDebugRemoveAlloc(p
, sz
);
595 #if MMM_USE_BUCKET_ALLOCATOR
596 if (m_bucketAllocator
.IsInAddressRange(p
))
598 m_bucketTotalRequested
-= sz
;
599 m_bucketTotalAllocated
-= m_bucketAllocator
.getSize(p
);
600 m_bucketAllocator
.deallocate(p
);
604 #if !defined(PURE_CLIENT)
605 m_generalHeapTotalRequested
-= sz
;
606 m_generalHeapTotalAllocated
-= m_pGeneralHeap
->UsableSize(p
);
607 m_pGeneralHeap
->Free(p
);
613 int pool
= std::max((int)IntegerLog2_RoundUp(sz
) - FIRST_POOL
, 0);
617 ((SFreeListHeader
*)p
)->pNext
= m_freeList
[pool
].pNext
;
618 m_freeList
[pool
].pNext
= (SFreeListHeader
*)p
;
620 m_numAllocated
[pool
]--;
624 #if !defined(PURE_CLIENT)
625 m_generalHeapTotalRequested
-= sz
;
626 m_generalHeapTotalAllocated
-= m_pGeneralHeap
->UsableSize(p
);
627 m_pGeneralHeap
->Free(p
);
639 void CMementoMemoryManager::CMementoMemoryManagerAllocator::InitHandleData(SHandleData
& hd
, size_t sz
)
641 MMM_ASSERT_GLOBAL_LOCK();
643 PREVENT_ZERO_ALLOCS(sz
);
644 #if MMM_USE_BUCKET_ALLOCATOR
645 if (sz
<= m_bucketAllocator
.MaxSize
)
647 hd
.p
= m_bucketAllocator
.allocate(sz
);
650 CryFatalError("Memento Allocation For %" PRISIZE_T
" Failed - Suggest increasing the bucket allocator size!!!!", sz
);
653 hd
.capacity
= m_bucketAllocator
.getSize(hd
.p
);
654 m_bucketTotalRequested
+= hd
.size
;
655 m_bucketTotalAllocated
+= hd
.capacity
;
656 #if LOG_BUCKET_ALLOCATOR_HIGH_WATERMARK
657 if (m_bucketTotalAllocated
> m_bucketHighWaterMark
)
659 m_bucketHighWaterMark
= m_bucketTotalAllocated
;
661 #endif // LOG_BUCKET_ALLOCATOR_HIGH_WATERMARK
665 #if !defined(PURE_CLIENT)
666 hd
.p
= m_pGeneralHeap
->Malloc(sz
, "MMM");
669 CryFatalError("Memento Allocation For %" PRISIZE_T
" Failed - Suggest increasing the general heap size!!!!", sz
);
672 hd
.capacity
= m_pGeneralHeap
->UsableSize(hd
.p
);
673 m_generalHeapTotalRequested
+= hd
.size
;
674 m_generalHeapTotalAllocated
+= hd
.capacity
;
675 #if LOG_BUCKET_ALLOCATOR_HIGH_WATERMARK
676 if (m_generalHeapTotalAllocated
> m_generalHeapHighWaterMark
)
678 m_generalHeapHighWaterMark
= m_generalHeapTotalAllocated
;
680 #endif // LOG_BUCKET_ALLOCATOR_HIGH_WATERMARK
685 CryFatalError("Allocation for %" PRISIZE_T
" Failed", sz
);
692 size_t szP2
= IntegerLog2_RoundUp(sz
);
693 uint32 pool
= std::max((int)szP2
- FIRST_POOL
, 0);
697 if (!m_freeList
[pool
].pNext
)
701 for (testPool
= pool
+ 1; testPool
< NPOOLS
; testPool
++)
703 if (m_freeList
[testPool
].pNext
)
709 if (testPool
== NPOOLS
)
711 testPool
= NPOOLS
- 1;
712 SFreeListHeader
* p1
= (SFreeListHeader
*)m_pool
.Allocate();
713 p1
->pNext
= m_freeList
[testPool
].pNext
;
714 m_freeList
[testPool
].pNext
= p1
;
715 m_numFree
[testPool
]++;
718 for (; testPool
> pool
; testPool
--)
720 SFreeListHeader
* p1
= m_freeList
[testPool
].pNext
;
721 SFreeListHeader
* p2
= (SFreeListHeader
*)((uint8
*)p1
+ (uint32
)(1 << (testPool
+ FIRST_POOL
- 1)));
723 m_freeList
[testPool
].pNext
= m_freeList
[testPool
].pNext
->pNext
;
724 m_numFree
[testPool
]--;
726 p1
->pNext
= m_freeList
[testPool
- 1].pNext
;
728 m_freeList
[testPool
- 1].pNext
= p2
;
729 m_numFree
[testPool
- 1] += 2;
733 if (m_freeList
[pool
].pNext
)
735 hd
.p
= m_freeList
[pool
].pNext
;
736 m_freeList
[pool
].pNext
= m_freeList
[pool
].pNext
->pNext
;
738 m_numAllocated
[pool
]++;
740 hd
.capacity
= (size_t)1 << szP2
;
751 #if !defined(PURE_CLIENT)
752 hd
.p
= m_pGeneralHeap
->Malloc(sz
, "MMM");
754 hd
.capacity
= m_pGeneralHeap
->UsableSize(hd
.p
);
755 m_generalHeapTotalRequested
+= hd
.size
;
756 m_generalHeapTotalAllocated
+= hd
.capacity
;
767 CryFatalError("Memento Allocation For %" PRISIZE_T
" Failed - Suggest increasing the memento heap size!!!!", sz
);
770 MMMDebugAddAlloc(hd
.p
, hd
.size
);
771 NET_ASSERT(hd
.capacity
>= sz
);
774 void CMementoMemoryManager::CMementoMemoryManagerAllocator::Tick()
778 void CMementoMemoryManager::CMementoMemoryManagerAllocator::DebugDraw(int x
, int& y
, size_t& totalAllocated
)
780 #if ENABLE_NETWORK_MEM_INFO
782 #if MMM_USE_BUCKET_ALLOCATOR
783 DrawDebugLine(x
, y
++, "Memento allocator memory");
784 DrawDebugLine(x
, y
++, "Bucket Allocator Requested %8" PRISIZE_T
" Allocated %8" PRISIZE_T
" Storage Size %8" PRISIZE_T
" Storage Capacity %8" PRISIZE_T
" pages", m_bucketTotalRequested
, m_bucketTotalAllocated
, m_bucketAllocator
.GetBucketStorageSize(), m_bucketAllocator
.GetBucketStoragePages());
785 totalAllocated
+= m_bucketTotalAllocated
;
787 DrawDebugLine(x
, y
++, "Memento allocator memory");
789 for (int i
= 0; i
< NPOOLS
; i
++)
791 DrawDebugLine(x
, y
++, "Pool %d (%4d byte blocks): Num Allocated %4d Num Free %4d Amount Allocated %8d Amount Free %8d", i
, 1 << (i
+ FIRST_POOL
), m_numAllocated
[i
], m_numFree
[i
], m_numAllocated
[i
] * (1 << (i
+ FIRST_POOL
)), m_numFree
[i
] * (1 << (i
+ FIRST_POOL
)));
792 totalAllocated
+= m_numAllocated
[i
] * (1 << (i
+ FIRST_POOL
));
795 DrawDebugLine(x
, y
++, "Total: Allocated %8d Pool Capacity %8d System Allocated %8d", totalAllocated
, m_pool
.GetTotalMemory().nUsed
, m_pool
.GetTotalMemory().nAlloc
);
798 #if !defined(PURE_CLIENT)
799 DrawDebugLine(x
, y
++, "General Heap Requested %8d Allocated %8d", m_generalHeapTotalRequested
, m_generalHeapTotalAllocated
);
800 totalAllocated
+= m_generalHeapTotalAllocated
;
805 CMementoMemoryManager::CMementoMemoryManager(const string
& name
) : m_name(name
)
809 CMementoMemoryManagerAllocator::AddCMementoMemoryManager();
811 #if ENABLE_NETWORK_MEM_INFO
814 m_pManagers
= new TManagers
;
817 m_pManagers
->push_back(this);
820 arith_zeroSizeHdl
= InvalidHdl
;
822 for (int i
= 0; i
< sizeof(pThings
) / sizeof(*pThings
); i
++)
827 m_totalAllocations
= 0;
830 CMementoMemoryManager::~CMementoMemoryManager()
834 FreeHdl(arith_zeroSizeHdl
);
838 for (int i
= 0; i
< sizeof(pThings
) / sizeof(*pThings
); i
++)
840 SAFE_RELEASE(pThings
[i
]);
843 NET_ASSERT(m_totalAllocations
== 0);
845 #if ENABLE_NETWORK_MEM_INFO
846 stl::find_and_erase(*m_pManagers
, this);
849 CMementoMemoryManagerAllocator::RemoveCMementoMemoryManager();
852 CMementoMemoryManager::Hdl
CMementoMemoryManager::AllocHdl(size_t sz
, void* callerOverride
)
854 MMM_ASSERT_GLOBAL_LOCK();
856 PREVENT_ZERO_ALLOCS(sz
);
858 Hdl hdl
= CMementoMemoryManagerAllocator::GetAllocator()->AllocHdl(sz
);
860 m_totalAllocations
+= sz
;
863 void* caller
= callerOverride
? callerOverride
: UP_STACK_PTR
;
864 m_hdlToAlloc
[hdl
] = caller
;
865 m_allocAmt
[caller
] += sz
;
871 CMementoMemoryManager::Hdl
CMementoMemoryManager::CloneHdl(Hdl hdl
)
873 MMM_ASSERT_GLOBAL_LOCK();
875 Hdl out
= AllocHdl(GetHdlSize(hdl
), UP_STACK_PTR
);
877 memcpy(PinHdl(out
), PinHdl(hdl
), GetHdlSize(hdl
));
882 void CMementoMemoryManager::ResizeHdl(Hdl hdl
, size_t sz
)
884 MMM_ASSERT_GLOBAL_LOCK();
886 PREVENT_ZERO_ALLOCS(sz
);
888 size_t oldSize
= GetHdlSize(hdl
);
890 CMementoMemoryManagerAllocator::GetAllocator()->ResizeHdl(hdl
, sz
);
892 m_totalAllocations
-= oldSize
;
893 m_totalAllocations
+= sz
;
896 void* caller
= m_hdlToAlloc
[hdl
];
897 uint32
& callerAlloc
= m_allocAmt
[caller
];
898 callerAlloc
-= oldSize
;
903 void CMementoMemoryManager::FreeHdl(Hdl hdl
)
905 MMM_ASSERT_GLOBAL_LOCK();
907 size_t size
= GetHdlSize(hdl
);
909 m_totalAllocations
-= size
;
912 void* caller
= m_hdlToAlloc
[hdl
];
914 m_hdlToAlloc
.erase(hdl
);
916 if (!(m_allocAmt
[caller
] -= size
))
918 m_allocAmt
.erase(caller
);
922 CMementoMemoryManagerAllocator::GetAllocator()->FreeHdl(hdl
);
925 void* CMementoMemoryManager::AllocPtr(size_t sz
, void* callerOverride
)
927 MMM_ASSERT_GLOBAL_LOCK();
929 PREVENT_ZERO_ALLOCS(sz
);
931 m_totalAllocations
+= sz
;
933 void* ret
= CMementoMemoryManagerAllocator::GetAllocator()->AllocPtr(sz
);
936 void* caller
= callerOverride
? callerOverride
: UP_STACK_PTR
;
937 m_ptrToAlloc
[ret
] = caller
;
938 m_allocAmt
[caller
] += sz
;
944 void CMementoMemoryManager::FreePtr(void* p
, size_t sz
)
946 MMM_ASSERT_GLOBAL_LOCK();
948 PREVENT_ZERO_ALLOCS(sz
);
950 CMementoMemoryManagerAllocator::GetAllocator()->FreePtr(p
, sz
);
952 m_totalAllocations
-= sz
;
955 void* caller
= m_ptrToAlloc
[p
];
957 m_ptrToAlloc
.erase(p
);
959 if (!(m_allocAmt
[caller
] -= sz
))
961 m_allocAmt
.erase(caller
);
966 void CMementoMemoryManager::AddHdlToSizer(Hdl hdl
, ICrySizer
* pSizer
)
968 if (hdl
!= InvalidHdl
)
970 pSizer
->AddObject(PinHdl(hdl
), GetHdlSize(hdl
));
974 void CMementoMemoryManager::GetMemoryStatistics(ICrySizer
* pSizer
, bool countingThis
/* = false */)
976 SIZER_COMPONENT_NAME(pSizer
, "CMementoMemoryManager");
984 void CMementoMemoryManager::DebugDraw()
986 #if ENABLE_NETWORK_MEM_INFO
987 if (m_pManagers
&& CMementoMemoryManagerAllocator::GetAllocator() && CVARS
.MemInfo
& eDMM_Mementos
)
989 static size_t maxTotalRequested
= 0;
990 static size_t maxTotalAllocated
= 0;
991 size_t totalRequested
= 0;
992 size_t totalAllocated
= 0;
995 bool changed
= false;
997 CMementoMemoryManagerAllocator::GetAllocator()->DebugDraw(x
, y
, totalAllocated
);
1000 for (TManagers::iterator it
= m_pManagers
->begin(); it
!= m_pManagers
->end(); ++it
)
1002 DrawDebugLine(x
, y
++, "Memento memory for %16s: Requested %8d", (*it
)->m_name
.c_str(), (*it
)->m_totalAllocations
);
1003 totalRequested
+= (*it
)->m_totalAllocations
;
1008 if (totalRequested
> maxTotalRequested
)
1010 maxTotalRequested
= totalRequested
;
1014 if (totalAllocated
> maxTotalAllocated
)
1016 maxTotalAllocated
= totalAllocated
;
1020 DrawDebugLine(x
, y
++, "Total MMM: Requested %8d Allocated %8d", totalRequested
, totalAllocated
);
1021 DrawDebugLine(x
, y
++, "Max Total MMM: Requested %8d Allocated %8d", maxTotalRequested
, maxTotalAllocated
);
1026 CryLogAlways("[net mmm] Max Total MMM: Requested %" PRISIZE_T
" Allocated %" PRISIZE_T
, maxTotalRequested
, maxTotalAllocated
);
1034 void CMementoMemoryManager::Tick()
1036 WriteMMMData(MMM_TYPE_TICK
, 0, 0);
1037 WriteMMMDataCache();
1040 static bool s_playbackDone
= false;
1041 if (!s_playbackDone
&& (gEnv
->pSystem
->GetApplicationInstance() == 0))
1043 s_playbackDone
= true;
1044 s_pMMMSaveFile
= fxopen("mmm.dat", "rb");
1046 s_readDataTime
= CTimeValue();
1047 CTimeValue start
= gEnv
->pTimer
->GetAsyncTime();
1049 NetLog("MMM playback start time %" PRId64
, start
.GetMilliSecondsAsInt64());
1053 MMMSaveDataFileCache entry
;
1055 if (ReadMMMData(entry
))
1059 case MMM_TYPE_ALLOC
:
1060 if (entry
.index
>= s_MMMSaveDataSize
)
1062 MMMSaveData
* pOldPtr
= s_pMMMSaveData
;
1063 uint32 oldSize
= s_MMMSaveDataSize
;
1067 s_MMMSaveDataSize
+= MMM_SAVE_DATA_ALLOC_SIZE
;
1069 while (entry
.index
>= s_MMMSaveDataSize
);
1071 s_pMMMSaveData
= new MMMSaveData
[s_MMMSaveDataSize
];
1072 memset(s_pMMMSaveData
, 0, s_MMMSaveDataSize
* sizeof(s_pMMMSaveData
[0]));
1073 memcpy(s_pMMMSaveData
, pOldPtr
, oldSize
* sizeof(s_pMMMSaveData
[0]));
1078 if (!s_pMMMSaveData
[entry
.index
].p
)
1080 s_pMMMSaveData
[entry
.index
].p
= CMementoMemoryManager::CMementoMemoryManagerAllocator::GetAllocator()->AllocPtr(entry
.size
);
1084 NetLog("MMM Playerback: Error allocating into a slot already allocated.");
1090 if ((entry
.index
< s_MMMSaveDataSize
) && s_pMMMSaveData
[entry
.index
].p
)
1092 CMementoMemoryManager::CMementoMemoryManagerAllocator::GetAllocator()->FreePtr(s_pMMMSaveData
[entry
.index
].p
, entry
.size
);
1093 s_pMMMSaveData
[entry
.index
].p
= NULL
;
1097 NetLog("MMM Playerback: Error freeing from a slot not allocated.");
1102 CMementoMemoryManager::CMementoMemoryManagerAllocator::GetAllocator()->Tick();
1112 CTimeValue end
= gEnv
->pTimer
->GetAsyncTime();
1113 NetLog("MMM playback end time %" PRId64
" time taken %" PRId64
" File read time %" PRId64
" time taken - file read time %" PRId64
, end
.GetMilliSecondsAsInt64(), (end
- start
).GetMilliSecondsAsInt64(), s_readDataTime
.GetMilliSecondsAsInt64(), ((end
- start
) - s_readDataTime
).GetMilliSecondsAsInt64());
1115 fclose(s_pMMMSaveFile
);
1119 CMementoMemoryManager::CMementoMemoryManagerAllocator::GetAllocator()->Tick();
1123 * CMementoStreamAllocator
1126 CMementoStreamAllocator::CMementoStreamAllocator(const CMementoMemoryManagerPtr
& mmm
) : m_hdl(CMementoMemoryManager::InvalidHdl
), m_pPin(0), m_mmm(mmm
)
1130 void* CMementoStreamAllocator::Alloc(size_t sz
, void* callerOverride
)
1132 MMM_ASSERT_GLOBAL_LOCK();
1134 PREVENT_ZERO_ALLOCS(sz
);
1136 NET_ASSERT(m_hdl
== CMementoMemoryManager::InvalidHdl
);
1138 m_hdl
= m_mmm
->AllocHdl(sz
, callerOverride
? callerOverride
: UP_STACK_PTR
);
1140 return m_pPin
= m_mmm
->PinHdl(m_hdl
);
1143 void* CMementoStreamAllocator::Realloc(void* old
, size_t sz
)
1145 MMM_ASSERT_GLOBAL_LOCK();
1147 PREVENT_ZERO_ALLOCS(sz
);
1149 NET_ASSERT(m_pPin
== old
&& m_pPin
);
1150 m_mmm
->ResizeHdl(m_hdl
, sz
);
1152 return m_pPin
= m_mmm
->PinHdl(m_hdl
);
1155 void CMementoStreamAllocator::Free(void* old
)