//
// File: hzMemory.cpp
//
// Legal Notice: This file is part of the HadronZoo C++ Class Library. Copyright 2025 HadronZoo Project (http://www.hadronzoo.com)
//
// The HadronZoo C++ Class Library is free software: You can redistribute it, and/or modify it under the terms of the GNU Lesser General Public License, as published by the Free
// Software Foundation, either version 3 of the License, or any later version.
//
// The HadronZoo C++ Class Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License along with the HadronZoo C++ Class Library. If not, see http://www.gnu.org/licenses.
//
//
// Desc: 1) Optional overide of general case new and delete operators (when hzOveride.h is included in application's main .cpp file)
// 2) Provision of memory use diagnostics
//
#include <iostream>
#include <fstream>
#include <sys/stat.h>
#include <malloc.h>
#include "hzBasedefs.h"
#include "hzDatabase.h"
#include "hzDate.h"
#include "hzDocument.h"
#include "hzTextproc.h"
#include "hzUnixacc.h"
#include "hzSMAR.h"
using namespace std ;
/*
** Global Variables
*/
global hzMeminfo _hzGlobal_Memstats ; // Memory statistics
#ifdef OVERRIDE
global bool _hzGlobal_XM = true ; // New/Delete Override activated
#else
global bool _hzGlobal_XM = false ; // New/Delete Override not activated
#endif
// Standard sequential memory allocation regimes
global hzSMAR* g_pSMAR_Str ; // Used exclusively by hzString
global hzSMAR* g_pSMAR_Inet ; // Used by hzEmaddr, hzDomain and hzUrl
global hzSMAR* g_pSMAR_Edo ; // Used exclusively by hdbObjRepos to store EDOs
/*
** SECTION 1: Overide of global new and delete operator
*/
class _hz_heap
{
struct _rblk
{
// RAM block.
//
// The global new/delete overload allocates small objects (between 8 and 128 bytes) from one of 16 separate free list, each of which deals only with objects of a specific
// size. There is a free list for 8 byte objects, another for 16 byte objects and so on. When any of these free lists become empty and new RAM block is allocated from main
// memory to top them up.
//
// The RAM blocks are 64K minus 8 bytes. The (not very compelling) reason for this weird size is that system memory allocation overhead is 8 bytes, so each block consumes
// exactly 64K of real memory. As the RAM blocks are always the same size, RAM blocks assigned to the free list of 8 byte objects will contain twice the number of 'object
// slots' that RAM blocks assigned to the free list of 16 byte objects will have. The larger the fixed sized objects, the fewer slots each RAM block will hold. For some
// sizes, a small proportion of the RAM block is wasted. Upon allocation of a RAM block, as many slots that will fit for the intended size, are set up within the block so
// that one slot points to the next with the last one pointing to NULL. Then the whole lot is added to the free list for the object size.
int32_t m_size ; // If block is dedicated show the size, otherwise this will be 0
int32_t m_usage ; // If the block is not dedicated, this will be the next object address to allocate
uint64_t m_data[1200] ; // Data area
} ;
// Mutexs
hzLockRWD m008 ; // Mutex for 8 byte allocations
hzLockRWD m016 ; // Mutex for 16 byte allocations
hzLockRWD m024 ; // Mutex for 24 byte allocations
hzLockRWD m032 ; // Mutex for 32 byte allocations
hzLockRWD m040 ; // Mutex for 40 byte allocations
hzLockRWD mAll ; // Mutex for all the above
hzLockRWD mSze ; // Mutex for oversized allocations
// Freelist pointers (last 3 digits denotes size)
uint64_t* fL008 ; // Freelist pointer for 8 byte objects
uint64_t* fL016 ; // Freelist pointer for 16 byte objects
uint64_t* fL024 ; // Freelist pointer for 24 byte objects
uint64_t* fL032 ; // Freelist pointer for 32 byte objects
uint64_t* fL040 ; // Freelist pointer for 40 byte objects
_rblk* _mkblk (int32_t size) ;
public:
void* m_allBlocks[8192] ; // Pointers to all managed blocks (max of 8192 blocks)
// Number of used objects
uint32_t nU008 ; // In use counter for 8 byte objects
uint32_t nU016 ; // In use counter for 16 byte objects
uint32_t nU024 ; // In use counter for 24 byte objects
uint32_t nU032 ; // In use counter for 32 byte objects
uint32_t nU040 ; // In use counter for 40 byte objects
// Number of free objects
uint32_t nF008 ; // Free counter for 8 byte objects
uint32_t nF016 ; // Free counter for 16 byte objects
uint32_t nF024 ; // Free counter for 24 byte objects
uint32_t nF032 ; // Free counter for 32 byte objects
uint32_t nF040 ; // Free counter for 40 byte objects
uint32_t nCallsMalloc ; // Number of objects over 128 bytes
uint32_t nCallsFree ; // Number of objects over 128 bytes
uint32_t nOver ; // Number of objects over 128 bytes
uint32_t nOverSize ; // Number of bytes in objects over 128 bytes
uint32_t numAllBlks ; // Number of blocks
uint32_t m_allSizes[1001] ; // Numbers alocated for each object size.
uint32_t m_allSizeA[1001] ; // Number of alocations for each object size.
uint32_t m_allSizeF[1001] ; // Number of deletions for each object size.
_hz_heap (void)
{
m008.Setname("Mem_fl_008") ;
m016.Setname("Mem_fl_016") ;
m024.Setname("Mem_fl_024") ;
m032.Setname("Mem_fl_032") ;
m040.Setname("Mem_fl_040") ;
fL008=0; fL016=0; fL024=0; fL032=0; fL040=0;
nU008 = nU016 = nU024 = nU032 = nU040 = 0 ;
nF008 = nF016 = nF024 = nF032 = nF040 = 0 ;
nCallsMalloc = nCallsFree = nOver = nOverSize = numAllBlks = 0 ;
}
~_hz_heap (void)
{
shutdown() ;
}
void* allocate (uint32_t size) ;
void release (void* ptr) ;
void shutdown (void) ;
};
/*
** Variables for memory regime
*/
static _hz_heap* s_Heap = 0 ; // The global heap
static hzChain s_memReport ; // Chain for memory report compilation
static uint32_t s_nBytesInit ; // Total bytes allocated under new override
static uint32_t s_nBytesExit ; // Total bytes reserved under new override
// The actual working functions are
static void* _regime_alloc_Init (uint32_t size) ; // Only called ONCE with the first thing allocated in the program anywhere
static void* _regime_alloc_Syst (uint32_t size) ; // Allocate using malloc
static void* _regime_alloc_Ovrd (uint32_t size) ; // Allocate using hzHeap
static void _regime_free_Syst (void* mem) ; // This frees objects
static void _regime_free_Ovrd (void* mem) ; // This frees objects
static void* _regime_alloc_Exit (uint32_t size) ; // Allocates memory during shutdown of the memory manager
// Note that hz_mem_allocate() and hz_mem_release() just called according to function pointers
void* (*fnptr_Alloc) (uint32_t) = _regime_alloc_Init ; // Allocator for new/delete override
void (*fnptr_Free) (void*) = _regime_free_Syst ; // De-allocator for new/delete override
/*
** Heap functions
*/
_hz_heap::_rblk* _hz_heap::_mkblk (int32_t size)
{
_rblk* pBlk ; // Block pointer
uint64_t* ptr ; // Treat internal data as 8 byte ints
int32_t n ; // Data segment iterator
int32_t max ; // Max number of data segments
// Allocate the block
pBlk= (_rblk*) malloc(sizeof(_rblk)) ;
nCallsMalloc++;
nOverSize += malloc_usable_size(pBlk) ;
m_allBlocks[numAllBlks] = pBlk ;
numAllBlks++ ;
memset(pBlk, 0, sizeof(_rblk)) ;
// Partition the block
switch (size)
{
case 8: max = 1200 ; nF008 += max ; break ;
case 16: max = 600 ; nF016 += max ; break ;
case 24: max = 400 ; nF024 += max ; break ;
case 32: max = 300 ; nF032 += max ; break ;
case 40: max = 240 ; nF040 += max ; break ;
}
size /= 8 ;
ptr = pBlk->m_data ;
ptr += size ;
for (n = 0, max-- ; max ; max--, n += size)
{
pBlk->m_data[n] = (uint64_t) ptr ;
ptr += size ;
}
pBlk->m_size = size * 8 ;
return pBlk ;
}
void* _hz_heap::allocate (uint32_t size)
{
// Allocate memory from the memory regime if required size is 64 bytes or less and from the heap otherwise. Under the regime, allocation is
// always from a freelist of segments of 8,16,24, ... 128 bytes. If the appropriate freelist is empty, a new block is allocated and divided
// into multiple segments. Allocations of greater than 128 bytes are placed in a map for oversized objects.
//
// Arguments: 1) size Number of bytes to allocate
//
// Returns: Pointer to the allocated memory
_rblk* pBlk = 0; // Fixed block allocated if any
void* pObj = 0; // Object allocated
uint64_t* ptr; // Intermeadiate pointer for free list navigation
int32_t nDiv; // Position devider
nCallsMalloc++;
nDiv = size%8;
if (nDiv)
size += (8-nDiv);
switch (size)
{
case 8: m008.LockWrite(); if (!fL008) {pBlk=_mkblk(8); fL008=pBlk->m_data;} nF008-- ; nU008++; ptr=fL008; fL008=(uint64_t*)*ptr; m008.Unlock(); break;
case 16: m016.LockWrite(); if (!fL016) {pBlk=_mkblk(16); fL016=pBlk->m_data;} nF016-- ; nU016++; ptr=fL016; fL016=(uint64_t*)*ptr; m016.Unlock(); break;
case 24: m024.LockWrite(); if (!fL024) {pBlk=_mkblk(24); fL024=pBlk->m_data;} nF024-- ; nU024++; ptr=fL024; fL024=(uint64_t*)*ptr; m024.Unlock(); break;
case 32: m032.LockWrite(); if (!fL032) {pBlk=_mkblk(32); fL032=pBlk->m_data;} nF032-- ; nU032++; ptr=fL032; fL032=(uint64_t*)*ptr; m032.Unlock(); break;
case 40: m040.LockWrite(); if (!fL040) {pBlk=_mkblk(40); fL040=pBlk->m_data;} nF040-- ; nU040++; ptr=fL040; fL040=(uint64_t*)*ptr; m040.Unlock(); break;
default: // Non-standard size.
mSze.LockWrite();
pObj = malloc(size);
nDiv = malloc_usable_size(pObj) ;
if (nDiv < 8192)
{
m_allSizes[nDiv/8]++ ;
m_allSizeA[nDiv/8]++ ;
}
nOver++ ;
nOverSize += nDiv ;
mSze.Unlock();
return pObj;
}
return (void*) ptr;
}
void _hz_heap::release (void* pObj)
{
// Places object in free list if it is of one of the precribed sizes, otherwise it frees it from the OS managed heap
//
// Arguments: 1) pObj Pointer to previously decclard memory
// Returns: None
_rblk* pBlk ; // Block in which object is found
uint64_t* ptr ; // Object as uint64_t*
char* pVoid ; // Start of block (for pointer comparison)
char* pLim ; // End of block (for pointer comparison)
uint32_t size = 0 ; // Size derived from block in which object is found
uint32_t nPos ; // Position in hzOrder
uint32_t nDiv ; // Position devider
if (!pObj)
return ;
if (pObj == this)
return ;
nCallsFree++;
ptr = (uint64_t*) pObj ;
// Size is not supplied so must be determined from the only thing that is supplied - the pointer to the object to be freed. From the
// address we can determine what block it is in and so the size.
mAll.LockWrite() ;
size = 1000000 ;
for (nPos = 2 ; nPos < numAllBlks ; nPos *= 2) ;
nDiv = nPos / 2 ;
nPos-- ;
for (;;)
{
//if (nPos >= m_allBlocks.Count())
if (nPos >= numAllBlks)
nPos -= nDiv ;
else
{
//pLim = pVoid = (char*) m_allBlocks.GetObj(nPos) ;
pLim = pVoid = (char*) m_allBlocks[nPos] ;
pLim += sizeof(_rblk) ;
if (pObj < pVoid)
nPos -= nDiv ;
else if (pObj > pLim)
nPos += nDiv ;
else
{
pBlk = (_rblk*) pVoid ;
size = pBlk->m_size ;
break ;
}
}
if (!nDiv)
break ;
nDiv /= 2 ;
}
mAll.Unlock() ;
// The following sets a pointer to the start of the object (first 8 bytes). Then it sets the contents of the start of the object so that it points
// to the start of the freelist (for the object size). The new start of the freelist is then set to the pointer (ie it is set to the start of the
// freed object)
switch (size)
{
case 8: m008.LockWrite(); nU008--; nF008++ ; ptr=(uint64_t*)pObj; *ptr=(uint64_t)fL008; fL008=ptr; m008.Unlock(); break;
case 16: m016.LockWrite(); nU016--; nF016++ ; ptr=(uint64_t*)pObj; *ptr=(uint64_t)fL016; fL016=ptr; m016.Unlock(); break;
case 24: m024.LockWrite(); nU024--; nF024++ ; ptr=(uint64_t*)pObj; *ptr=(uint64_t)fL024; fL024=ptr; m024.Unlock(); break;
case 32: m032.LockWrite(); nU032--; nF032++ ; ptr=(uint64_t*)pObj; *ptr=(uint64_t)fL032; fL032=ptr; m032.Unlock(); break;
case 40: m040.LockWrite(); nU040--; nF040++ ; ptr=(uint64_t*)pObj; *ptr=(uint64_t)fL040; fL040=ptr; m040.Unlock(); break;
default:
nOver-- ;
nDiv = malloc_usable_size(pObj) ;
if (nDiv < 8192)
{
m_allSizes[nDiv/8]-- ;
m_allSizeF[nDiv/8]++ ;
}
nOverSize -= nDiv ;
break ;
}
}
void _hz_heap::shutdown (void)
{
// Shutdown the heap
//
// Arguments: None
// Returns: None
fnptr_Alloc = _regime_alloc_Exit ;
}
/*
** Global memory management functions
*/
void* hz_mem_allocate (uint32_t size)
{
// Category: Memory
//
// This function is ALWAYS called whenever operator new or new[] is called on ANY object. It will invoke whater function fnptr_Alloc points to
//
// Argument: size Requested number of bytes for allocation
//
// Returns: Pointer to the allocated memory
return fnptr_Alloc(size) ;
}
void hz_mem_release (void* ptr)
{
// Category: Memory
//
// This function is ALWAYS called whenever operator delete or delete[] is called on ANY object. It will invoke whater function fnptr_Free points to
//
// Argument: ptr Pointer to object to be freed
//
// Returns: None
fnptr_Free(ptr) ;
}
static void* _regime_alloc_Init (uint32_t size)
{
// Category: Memory
//
// Under the override regime operator new is defined as _hz_mem_allocate(), which calls whatever function fnptr_Alloc points to (initially this function). Delete is defined as
// _hz_mem_release(), which calls whatever function fnptr_Free points to. Currently, fnptr_Free always points to _regime_free_norm(), which tests _hzGlobal_XM to decide how to
// delete memory.
//
// The first memory allocated for the program is allocated via this function, purely so _hzGlobal_XM can be tested before ANY further allocations. This function decides to set
// fnptr_Alloc to either _regime_alloc_Syst() for malloc/free and _regime_alloc_Ovrd for the override - then calls the selected function to allocate the requested memory. All
// subsequent allocations will be from whichever funtion fnptr_Alloc is set to.
//
// Arguments: 1) size Number of bytes to allocate
// Returns: Pointer to allocated memory block
static bool bBeenHere = false ;
void* ptr ; // New object space
if (_hzGlobal_XM)
{
if (bBeenHere)
{ printf("_regime_alloc_Init: Duplicate Call\n") ; exit(1) ; }
bBeenHere = true ;
// printf("Allocating the heap %p %p\n", *fnptr_Alloc, *fnptr_Free) ; fflush(stdout) ;
s_Heap = (_hz_heap*) malloc(sizeof(_hz_heap)) ;
memset(s_Heap, 0, sizeof(_hz_heap)) ;
s_Heap->nCallsMalloc++ ;
s_Heap->nOverSize += sizeof(_hz_heap) ;
fnptr_Alloc = _regime_alloc_Ovrd ;
fnptr_Free = _regime_free_Ovrd ;
}
else
{
fnptr_Alloc = _regime_alloc_Syst ;
fnptr_Free = _regime_free_Syst ;
}
// printf("Now Allocating the memory using approved fn\n") ; fflush(stdout) ;
ptr = fnptr_Alloc(size) ;
return ptr ;
}
static void* _regime_alloc_Syst (uint32_t size)
{
// Category: Memory
//
// Only called during new-overide initialization
//
// Arguments: 1) size Bytes to allocate
// Returns: Pointer to the allocated block
void* ptr ; // New object space
s_nBytesInit += size ;
ptr = malloc(size) ;
return ptr ;
}
static void* _regime_alloc_Ovrd (uint32_t size)
{
// Category: Memory
//
// This will allocate an object of the required size from a managed block if the size is small and by a direct call to malloc otherwise. In the
// latter case, the object will be placed in the map of outsized objects.
//
// Arguments: 1) size Number of bytes requested
// Returns: Pointer to the allocated block
if (!s_Heap)
{
// Fatal("No heap initialized\n") ;
printf("No heap initialized\n") ; fflush(stdout) ;
exit(1) ;
}
// printf("_regime_alloc_Ovrd %d bytes\n", size) ; fflush(stdout) ;
return s_Heap->allocate(size) ;
}
static void _regime_free_Ovrd (void* ptr) { s_Heap->release(ptr) ; }
static void _regime_free_Syst (void* ptr) { free(ptr) ; }
static void* _regime_alloc_Exit (uint32_t size)
{
// Category: Memory
//
// Only called to allocate memory during shutdown (generally for diagnostic pursose only)
//
// Arguments: 1) size Bytes to allocate
// Returns: Pointer to the allocated block
void* ptr ; // New object space
s_nBytesExit += size ;
ptr = malloc(size) ;
memset(ptr, 0, size) ;
return ptr ;
}
/*
** SECTION 2: Memory use dianostics
*/
hzMeminfo::hzMeminfo (void)
{
m_numMCH = 0 ; // Total number of hzMCH instances (with or without data)
m_numMCH_D = 0 ; // Number of hzMCH instances with data
m_numChain = 0 ; // Total number of hzChain instances (with or without data container)
m_numChainDC = 0 ; // Number of hzChain instances with data container
m_numChainBlks = 0 ; // Total number of hzChain blocks
m_numChainBF = 0 ; // Number of hzChain blocks in free list
memset(m_strSm_u, 0, sizeof(uint32_t) * 32) ; // Small string spaces (8 to 256 bytes), in use
memset(m_strSm_f, 0, sizeof(uint32_t) * 32) ; // Small string spaces (8 to 256 bytes), free
m_numSblks = 0 ; // Number of string superblocks
m_numStrOver = 0 ; // Number of hzString instances (oversize)
m_ramStrOver = 0 ; // Total memory allocated to oversized hzStrings
m_numStrings = 0 ; // Number of hzString instances
m_numMemblkA = 0 ; // Number of type A memblk instances in RAM (for size A 16 byte objects)
m_numMemblkB = 0 ; // Number of type B memblk instances in RAM (for size B 24 byte objects)
m_numMemblkC = 0 ; // Number of type C memblk instances in RAM (for size C 32 byte objects)
m_numMemblkD = 0 ; // Number of type D memblk instances in RAM (for size D 48 byte objects)
m_numMemblkE = 0 ; // Number of type E memblk instances in RAM (for size E 64 byte objects)
m_numIsams = 0 ; // Number of ISAM collections
m_numIsamIndx = 0 ; // Number of ISAM index blocks
m_numIsamData = 0 ; // Number of ISAM data blocks
m_numArrays = 0 ; // Number of hzArray instances
m_numArrayDA = 0 ; // Number of hzArray instances with data area
m_numLists = 0 ; // Number of hzList instances
m_numListDC = 0 ; // Number of hzList instances with data area
m_numQues = 0 ; // Number of hzQue instances
m_numStacks = 0 ; // Number of hzStack instances
m_numSmaps = 0 ; // Number of hzMapS instances
m_numMmaps = 0 ; // Number of hzMapM instances
m_numSpmaps = 0 ; // Number of hzLookup instances
m_numSets = 0 ; // Number of hzSet instances
m_numVectors = 0 ; // Number of hzVect instances
m_numBitmaps = 0 ; // Number of hzBitmap instances
m_numBitmapSB = 0 ; // Number of hzBitmap 'segment block' instances
m_numMCHB = 0 ; // Number of 'micro chain' blocks.
m_numDochtm = 0 ; // Number of hzDocHtm instances
m_numDocxml = 0 ; // Number of hzDocXml instances
m_numBincron = 0 ; // Number of hdbBinCron instances
m_numBinstore = 0 ; // Number of hdbBinStore instances
}
static const char* _snt (uint32_t nValue) { return FormalNumber(nValue, 13) ; }
static const char* _snh (uint32_t nValue) { return FormalNumber(nValue, 0) ; }
static void _report_mem_item3 (hzChain& Z, const char* title, uint32_t vA, uint32_t vB, uint32_t vC, bool bHtml)
{
// Reports 3 values (e.g allocated and in use, free reserves and total)
if (bHtml)
Z.Printf("\t<tr align=\"right\"><td align=\"left\">%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n", title, _snh(vA), _snh(vB), _snh(vC)) ;
else
Z.Printf("%s %s %s %s\n", title, _snt(vA), _snt(vB), _snt(vC)) ;
}
static void _report_mem_itemA (hzChain& Z, const char* title, uint32_t curr, uint32_t prev, uint32_t sum, bool bHtml)
{
// Reports 3 values (e.g allocated and in use, free reserves and total)
if (bHtml)
{
Z << "<tr align=\"right\"><td align=\"left\">" ;
if (!title)
Z << "untitled" ;
else
Z << title ;
Z << "</td><td></td><td></td><td></td><td></td>" ;
Z.Printf("<td>%s</td><td>%s</td><td>%s</td></tr>\n", _snh(curr), _snh(prev), _snh(sum)) ;
}
else
{
Z.Printf("%s %s %s %s\n", title, _snt(curr), _snt(prev), _snt(sum)) ;
}
}
static void _report_mem_itemC (hzChain& Z, const char* title, uint32_t A, uint32_t B, uint32_t C, uint32_t D, uint32_t curr, uint32_t prev, uint32_t sum, bool bHtml)
{
// Reports 7 values
if (bHtml)
{
Z << "<tr align=\"right\"><td align=\"left\">" ;
if (!title)
Z << "untitled" ;
else
Z << title ;
Z.Printf("</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n",
_snh(A), _snh(B), _snh(C), _snh(D), _snh(curr), _snh(prev), _snh(sum)) ;
}
else
{
Z.Printf("%s %s %s %s %s %s %s %s\n",
title, _snt(A), _snt(B), _snt(C), _snt(D), _snt(curr), _snt(prev), _snt(sum)) ;
}
}
static void _report_objects (hzChain& Z, const hzMeminfo& cms, const hzMeminfo& pms, uint32_t& total, bool bHtml)
{
// Category: Diagnostics
//
// Support function to ReportMemoryUsage(). Provides Report on strings and chain memory usage by the application.
//
// Arguments: 1) Z The hzChain instance to receive the report
// 2) cms Current memory stats
// 3) pms Previous memory stats
// 4) total Running total RAM
//
// Returns: None
static int32_t prev_StrTbl = 0 ; // Previous count of strings held in string table
uint32_t U ; // Memory used by given object class
if (bHtml)
{
Z <<
"<table width=\"750\" align=\"center\" border=\"1\" cellspacing=\"0\" cellpadding=\"0\" "
"style=\"text-decoration:none; font-family:verdana; font-size:11px; font-weight:normal; color:#000000;\">\n"
"<tr>\n"
"\t<th width=\"90\">Entity</th>\n"
"\t<th width=\"90\">Assigned</th>\n"
"\t<th width=\"90\">Prev</th>\n"
"\t<th width=\"90\">Free</th>\n"
"\t<th width=\"90\">Prev</th>\n"
"\t<th width=\"90\">Total</th>\n"
"\t<th width=\"90\">Prev</th>\n"
"\t<th width=\"110\">Total RAM</th>\n"
"</tr>\n" ;
}
else
{
Z << "Entity__________ Assigned_____ Prev_________ Free_________ Prev_________ Total________ Prev_________ Total RAM____\n" ;
}
// CHAINS
U = cms.m_numChain * sizeof(hzChain) ;
U += (cms.m_numChainDC * 32) ;
total += U ;
_report_mem_itemC(Z, "Chains..........",
cms.m_numChainDC, pms.m_numChainDC, cms.m_numChain - cms.m_numChainDC, pms.m_numChain - pms.m_numChainDC, cms.m_numChain, pms.m_numChain, U, bHtml) ;
// CHAIN BLOCKS. Note that count of allocated blocks is the total number of blocks created minus the count of those in the freelist
U = cms.m_numChainBlks * 1480 ;
total += U ;
_report_mem_itemC(Z, "Chain Blocks....",
cms.m_numChainBlks - cms.m_numChainBF, pms.m_numChainBlks - pms.m_numChainBF, cms.m_numChainBF, pms.m_numChainBF, cms.m_numChainBlks, pms.m_numChainBlks, U, bHtml) ;
if (bHtml)
{
Z <<
"</table>\n"
"<table width=\"350\" align=\"center\" border=\"1\" cellspacing=\"0\" cellpadding=\"0\" "
"style=\"text-decoration:none; font-family:verdana; font-size:11px; font-weight:normal; color:#000000;\">\n"
"<tr>\n"
"\t<th width=\"90\">Entity</th>\n"
"\t<th width=\"90\">Assigned</th>\n"
"\t<th width=\"90\">Prev</th>\n"
"\t<th width=\"90\">TOTAL RAM</th>\n"
"\t<th width=\"90\"></th>\n"
"</tr>\n" ;
}
else
{
Z << "__________________________________________________________________________________________________________________\n\n" ;
Z << "Entity__________ Assigned_____ Prev_________ Total RAM____\n" ;
}
// Fixed Strings
/*
if (_hzGlobal_setStrings)
{
U = _hzGlobal_setStrings->Count() * sizeof(hzStrRepos) ;
total += U ;
_report_mem_itemA(Z, "Fix Str Repos :", _hzGlobal_setStrings->Count(), prev_StrTbl, U, bHtml) ;
U = _hzGlobal_setStrings->Blocks() * 65536 ;
total += U ;
_report_mem_itemA(Z, "Fix Str Blocks :", _hzGlobal_setStrings->Blocks(), prev_StrTbl, U, bHtml) ;
}
_report_mem_itemA(Z, "Fixed Strings :", cms.m_numStrings, pms.m_numStrings, U, bHtml) ;
*/
// COLLECTIONS
U = cms.m_numLists * 8 ; total += U ; _report_mem_itemA(Z, "Lists :", cms.m_numLists, pms.m_numLists, U, bHtml) ;
U = cms.m_numListDC * 32 ; total += U ; _report_mem_itemA(Z, "Lists (active) :", cms.m_numListDC, pms.m_numListDC, U, bHtml) ;
U = cms.m_numSmaps * 64 ; total += U ; _report_mem_itemA(Z, "Maps(S) :", cms.m_numSmaps, pms.m_numSmaps, U, bHtml) ;
U = cms.m_numMmaps * 64 ; total += U ; _report_mem_itemA(Z, "Maps(M) :", cms.m_numMmaps, pms.m_numMmaps, U, bHtml) ;
U = cms.m_numSets * 64 ; total += U ; _report_mem_itemA(Z, "Sets :", cms.m_numSets, pms.m_numSets, U, bHtml) ;
U = cms.m_numArrays * 64 ; total += U ; _report_mem_itemA(Z, "Arrays :", cms.m_numArrays, pms.m_numArrays, U, bHtml) ;
U = cms.m_numVectors * 64 ; total += U ; _report_mem_itemA(Z, "Vectors :", cms.m_numVectors, pms.m_numVectors, U, bHtml) ;
U = cms.m_numIsams * 64 ; total += U ; _report_mem_itemA(Z, "ISAMS :", cms.m_numIsams, pms.m_numIsams, U, bHtml) ;
U = cms.m_numIsamIndx * 64 ; total += U ; _report_mem_itemA(Z, "ISAM Blk Index :", cms.m_numIsamIndx, pms.m_numIsamIndx, U, bHtml) ;
U = cms.m_numIsamData * 64 ; total += U ; _report_mem_itemA(Z, "ISAM Blk Data :", cms.m_numIsamData, pms.m_numIsamData, U, bHtml) ;
U = cms.m_numBitmaps * 64 ; total += U ; _report_mem_itemA(Z, "Bitmaps :", cms.m_numBitmaps, pms.m_numBitmaps, U, bHtml) ;
U = cms.m_numBitmapSB * 64 ; total += U ; _report_mem_itemA(Z, "Bitmap Segments:", cms.m_numBitmapSB, pms.m_numBitmapSB, U, bHtml) ;
U = cms.m_numDochtm * 64 ; total += U ; _report_mem_itemA(Z, "Doc HTML :", cms.m_numDochtm, pms.m_numDochtm, U, bHtml) ;
U = cms.m_numDocxml * 64 ; total += U ; _report_mem_itemA(Z, "Doc XML :", cms.m_numDocxml, pms.m_numDocxml, U, bHtml) ;
U = cms.m_numBincron * 64 ; total += U ; _report_mem_itemA(Z, "BinCrons :", cms.m_numBincron, pms.m_numBincron, U, bHtml) ;
U = cms.m_numBinstore * 64 ; total += U ; _report_mem_itemA(Z, "BinStores :", cms.m_numBinstore, pms.m_numBinstore, U, bHtml) ;
// TOTAL
if (bHtml)
{
Z << "<tr><td>TOTAL EST:</td><td></td><td></td><td></td><td></td><td></td><td></td>" ;
Z.Printf("<td align=\"right\">%s</td></tr>\n", _snh(total)) ;
Z << "</table>\n\n" ;
}
else
{
Z << "__________________________________________________________\n" ;
Z.Printf("TOTAL EST: %s\n", _snt(total)) ;
}
ReportStringAllocations(Z, bHtml) ;
}
void ReportStringAllocations (hzChain& Z, bool bHtml)
{
// Category: Diagnostics
hzMeminfo cms ; // Current snapshot
uint32_t N ; // Number of string spaces used (for a given size)
uint32_t U ; // Memory used by N
uint32_t F ; // Number of string spaces free (for a given size)
uint32_t V ; // Memory used by F
uint32_t nss = 0 ; // Number of string spaces in use
uint32_t fss = 0 ; // Number of string spaces free
uint32_t mcu ; // Total memory consumed by used string spaces
uint32_t mcf ; // Total memory consumed by free string spaces
//uint32_t fre ; // Total memory held in free lists
cms = _hzGlobal_Memstats ;
// Report number of string superblocks
_report_mem_item3(Z, "512K Superblocks:", cms.m_numSblks, 0, cms.m_numSblks * 589832, bHtml) ;
N = cms.m_strSm_u[0] ; nss+=N ; U=N*8 ; mcu+=U ; F = cms.m_strSm_f[0] ; fss+=F ; V=F*9 ; mcf+=V ; _report_mem_item3(Z, "Strings (008)", N, F, U, bHtml) ;
N = cms.m_strSm_u[1] ; nss+=N ; U=N*16 ; mcu+=U ; F = cms.m_strSm_f[1] ; fss+=F ; V=F*16 ; mcf+=V ; _report_mem_item3(Z, "Strings (016)", N, F, U, bHtml) ;
N = cms.m_strSm_u[2] ; nss+=N ; U=N*24 ; mcu+=U ; F = cms.m_strSm_f[2] ; fss+=F ; V=F*24 ; mcf+=V ; _report_mem_item3(Z, "Strings (024)", N, F, U, bHtml) ;
N = cms.m_strSm_u[3] ; nss+=N ; U=N*32 ; mcu+=U ; F = cms.m_strSm_f[3] ; fss+=F ; V=F*32 ; mcf+=V ; _report_mem_item3(Z, "Strings (032)", N, F, U, bHtml) ;
N = cms.m_strSm_u[4] ; nss+=N ; U=N*40 ; mcu+=U ; F = cms.m_strSm_f[4] ; fss+=F ; V=F*40 ; mcf+=V ; _report_mem_item3(Z, "Strings (040)", N, F, U, bHtml) ;
N = cms.m_strSm_u[5] ; nss+=N ; U=N*48 ; mcu+=U ; F = cms.m_strSm_f[5] ; fss+=F ; V=F*48 ; mcf+=V ; _report_mem_item3(Z, "Strings (048)", N, F, U, bHtml) ;
N = cms.m_strSm_u[6] ; nss+=N ; U=N*56 ; mcu+=U ; F = cms.m_strSm_f[6] ; fss+=F ; V=F*56 ; mcf+=V ; _report_mem_item3(Z, "Strings (056)", N, F, U, bHtml) ;
N = cms.m_strSm_u[7] ; nss+=N ; U=N*64 ; mcu+=U ; F = cms.m_strSm_f[7] ; fss+=F ; V=F*64 ; mcf+=V ; _report_mem_item3(Z, "Strings (064)", N, F, U, bHtml) ;
N = cms.m_strSm_u[8] ; nss+=N ; U=N*72 ; mcu+=U ; F = cms.m_strSm_f[8] ; fss+=F ; V=F*72 ; mcf+=V ; _report_mem_item3(Z, "Strings (072)", N, F, U, bHtml) ;
N = cms.m_strSm_u[9] ; nss+=N ; U=N*80 ; mcu+=U ; F = cms.m_strSm_f[9] ; fss+=F ; V=F*80 ; mcf+=V ; _report_mem_item3(Z, "Strings (080)", N, F, U, bHtml) ;
N = cms.m_strSm_u[10] ; nss+=N ; U=N*88 ; mcu+=U ; F = cms.m_strSm_f[10] ; fss+=F ; V=F*88 ; mcf+=V ; _report_mem_item3(Z, "Strings (088)", N, F, U, bHtml) ;
N = cms.m_strSm_u[11] ; nss+=N ; U=N*96 ; mcu+=U ; F = cms.m_strSm_f[11] ; fss+=F ; V=F*96 ; mcf+=V ; _report_mem_item3(Z, "Strings (096)", N, F, U, bHtml) ;
N = cms.m_strSm_u[12] ; nss+=N ; U=N*104 ; mcu+=U ; F = cms.m_strSm_f[12] ; fss+=F ; V=F*104 ; mcf+=V ; _report_mem_item3(Z, "Strings (104)", N, F, U, bHtml) ;
N = cms.m_strSm_u[13] ; nss+=N ; U=N*112 ; mcu+=U ; F = cms.m_strSm_f[13] ; fss+=F ; V=F*112 ; mcf+=V ; _report_mem_item3(Z, "Strings (112)", N, F, U, bHtml) ;
N = cms.m_strSm_u[14] ; nss+=N ; U=N*120 ; mcu+=U ; F = cms.m_strSm_f[14] ; fss+=F ; V=F*120 ; mcf+=V ; _report_mem_item3(Z, "Strings (120)", N, F, U, bHtml) ;
N = cms.m_strSm_u[15] ; nss+=N ; U=N*128 ; mcu+=U ; F = cms.m_strSm_f[15] ; fss+=F ; V=F*128 ; mcf+=V ; _report_mem_item3(Z, "Strings (128)", N, F, U, bHtml) ;
N = cms.m_strSm_u[16] ; nss+=N ; U=N*136 ; mcu+=U ; F = cms.m_strSm_f[16] ; fss+=F ; V=F*136 ; mcf+=V ; _report_mem_item3(Z, "Strings (136)", N, F, U, bHtml) ;
N = cms.m_strSm_u[17] ; nss+=N ; U=N*144 ; mcu+=U ; F = cms.m_strSm_f[17] ; fss+=F ; V=F*144 ; mcf+=V ; _report_mem_item3(Z, "Strings (144)", N, F, U, bHtml) ;
N = cms.m_strSm_u[18] ; nss+=N ; U=N*152 ; mcu+=U ; F = cms.m_strSm_f[18] ; fss+=F ; V=F*152 ; mcf+=V ; _report_mem_item3(Z, "Strings (152)", N, F, U, bHtml) ;
N = cms.m_strSm_u[19] ; nss+=N ; U=N*160 ; mcu+=U ; F = cms.m_strSm_f[19] ; fss+=F ; V=F*160 ; mcf+=V ; _report_mem_item3(Z, "Strings (160)", N, F, U, bHtml) ;
N = cms.m_strSm_u[20] ; nss+=N ; U=N*168 ; mcu+=U ; F = cms.m_strSm_f[20] ; fss+=F ; V=F*168 ; mcf+=V ; _report_mem_item3(Z, "Strings (168)", N, F, U, bHtml) ;
N = cms.m_strSm_u[21] ; nss+=N ; U=N*176 ; mcu+=U ; F = cms.m_strSm_f[21] ; fss+=F ; V=F*176 ; mcf+=V ; _report_mem_item3(Z, "Strings (176)", N, F, U, bHtml) ;
N = cms.m_strSm_u[22] ; nss+=N ; U=N*184 ; mcu+=U ; F = cms.m_strSm_f[22] ; fss+=F ; V=F*184 ; mcf+=V ; _report_mem_item3(Z, "Strings (184)", N, F, U, bHtml) ;
N = cms.m_strSm_u[23] ; nss+=N ; U=N*192 ; mcu+=U ; F = cms.m_strSm_f[23] ; fss+=F ; V=F*192 ; mcf+=V ; _report_mem_item3(Z, "Strings (192)", N, F, U, bHtml) ;
N = cms.m_strSm_u[24] ; nss+=N ; U=N*200 ; mcu+=U ; F = cms.m_strSm_f[24] ; fss+=F ; V=F*200 ; mcf+=V ; _report_mem_item3(Z, "Strings (200)", N, F, U, bHtml) ;
N = cms.m_strSm_u[25] ; nss+=N ; U=N*208 ; mcu+=U ; F = cms.m_strSm_f[25] ; fss+=F ; V=F*208 ; mcf+=V ; _report_mem_item3(Z, "Strings (208)", N, F, U, bHtml) ;
N = cms.m_strSm_u[26] ; nss+=N ; U=N*216 ; mcu+=U ; F = cms.m_strSm_f[26] ; fss+=F ; V=F*216 ; mcf+=V ; _report_mem_item3(Z, "Strings (216)", N, F, U, bHtml) ;
N = cms.m_strSm_u[27] ; nss+=N ; U=N*224 ; mcu+=U ; F = cms.m_strSm_f[27] ; fss+=F ; V=F*224 ; mcf+=V ; _report_mem_item3(Z, "Strings (224)", N, F, U, bHtml) ;
N = cms.m_strSm_u[28] ; nss+=N ; U=N*232 ; mcu+=U ; F = cms.m_strSm_f[28] ; fss+=F ; V=F*232 ; mcf+=V ; _report_mem_item3(Z, "Strings (232)", N, F, U, bHtml) ;
N = cms.m_strSm_u[29] ; nss+=N ; U=N*240 ; mcu+=U ; F = cms.m_strSm_f[29] ; fss+=F ; V=F*240 ; mcf+=V ; _report_mem_item3(Z, "Strings (240)", N, F, U, bHtml) ;
N = cms.m_strSm_u[30] ; nss+=N ; U=N*248 ; mcu+=U ; F = cms.m_strSm_f[30] ; fss+=F ; V=F*248 ; mcf+=V ; _report_mem_item3(Z, "Strings (248)", N, F, U, bHtml) ;
N = cms.m_strSm_u[31] ; nss+=N ; U=N*256 ; mcu+=U ; F = cms.m_strSm_f[31] ; fss+=F ; V=F*256 ; mcf+=V ; _report_mem_item3(Z, "Strings (256)", N, F, U, bHtml) ;
// Oversized strings
U = cms.m_ramStrOver ; mcu += U ; _report_mem_item3(Z, "Strings (ovr)", cms.m_numStrOver, 0, U, bHtml) ;
// Report number of string (use)
nss += cms.m_numStrings ;
U = cms.m_numStrings * sizeof(hzString) ;
mcu += U ;
_report_mem_item3(Z, "Population (incl copies)", cms.m_numStrings, 0, U, bHtml) ;
_report_mem_item3(Z, "Total string spaces", nss, fss, mcu, bHtml) ;
}
static void _report_heap (hzChain& Z, const hzMeminfo& cms, const hzMeminfo& pms, uint32_t& total, bool bHtml)
{
// Category: Diagnostics
//
// Support function to ReportMemoryUsage(). Provides Report on global new/delete override by the application, if applicable
//
// Argument: Z The hzChain instance to receive the report
// Returns: None
uint32_t usage ; // Memory used by given object class
uint32_t nA ; // Iterator for all sizes
Z <<
"<div class=\"stdpg\">\n"
"<table width=\"506\" align=\"center\" border=\"1\" cellspacing=\"0\" cellpadding=\"0\" "
"style=\"text-decoration:none; font-family:verdana; font-size:11px; font-weight:normal; color:#000000;\">\n"
"<tr>\n"
"\t<th width=\"120\">HadronZoo Entity</th>\n"
"\t<th width=\"90\">Assigned</th>\n"
"\t<th width=\"90\">Free</th>\n"
"\t<th width=\"90\">Total</th>\n"
"\t<th width=\"110\">Total RAM</th>\n"
"</tr>\n" ;
// Managed
Z << "<tr align=\"right\"><td align=\"left\">Heap 8-byte objects</td>" ;
usage = (s_Heap->nU008 + s_Heap->nF008) * 8 ;
Z.Printf("<td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n",
_snh(s_Heap->nU008), _snh(s_Heap->nF008), _snh(s_Heap->nU008 + s_Heap->nF008), _snh(usage)) ;
Z << "<tr align=\"right\"><td align=\"left\">Heap 16-byte objects</td>" ;
usage = (s_Heap->nU016 + s_Heap->nF016) * 16 ;
Z.Printf("<td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n",
_snh(s_Heap->nU016), _snh(s_Heap->nF016), _snh(s_Heap->nU016 + s_Heap->nF016), _snh(usage)) ;
Z << "<tr align=\"right\"><td align=\"left\">Heap 24-byte objects</td>" ;
usage = (s_Heap->nU024 + s_Heap->nF024) * 24 ;
Z.Printf("<td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n",
_snh(s_Heap->nU024), _snh(s_Heap->nF024), _snh(s_Heap->nU024 + s_Heap->nF024), _snh(usage)) ;
Z << "<tr align=\"right\"><td align=\"left\">Heap 32-byte objects</td>" ;
usage = (s_Heap->nU032 + s_Heap->nF032) * 32 ;
Z.Printf("<td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n",
_snh(s_Heap->nU032), _snh(s_Heap->nF032), _snh(s_Heap->nU032 + s_Heap->nF032), _snh(usage)) ;
Z << "<tr align=\"right\"><td align=\"left\">Heap 40-byte objects</td>" ;
usage = (s_Heap->nU040 + s_Heap->nF040) * 40 ;
Z.Printf("<td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n",
_snh(s_Heap->nU040), _snh(s_Heap->nF040), _snh(s_Heap->nU040 + s_Heap->nF040), _snh(usage)) ;
// Print report for oversized objects for each multiple of 8 bytes for which there are outstanding allocatons
Z << "<tr><td>Oversize (48+ bytes)</td><td></td><td></td><td></td></tr>\n" ;
for (nA = 0 ; nA < 1001 ; nA++)
{
if (!s_Heap->m_allSizes[nA] && !s_Heap->m_allSizeF[nA])
continue ;
Z.Printf("<tr align=\"right\"><td align=\"left\">Obj size %d</td>", nA * 8) ;
usage = s_Heap->m_allSizes[nA] * nA * 8 ;
Z.Printf("<td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n",
_snh(s_Heap->m_allSizeA[nA]), _snh(s_Heap->m_allSizeF[nA]), _snh(s_Heap->m_allSizes[nA]), _snh(usage)) ;
}
Z << "<tr align=\"right\"><td align=\"left\">All objects</td>" ;
Z.Printf("<td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n",
_snh(s_Heap->nCallsMalloc),
_snh(s_Heap->nCallsFree),
_snh(s_Heap->nCallsMalloc - s_Heap->nCallsFree),
_snh(s_Heap->nOverSize)) ;
Z <<
"</table>\n"
"</div>\n" ;
}
void ReportMemoryUsage (hzChain& Z, bool bHtml)
{
// Category: Diagnostics
//
// Provides Report on memory usage by the application.
//
// Please note, the HTML generated by this function is partial and comprises only the table of interest.
//
// Argument: Z The hzChain instance to receive the report
// Returns: None
static hzMeminfo pms = _hzGlobal_Memstats ; // Previous/initial memory statistics
hzMeminfo cms ; // Current memory stats
hzXDate now ; // Current date and time
uint32_t total = 0 ; // Total memory usage
now.SysDateTime() ;
// Take current snapshot
cms = _hzGlobal_Memstats ;
if (bHtml)
Z.Printf("<p><center>Memory Report at %s</center></p>\n", *now) ;
else
Z.Printf("Memory Report at %s\n", *now) ;
g_pSMAR_Str->Report(Z) ; // Used exclusively by hzString
g_pSMAR_Inet->Report(Z) ; // Used by hzEmaddr, hzDomain and hzUrl
g_pSMAR_Edo->Report(Z) ; // Used exclusively by hdbObjRepos to store EDOs
// If no heap, this is presented as collections on the LHS and string/chains on the RHS in one 'row'. If there is a heap we have string/chains on the top
// LHS, collections on the bottom LHS and the heap activity on the RHS
if (s_Heap)
{
// Two reports on LHS
if (bHtml)
{
Z <<
"<table width=\"1400\" slign=\"center\">\n"
"<tr>\n"
" <td valign=\"top\">\n"
" <table width=\"750\" slign=\"center\">\n"
" <tr>\n"
" <td>\n" ;
_report_objects(Z, cms, pms, total, bHtml) ;
Z <<
" </td>\n"
" </tr>\n"
" </table>\n"
" </td>\n"
" <td width=\"15\"> </td>\n"
" <td>\n"
" <table width=\"550\" slign=\"center\">\n"
" <tr>\n"
" <td>\n" ;
// Heap on RHS
_report_heap(Z, cms, pms, total, bHtml) ;
Z <<
" </td>\n"
" </tr>\n"
" </table>\n"
" </td>\n"
"</tr>\n"
"</table>\n" ;
}
else
{
_report_objects(Z, cms, pms, total, bHtml) ;
_report_heap(Z, cms, pms, total, bHtml) ;
}
}
else
{
// collection on LHS, string chans on RHS
if (!bHtml)
_report_objects(Z, cms, pms, total, bHtml) ;
else
{
Z <<
"<table width=\"1400\" slign=\"center\">\n"
"<tr>\n"
" <td valign=\"top\">\n" ;
_report_objects(Z, cms, pms, total, bHtml) ;
Z <<
" </td>\n"
"</tr>\n"
"</table>\n" ;
}
}
pms = cms ;
}
void RecordMemoryUsage (bool bHtml)
{
// Category: Diagnostics
//
// Provides Report on memory usage by the application and writes it to the logfile for the current thread
//
// Arguments: None
// Returns: None
hzChain Z ; // Report output chain
hzLogger* pLog ; // Current thread logger
pLog = GetThreadLogger() ;
if (!pLog)
return ;
pLog->Out("Start of Memory Report\n") ;
ReportMemoryUsage(Z, bHtml) ;
pLog->Out(Z) ;
}
void ReportIsamUsage (hzChain& Z)
{
// Category: Diagnostics
//
// Provides Report on ISAM usage by the application.
//
// Argument: Z The hzChain instance to receive the report
// Returns: None
hzXDate now ; // Current date and time
now.SysDateTime() ;
Z.Clear() ;
Z.Printf("<p><center>ISAM Report at %s</center></p>\n", *now) ;
Z <<
"<html>\n"
"<head>\n"
"<style>\n"
".main { text-decoration:none; font-family:verdana; font-size:11px; font-weight:normal; color:#000000; }\n"
".stdpg { height:600px; border:0px; margin-left:5px; overflow-x:auto; overflow-y:auto; }\n"
"</style>\n"
"</head>\n"
"<body>\n"
"<div class=\"stdpg\">\n"
"<table width=\"70%\" align=\"center\" border=\"1\" cellspacing=\"0\" cellpadding=\"0\" "
"style=\"text-decoration:none; font-family:verdana; font-size:11px; font-weight:normal; color:#000000;\">\n"
"<tr>\n"
"\t<th>Type</th>\n"
"\t<th>Name</th>\n"
"\t<th>Blocks</th>\n"
"\t<th>Object Size</th>\n"
"\t<th>Objects</th>\n"
"\t<th>Total RAM</th>\n"
"</tr>\n" ;
Z << "<tr align=\"right\"><td align=\"left\">hzMapS</td><td align=\"left\">_hzGlobal_BinDataCrons</td>" ;
Z << "<tr align=\"right\"><td align=\"left\">hzMapS</td><td align=\"left\">_hzGlobal_BinDataStores</td>" ;
Z << "<tr align=\"right\"><td align=\"left\">hzMapS</td><td align=\"left\">_hzGlobal_Datatypes</td>" ;
Z << "<tr align=\"right\"><td align=\"left\">hzMapS</td><td align=\"left\">_hzGlobal_Enums</td>" ;
Z << "<tr align=\"right\"><td align=\"left\">hzMapS</td><td align=\"left\">_hzGlobal_Classes</td>" ;
Z << "<tr align=\"right\"><td align=\"left\">hzMapS</td><td align=\"left\">_hzGlobal_setitories</td>" ;
Z << "<tr align=\"right\"><td align=\"left\">hzMapS</td><td align=\"left\">s_SSIncludes</td>" ;
Z << "<tr align=\"right\"><td align=\"left\">hzMapS</td><td align=\"left\">s_PageStore</td>" ;
Z << "<tr align=\"right\"><td align=\"left\">hzMapS</td><td align=\"left\">_hzGlobal_blockedIPs</td>" ;
Z << "<tr align=\"right\"><td align=\"left\">hzMapS</td><td align=\"left\">s_mimesFile</td>" ;
Z << "<tr align=\"right\"><td align=\"left\">hzMapS</td><td align=\"left\">s_mimesDesc</td>" ;
Z << "<tr align=\"right\"><td align=\"left\">hzMapS</td><td align=\"left\">s_mimesEnum</td>" ;
Z << "<tr align=\"right\"><td align=\"left\">hzMapS</td><td align=\"left\">_hzGlobal_Userlist</td>" ;
Z << "<tr align=\"right\"><td align=\"left\">hzMapS</td><td align=\"left\">_hzGlobal_Grouplist</td>" ;
Z <<
"</table>\n"
"</div>\n"
"</body>\n"
"</html>\n" ;
}