2 #ifdef DWC_DEBUG_MEMORY
14 DWC_CIRCLEQ_ENTRY(allocation) entry;
17 DWC_CIRCLEQ_HEAD(allocation_queue, allocation);
19 struct allocation_manager {
21 struct allocation_queue allocations;
32 static struct allocation_manager *manager;
34 static int add_allocation(void *ctx, uint32_t size, char const *func, int line, void *addr,
39 DWC_ASSERT(manager != NULL, "manager not allocated");
41 a = __DWC_ALLOC_ATOMIC(manager->mem_ctx, sizeof(*a));
43 return -DWC_E_NO_MEMORY;
46 a->func = __DWC_ALLOC_ATOMIC(manager->mem_ctx, DWC_STRLEN(func) + 1);
48 __DWC_FREE(manager->mem_ctx, a);
49 return -DWC_E_NO_MEMORY;
52 DWC_MEMCPY(a->func, func, DWC_STRLEN(func) + 1);
58 DWC_CIRCLEQ_INSERT_TAIL(&manager->allocations, a, entry);
62 manager->num_active++;
63 manager->total += size;
66 if (manager->max < manager->cur) {
67 manager->max = manager->cur;
73 static struct allocation *find_allocation(void *ctx, void *addr)
77 DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
78 if (a->ctx == ctx && a->addr == addr) {
86 static void free_allocation(void *ctx, void *addr, char const *func, int line)
88 struct allocation *a = find_allocation(ctx, addr);
92 "Free of address %p that was never allocated or already freed %s:%d",
97 DWC_CIRCLEQ_REMOVE(&manager->allocations, a, entry);
99 manager->num_active--;
100 manager->num_freed++;
101 manager->cur -= a->size;
102 __DWC_FREE(manager->mem_ctx, a->func);
103 __DWC_FREE(manager->mem_ctx, a);
106 int dwc_memory_debug_start(void *mem_ctx)
108 DWC_ASSERT(manager == NULL, "Memory debugging has already started\n");
114 manager = __DWC_ALLOC(mem_ctx, sizeof(*manager));
116 return -DWC_E_NO_MEMORY;
119 DWC_CIRCLEQ_INIT(&manager->allocations);
120 manager->mem_ctx = mem_ctx;
122 manager->num_freed = 0;
123 manager->num_active = 0;
131 void dwc_memory_debug_stop(void)
133 struct allocation *a;
135 dwc_memory_debug_report();
137 DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
138 DWC_ERROR("Memory leaked from %s:%d\n", a->func, a->line);
139 free_allocation(a->ctx, a->addr, NULL, -1);
142 __DWC_FREE(manager->mem_ctx, manager);
145 void dwc_memory_debug_report(void)
147 struct allocation *a;
149 DWC_PRINTF("\n\n\n----------------- Memory Debugging Report -----------------\n\n");
150 DWC_PRINTF("Num Allocations = %d\n", manager->num);
151 DWC_PRINTF("Freed = %d\n", manager->num_freed);
152 DWC_PRINTF("Active = %d\n", manager->num_active);
153 DWC_PRINTF("Current Memory Used = %d\n", manager->cur);
154 DWC_PRINTF("Total Memory Used = %d\n", manager->total);
155 DWC_PRINTF("Maximum Memory Used at Once = %d\n", manager->max);
156 DWC_PRINTF("Unfreed allocations:\n");
158 DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
159 DWC_PRINTF(" addr=%p, size=%d from %s:%d, DMA=%d\n",
160 a->addr, a->size, a->func, a->line, a->dma);
164 /* The replacement functions */
165 void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line)
167 void *addr = __DWC_ALLOC(mem_ctx, size);
173 if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
174 __DWC_FREE(mem_ctx, addr);
181 void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func,
184 void *addr = __DWC_ALLOC_ATOMIC(mem_ctx, size);
190 if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
191 __DWC_FREE(mem_ctx, addr);
198 void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line)
200 free_allocation(mem_ctx, addr, func, line);
201 __DWC_FREE(mem_ctx, addr);
204 void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
205 char const *func, int line)
207 void *addr = __DWC_DMA_ALLOC(dma_ctx, size, dma_addr);
213 if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
214 __DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
221 void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size,
222 dwc_dma_t *dma_addr, char const *func, int line)
224 void *addr = __DWC_DMA_ALLOC_ATOMIC(dma_ctx, size, dma_addr);
230 if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
231 __DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
238 void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
239 dwc_dma_t dma_addr, char const *func, int line)
241 free_allocation(dma_ctx, virt_addr, func, line);
242 __DWC_DMA_FREE(dma_ctx, size, virt_addr, dma_addr);
245 #endif /* DWC_DEBUG_MEMORY */