!B (CE-20767) Enabled opaque rendering and shadows for GPU particles. Added ZPassGPU...
[CRYENGINE.git] / Code / CryEngine / CryNetwork / MementoMemoryManager.cpp
bloba32d27b488634cd30b9105ce80e1ee3646558d03
1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
4 #include "MementoMemoryManager.h"
5 #include "Network.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);
14 #endif
16 #define MMM_SAVE 0
17 #define MMM_PLAY 0
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;
26 struct MMMSaveData
28 void* p;
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)
43 type = t;
44 size = s;
45 index = i;
48 uint32 index;
49 uint16 size;
50 uint16 type;
52 static MMMSaveDataFileCache s_mmmSaveDataFileCache[MMM_SAVE_DATA_FILE_CACHE_SIZE];
53 static uint32 s_mmmSaveDataFileCacheSize = 0;
54 static uint32 s_mmmSaveDataFileCacheIndex = 0;
55 #endif
57 #if MMM_SAVE
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)
82 uint32 index;
84 switch (type)
86 case MMM_TYPE_ALLOC:
87 for (index = 0; index < s_MMMSaveDataSize; index++)
89 if (!s_pMMMSaveData[index].p)
91 break;
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]));
105 delete[] pOldPtr;
108 s_pMMMSaveData[index].p = p;
110 break;
112 case MMM_TYPE_FREE:
113 for (index = 0; index < s_MMMSaveDataSize; index++)
115 if (s_pMMMSaveData[index].p == p)
117 s_pMMMSaveData[index].p = NULL;
118 break;
122 if (index == s_MMMSaveDataSize)
124 NetLog("WriteMMMData: Error freeing pointer %p that hasn't been allocated", p);
127 break;
129 default:
130 index = 0;
131 break;
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)
141 WriteMMMDataCache();
145 #else
146 #define WriteMMMDataCache()
147 #define WriteMMMData(type, p, size)
148 #endif
150 #if MMM_PLAY
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;
170 break;
174 CTimeValue end = gEnv->pTimer->GetAsyncTime();
175 s_readDataTime += (end - start);
179 static bool ReadMMMData(MMMSaveDataFileCache& entry)
181 if (s_mmmSaveDataFileCacheIndex >= s_mmmSaveDataFileCacheSize)
183 ReadMMMDataCache();
186 if (s_mmmSaveDataFileCacheIndex < s_mmmSaveDataFileCacheSize)
188 entry = s_mmmSaveDataFileCache[s_mmmSaveDataFileCacheIndex];
189 s_mmmSaveDataFileCacheIndex++;
190 return true;
193 return false;
195 #endif
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;
202 #if MMM_MUTEX_ENABLE
203 CryLockT<CRYLOCK_RECURSIVE> CMementoMemoryManager::CMementoMemoryManagerAllocator::m_mutex;
204 #endif
206 #if ENABLE_NETWORK_MEM_INFO
207 CMementoMemoryManager::TManagers* CMementoMemoryManager::m_pManagers;
208 #endif
210 static void DrawDebugLine(int x, int y, const char* fmt, ...)
212 char buffer[512];
214 va_list args;
215 va_start(args, fmt);
216 cry_vsprintf(buffer, fmt, args);
217 va_end(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);
229 #if ENABLE_MMM_DEBUG
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;
234 struct MMMDebugData
236 #if !MMM_USE_BUCKET_ALLOCATOR
237 int m_numAllocs[MMMDEBUG_NPOOLS];
238 int m_numFrees[MMMDEBUG_NPOOLS];
239 #endif
240 int m_totalNumAllocs;
241 int m_totalNumFrees;
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));
253 #endif
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]));
267 #endif
269 #if MMM_SAVE
270 if (gEnv->pSystem->GetApplicationInstance() == 0)
272 s_pMMMSaveFile = fxopen("mmm.dat", "wb");
273 fclose(s_pMMMSaveFile);
275 #endif
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]++;
288 #endif
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]++;
306 #endif
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]);
321 #endif
323 DrawDebugLine(x, y++, "Total: Frame Allocs %4d Frame Frees %4d", s_MMMDebug.m_totalNumAllocs, s_MMMDebug.m_totalNumFrees);
324 y++;
325 DrawDebugLine(x, y++, "Current Num Allocations %4d", s_MMMDebug.m_currentNumAllocs);
327 MMMDebugClearFrameData();
329 #else
330 #define MMMDebugInit()
331 #define MMMDebugRemoveAlloc(p, sz)
332 #define MMMDebugAddAlloc(p, sz)
333 #define MMMDebugDraw(x, y)
334 #endif
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
346 #else
347 memset(m_freeList, 0, sizeof(m_freeList));
348 memset(m_numAllocated, 0, sizeof(m_numAllocated));
349 memset(m_numFree, 0, sizeof(m_numFree));
350 #endif
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;
356 #endif
358 MMMDebugInit();
361 CMementoMemoryManager::CMementoMemoryManagerAllocator::~CMementoMemoryManagerAllocator()
363 NET_ASSERT(m_handles.size() == m_freeHandles.size());
365 #if !defined(PURE_CLIENT)
366 if (m_pGeneralHeap)
368 m_pGeneralHeap->Release();
370 #endif
373 void CMementoMemoryManager::CMementoMemoryManagerAllocator::AddCMementoMemoryManager()
375 #if MMM_MUTEX_ENABLE
376 m_mutex.Lock();
377 #endif
379 if (m_numCMementoMemoryManagers == 0)
381 m_allocator = new CMementoMemoryManagerAllocator();
384 m_numCMementoMemoryManagers++;
386 #if MMM_MUTEX_ENABLE
387 m_mutex.Unlock();
388 #endif
391 void CMementoMemoryManager::CMementoMemoryManagerAllocator::RemoveCMementoMemoryManager()
393 #if MMM_MUTEX_ENABLE
394 m_mutex.Lock();
395 #endif
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
405 delete m_allocator;
406 m_allocator = NULL;
409 #if MMM_MUTEX_ENABLE
410 m_mutex.Unlock();
411 #endif
414 #ifdef _DEBUG
415 #define MMM_MUTEX_DEBUG (1)
416 #else
417 #define MMM_MUTEX_DEBUG (0)
418 #endif
420 #if MMM_MUTEX_DEBUG
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
431 int* a = 0;
432 *a = 32;
433 #endif
436 #else
437 #define MMM_ASSERT_GLOBAL_LOCK()
438 #endif
440 CMementoMemoryManager::Hdl CMementoMemoryManager::CMementoMemoryManagerAllocator::AllocHdl(size_t sz)
442 MMM_ASSERT_GLOBAL_LOCK();
443 Hdl hdl;
444 PREVENT_ZERO_ALLOCS(sz);
446 #if MMM_MUTEX_ENABLE
447 m_mutex.Lock();
448 #endif
450 if (m_freeHandles.empty())
452 hdl = m_handles.size();
453 m_handles.push_back(SHandleData());
455 else
457 hdl = m_freeHandles.back();
458 m_freeHandles.pop_back();
461 InitHandleData(m_handles[hdl], sz);
463 hdl = ProtectHdl(hdl);
465 #if MMM_MUTEX_ENABLE
466 m_mutex.Unlock();
467 #endif
469 return hdl;
472 void CMementoMemoryManager::CMementoMemoryManagerAllocator::ResizeHdl(Hdl hdl, size_t sz)
474 MMM_ASSERT_GLOBAL_LOCK();
475 PREVENT_ZERO_ALLOCS(sz);
476 #if MMM_MUTEX_ENABLE
477 m_mutex.Lock();
478 #endif
480 hdl = UnprotectHdl(hdl);
482 NET_ASSERT(hdl != InvalidHdl);
484 SHandleData& hd = m_handles[hdl];
486 #if MMM_USE_BUCKET_ALLOCATOR
487 if (sz != hd.size)
489 SHandleData hdp;
491 InitHandleData(hdp, sz);
493 if (sz < hd.size)
495 memcpy(hdp.p, hd.p, sz);
497 else
499 memcpy(hdp.p, hd.p, hd.size);
502 FreePtr(hd.p, hd.size);
504 hd = hdp;
506 #else
507 if (sz > hd.size) // growing
509 if (sz > hd.capacity) // growing and changing pools
511 SHandleData hdp;
512 InitHandleData(hdp, sz);
513 memcpy(hdp.p, hd.p, hd.size);
514 FreePtr(hd.p, hd.size);
515 hd = hdp;
517 else
519 hd.size = sz;
522 else if (sz < hd.size) // shrinking
524 if (sz <= hd.capacity / 2) // shrinking and changing pools
526 SHandleData hdp;
527 InitHandleData(hdp, sz);
528 memcpy(hdp.p, hd.p, sz);
529 FreePtr(hd.p, hd.size);
530 hd = hdp;
532 else
534 hd.size = sz;
537 #endif
539 #if MMM_MUTEX_ENABLE
540 m_mutex.Unlock();
541 #endif
544 void CMementoMemoryManager::CMementoMemoryManagerAllocator::FreeHdl(Hdl hdl)
546 MMM_ASSERT_GLOBAL_LOCK();
547 #if MMM_MUTEX_ENABLE
548 m_mutex.Lock();
549 #endif
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);
561 #if MMM_MUTEX_ENABLE
562 m_mutex.Unlock();
563 #endif
566 void* CMementoMemoryManager::CMementoMemoryManagerAllocator::AllocPtr(size_t sz)
568 MMM_ASSERT_GLOBAL_LOCK();
569 SHandleData hd;
570 PREVENT_ZERO_ALLOCS(sz);
572 #if MMM_MUTEX_ENABLE
573 m_mutex.Lock();
574 #endif
576 InitHandleData(hd, sz);
578 #if MMM_MUTEX_ENABLE
579 m_mutex.Unlock();
580 #endif
582 return hd.p;
585 void CMementoMemoryManager::CMementoMemoryManagerAllocator::FreePtr(void* p, size_t sz)
587 MMM_ASSERT_GLOBAL_LOCK();
588 PREVENT_ZERO_ALLOCS(sz);
589 #if MMM_MUTEX_ENABLE
590 m_mutex.Lock();
591 #endif
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);
602 else
604 #if !defined(PURE_CLIENT)
605 m_generalHeapTotalRequested -= sz;
606 m_generalHeapTotalAllocated -= m_pGeneralHeap->UsableSize(p);
607 m_pGeneralHeap->Free(p);
608 #else
609 free(p);
610 #endif
612 #else
613 int pool = std::max((int)IntegerLog2_RoundUp(sz) - FIRST_POOL, 0);
615 if (pool < NPOOLS)
617 ((SFreeListHeader*)p)->pNext = m_freeList[pool].pNext;
618 m_freeList[pool].pNext = (SFreeListHeader*)p;
619 m_numFree[pool]++;
620 m_numAllocated[pool]--;
622 else
624 #if !defined(PURE_CLIENT)
625 m_generalHeapTotalRequested -= sz;
626 m_generalHeapTotalAllocated -= m_pGeneralHeap->UsableSize(p);
627 m_pGeneralHeap->Free(p);
628 #else
629 free(p);
630 #endif
632 #endif
634 #if MMM_MUTEX_ENABLE
635 m_mutex.Unlock();
636 #endif
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);
648 if (hd.p == NULL)
650 CryFatalError("Memento Allocation For %" PRISIZE_T " Failed - Suggest increasing the bucket allocator size!!!!", sz);
652 hd.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
663 else
665 #if !defined(PURE_CLIENT)
666 hd.p = m_pGeneralHeap->Malloc(sz, "MMM");
667 if (hd.p == NULL)
669 CryFatalError("Memento Allocation For %" PRISIZE_T " Failed - Suggest increasing the general heap size!!!!", sz);
671 hd.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
681 #else
682 hd.p = malloc(sz);
683 if (hd.p == NULL)
685 CryFatalError("Allocation for %" PRISIZE_T " Failed", sz);
687 hd.size = sz;
688 hd.capacity = sz;
689 #endif
691 #else
692 size_t szP2 = IntegerLog2_RoundUp(sz);
693 uint32 pool = std::max((int)szP2 - FIRST_POOL, 0);
695 if (pool < NPOOLS)
697 if (!m_freeList[pool].pNext)
699 uint32 testPool;
701 for (testPool = pool + 1; testPool < NPOOLS; testPool++)
703 if (m_freeList[testPool].pNext)
705 break;
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;
727 p2->pNext = p1;
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;
737 m_numFree[pool]--;
738 m_numAllocated[pool]++;
739 hd.size = sz;
740 hd.capacity = (size_t)1 << szP2;
742 else
744 hd.p = NULL;
745 hd.size = 0;
746 hd.capacity = 0;
749 else
751 #if !defined(PURE_CLIENT)
752 hd.p = m_pGeneralHeap->Malloc(sz, "MMM");
753 hd.size = sz;
754 hd.capacity = m_pGeneralHeap->UsableSize(hd.p);
755 m_generalHeapTotalRequested += hd.size;
756 m_generalHeapTotalAllocated += hd.capacity;
757 #else
758 hd.p = malloc(sz);
759 hd.size = sz;
760 hd.capacity = sz;
761 #endif
763 #endif
765 if (hd.p == NULL)
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;
786 #else
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);
796 #endif
798 #if !defined(PURE_CLIENT)
799 DrawDebugLine(x, y++, "General Heap Requested %8d Allocated %8d", m_generalHeapTotalRequested, m_generalHeapTotalAllocated);
800 totalAllocated += m_generalHeapTotalAllocated;
801 #endif
802 #endif
805 CMementoMemoryManager::CMementoMemoryManager(const string& name) : m_name(name)
807 ASSERT_GLOBAL_LOCK;
809 CMementoMemoryManagerAllocator::AddCMementoMemoryManager();
811 #if ENABLE_NETWORK_MEM_INFO
812 if (!m_pManagers)
814 m_pManagers = new TManagers;
817 m_pManagers->push_back(this);
818 #endif
820 arith_zeroSizeHdl = InvalidHdl;
822 for (int i = 0; i < sizeof(pThings) / sizeof(*pThings); i++)
824 pThings[i] = 0;
827 m_totalAllocations = 0;
830 CMementoMemoryManager::~CMementoMemoryManager()
832 SCOPED_GLOBAL_LOCK;
834 FreeHdl(arith_zeroSizeHdl);
836 MMM_REGION(this);
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);
847 #endif
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;
862 #if MMM_CHECK_LEAKS
863 void* caller = callerOverride ? callerOverride : UP_STACK_PTR;
864 m_hdlToAlloc[hdl] = caller;
865 m_allocAmt[caller] += sz;
866 #endif
868 return hdl;
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));
879 return out;
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;
895 #if MMM_CHECK_LEAKS
896 void* caller = m_hdlToAlloc[hdl];
897 uint32& callerAlloc = m_allocAmt[caller];
898 callerAlloc -= oldSize;
899 callerAlloc += sz;
900 #endif
903 void CMementoMemoryManager::FreeHdl(Hdl hdl)
905 MMM_ASSERT_GLOBAL_LOCK();
907 size_t size = GetHdlSize(hdl);
909 m_totalAllocations -= size;
911 #if MMM_CHECK_LEAKS
912 void* caller = m_hdlToAlloc[hdl];
914 m_hdlToAlloc.erase(hdl);
916 if (!(m_allocAmt[caller] -= size))
918 m_allocAmt.erase(caller);
920 #endif
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);
935 #if MMM_CHECK_LEAKS
936 void* caller = callerOverride ? callerOverride : UP_STACK_PTR;
937 m_ptrToAlloc[ret] = caller;
938 m_allocAmt[caller] += sz;
939 #endif
941 return ret;
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;
954 #if MMM_CHECK_LEAKS
955 void* caller = m_ptrToAlloc[p];
957 m_ptrToAlloc.erase(p);
959 if (!(m_allocAmt[caller] -= sz))
961 m_allocAmt.erase(caller);
963 #endif
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");
978 if (countingThis)
980 pSizer->Add(*this);
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;
993 int x = 0;
994 int y = 2;
995 bool changed = false;
997 CMementoMemoryManagerAllocator::GetAllocator()->DebugDraw(x, y, totalAllocated);
998 y++;
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;
1006 y++;
1008 if (totalRequested > maxTotalRequested)
1010 maxTotalRequested = totalRequested;
1011 changed = true;
1014 if (totalAllocated > maxTotalAllocated)
1016 maxTotalAllocated = totalAllocated;
1017 changed = true;
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);
1022 y++;
1024 if (changed)
1026 CryLogAlways("[net mmm] Max Total MMM: Requested %" PRISIZE_T " Allocated %" PRISIZE_T, maxTotalRequested, maxTotalAllocated);
1029 MMMDebugDraw(x, y);
1031 #endif
1034 void CMementoMemoryManager::Tick()
1036 WriteMMMData(MMM_TYPE_TICK, 0, 0);
1037 WriteMMMDataCache();
1039 #if MMM_PLAY
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());
1051 while (true)
1053 MMMSaveDataFileCache entry;
1055 if (ReadMMMData(entry))
1057 switch (entry.type)
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]));
1075 delete[] pOldPtr;
1078 if (!s_pMMMSaveData[entry.index].p)
1080 s_pMMMSaveData[entry.index].p = CMementoMemoryManager::CMementoMemoryManagerAllocator::GetAllocator()->AllocPtr(entry.size);
1082 else
1084 NetLog("MMM Playerback: Error allocating into a slot already allocated.");
1087 break;
1089 case MMM_TYPE_FREE:
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;
1095 else
1097 NetLog("MMM Playerback: Error freeing from a slot not allocated.");
1099 break;
1101 case MMM_TYPE_TICK:
1102 CMementoMemoryManager::CMementoMemoryManagerAllocator::GetAllocator()->Tick();
1103 break;
1106 else
1108 break;
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);
1117 #endif
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)