static void heap_walk(Heap *h,int idx,int depth,HEAPWALKFUNC func) { HeapElement *he; if (idx < 0 || idx >= HSIZE(h)) return; he = HARRAY(h,idx); func(depth,he->heKey,he->heData); heap_walk(h,HLEFT(idx),depth + 1,func); heap_walk(h,HRIGHT(idx),depth + 1,func); }
/* * Parse user options and invoke corresponding heap-related functions */ CA_BOOL heap_command_impl(char* args) { CA_BOOL rc = CA_TRUE; address_t addr = 0; CA_BOOL verbose = CA_FALSE; CA_BOOL check_leak = CA_FALSE; CA_BOOL calc_usage = CA_FALSE; CA_BOOL block_info = CA_FALSE; CA_BOOL cluster_blocks = CA_FALSE; CA_BOOL top_block = CA_FALSE; CA_BOOL top_user = CA_FALSE; CA_BOOL all_reachable_blocks = CA_FALSE; // experimental option char* expr = NULL; // Parse user input options // argument is either an address or /v or /leak if (args) { char* options[MAX_NUM_OPTIONS]; int num_options = ca_parse_options(args, options); int i; for (i = 0; i < num_options; i++) { char* option = options[i]; if (*option == '/') { if (strcmp(option, "/leak") == 0 || strcmp(option, "/l") == 0) { check_leak = CA_TRUE; if (block_info || cluster_blocks || calc_usage || top_block || top_user || addr) { CA_PRINT("Option [%s] conflicts with one of the previous options\n", option); return CA_FALSE; } } else if (strcmp(option, "/verbose") == 0 || strcmp(option, "/v") == 0) { verbose = CA_TRUE; } else if (strcmp(option, "/block") == 0 || strcmp(option, "/b") == 0) { block_info = CA_TRUE; if (check_leak || cluster_blocks || calc_usage || top_block || top_user) { CA_PRINT("Option [%s] conflicts with one of the previous options\n", option); return CA_FALSE; } } else if (strcmp(option, "/cluster") == 0 || strcmp(option, "/c") == 0) { cluster_blocks = CA_TRUE; if (check_leak || block_info || calc_usage || top_block || top_user) { CA_PRINT("Option [%s] conflicts with one of the previous options\n", option); return CA_FALSE; } } else if (strcmp(option, "/usage") == 0 || strcmp(option, "/u") == 0) { calc_usage = CA_TRUE; if (check_leak || block_info || cluster_blocks || top_block || top_user) { CA_PRINT("Option [%s] conflicts with one of the previous options\n", option); return CA_FALSE; } } else if (strcmp(option, "/topblock") == 0 || strcmp(option, "/tb") == 0) { top_block = CA_TRUE; if (check_leak || block_info || cluster_blocks || calc_usage || top_user) { CA_PRINT("Option [%s] conflicts with one of the previous options\n", option); return CA_FALSE; } } else if (strcmp(option, "/topuser") == 0 || strcmp(option, "/tu") == 0) { top_user = CA_TRUE; if (check_leak || block_info || cluster_blocks || calc_usage || top_block) { CA_PRINT("Option [%s] conflicts with one of the previous options\n", option); return CA_FALSE; } } else if (strcmp(option, "/all") == 0 || strcmp(option, "/a") == 0) all_reachable_blocks = CA_TRUE; else { CA_PRINT("Invalid option: [%s]\n", option); return CA_FALSE; } } else if (calc_usage) { expr = option; break; } else if (addr == 0) addr = ca_eval_address (option); else { CA_PRINT("Invalid option: [%s]\n", option); return CA_FALSE; } } } if (check_leak) { if (addr) CA_PRINT("Unexpected address expression\n"); else display_heap_leak_candidates(); } else if (block_info) { if (!addr) CA_PRINT("Heap block address is expected\n"); else { struct heap_block heap_block; if (get_heap_block_info(addr, &heap_block)) { if (heap_block.inuse) CA_PRINT("\t[In-use]\n"); else CA_PRINT("\t[Free]\n"); CA_PRINT("\t[Address] "PRINT_FORMAT_POINTER"\n", heap_block.addr); CA_PRINT("\t[Size] "PRINT_FORMAT_SIZE"\n", heap_block.size); CA_PRINT("\t[Offset] "PRINT_FORMAT_SIZE"\n", addr - heap_block.addr); } else CA_PRINT("[Error] Failed to query the memory block\n"); } } else if (cluster_blocks) { if (addr) { if (!heap_walk(addr, verbose)) CA_PRINT("[Error] Failed to walk heap\n"); } else CA_PRINT("Heap block address is expected\n"); } else if (calc_usage) { if (expr) calc_heap_usage(expr); else CA_PRINT("An expression of heap memory owner is expected\n"); } else if (top_block || top_user) { unsigned int n = (unsigned int)addr; if (n == 0) CA_PRINT("A number is expected\n"); else if (top_user) biggest_heap_owners_generic(n, all_reachable_blocks); else biggest_blocks(n); } else { if (addr) CA_PRINT("Unexpected address expression\n"); else if (!heap_walk(addr, verbose)) CA_PRINT("[Error] Failed to walk heap\n"); } return rc; }
/*返回实际统计的数目*/ ULONG heap_stats( ULONG heapId, VOID *usrTbl, INT sort, INT sortBy, VOID *results, ULONG cnts) { ULONG loop; BYTE *start, *end, *cur; HeapStatTbl *tbl = (HeapStatTbl*)usrTbl; ULONG entrySize = tbl->entrySize; ULONG statSize = tbl->statSize; struct rb_node *node; vos_mutex_lock(&tbl->mutex); /*清空上次的统计结果*/ tbl->cur = tbl->start; tbl->entryIdx = 0; tbl->noEntry = 0; tbl->root.rb_node = NULL; /*遍历heap上所有已使用的chip统计使用情况*/ heap_walk(heapId, &stat_hook, (VOID*)tbl); /*输出统计结果*/ cnts = (tbl->entryIdx < cnts) ? tbl->entryIdx : cnts; if(0 == cnts) { vos_mutex_unlock(&tbl->mutex); return tbl->entryIdx; } start = tbl->start; if(0 == sort) { end = start + cnts * statSize; for(cur = start; cur != end; cur += statSize) { memcpy(results, cur + sizeof(struct rb_node), entrySize); results = (VOID*)((BYTE*)results + entrySize); } vos_mutex_unlock(&tbl->mutex); return tbl->entryIdx; } end = tbl->cur; for(loop = 0; loop < cnts; loop++) { node = (struct rb_node*)start; for(cur = start + statSize; cur != end; cur += statSize) { /*第一个指针指向的key比第2个大*/ if(0 < (*(tbl->attrCmp))((VOID*)(cur + sizeof(struct rb_node)), (VOID*)(node + 1), sortBy)) node = (struct rb_node*)cur; } memcpy(results, (VOID*)(node + 1), entrySize); results = (VOID*)((BYTE*)results + entrySize); memcpy((VOID*)node, (VOID*)start, statSize); start += statSize; } vos_mutex_unlock(&tbl->mutex); return tbl->entryIdx; }
void heapWalk(HEAP heap,HEAPWALKFUNC func) { heap_walk((Heap*)heap,0,0,func); }