home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2006 March / Gamestar_82_2006-03_dvd.iso / DVDStar / Editace / quake4_sdkv10.exe / source / idlib / rvMemSys.cpp < prev    next >
C/C++ Source or Header  |  2005-11-14  |  28KB  |  1,269 lines

  1. //
  2. // rvMemSys.cpp - Memory management system
  3. // Date: 12/17/04
  4. // Created by: Dwight Luetscher
  5. //
  6.  
  7. #include "../idlib/precompiled.h"
  8. #pragma hdrstop
  9.  
  10. #ifdef _RV_MEM_SYS_SUPPORT
  11.  
  12. static memoryStats_t    mem_total_allocs = { 0, 0x0fffffff, -1, 0 };
  13. static memoryStats_t    mem_frame_allocs;
  14. static memoryStats_t    mem_frame_frees;
  15.  
  16. rvHeapArena mainHeapArena;
  17. rvHeapArena *currentHeapArena;        // this is the main heap arena that all other heaps use
  18. rvHeap defaultHeap;                    // this is the default system heap
  19.  
  20. static rvHeap *systemHeapArray[MAX_SYSTEM_HEAPS];        // array of pointers to rvHeaps that are common to idLib, Game, and executable 
  21.  
  22. #if defined(_WIN32) && !defined(_XENON)
  23. static LPVOID sharedMem = NULL;      // pointer to shared memory
  24. static HANDLE hMapObject = NULL;    // handle to file mapping
  25. #endif
  26.  
  27. // Descriptions that go with each tag.  When updating the tag enum in Heap.h please 
  28. // update this list as well.
  29. // (also update the list in Heap.cpp)
  30. char *TagNames[] = {
  31.     "none",
  32.     "New operation",
  33.     "default",
  34.     "Lexer",
  35.     "Parser",
  36.     "AAS routing",
  37.     "Class",
  38.     "Script program",
  39.     "Collision Model",
  40.     "CVar",
  41.     "Decl System",
  42.     "File System",
  43.     "Images",
  44.     "Materials",
  45.     "Models",
  46.     "Fonts",
  47.     "Main renderer",
  48.     "Vertex data",
  49.     "Sound",
  50.     "Window",
  51.     "Event loop",
  52.     "Math - Matrices and vectors",
  53.     "Animation",
  54.     "Dynamic Blocks",
  55.     "Strings",
  56.     "GUI",
  57.     "Effects",
  58.     "Entities",
  59.     "Physics",
  60.     "AI",
  61.     "Network",
  62.     "Not Used"
  63. };
  64.  
  65. template<int X>
  66. class TagTableCheck
  67. {
  68. private:
  69.     TagTableCheck();
  70. };
  71.  
  72. template<>
  73. class TagTableCheck<1>
  74. {
  75. };
  76.  
  77. // An error here means you need to synchronize TagNames and Mem_Alloc_Types_t 
  78. TagTableCheck<sizeof(TagNames)/sizeof(char*) == MA_MAX> TagTableCheckedHere;
  79. // An error here means there are too many tags.  No more than 32! 
  80. TagTableCheck<MA_DO_NOT_USE<32> TagMaxCheckedHere;
  81.  
  82. #ifndef ENABLE_INTEL_SMP
  83. MemScopedTag* MemScopedTag::mTop = NULL;
  84. #endif
  85.  
  86. /*
  87. ==================
  88. GetMemAllocStats
  89.  
  90. Gets some memory allocation stats based on a particular tag.
  91. ==================
  92. */
  93. const char *GetMemAllocStats(int tag, int &num, int &size, int &peak)
  94. {
  95.     assert( tag < MA_MAX );
  96.  
  97.     currentHeapArena->GetTagStats( tag, num, size, peak );
  98.     return TagNames[tag];
  99. }
  100.  
  101. /*
  102. ==================
  103. rvSetSysHeap
  104.  
  105. sets the system heap that is associated with the given heap ID value
  106. ==================
  107. */
  108. void rvSetSysHeap(Rv_Sys_Heap_ID_t sysHeapID, rvHeap *heapPtr)
  109. {
  110.     assert( (uint) sysHeapID < (uint) rv_heap_ID_max_count );
  111.     if ( NULL == heapPtr )
  112.     {
  113.         // set the system heap back to the default heap
  114.         systemHeapArray[ (uint) sysHeapID ] = &defaultHeap;
  115.     }
  116.     else 
  117.     {
  118.         systemHeapArray[ (uint) sysHeapID ] = heapPtr;
  119.     }
  120. }
  121.  
  122. /*
  123. ==================
  124.  rvPushSysHeap
  125.  
  126. pushes the system heap associated with the given identifier to the top of the arena stack, making it current.
  127. ==================
  128. */
  129. void rvPushSysHeap(Rv_Sys_Heap_ID_t sysHeapID)
  130. {
  131.     assert( (uint) sysHeapID < (uint) rv_heap_ID_max_count );
  132.     assert( systemHeapArray[ (uint) sysHeapID ] != NULL );
  133.     systemHeapArray[ (uint) sysHeapID ]->PushCurrent( );
  134. }
  135.  
  136. /*
  137. ==================
  138.  rvEnterArenaCriticalSection
  139.  
  140. enters the heap arena critical section.
  141. ==================
  142. */
  143. void rvEnterArenaCriticalSection( )
  144. {
  145.     // the following is necessary for memory allocations that take place
  146.     // in static/global object constructors
  147.     if ( NULL == currentHeapArena )
  148.     {
  149.         Mem_Init();
  150.     }
  151.     assert( currentHeapArena != NULL );
  152.     currentHeapArena->EnterArenaCriticalSection( );
  153. }
  154.  
  155. /*
  156. ==================
  157.  rvExitArenaCriticalSection
  158.  
  159. exits the heap arena critical section
  160. ==================
  161. */
  162. void rvExitArenaCriticalSection( )
  163. {
  164.     assert( currentHeapArena != NULL );
  165.     currentHeapArena->ExitArenaCriticalSection( );
  166. }
  167.  
  168. /*
  169. ==================
  170. Mem_Init
  171.  
  172. initializes the memory system for use
  173. ==================
  174. */
  175. void Mem_Init( void )
  176. {
  177.     if ( NULL == currentHeapArena )
  178.     {
  179.  
  180. #if defined(_WIN32) && !defined(_XENON)
  181.         hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, // use paging file
  182.                                        NULL,                 // default security attributes
  183.                                        PAGE_READWRITE,       // read/write access
  184.                                        0,                    // size: high 32-bits
  185.                                        sizeof(systemHeapArray)+sizeof(currentHeapArena),     // size: low 32-bits
  186.                                        "quake4share");        // name of map object
  187.         if ( hMapObject == NULL ) 
  188.         {
  189.             return; 
  190.         }
  191.  
  192.         // The first process to attach initializes memory.
  193.         bool firstInit = (GetLastError() != ERROR_ALREADY_EXISTS); 
  194.  
  195.         // Get a pointer to the file-mapped shared memory.
  196.         sharedMem = MapViewOfFile(hMapObject,     // object to map view of
  197.                                   FILE_MAP_WRITE, // read/write access
  198.                                   0,              // high offset:  map from
  199.                                   0,              // low offset:   beginning
  200.                                   0);             // default: map entire file
  201.         if ( sharedMem == NULL ) 
  202.         {
  203.             return; 
  204.         }
  205.  
  206.         if ( !firstInit )
  207.         {
  208.             memcpy( ¤tHeapArena, sharedMem, sizeof(currentHeapArena) );
  209.             memcpy( &systemHeapArray, (byte*) sharedMem + sizeof(currentHeapArena), sizeof(systemHeapArray) );
  210.  
  211.             UnmapViewOfFile( sharedMem );
  212.             CloseHandle( hMapObject );
  213.  
  214.             sharedMem = NULL;
  215.             hMapObject = NULL;
  216.             return;
  217.         }
  218. #endif
  219.  
  220.         currentHeapArena = &mainHeapArena;
  221.         currentHeapArena->Init();
  222.         defaultHeap.Init( *currentHeapArena, 256*1024*1024 );
  223.         defaultHeap.SetDebugID(0);
  224.         defaultHeap.SetName("DEFAULT");
  225.         rvSetSysHeap( RV_HEAP_ID_DEFAULT, &defaultHeap );
  226.         rvSetSysHeap( RV_HEAP_ID_PERMANENT, &defaultHeap );
  227.         rvSetSysHeap( RV_HEAP_ID_LEVEL, &defaultHeap );
  228.         rvSetSysHeap( RV_HEAP_ID_MULTIPLE_FRAME, &defaultHeap );
  229.         rvSetSysHeap( RV_HEAP_ID_SINGLE_FRAME, &defaultHeap );
  230.         rvSetSysHeap( RV_HEAP_ID_TEMPORARY, &defaultHeap );
  231.         rvSetSysHeap( RV_HEAP_ID_IO_TEMP, &defaultHeap );
  232.         RV_PUSH_SYS_HEAP_ID( RV_HEAP_ID_DEFAULT );
  233.  
  234. #if defined(_WIN32) && !defined(_XENON)
  235.         memcpy( sharedMem,  ¤tHeapArena, sizeof(currentHeapArena) );
  236.         memcpy( (byte*) sharedMem + sizeof(currentHeapArena), &systemHeapArray, sizeof(systemHeapArray) );
  237. #endif
  238.     }
  239. }
  240.  
  241. /*
  242. ==================
  243. Mem_Shutdown
  244.  
  245. Shuts down the memory system from all further use
  246. ==================
  247. */
  248. void Mem_Shutdown( void )
  249. {
  250. #if defined(_WIN32) && !defined(_XENON)
  251.     if ( sharedMem != NULL )
  252.     {
  253.         UnmapViewOfFile( sharedMem );
  254.         CloseHandle( hMapObject );
  255.         sharedMem = NULL;
  256.         hMapObject = NULL;
  257.     }
  258. #endif
  259.  
  260.     if ( currentHeapArena == &mainHeapArena )
  261.     {
  262.         memset(systemHeapArray, 0, sizeof(systemHeapArray));
  263.         defaultHeap.Shutdown();
  264.         currentHeapArena->Shutdown();
  265.     }
  266. }
  267.  
  268. void Mem_EnableLeakTest( const char *name )
  269. {
  270.  
  271. }
  272.  
  273. /*
  274. ==================
  275. Mem_UpdateStats
  276. ==================
  277. */
  278. void Mem_UpdateStats( memoryStats_t &stats, int size ) 
  279. {
  280.     stats.num++;
  281.     if ( size < stats.minSize ) {
  282.         stats.minSize = size;
  283.     }
  284.     if ( size > stats.maxSize ) {
  285.         stats.maxSize = size;
  286.     }
  287.     stats.totalSize += size;
  288. }
  289.  
  290. /*
  291. ==================
  292. Mem_UpdateAllocStats
  293. ==================
  294. */
  295. void Mem_UpdateAllocStats( int size ) 
  296. {
  297.     Mem_UpdateStats( mem_frame_allocs, size );
  298.     Mem_UpdateStats( mem_total_allocs, size );
  299. }
  300.  
  301. /*
  302. ==================
  303. Mem_UpdateFreeStats
  304. ==================
  305. */
  306. void Mem_UpdateFreeStats( int size ) {
  307.     Mem_UpdateStats( mem_frame_frees, size );
  308.     mem_total_allocs.num--;
  309.     mem_total_allocs.totalSize -= size;
  310. }
  311.  
  312. /*
  313. ==================
  314. Mem_ClearFrameStats
  315. ==================
  316. */
  317. void Mem_ClearFrameStats( void )
  318. {
  319.     mem_frame_allocs.num = mem_frame_frees.num = 0;
  320.     mem_frame_allocs.minSize = mem_frame_frees.minSize = 0x0fffffff;
  321.     mem_frame_allocs.maxSize = mem_frame_frees.maxSize = -1;
  322.     mem_frame_allocs.totalSize = mem_frame_frees.totalSize = 0;
  323. }
  324.  
  325. /*
  326. ==================
  327. Mem_GetFrameStats
  328. ==================
  329. */
  330. void Mem_GetFrameStats( memoryStats_t &allocs, memoryStats_t &frees )
  331. {
  332.     allocs = mem_frame_allocs;
  333.     frees = mem_frame_frees;
  334. }
  335.  
  336. /*
  337. ==================
  338. Mem_GetStats
  339. ==================
  340. */
  341. void Mem_GetStats( memoryStats_t &stats )
  342. {
  343.     stats = mem_total_allocs;
  344. }
  345.  
  346. void Mem_AllocDefragBlock( void )
  347. {
  348.  
  349. }
  350.  
  351. /*
  352. ==================
  353. Mem_ShowMemAlloc_f
  354. ==================
  355. */
  356. void Mem_ShowMemAlloc_f( const idCmdArgs &args )
  357. {
  358.     const char *tagName;
  359.     int tag, num, size, peak;
  360.     DWORD totalOutstanding = 0;
  361.  
  362.     for ( tag = 1; tag < MA_DO_NOT_USE; tag++ )
  363.     {
  364.         tagName = GetMemAllocStats( tag, num, size, peak );
  365.  
  366.         if ( size || peak )
  367.         {
  368.             idLib::common->Printf("%-25s peak %9d curr %9d count %9d\n", tagName, peak, size, num );
  369.             totalOutstanding += size;
  370.         }
  371.     }
  372.     idLib::common->Printf("Mem_Alloc Outstanding: %d\n", totalOutstanding);
  373. }
  374.  
  375. #ifdef ID_DEBUG_MEMORY
  376.  
  377. #undef        Mem_Alloc
  378. #undef        Mem_ClearedAlloc
  379. #undef        Com_ClearedReAlloc
  380. #undef        Mem_Free
  381. #undef        Mem_CopyString
  382. #undef        Mem_Alloc16
  383. #undef        Mem_Free16
  384.  
  385. #define MAX_CALLSTACK_DEPTH        10
  386.  
  387. // size of this struct must be a multiple of 16 bytes
  388. typedef struct debugMemory_s {
  389.     const char *            fileName;
  390.     short                    lineNumber;
  391.     byte                    heapId;
  392.     byte                    memTag;
  393.     int                        frameNumber;
  394.     int                        size;
  395.     address_t                callStack[MAX_CALLSTACK_DEPTH];
  396.     struct debugMemory_s *    prev;
  397.     struct debugMemory_s *    next;
  398. } debugMemory_t;
  399.  
  400. static debugMemory_t *    mem_debugMemory = NULL;
  401. static char                mem_leakName[256] = "";
  402.  
  403. /*
  404. ==================
  405. Mem_CleanupFileName
  406. ==================
  407. */
  408. const char *Mem_CleanupFileName( const char *fileName ) 
  409. {
  410.     int i1, i2;
  411.     idStr newFileName;
  412.     static char newFileNames[4][MAX_STRING_CHARS];
  413.     static int index;
  414.  
  415.     newFileName = fileName;
  416.     newFileName.BackSlashesToSlashes();
  417.     i1 = newFileName.Find( "neo", false );
  418.     if ( i1 >= 0 ) {
  419.         i1 = newFileName.Find( "/", false, i1 );
  420.         newFileName = newFileName.Right( newFileName.Length() - ( i1 + 1 ) );
  421.     }
  422.     while( 1 ) {
  423.         i1 = newFileName.Find( "/../" );
  424.         if ( i1 <= 0 ) {
  425.             break;
  426.         }
  427.         i2 = i1 - 1;
  428.         while( i2 > 1 && newFileName[i2-1] != '/' ) {
  429.             i2--;
  430.         }
  431.         newFileName = newFileName.Left( i2 - 1 ) + newFileName.Right( newFileName.Length() - ( i1 + 4 ) );
  432.     }
  433.     index = ( index + 1 ) & 3;
  434.     strncpy( newFileNames[index], newFileName.c_str(), sizeof( newFileNames[index] ) );
  435.     return newFileNames[index];
  436. }
  437.  
  438. /*
  439. ==================
  440. Mem_Dump
  441. ==================
  442. */
  443. void Mem_Dump( const char *fileName ) 
  444. {
  445.     int i, numBlocks, totalSize;
  446.     char dump[32], *ptr;
  447.     debugMemory_t *b;
  448.     idStr module, funcName;
  449.     FILE *f;
  450.  
  451.     f = fopen( fileName, "wb" );
  452.     if ( !f ) {
  453.         return;
  454.     }
  455.  
  456.     totalSize = 0;
  457.     for ( numBlocks = 0, b = mem_debugMemory; b; b = b->next, numBlocks++ ) {
  458.         ptr = ((char *) b) + sizeof(debugMemory_t);
  459.         totalSize += b->size;
  460.         for ( i = 0; i < (sizeof(dump)-1) && i < b->size; i++) {
  461.             if ( ptr[i] >= 32 && ptr[i] < 127 ) {
  462.                 dump[i] = ptr[i];
  463.             } else {
  464.                 dump[i] = '_';
  465.             }
  466.         }
  467.         dump[i] = '\0';
  468.         if ( ( b->size >> 10 ) != 0 ) {
  469.             fprintf( f, "size: %6d KB: %s, line: %d [%s], call stack: %s\r\n", ( b->size >> 10 ), Mem_CleanupFileName(b->fileName), b->lineNumber, dump, idLib::sys->GetCallStackStr( b->callStack, MAX_CALLSTACK_DEPTH ) );
  470.         }
  471.         else {
  472.             fprintf( f, "size: %7d B: %s, line: %d [%s], call stack: %s\r\n", b->size, Mem_CleanupFileName(b->fileName), b->lineNumber, dump, idLib::sys->GetCallStackStr( b->callStack, MAX_CALLSTACK_DEPTH ) );
  473.         }
  474.     }
  475.  
  476.     idLib::sys->ShutdownSymbols();
  477.  
  478.     fprintf( f, "%8d total memory blocks allocated\r\n", numBlocks );
  479.     fprintf( f, "%8d KB memory allocated\r\n", ( totalSize >> 10 ) );
  480.  
  481.     fclose( f );
  482. }
  483.  
  484. /*
  485. ==================
  486. Mem_Dump_f
  487. ==================
  488. */
  489. void Mem_Dump_f( const idCmdArgs &args ) 
  490. {
  491.     const char *fileName;
  492.  
  493.     if ( args.Argc() >= 2 ) {
  494.         fileName = args.Argv( 1 );
  495.     }
  496.     else {
  497.         fileName = "memorydump.txt";
  498.     }
  499.     Mem_Dump( fileName );
  500. }
  501.  
  502. typedef struct allocInfo_s 
  503. {
  504.     const char *            fileName;
  505.     short                    lineNumber;
  506.     byte                    heapId;
  507.     byte                    memTag;
  508.     int                        size;
  509.     int                        numAllocs;
  510.     address_t                callStack[MAX_CALLSTACK_DEPTH];
  511.     struct allocInfo_s *    next;
  512. } allocInfo_t;
  513.  
  514. typedef enum 
  515. {
  516.     MEMSORT_SIZE,
  517.     MEMSORT_LOCATION,
  518.     MEMSORT_NUMALLOCS,
  519.     MEMSORT_CALLSTACK,
  520.     MEMSORT_HEAPID,
  521.     MEMSORT_MEMTAG
  522. } memorySortType_t;
  523.  
  524. /*
  525. ==================
  526. Mem_DumpCompressed
  527. ==================
  528. */
  529. void Mem_DumpCompressed( const char *fileName, memorySortType_t memSort, int sortCallStack, int numFrames, bool verbose  ) 
  530. {
  531.     int numBlocks, totalSize, r, j;
  532.     debugMemory_t *b;
  533.     allocInfo_t *a, *nexta, *allocInfo = NULL, *sortedAllocInfo = NULL, *prevSorted, *nextSorted;
  534.     idStr module, funcName;
  535.  
  536.     // build list with memory allocations
  537.     totalSize = 0;
  538.     numBlocks = 0;
  539.     nextSorted = NULL;
  540.  
  541.     for ( b = mem_debugMemory; b; b = b->next ) {
  542.  
  543.         if ( numFrames && b->frameNumber < idLib::frameNumber - numFrames ) {
  544.             continue;
  545.         }
  546.  
  547.         numBlocks++;
  548.         totalSize += b->size;
  549.  
  550.         // search for an allocation from the same source location
  551.         for ( a = allocInfo; a; a = a->next ) 
  552.         {
  553.             if ( a->lineNumber != b->lineNumber )
  554.             {
  555.                 continue;
  556.             }
  557. #ifndef _XENON
  558.             // removed the call stack info for better consolidation of info and speed of dump
  559.             for ( j = 0; j < MAX_CALLSTACK_DEPTH; j++ ) {
  560.                 if ( a->callStack[j] != b->callStack[j] ) {
  561.                     break;
  562.                 }
  563.             }
  564.             if ( j < MAX_CALLSTACK_DEPTH ) {
  565.                 continue;
  566.             }
  567. #endif
  568.             if ( idStr::Cmp( a->fileName, b->fileName ) != 0 ) {
  569.                 continue;
  570.             }
  571.  
  572.             if ( a->heapId != b->heapId )
  573.             {
  574.                 continue;
  575.             }
  576.  
  577.             a->numAllocs++;
  578.             a->size += b->size;
  579.             break;
  580.         }
  581.  
  582.         // if this is an allocation from a new source location
  583.         if ( !a ) 
  584.         {
  585.             a = (allocInfo_t *) currentHeapArena->Allocate( sizeof( allocInfo_t ) );
  586.             a->fileName = b->fileName;
  587.             a->lineNumber = b->lineNumber;
  588.             a->heapId = b->heapId;
  589.             a->memTag = b->memTag;
  590.             a->size = b->size;
  591.             a->numAllocs = 1;
  592.             for ( j = 0; j < MAX_CALLSTACK_DEPTH; j++ ) {
  593.                 a->callStack[j] = b->callStack[j];
  594.             }
  595.             a->next = allocInfo;
  596.             allocInfo = a;
  597.         }
  598.     }
  599.  
  600.     // sort list
  601.     for ( a = allocInfo; a; a = nexta ) 
  602.     {
  603.         nexta = a->next;
  604.  
  605.         prevSorted = NULL;
  606.         switch( memSort ) {
  607.             // sort on size
  608.             case MEMSORT_SIZE: {
  609.                 for ( nextSorted = sortedAllocInfo; nextSorted; nextSorted = nextSorted->next ) {
  610.                     if ( a->size > nextSorted->size ) {
  611.                         break;
  612.                     }
  613.                     prevSorted = nextSorted;
  614.                 }
  615.                 break;
  616.             }
  617.             // sort on file name and line number
  618.             case MEMSORT_LOCATION: {
  619.                 for ( nextSorted = sortedAllocInfo; nextSorted; nextSorted = nextSorted->next ) {
  620.                     r = idStr::Cmp( Mem_CleanupFileName( a->fileName ), Mem_CleanupFileName( nextSorted->fileName ) );
  621.                     if ( r < 0 || ( r == 0 && a->lineNumber < nextSorted->lineNumber ) ) {
  622.                         break;
  623.                     }
  624.                     prevSorted = nextSorted;
  625.                 }
  626.                 break;
  627.             }
  628.             // sort on the number of allocations
  629.             case MEMSORT_NUMALLOCS: {
  630.                 for ( nextSorted = sortedAllocInfo; nextSorted; nextSorted = nextSorted->next ) {
  631.                     if ( a->numAllocs > nextSorted->numAllocs ) {
  632.                         break;
  633.                     }
  634.                     prevSorted = nextSorted;
  635.                 }
  636.                 break;
  637.             }
  638.             // sort on call stack
  639.             case MEMSORT_CALLSTACK: {
  640.                 for ( nextSorted = sortedAllocInfo; nextSorted; nextSorted = nextSorted->next ) {
  641.                     if ( a->callStack[sortCallStack] < nextSorted->callStack[sortCallStack] ) {
  642.                         break;
  643.                     }
  644.                     prevSorted = nextSorted;
  645.                 }
  646.                 break;
  647.             }
  648.             // sort on heap ID
  649.             case MEMSORT_HEAPID: {
  650.                 for ( nextSorted = sortedAllocInfo; nextSorted; nextSorted = nextSorted->next ) {
  651.                     if ( a->heapId > nextSorted->heapId ) {
  652.                         break;
  653.                     }
  654.                     prevSorted = nextSorted;
  655.                 }
  656.                 break;
  657.             }
  658.         }
  659.         if ( !prevSorted ) {
  660.             a->next = sortedAllocInfo;
  661.             sortedAllocInfo = a;
  662.         }
  663.         else {
  664.             prevSorted->next = a;
  665.             a->next = nextSorted;
  666.         }
  667.     }
  668.  
  669. // RAVEN BEGIN
  670. // dluetscher: changed xenon version to output anything above 1K to the console 
  671. // mwhitlock: added verbose option to show < 1K also since I need to see leaks,
  672. // no matter how small.
  673. #ifdef _XENON
  674.     
  675.     unsigned int notShownSize = 0;
  676.     unsigned int notShownNumAllocs = 0;
  677.     
  678.     // write list to debug output and console
  679.     char buff[256];
  680.     for ( a = sortedAllocInfo; a; a = nexta ) {
  681.         nexta = a->next;
  682.  
  683.         if((a->size >> 10) > 0)
  684.         {
  685.             idStr::snPrintf(buff, sizeof(buff), "%6d K",( a->size >> 10));
  686.         }
  687.         else
  688.         {
  689.             idStr::snPrintf(buff, sizeof(buff), "%6d B", a->size);
  690.         }
  691.  
  692.         if ( verbose || ((a->size >> 10) > 0 ) )
  693.         {
  694.                 idLib::common->Printf("size: %s, allocs: %5d: %s, line: %d, heap: %d, call stack: %s\r\n",
  695.                             buff, a->numAllocs, Mem_CleanupFileName(a->fileName),
  696.                             a->lineNumber, a->heapId, idLib::sys->GetCallStackStr( a->callStack, MAX_CALLSTACK_DEPTH ) );
  697.         }
  698.         else
  699.         {
  700.             notShownSize+=(unsigned int)a->size;
  701.             notShownNumAllocs+=(unsigned int)a->numAllocs;
  702.         }
  703.  
  704.         currentHeapArena->Free( a );
  705.     }
  706.  
  707.     idLib::sys->ShutdownSymbols();
  708.  
  709.     idLib::common->Printf("%8d bytes in %d allocs not shown\r\n", notShownSize, notShownNumAllocs );
  710.     idLib::common->Printf("%8d total memory blocks allocated\r\n", numBlocks );
  711.     idLib::common->Printf("%8d KB memory allocated\r\n", ( totalSize >> 10 ) );
  712.  
  713. #else
  714. // RAVEN END
  715.     FILE *f;
  716.  
  717. // in case you want to flip the above ifdef and write to disc on the xenon
  718.     f = fopen( fileName, "wb" );
  719.     if ( !f ) {
  720.         return;
  721.     }
  722.  
  723.     // write list to file
  724.     for ( a = sortedAllocInfo; a; a = nexta ) {
  725.         nexta = a->next;
  726.         fprintf( f, "size: %6d KB, allocs: %5d: %s, line: %d, call stack: %s\r\n",
  727.                     (a->size >> 10), a->numAllocs, Mem_CleanupFileName(a->fileName),
  728.                             a->lineNumber, idLib::sys->GetCallStackStr( a->callStack, MAX_CALLSTACK_DEPTH ) );
  729. // RAVEN BEGIN
  730. // jnewquist: send all allocations through one place on the Xenon
  731.         currentHeapArena->Free( a );
  732. // RAVEN END
  733.     }
  734.  
  735.     idLib::sys->ShutdownSymbols();
  736.  
  737.     fprintf( f, "%8d total memory blocks allocated\r\n", numBlocks );
  738.     fprintf( f, "%8d KB memory allocated\r\n", ( totalSize >> 10 ) );
  739.  
  740.     fclose( f );
  741. #endif
  742. }
  743.  
  744. /*
  745. ==================
  746. Mem_DumpCompressed_f
  747. ==================
  748. */
  749. void Mem_DumpCompressed_f( const idCmdArgs &args ) 
  750. {
  751.     int argNum;
  752.     const char *arg, *fileName;
  753.     memorySortType_t memSort = MEMSORT_LOCATION;
  754.     int sortCallStack = 0, numFrames = 0;
  755.     bool verbose = false;
  756.  
  757.     // get cmd-line options
  758.     argNum = 1;
  759.     arg = args.Argv( argNum );
  760.     while( arg[0] == '-' ) {
  761.         arg = args.Argv( ++argNum );
  762.         if ( idStr::Icmp( arg, "s" ) == 0 ) {
  763.             memSort = MEMSORT_SIZE;
  764.         } else if ( idStr::Icmp( arg, "l" ) == 0 ) {
  765.             memSort = MEMSORT_LOCATION;
  766.         } else if ( idStr::Icmp( arg, "a" ) == 0 ) {
  767.             memSort = MEMSORT_NUMALLOCS;
  768.         } else if ( idStr::Icmp( arg, "cs1" ) == 0 ) {
  769.             memSort = MEMSORT_CALLSTACK;
  770.             sortCallStack = 2;
  771.         } else if ( idStr::Icmp( arg, "cs2" ) == 0 ) {
  772.             memSort = MEMSORT_CALLSTACK;
  773.             sortCallStack = 1;
  774.         } else if ( idStr::Icmp( arg, "cs3" ) == 0 ) {
  775.             memSort = MEMSORT_CALLSTACK;
  776.             sortCallStack = 0;
  777.         } else if ( idStr::Icmp( arg, "h" ) == 0 ) {
  778.             memSort = MEMSORT_HEAPID;
  779.         } else if ( idStr::Icmp( arg, "v" ) == 0 ) {
  780.             verbose = true;
  781.         } else if ( arg[0] == 'f' ) {
  782.             numFrames = atoi( arg + 1 );
  783.         } else {
  784.             idLib::common->Printf( "memoryDumpCompressed [options] [filename]\n"
  785.                         "options:\n"
  786.                         "  -s     sort on size\n"
  787.                         "  -l     sort on location\n"
  788.                         "  -a     sort on the number of allocations\n"
  789.                         "  -cs1   sort on first function on call stack\n"
  790.                         "  -cs2   sort on second function on call stack\n"
  791.                         "  -cs3   sort on third function on call stack\n"
  792.                         "  -h     sort on heap ID\n"
  793.                         "  -f<X>  only report allocations the last X frames\n"
  794.                         "  -v     verbose (list all, even those totalling less than 1K\n"
  795.                         "By default the memory allocations are sorted on location.\n"
  796.                         "By default a 'memorydump.txt' is written if no file name is specified.\n" );
  797.             return;
  798.         }
  799.         arg = args.Argv( ++argNum );
  800.     }
  801.     if ( argNum >= args.Argc() ) {
  802.         fileName = "memorydump.txt";
  803.     } else {
  804.         fileName = arg;
  805.     }
  806.     Mem_DumpCompressed( fileName, memSort, sortCallStack, numFrames, verbose );
  807. }
  808.  
  809. /*
  810. ==================
  811. Mem_AllocDebugMemory
  812. ==================
  813. */
  814. void *Mem_AllocDebugMemory( const int size, const char *fileName, const int lineNumber, const bool align16, byte tag ) 
  815. {
  816.     void *p;
  817.     debugMemory_t *m;
  818.  
  819.     // the following is necessary for memory allocations that take place
  820.     // in static/global object constructors
  821.     if ( NULL == currentHeapArena )
  822.     {
  823.         Mem_Init();
  824.     }
  825.  
  826.     if ( align16 ) 
  827.     {
  828.         p = currentHeapArena->Allocate16( size + sizeof( debugMemory_t ), tag );
  829.     }
  830.     else 
  831.     {
  832.         p = currentHeapArena->Allocate( size + sizeof( debugMemory_t ), tag );
  833.     }
  834.  
  835.     if ( NULL == p )
  836.     {
  837.         return NULL;
  838.     }
  839.  
  840.     Mem_UpdateAllocStats( currentHeapArena->Msize( p ) );
  841.  
  842.     m = (debugMemory_t *) p;
  843.     m->fileName = fileName;
  844.     m->lineNumber = lineNumber;
  845.     m->heapId = currentHeapArena->GetHeap(p)->DebugID();
  846.     m->memTag = tag;
  847.     m->frameNumber = idLib::frameNumber;
  848.     m->size = size;
  849.     m->next = mem_debugMemory;
  850.     m->prev = NULL;
  851.     if ( mem_debugMemory ) {
  852.         mem_debugMemory->prev = m;
  853.     }
  854.     mem_debugMemory = m;
  855.  
  856.     if ( idLib::sys != NULL )
  857.     {
  858.         idLib::sys->GetCallStack( m->callStack, MAX_CALLSTACK_DEPTH );
  859.     }
  860.     else 
  861.     {
  862.         memset( m->callStack, 0, sizeof(m->callStack) );
  863.     }
  864.  
  865.     return ( ( (byte *) p ) + sizeof( debugMemory_t ) );
  866. }
  867.  
  868. /*
  869. ==================
  870. Mem_FreeDebugMemory
  871. ==================
  872. */
  873. void Mem_FreeDebugMemory( void *p, const char *fileName, const int lineNumber, const bool align16 ) 
  874. {
  875.     debugMemory_t *m;
  876.  
  877.     if ( !p ) 
  878.     {
  879.         return;
  880.     }
  881.  
  882.     m = (debugMemory_t *) ( ( (byte *) p ) - sizeof( debugMemory_t ) );
  883.  
  884.     if ( m->size < 0 ) 
  885.     {
  886.         idLib::common->FatalError( "memory freed twice, first from %s, now from %s", idLib::sys->GetCallStackStr( m->callStack, MAX_CALLSTACK_DEPTH ), idLib::sys->GetCallStackCurStr( MAX_CALLSTACK_DEPTH ) );
  887.     }
  888.  
  889.     Mem_UpdateFreeStats( currentHeapArena->Msize( m ) );
  890.  
  891.     if ( m->next ) 
  892.     {
  893.         m->next->prev = m->prev;
  894.     }
  895.  
  896.     if ( m->prev ) 
  897.     {
  898.         m->prev->next = m->next;
  899.     }
  900.     else 
  901.     {
  902.         mem_debugMemory = m->next;
  903.     }
  904.  
  905.     m->fileName = fileName;
  906.     m->lineNumber = lineNumber;
  907.     m->frameNumber = idLib::frameNumber;
  908.     m->size = -m->size;
  909.     idLib::sys->GetCallStack( m->callStack, MAX_CALLSTACK_DEPTH );
  910.  
  911.     assert( currentHeapArena != NULL );
  912.     currentHeapArena->Free( m );
  913. }
  914.  
  915. /*
  916. ==================
  917. Mem_Alloc
  918. ==================
  919. */
  920. void *Mem_Alloc( const int size, const char *fileName, const int lineNumber, byte tag )
  921. {
  922.     return Mem_AllocDebugMemory( size, fileName, lineNumber, false, tag );
  923. }
  924.  
  925. /*
  926. ==================
  927. Mem_Free
  928. ==================
  929. */
  930. void Mem_Free( void *ptr, const char *fileName, const int lineNumber ) 
  931. {
  932.     if ( !ptr ) 
  933.     {
  934.         return;
  935.     }
  936.     Mem_FreeDebugMemory( ptr, fileName, lineNumber, false );
  937. }
  938.  
  939. /*
  940. ==================
  941. Mem_Alloc16
  942. ==================
  943. */
  944. void *Mem_Alloc16( const int size, const char *fileName, const int lineNumber, byte tag ) 
  945. {
  946.     void *mem = Mem_AllocDebugMemory( size, fileName, lineNumber, true, tag );
  947.     // make sure the memory is 16 byte aligned
  948.     assert( ( ((int)mem) & 15) == 0 );
  949.     return mem;
  950. }
  951.  
  952. /*
  953. ==================
  954. Mem_Free16
  955. ==================
  956. */
  957. void Mem_Free16( void *ptr, const char *fileName, const int lineNumber ) 
  958. {
  959.     if ( !ptr ) {
  960.         return;
  961.     }
  962.     // make sure the memory is 16 byte aligned
  963.     assert( ( ((int)ptr) & 15) == 0 );
  964.     Mem_FreeDebugMemory( ptr, fileName, lineNumber, true );
  965. }
  966.  
  967. /*
  968. ==================
  969. Mem_ClearedAlloc
  970. ==================
  971. */
  972. void *Mem_ClearedAlloc( const int size, const char *fileName, const int lineNumber, byte tag ) 
  973. {
  974.     void *mem = Mem_Alloc( size, fileName, lineNumber, tag );
  975.  
  976.     if ( mem != NULL )
  977.     {
  978.         SIMDProcessor->Memset( mem, 0, size );
  979.     }
  980.     else 
  981.     {
  982.         idLib::common->FatalError( "Ran out of memory during a cleared allocation" );
  983.     }
  984.     return mem;
  985. }
  986.  
  987. /*
  988. ==================
  989. Mem_CopyString
  990. ==================
  991. */
  992. char *Mem_CopyString( const char *in, const char *fileName, const int lineNumber ) 
  993. {
  994.     char    *out;
  995.     
  996.     out = (char *)Mem_Alloc( strlen(in) + 1, fileName, lineNumber );
  997.     strcpy( out, in );
  998.     return out;
  999. }
  1000.  
  1001. /*
  1002. ==================
  1003. Mem_Size
  1004. ==================
  1005. */
  1006. int Mem_Size( void *ptr )
  1007. {
  1008.     if ( !ptr )
  1009.     {
  1010.         return 0;
  1011.     }
  1012.     assert( currentHeapArena != NULL );
  1013.     return currentHeapArena->Msize( (byte*)ptr - sizeof( debugMemory_t ) );
  1014. }
  1015.  
  1016. #else    // #ifdef ID_DEBUG_MEMORY
  1017.  
  1018. void Mem_Dump_f( const class idCmdArgs &args )
  1019. {
  1020.  
  1021. }
  1022.  
  1023. void Mem_DumpCompressed_f( const class idCmdArgs &args )
  1024. {
  1025.  
  1026. }
  1027.  
  1028. /*
  1029. ==================
  1030. Mem_Alloc
  1031.  
  1032. Allocate memory from the heap at the top of the current arena stack
  1033. ==================
  1034. */
  1035. void *Mem_Alloc( const int size, byte tag )
  1036. {
  1037.     void *p;
  1038.  
  1039.     // the following is necessary for memory allocations that take place
  1040.     // in static/global object constructors
  1041.     if ( NULL == currentHeapArena )
  1042.     {
  1043.         Mem_Init();
  1044.     }
  1045.  
  1046.     p = currentHeapArena->Allocate( size, tag );
  1047.     if ( NULL == p )
  1048.     {
  1049.         return NULL;
  1050.     }
  1051.  
  1052.     Mem_UpdateAllocStats( currentHeapArena->Msize( p ) );
  1053.  
  1054. #if defined( _XENON ) && !defined( _FINAL )
  1055.     MemTracker::OnAlloc(p, size);
  1056. #endif
  1057.     
  1058.     return p;
  1059. }
  1060.  
  1061. // Mem_ClearedAlloc
  1062. // 
  1063. // Allocate memory from the heap at the top of the current arena stack,
  1064. // clear that memory to zero before returning it.
  1065. void *Mem_ClearedAlloc( const int size, byte tag )
  1066. {
  1067.     byte *allocation = (byte *) Mem_Alloc( size, tag );
  1068.     
  1069. #if defined( _XENON ) && !defined( _FINAL )
  1070.     MemTracker::OnAlloc(allocation, size);
  1071. #endif
  1072.     
  1073.     if ( allocation != NULL )
  1074.     {
  1075.         SIMDProcessor->Memset( allocation, 0, size );
  1076.     }
  1077.     else 
  1078.     {
  1079.         idLib::common->FatalError( "Ran out of memory during a cleared allocation" );
  1080.     }
  1081.     return allocation;
  1082.  
  1083. }
  1084.  
  1085. /*
  1086. ==================
  1087. Mem_Free
  1088. ==================
  1089. */
  1090. void Mem_Free( void *ptr )
  1091. {
  1092.     if ( !ptr ) 
  1093.     {
  1094.         return;
  1095.     }
  1096.     assert( currentHeapArena != NULL );
  1097.     
  1098. #if defined( _XENON ) && !defined( _FINAL )
  1099.     MemTracker::OnDelete(ptr);
  1100. #endif
  1101.  
  1102.     Mem_UpdateFreeStats( currentHeapArena->Msize( ptr ) );
  1103.  
  1104.     currentHeapArena->Free( ptr );
  1105. }
  1106.  
  1107. /*
  1108. ==================
  1109. Mem_CopyString
  1110.  
  1111. Allocates memory for a copy of the given string, and copies
  1112. that string into the new allocation.
  1113. ==================
  1114. */
  1115. char *Mem_CopyString( const char *in )
  1116. {
  1117.     char *out;
  1118.  
  1119.     out = (char *)Mem_Alloc( strlen(in) + 1, MA_STRING );
  1120.     if ( out != NULL )
  1121.     {
  1122.         strcpy( out, in );
  1123.     }
  1124.     else 
  1125.     {
  1126.         idLib::common->FatalError( "Ran out of memory during string copy allocation" );
  1127.     }
  1128.     return out;
  1129. }
  1130.  
  1131. /*
  1132. ==================
  1133. Mem_Alloc16
  1134.  
  1135. Allocate memory from the heap at the top of the current arena 
  1136. stack that is aligned on a 16-byte boundary.
  1137. ==================
  1138. */
  1139. void *Mem_Alloc16( const int size, byte tag )
  1140. {
  1141.     // the following is necessary for memory allocations that take place
  1142.     // in static/global object constructors
  1143.     if ( NULL == currentHeapArena )
  1144.     {
  1145.         Mem_Init();
  1146.     }
  1147.     void *mem = currentHeapArena->Allocate16( size, tag );
  1148.  
  1149. #if defined( _XENON ) && !defined( _FINAL )
  1150.     MemTracker::OnAlloc(mem, size);
  1151. #endif
  1152.  
  1153.     return mem;
  1154. }
  1155.  
  1156. /*
  1157. ==================
  1158. Mem_Free
  1159. ==================
  1160. */
  1161. void Mem_Free16( void *ptr )
  1162. {
  1163.     if ( !ptr ) 
  1164.     {
  1165.         return;
  1166.     }
  1167.     assert( currentHeapArena != NULL );
  1168.     currentHeapArena->Free( ptr );
  1169.     
  1170. #if defined( _XENON ) && !defined( _FINAL )
  1171.     MemTracker::OnDelete(ptr);
  1172. #endif
  1173. }
  1174.  
  1175. /*
  1176. ==================
  1177. Mem_Size
  1178. ==================
  1179. */
  1180. int Mem_Size( void *ptr )
  1181. {
  1182.     if ( !ptr )
  1183.     {
  1184.         return 0;
  1185.     }
  1186.     assert( currentHeapArena != NULL );
  1187.     return currentHeapArena->Msize( ptr );
  1188. }
  1189.  
  1190. #endif    // #else #ifdef ID_DEBUG_MEMORY
  1191.  
  1192. /*
  1193. ==================
  1194. rvGetAllSysHeaps
  1195.  
  1196. retrieves the specified system heap
  1197. ==================
  1198. */
  1199.  
  1200. rvHeap* rvGetSysHeap( Rv_Sys_Heap_ID_t sysHeapID )
  1201. {
  1202.     assert( (uint) sysHeapID < (uint) rv_heap_ID_max_count );
  1203.     return systemHeapArray[ (uint) sysHeapID ];
  1204. }
  1205.  
  1206. /*
  1207. ==================
  1208. rvGetAllSysHeaps
  1209.  
  1210. retrieves all the MAX_SYSTEM_HEAPS heap pointers into the given array
  1211. ==================
  1212. */
  1213. void rvGetAllSysHeaps( rvHeap *destSystemHeapArray[MAX_SYSTEM_HEAPS] )
  1214. {
  1215.     memcpy(destSystemHeapArray, systemHeapArray, sizeof(systemHeapArray));
  1216. }
  1217.  
  1218. /*
  1219. ==================
  1220. rvSetAllSysHeaps
  1221.  
  1222. associates all the MAX_SYSTEM_HEAPS heap pointers from the given array with their corresponding id value
  1223. ==================
  1224. */
  1225. void rvSetAllSysHeaps( rvHeap *srcSystemHeapArray[MAX_SYSTEM_HEAPS] )
  1226. {
  1227.     memcpy(systemHeapArray, srcSystemHeapArray, sizeof(systemHeapArray));
  1228. }
  1229.  
  1230. #if 0
  1231. /*
  1232. ==================
  1233. rvGetHeapContainingMemory
  1234.  
  1235. Returns pointer to the heap containg the memory specified. If the memory specified
  1236. is not in a heap, returns 0.
  1237. ==================
  1238. */
  1239. rvHeap* rvGetHeapContainingMemory( const void* mem )
  1240. {
  1241.     return (currentHeapArena!=0)?currentHeapArena->GetHeap(const_cast<void*>(mem)):0;
  1242. }
  1243. #endif 
  1244.  
  1245. /*
  1246. ==================
  1247. rvPushHeapContainingMemory
  1248.  
  1249. Pushes the heap containg the memory specified. If the memory specified
  1250. is not in a heap, does nothing and returns false, otherwise returns
  1251. true on success.
  1252. ==================
  1253. */
  1254. bool rvPushHeapContainingMemory( const void* mem )
  1255. {
  1256.     if(currentHeapArena)
  1257.     {
  1258.         rvHeap* heap=currentHeapArena->GetHeap(const_cast<void*>(mem));
  1259.         if(heap)
  1260.         {
  1261.             heap->PushCurrent();
  1262.             return true;
  1263.         }
  1264.     }
  1265.     return false;
  1266. }
  1267.  
  1268. #endif    // #ifdef _RV_MEM_SYS_SUPPORT
  1269.