256 static const unsigned int MemTraceBuffSize = 256;
265 static const unsigned int nNoMansLandSize = 4;
274 unsigned char gap[nNoMansLandSize];
289 memset(&privBuff[0], 0, MemTraceBuffSize);
299 void privOut(
const char *
const fmt, ...)
301 MemTrace *pTrace = MemTrace::privGetInstance();
308 #pragma warning( push )
309 #pragma warning( disable : 26492 )
310 #pragma warning( disable : 26481 )
312 #pragma warning( pop )
314 vsprintf_s(&pTrace->privBuff[0], MemTraceBuffSize, fmt, args);
315 OutputDebugString(&pTrace->privBuff[0]);
318 args =
static_cast<va_list
> (
nullptr);
320 pTrace->mtx.unlock();
323 char *privStripDir(
const char *
const pInName)
325 char *pReturn = (
char *)pInName;
327 const char *pch = pInName;
331 pch = strstr(pch,
"\\");
335 pReturn = (
char *)pch;
342 void privDisplayLogLink()
344 char sBuff[512] = { 0 };
345 GetCurrentDirectory(512, sBuff);
347 const char *pch = sBuff;
348 char *pSlash =
nullptr;
352 pch = strstr(pch,
"\\");
356 pSlash = (
char *)pch;
360 size_t numBytes = (size_t)(pSlash - sBuff);
362 char pBuff[512] = { 0 };
363 memcpy_s(pBuff, 512, sBuff, numBytes);
365#ifndef MEMORY_LOGS_DIR
366 std::string strLogFile =
"";
367 strLogFile.append(
"Logs");
368 strLogFile.append(
"\\MemTrackerLog.txt");
370 std::string strLogFile = MEMORY_LOGS_DIR;
371 strLogFile.append(
"Logs");
372 strLogFile.append(
"\\MemTrackerLog.txt");
375 this->privOut(
" MemTrackerLog Link: \n");
376 this->privOut(
" %s(1) : <Double Click>\n", strLogFile.c_str());
381 static void ProcessEnd() noexcept
383 MemTrace *pTrace = MemTrace::privGetInstance();
386 std::call_once(pTrace->ProcessEndFlag, [pTrace]()
388 FILE* pFile = nullptr;
390#ifndef MEMORY_LOGS_DIR
391 system(
"if not exist .\\..\\Logs mkdir .\\..\\Logs");
392 fopen_s(&pFile,
".\\..\\Logs\\MemTrackerLog.txt",
"w");
394 std::string strLogDir = MEMORY_LOGS_DIR;
395 strLogDir.append(
"Logs");
396 strLogDir.append(
"\"");
397 strLogDir.insert(0,
"\"");
399 std::string mkLogDir =
"if not exist " + strLogDir +
" mkdir " + strLogDir;
400 system(mkLogDir.c_str());
402 std::string strLogFile = MEMORY_LOGS_DIR;
403 strLogFile.append(
"Logs");
404 strLogFile.append(
"\\MemTrackerLog.txt");
405 fopen_s(&pFile, strLogFile.c_str(),
"w");
409 if (pFile != nullptr)
411 fprintf(pFile,
"\n");
412 fprintf(pFile,
"****************************************\n");
413 fprintf(pFile,
"\n");
414 fprintf(pFile,
" MemTrackerLog \n");
415 fprintf(pFile,
"\n");
416 fprintf(pFile,
" %s \n", __DATE__);
417 fprintf(pFile,
" %s \n", __TIME__);
418 fprintf(pFile,
"\n");
419 fprintf(pFile,
"****************************************\n");
420 fprintf(pFile,
"\n");
421 fprintf(pFile,
"External Libs: \n");
422 fprintf(pFile,
"\n");
425 _CrtMemCheckpoint(&state);
427 pTrace->privOut(
"\n");
429 pTmp =
reinterpret_cast<MemTrace::_CrtMemBlockHeader *
> (state.pBlockHeader);
433 size_t appMaxIndex = 0;
434 size_t appMaxSize = 0;
436 size_t appTotalSize = 0;
439 size_t extMaxIndex = 0;
440 size_t extMaxSize = 0;
442 size_t extTotalSize = 0;
445 int NormBlockLeakCount = 0;
448 while (pTmp !=
nullptr)
450 if (pTmp->nBlockUse == _NORMAL_BLOCK)
452 NormBlockLeakCount++;
455 if (pTmp->pBlockHeaderNext ==
nullptr)
459 pTmp = pTmp->pBlockHeaderNext;
462 if (NormBlockLeakCount > 0)
464 pTrace->privOut(
"------------------------------------------------------\n");
465 pTrace->privOut(
">>> Memory Tracking: Leaks detected <<<\n");
466 pTrace->privOut(
">>> Double click on file string to Leak location <<<\n");
467 pTrace->privOut(
"------------------------------------------------------\n");
468 pTrace->privOut(
"\n");
470 while (pTmp !=
nullptr)
472 if (pTmp->nBlockUse == _NORMAL_BLOCK)
475 if (pTmp->szFileName ==
nullptr)
477 extTotalSize += pTmp->nDataSize;
479 if (extMaxSize < pTmp->nDataSize)
481 extMaxSize = pTmp->nDataSize;
485 if (pFile !=
nullptr)
487 fprintf(pFile,
"Leak(%d) %d bytes ref:%d \n", (
int)i, (
int)pTmp->nDataSize, (
int)pTmp->lRequest);
492 appTotalSize += pTmp->nDataSize;
494 if (appMaxSize < pTmp->nDataSize)
496 appMaxSize = pTmp->nDataSize;
501 pTrace->privOut(
"Leak(%d) %d bytes ref:%d %s \n", i, pTmp->nDataSize, pTmp->lRequest, pTrace->privStripDir(pTmp->szFileName));
502 pTrace->privOut(
" %s(%d) : <Double Click> \n", pTmp->szFileName, pTmp->nLine);
503 pTrace->privOut(
"\n");
508 pTmp = pTmp->pBlockHeaderPrev;
511 pTrace->privOut(
"Memory Tracking statistics \n");
512 pTrace->privOut(
"\n");
513 pTrace->privOut(
" Application files: \n");
514 pTrace->privOut(
" num of leaks: %d \n", appCount);
515 pTrace->privOut(
" total bytes leaked: %d \n", appTotalSize);
516 if (pAppMaxTmp !=
nullptr)
518 pTrace->privOut(
" largest individual: Leak(%d) size: %d \n", appMaxIndex, pAppMaxTmp->nDataSize);
520 pTrace->privOut(
"\n");
521 pTrace->privOut(
" External Libs: \n");
522 pTrace->privOut(
" num of leaks: %d \n", extCount);
523 pTrace->privOut(
" total bytes leaked: %d \n", extTotalSize);
525 if (pExtMaxTmp !=
nullptr)
527 pTrace->privOut(
" largest individual: Leak(%d) size: %d \n", extMaxIndex, pExtMaxTmp->nDataSize);
529 if (pFile !=
nullptr)
531 fprintf(pFile,
"\n");
532 fprintf(pFile,
"Memory Tracking Stats:\n");
533 fprintf(pFile,
"\n");
534 fprintf(pFile,
" Application files: \n");
535 fprintf(pFile,
" num of leaks: %d \n", (
int)appCount);
536 fprintf(pFile,
" total bytes leaked: %d \n", (
int)appTotalSize);
537 if (pAppMaxTmp !=
nullptr)
539 fprintf(pFile,
" largest individual: Leak(%d) size: %d \n", (
int)appMaxIndex, (
int)pAppMaxTmp->nDataSize);
541 fprintf(pFile,
"\n");
542 fprintf(pFile,
" External Libs: \n");
543 fprintf(pFile,
" num of leaks: %d \n", (
int)extCount);
544 fprintf(pFile,
" total bytes leaked: %d \n", (
int)extTotalSize);
546 if (pExtMaxTmp !=
nullptr)
548 fprintf(pFile,
" largest individual: Leak(%d) size: %d \n", (
int)extMaxIndex, (
int)pExtMaxTmp->nDataSize);
551 fprintf(pFile,
"\n");
552 fprintf(pFile,
"CRT Debug Stats: \n");
553 fprintf(pFile,
"\n");
554 fprintf(pFile,
" %d bytes in %d Free Blocks \n", (
int)state.lSizes[_FREE_BLOCK], (
int)state.lCounts[_FREE_BLOCK]);
555 fprintf(pFile,
" %d bytes in %d Normal Blocks \n", (
int)state.lSizes[_NORMAL_BLOCK], (
int)state.lCounts[_NORMAL_BLOCK]);
556 fprintf(pFile,
" %d bytes in %d CRT Blocks \n", (
int)state.lSizes[_CRT_BLOCK], (
int)state.lCounts[_CRT_BLOCK]);
557 fprintf(pFile,
" %d bytes in %d Ignore Blocks \n", (
int)state.lSizes[_IGNORE_BLOCK], (
int)state.lCounts[_IGNORE_BLOCK]);
558 fprintf(pFile,
" %d bytes in %d Client Blocks \n", (
int)state.lSizes[_CLIENT_BLOCK], (
int)state.lCounts[_CLIENT_BLOCK]);
560 pTrace->privDisplayLogLink();
565 pTrace->privOut(
"--------------------------------\n");
567 printf(
"--------------------------------\n");
570 pTrace->privOut(
">>> Memory Tracking: FAIL <<<<<<\n");
571 printf(
">>> Memory Tracking: FAIL <<<<<<\n");
575 pTrace->privOut(
" Memory Tracking: passed \n");
576 printf(
" Memory Tracking: passed \n");
578 pTrace->privOut(
"--------------------------------\n");
579 pTrace->privOut(
" Memory Tracking: end() \n");
580 pTrace->privOut(
"--------------------------------\n");
581 printf(
"--------------------------------\n");
582 printf(
" Memory Tracking: end() \n");
583 printf(
"--------------------------------\n");
588 if (pFile !=
nullptr)
597 static void ProcessBegin() noexcept
599 MemTrace *pTrace = MemTrace::privGetInstance();
602 std::call_once(pTrace->ProcessBeginFlag, [pTrace]()
604 pTrace->privOut(
"\n");
605 pTrace->privOut(
"****************************************\n");
606 pTrace->privOut(
"** Framework: %s **\n", FRAMEWORK_VER);
607 pTrace->privOut(
"** C++ Compiler: %d **\n", _MSC_FULL_VER);
608 pTrace->privOut(
"** Windows SDK: %s **\n", WINDOWS_TARGET_PLATFORM);
609 pTrace->privOut(
"** Mem Tracking: %s **\n", MEMORY_TRACKING_ENABLE_STRING);
610 pTrace->privOut(
"** Mode: %s **\n", BUILD_CONFIG_MODE);
611 pTrace->privOut(
"****************************************\n");
612 pTrace->privOut(
"\n");
614 printf(
"****************************************\n");
615 printf(
"** Framework: %s **\n", FRAMEWORK_VER);
616 printf(
"** C++ Compiler: %d **\n", _MSC_FULL_VER);
617 printf(
"** Windows SDK: %s **\n", WINDOWS_TARGET_PLATFORM);
618 printf(
"** Mem Tracking: %s **\n", MEMORY_TRACKING_ENABLE_STRING);
619 printf(
"** Mode: %s **\n", BUILD_CONFIG_MODE);
620 printf(
"****************************************\n");
622 pTrace->privOut(
"--------------------------------\n");
623 pTrace->privOut(
" Memory Tracking: start() \n");
624 pTrace->privOut(
"--------------------------------\n");
625 pTrace->privOut(
"\n");
626 printf(
"--------------------------------\n");
627 printf(
" Memory Tracking: start() \n");
628 printf(
"--------------------------------\n");
634 static void ProcessBegin_Release() noexcept
636 MemTrace *pTrace = MemTrace::privGetInstance();
639 std::call_once(pTrace->ProcessBeginFlag, [pTrace]()
641 pTrace->privOut(
"\n");
642 pTrace->privOut(
"****************************************\n");
643 pTrace->privOut(
"** Framework: %s **\n", FRAMEWORK_VER);
644 pTrace->privOut(
"** C++ Compiler: %d **\n", _MSC_FULL_VER);
645 pTrace->privOut(
"** Windows SDK: %s **\n", WINDOWS_TARGET_PLATFORM);
646 pTrace->privOut(
"** Mem Tracking: %s **\n", MEMORY_TRACKING_ENABLE_STRING);
647 pTrace->privOut(
"** Mode: %s **\n", BUILD_CONFIG_MODE);
648 pTrace->privOut(
"****************************************\n");
649 pTrace->privOut(
"\n");
651 printf(
"****************************************\n");
652 printf(
"** Framework: %s **\n", FRAMEWORK_VER);
653 printf(
"** C++ Compiler: %d **\n", _MSC_FULL_VER);
654 printf(
"** Windows SDK: %s **\n", WINDOWS_TARGET_PLATFORM);
655 printf(
"** Mem Tracking: %s **\n", MEMORY_TRACKING_ENABLE_STRING);
656 printf(
"** Mode: %s **\n", BUILD_CONFIG_MODE);
657 printf(
"****************************************\n");
663 std::once_flag ProcessBeginFlag;
664 std::once_flag ProcessEndFlag;
667 static MemTrace *privGetInstance() noexcept
673 char privBuff[MemTraceBuffSize];
975 class Test :
public UnitSLink
979 Test(
const char *
const pTestName) noexcept
985 this->testFunc =
this;
994 Test(
const Test &) =
delete;
995 Test(Test &&) =
delete;
996 Test & operator = (
const Test &) =
delete;
997 Test & operator = (Test &&) =
delete;
1002 virtual void teardown()
noexcept
1006 static void RunTests()
1009 UnitTrace::out(
"------------------- Testing DEBUG ------------------------\n");
1012 const char *
const mode =
"x64 Debug";
1014 const char *
const mode =
"x86 Debug";
1018 const char *
const mode =
"x64 Release";
1020 const char *
const mode =
"x86 Release";
1024 UnitTrace::out(
"------------------- Testing MR_FAST ----------------------\n");
1026 UnitTrace::out(
"------------------- Testing RELEASE ----------------------\n");
1030 UnitTrace::out(
"\n");
1032 UnitSLink *pTmp = rRegistry.GetRoot();
1034 UnitStats &unitStats = rRegistry.GetStats();
1035 UnitData &unitData = rRegistry.GetData();
1037 while (pTmp !=
nullptr)
1039 unitStats.testCount++;
1042 Test *pTest = (Test *)(pTmp);
1045 printf(
"Test:%s \n", pTest->pName);
1051 atomic_thread_fence(std::memory_order_acq_rel);
1054 unitData.result =
true;
1056 assert(pTest->testFunc !=
nullptr);
1057 pTest->testFunc->run(unitData, unitStats);
1060 atomic_thread_fence(std::memory_order_acq_rel);
1063 pTest->testFunc->teardown();
1066 atomic_thread_fence(std::memory_order_acq_rel);
1069 if (unitData.result ==
true)
1071 unitStats.testPass++;
1075 unitStats.testFail++;
1079 pTmp = pTmp->_pNext;
1082 if (unitStats.testFail)
1084 UnitTrace::out(
"\n");
1086 UnitTrace::out(
" (%s) testPass: %d\n", mode, unitStats.testPass);
1087 UnitTrace::out(
" (%s) testFail: %d\n", mode, unitStats.testFail);
1088 UnitTrace::out(
"\n");
1089 UnitTrace::out(
" testCount: %d\n", unitStats.testCount);
1090 UnitTrace::out(
"indvChecks: %d\n", unitStats.indvAsserts);
1091 UnitTrace::out(
"\n");
1092 UnitTrace::out(
"-----------------\n");
1095 printf(
" (%s) testPass: %d\n", mode, unitStats.testPass);
1096 printf(
" (%s) testFail: %d\n", mode, unitStats.testFail);
1098 printf(
" testCount: %d\n", unitStats.testCount);
1099 printf(
"indvChecks: %d\n", unitStats.indvAsserts);
1101 printf(
"-----------------\n");
1105 const char *
const pName;
1233 class PerformanceTimer
1237 PerformanceTimer() noexcept
1242 SecondsPerCycle(0.0f),
1245 this->privInitTimer();
1248 PerformanceTimer(
const PerformanceTimer &) =
delete;
1249 PerformanceTimer(PerformanceTimer &&) =
delete;
1250 PerformanceTimer & operator= (
const PerformanceTimer &) =
delete;
1251 PerformanceTimer & operator= (PerformanceTimer &&) =
delete;
1252 ~PerformanceTimer() =
default;
1257 atomic_thread_fence(std::memory_order_acq_rel);
1259 this->ticTime = this->privGetTimer();
1262 atomic_thread_fence(std::memory_order_acq_rel);
1267 atomic_thread_fence(std::memory_order_acq_rel);
1269 this->tocTime = this->privGetTimer();
1270 assert(this->tocTime.QuadPart >= this->ticTime.QuadPart);
1271 this->deltaTime.QuadPart = this->tocTime.QuadPart - this->ticTime.QuadPart;
1274 atomic_thread_fence(std::memory_order_acq_rel);
1276 void Reset()
noexcept
1278 this->ticTime.QuadPart = 0;
1279 this->tocTime.QuadPart = 0;
1280 this->deltaTime.QuadPart = 0;
1282 float TimeInSeconds()
noexcept
1285 floatTime =
static_cast<float>(this->deltaTime.QuadPart);
1286 floatTime *= this->SecondsPerCycle;
1292 void privInitTimer()
noexcept
1294 LARGE_INTEGER Frequency;
1295 QueryPerformanceFrequency(&Frequency);
1296 this->SecondsPerCycle = 1.0f / Frequency.QuadPart;
1298 LARGE_INTEGER privGetTimer()
noexcept
1301 QueryPerformanceCounter(&time);
1309 LARGE_INTEGER ticTime;
1310 LARGE_INTEGER tocTime;
1311 LARGE_INTEGER deltaTime;
1312 float SecondsPerCycle;
1420 static void Open(
const char *
const pFirstName,
const char *
const pLastName)
noexcept
1424 FileIO::privGetInstance()->privOpen(pFirstName, pLastName);
1426 static void Close()
noexcept
1428 FileIO::privGetInstance()->privClose();
1430 static FILE *GetHandle()
noexcept
1432 return FileIO::privGetInstance()->privGetHandle();
1437 void privOpen(
const char *
const pFirstName,
const char *
const pLastName)
noexcept
1439 system(
"if not exist .\\..\\Logs mkdir .\\..\\Logs");
1441 const char *
const pFile_extension =
".txt";
1442 const char *
const pFile_io_path =
".\\..\\Logs\\";
1444 const int length = 256;
1446 char pFileName[length] = { 0 };
1449 errno_t fileError(0);
1452 memset(&pFileName[0], 0, length);
1455 assert( (strlen(pFile_io_path)
1456 + strlen(pFirstName)
1459 + strlen(pFileio_mode)
1460 + strlen(pFile_extension)
1461 + strlen(
"/0") ) < length);
1463 strcat_s(&pFileName[0], length, pFile_io_path);
1464 strcat_s(&pFileName[0], length, pFirstName);
1465 strcat_s(&pFileName[0], length, pLastName);
1466 strcat_s(&pFileName[0], length,
"_");
1467 strcat_s(&pFileName[0], length, pFileio_mode);
1468 strcat_s(&pFileName[0], length, pFile_extension);
1471 fileError = fopen_s(&pFileHandle, &pFileName[0],
"wt");
1472 assert(pFileHandle);
1473 if(pFileHandle !=
nullptr)
1475 fprintf(this->pFileHandle,
"-------------------------------------------------\n");
1476 fprintf(this->pFileHandle,
"\n");
1477 fprintf(this->pFileHandle,
"Log File \n");
1478 fprintf(this->pFileHandle,
"\n");
1479 fprintf(this->pFileHandle,
"Name: %s %s\n", pFirstName, pLastName);
1480 fprintf(this->pFileHandle,
"Mode: %s\n", pFileio_mode);
1481 fprintf(this->pFileHandle,
"\n");
1482 fprintf(this->pFileHandle,
"-------------------------------------------------\n");
1483 fprintf(this->pFileHandle,
"\n");
1486 FILE *privGetHandle()
noexcept
1488 assert(pFileHandle);
1489 return this->pFileHandle;
1491 static FileIO *privGetInstance()
noexcept
1493 static FileIO instance;
1496 void privClose()
noexcept
1498 errno_t fileError(0);
1499 assert(pFileHandle);
1501 fileError = fflush(this->pFileHandle);
1504 fileError = fclose(this->pFileHandle);
1505 this->pFileHandle =
nullptr;
1510 constexpr FileIO() noexcept
1511 :pFileHandle(
nullptr)
1515 FileIO(
const FileIO &) =
delete;
1516 FileIO(FileIO &&) =
delete;
1517 FileIO & operator=(
const FileIO &) =
delete;
1518 FileIO & operator=(FileIO &&) =
delete;
1521 if (
nullptr != this->pFileHandle)
1562 void*
operator new(size_t,
void *p)
noexcept
1564 ALIGN_UNUSED_VAR(p);
1568 void *
operator new(
size_t size)
noexcept
1570 void *p = _aligned_malloc(size, 16);
1574 void operator delete(
void *p)
1579 void *
operator new[](
size_t size)
noexcept
1581 void *p = _aligned_malloc(size, 16);
1585 void operator delete[](
void *p)
1590 void *
operator new(
size_t size,
1592 char const* _FileName,
1593 int _LineNumber)
noexcept
1595 ALIGN_UNUSED_VAR(_BlockUse);
1596 ALIGN_UNUSED_VAR(_FileName);
1597 ALIGN_UNUSED_VAR(_LineNumber);
1599 void *p = _aligned_malloc_dbg(size, 16, _FileName, _LineNumber);
1603 void operator delete(
void *p,
1605 char const* _FileName,
1608 ALIGN_UNUSED_VAR(_BlockUse);
1609 ALIGN_UNUSED_VAR(_FileName);
1610 ALIGN_UNUSED_VAR(_LineNumber);
1611 _aligned_free_dbg(p);
1614 void *
operator new[](
size_t size,
1616 char const* _FileName,
1617 int _LineNumber)
noexcept
1619 ALIGN_UNUSED_VAR(_BlockUse);
1620 ALIGN_UNUSED_VAR(_FileName);
1621 ALIGN_UNUSED_VAR(_LineNumber);
1623 void *p = _aligned_malloc_dbg(size, 16, _FileName, _LineNumber);
1627 void operator delete[](
void *p,
1629 char const* _FileName,
1632 ALIGN_UNUSED_VAR(_BlockUse);
1633 ALIGN_UNUSED_VAR(_FileName);
1634 ALIGN_UNUSED_VAR(_LineNumber);
1635 _aligned_free_dbg(p);