#help_index "Debugging/Heap;Memory/Debugging" #help_file "::/Doc/HeapDebug" #define HL_CALLER_DEPTH 5 //Feel free to change this. #define HL_HASH_SIZE 0x1000 class CHeapLog { CHeapLog *next, *last; union { U8 *addr; I64 size; } I64 count; U8 *caller[HL_CALLER_DEPTH]; }; class CHeapLogHash { CHeapLog *next, *last; }; CHeapCtrl *heaplog_hc_watched, *heaplog_hc = NULL; CHeapLogHash *heaplog_head = NULL; U0 HeapLogMAlloc(U8 *addr) { CHeapLog *tmphl; I64 i; if (MHeapCtrl(addr) == heaplog_hc_watched) { tmphl = MAlloc(sizeof(CHeapLog), heaplog_hc); tmphl->addr = addr; for (i = 0; i < HL_CALLER_DEPTH; i++) tmphl->caller[i] = Caller(i + 2); i = addr >> 3 & (HL_HASH_SIZE - 1); PUSHFD CLI while (LBts(&sys_semas[SEMA_HEAPLOG_LOCK], 0)) PAUSE QueueInsert(tmphl, heaplog_head[i].last); LBtr(&sys_semas[SEMA_HEAPLOG_LOCK], 0); POPFD } } U0 HeapLogFree(U8 *addr) { I64 i; CHeapLog *tmphl; if (!addr) return; if (MHeapCtrl(addr) == heaplog_hc_watched) { i = addr >> 3 & (HL_HASH_SIZE - 1); PUSHFD CLI while (LBts(&sys_semas[SEMA_HEAPLOG_LOCK], 0)) PAUSE tmphl = heaplog_head[i].next; while (tmphl != &heaplog_head[i]) { if (addr == tmphl->addr) { QueueRemove(tmphl); LBtr(&sys_semas[SEMA_HEAPLOG_LOCK], 0); POPFD Free(tmphl); return; } tmphl = tmphl->next; } LBtr(&sys_semas[SEMA_HEAPLOG_LOCK], 0); POPFD } } public Bool HeapLog(Bool val=ON, CTask *task=NULL) {//Turn on. Collect data. Call HeapLogAddrRep() or HeapLogSizeRep(). I64 i; if (val) { if (Bt(&sys_semas[SEMA_HEAPLOG_ACTIVE], 0)) { "HeapLog Already Active\n"; return TRUE; } else { if (!task) task = Fs; if (TaskValidate(task)) heaplog_hc_watched = task->data_heap; else heaplog_hc_watched = task;//Actually, not a task, must be a HeapCtrl. PUSHFD CLI while (LBts(&sys_semas[SEMA_HEAPLOG_LOCK], 0)) PAUSE heaplog_hc = HeapCtrlInit(,, sys_data_bp); ext[EXT_HEAPLOG_MALLOC] = &HeapLogMAlloc; ext[EXT_HEAPLOG_FREE] = &HeapLogFree; heaplog_head = MAlloc(sizeof(CHeapLogHash) * HL_HASH_SIZE, heaplog_hc); for (i = 0; i < HL_HASH_SIZE; i++) QueueInit(&heaplog_head[i]); LBtr(&sys_semas[SEMA_HEAPLOG_LOCK], 0); POPFD LBts(&sys_semas[SEMA_HEAPLOG_ACTIVE], 0); return FALSE; } } else { if (!LBtr(&sys_semas[SEMA_HEAPLOG_ACTIVE], 0)) { "HeapLog Not Active\n"; return FALSE; } else { HeapCtrlDel(heaplog_hc); heaplog_head = heaplog_hc = NULL; ext[EXT_HEAPLOG_MALLOC] = NULL; ext[EXT_HEAPLOG_FREE] = NULL; return TRUE; } } } public U0 HeapLogAddrRep(Bool leave_it=OFF) {//Call HeapLog() first and collect data. I64 i, j, total = 0; CHeapLog *tmphl, hl; if (!LBtr(&sys_semas[SEMA_HEAPLOG_ACTIVE], 0)) { "HeapLog Not Active\n"; return; } "$WW,0$"; while (LBts(&sys_semas[SEMA_HEAPLOG_LOCK], 0)) PAUSE "$LTCYAN$ Size Address$FG$\n"; for (i = 0; i < HL_HASH_SIZE; i++) { tmphl = heaplog_head[i].next; while (tmphl != &heaplog_head[i]) { //Take snapshot in case modified. (while we work) MemCopy(&hl, tmphl, sizeof(CHeapLog)); "$PURPLE$%08X$FG$ %08X %P", MSize(hl.addr), hl.addr, hl.caller[0]; for (j = 1; j < HL_CALLER_DEPTH; j++) " . %P", hl.caller[j]; '\n'; total += MSize(hl.addr); tmphl = hl.next; } } LBtr(&sys_semas[SEMA_HEAPLOG_LOCK], 0); "\n$LTRED$Total:%08X$FG$\n", total; LBts(&sys_semas[SEMA_HEAPLOG_ACTIVE], 0); if (!leave_it) HeapLog(OFF); } public U0 HeapLogSizeRep(Bool leave_it=OFF) {//Call HeapLog() first and collect data. I64 i, j, k, total = 0; CHeapLog *tmphla, hla, *tmphls, *tmphls1; CHeapLogHash *size_head; if (!LBtr(&sys_semas[SEMA_HEAPLOG_ACTIVE], 0)) { "HeapLog Not Active\n"; return; } size_head = MAlloc(sizeof(CHeapLogHash) * HL_HASH_SIZE, heaplog_hc); for (i = 0; i < HL_HASH_SIZE; i++) QueueInit(&size_head[i]); "$WW,0$"; while (LBts(&sys_semas[SEMA_HEAPLOG_LOCK], 0)) PAUSE for (i = 0; i < HL_HASH_SIZE; i++) { tmphla = heaplog_head[i].next; while (tmphla != &heaplog_head[i]) { //Take snapshot in case modified. (while we work) MemCopy(&hla, tmphla, sizeof(CHeapLog)); k = (MSize(hla.addr) >> 3 + hla.caller[0]) & (HL_HASH_SIZE - 1); tmphls = size_head[k].next; while (tmphls != &size_head[k]) { if (MSize(hla.addr) == tmphls->size) { for (j = 0; j < HL_CALLER_DEPTH; j++) if (hla.caller[j] != tmphls->caller[j]) goto hl_next; tmphls->count++; goto hl_found; } hl_next: tmphls = tmphls->next; } tmphls = MAlloc(sizeof(CHeapLog), heaplog_hc); MemCopy(tmphls, &hla, sizeof(CHeapLog)); tmphls->count = 1; tmphls->size = MSize(hla.addr); QueueInsert(tmphls, size_head[k].last); hl_found: tmphla = hla.next; } } LBtr(&sys_semas[SEMA_HEAPLOG_LOCK], 0); "$LTCYAN$ Size * Count = Total$FG$\n"; for (i = 0; i < HL_HASH_SIZE; i++) { tmphls = size_head[i].next; while (tmphls != &size_head[i]) { tmphls1 = tmphls->next; "%08X*%08X=%08X %P", tmphls->size, tmphls->count, tmphls->size * tmphls->count, tmphls->caller[0]; for (j = 1; j < HL_CALLER_DEPTH; j++) " . %P", tmphls->caller[j]; '\n'; total += tmphls->size * tmphls->count; Free(tmphls); tmphls = tmphls1; } } Free(size_head); "\n$LTRED$Total:%08X$FG$\n", total; LBts(&sys_semas[SEMA_HEAPLOG_ACTIVE], 0); if (!leave_it) HeapLog(OFF); }