diff --git a/include/sys/sys_heap.h b/include/sys/sys_heap.h index 5ee91a21ffa..598bdb69560 100644 --- a/include/sys/sys_heap.h +++ b/include/sys/sys_heap.h @@ -201,13 +201,14 @@ void sys_heap_stress(void *(*alloc)(void *arg, size_t bytes), int target_percent, struct z_heap_stress_result *result); -/** @brief Dump heap structure content for debugging to the console +/** @brief Print heap internal structure information to the console * - * Print information on the heap structure such as its size, chunk buckets - * and chunk list. + * Print information on the heap structure such as its size, chunk buckets, + * chunk list and some statistics for debugging purpose. * * @param h Heap to print information about + * @param dump_chunks True to print the entire heap chunk list */ -void sys_heap_dump(struct sys_heap *h); +void sys_heap_print_info(struct sys_heap *h, bool dump_chunks); #endif /* ZEPHYR_INCLUDE_SYS_SYS_HEAP_H_ */ diff --git a/lib/os/heap-validate.c b/lib/os/heap-validate.c index ee134f240a2..dffe2193386 100644 --- a/lib/os/heap-validate.c +++ b/lib/os/heap-validate.c @@ -314,41 +314,81 @@ void sys_heap_stress(void *(*alloc)(void *arg, size_t bytes), } /* - * Dump heap structure content for debugging / analysis purpose + * Print heap info for debugging / analysis purpose */ -void heap_dump(struct z_heap *h) +void heap_print_info(struct z_heap *h, bool dump_chunks) { int i, nb_buckets = bucket_idx(h, h->len) + 1; + size_t free_bytes, allocated_bytes, total, overhead; - printk("Heap at %p contains %d units\n", chunk_buf(h), h->len); + printk("Heap at %p contains %d units in %d buckets\n\n", + chunk_buf(h), h->len, nb_buckets); + printk(" bucket# min units total largest largest\n" + " threshold chunks (units) (bytes)\n" + " -----------------------------------------------------------\n"); for (i = 0; i < nb_buckets; i++) { chunkid_t first = h->buckets[i].next; + size_t largest = 0; int count = 0; if (first) { chunkid_t curr = first; do { count++; + largest = MAX(largest, chunk_size(h, curr)); curr = next_free_chunk(h, curr); } while (curr != first); } - - printk("bucket %d (min %d units): %d chunks\n", i, - (1 << i) - 1 + min_chunk_size(h), count); + if (count) { + printk("%9d %12d %12d %12zd %12zd\n", + i, (1 << i) - 1 + min_chunk_size(h), count, + largest, largest * CHUNK_UNIT - chunk_header_bytes(h)); + } } + if (dump_chunks) { + printk("\nChunk dump:\n"); + } + free_bytes = allocated_bytes = 0; for (chunkid_t c = 0; ; c = right_chunk(h, c)) { - printk("chunk %3zd: %c %3zd] %3zd [%zd\n", - c, chunk_used(h, c) ? '*' : '-', - left_chunk(h, c), chunk_size(h, c), right_chunk(h, c)); + if (c == 0 || c == h->len) { + /* those are always allocated for internal purposes */ + } else if (chunk_used(h, c)) { + allocated_bytes += chunk_size(h, c) * CHUNK_UNIT + - chunk_header_bytes(h); + } else if (!solo_free_header(h, c)) { + free_bytes += chunk_size(h, c) * CHUNK_UNIT + - chunk_header_bytes(h); + } + if (dump_chunks) { + printk("chunk %4zd: [%c] size=%-4zd left=%-4zd right=%zd\n", + c, + chunk_used(h, c) ? '*' + : solo_free_header(h, c) ? '.' + : '-', + chunk_size(h, c), + left_chunk(h, c), + right_chunk(h, c)); + } if (c == h->len) { break; } } + + /* + * The final chunk at h->len is just a header serving as a end + * marker. It is part of the overhead. + */ + total = h->len * CHUNK_UNIT + chunk_header_bytes(h); + overhead = total - free_bytes - allocated_bytes; + printk("\n%zd free bytes, %zd allocated bytes, overhead = %zd bytes (%zd.%zd%%)\n", + free_bytes, allocated_bytes, overhead, + (1000 * overhead + total/2) / total / 10, + (1000 * overhead + total/2) / total % 10); } -void sys_heap_dump(struct sys_heap *heap) +void sys_heap_print_info(struct sys_heap *heap, bool dump_chunks) { - heap_dump(heap->heap); + heap_print_info(heap->heap, dump_chunks); } diff --git a/lib/os/heap.h b/lib/os/heap.h index d2b0d6d049c..54821891906 100644 --- a/lib/os/heap.h +++ b/lib/os/heap.h @@ -240,6 +240,6 @@ static inline bool size_too_big(struct z_heap *h, size_t bytes) } /* For debugging */ -void heap_dump(struct z_heap *h); +void heap_print_info(struct z_heap *h, bool dump_chunks); #endif /* ZEPHYR_INCLUDE_LIB_OS_HEAP_H_ */