1 /*
2  * Copyright (C) 2015-2017 Alibaba Group Holding Limited
3  */
4 
5 #include <stdio.h>
6 #include "k_api.h"
7 
8 #if AOS_COMP_DEBUG
9 #include "aos/debug.h"
10 #endif
11 
12 #if 0
13 #include "cli_console.h"
14 
15 extern cli_console cli_uart_console;
16 #define KMM_CRITICAL_ENTER(head, cpsr)                 \
17     do {                                               \
18         cli_console *console = get_current_console();  \
19         if(console && console == &cli_uart_console) {  \
20             MM_CRITICAL_ENTER(head, cpsr);             \
21         }                                              \
22     } while(0);
23 
24 #define KMM_CRITICAL_EXIT(head, cpsr)                  \
25     do {                                               \
26         cli_console *console = get_current_console();  \
27         if(console && console == &cli_uart_console) {  \
28             MM_CRITICAL_EXIT(head, cpsr);              \
29         }                                              \
30     } while(0);
31 
32 #endif
33 #define KMM_CRITICAL_ENTER(head, cpsr) MM_CRITICAL_ENTER(head, cpsr)
34 #define KMM_CRITICAL_EXIT(head, cpsr)  MM_CRITICAL_EXIT(head, cpsr)
35 
36 typedef int (*KMM_PRINT)(const char *fmt, ...);
37 
38 KMM_PRINT print = printf;
39 
40 #if (RHINO_CONFIG_MM_DEBUG > 0)
41 uint8_t g_mmlk_cnt;
42 
43 #define MM_CHK 0xff
44 
45 #if (RHINO_CONFIG_MM_TLF > 0)
46 
print_block(k_mm_list_t * b)47 void print_block(k_mm_list_t *b)
48 {
49     if (!b) {
50         return;
51     }
52 
53     print("0x%p ", (void *)b);
54 
55     if (b->buf_size & MM_BUFF_FREE) {
56         if (b->dye != MM_DYE_FREE) {
57             print("!");
58         } else {
59             print(" ");
60         }
61         print("free ");
62     } else {
63         if (b->dye != MM_DYE_USED) {
64             print("!");
65         } else {
66             print(" ");
67         }
68         print("used ");
69     }
70 
71     if (MM_GET_BUF_SIZE(b)) {
72         print(" %6lu ", (unsigned long)MM_GET_BUF_SIZE(b));
73     } else {
74         print(" sentinel ");
75     }
76 
77     if (b->buf_size & MM_BUFF_FREE) {
78         if (b->dye != MM_DYE_FREE) {
79             print(" %8x ", b->dye);
80         } else {
81             print("  OK ");
82         }
83     } else {
84         if (b->dye != MM_DYE_USED) {
85             print(" %8x ", b->dye);
86         } else {
87             print("  OK ");
88         }
89     }
90 
91     print(" 0x%-8x ", b->owner);
92 
93 #if (RHINO_CONFIG_MM_TRACE_LVL > 0)
94     /* If double free, print last alloc trace maybe useful.
95     This info is not useful if this mem alloc-and-freed by another module between.
96     */
97     //if ((b->buf_size & MM_BUFF_FREE) == 0)
98     {
99         int idx;
100         print(" (%p", b->trace[0]);
101         for (idx = 1 ; idx < RHINO_CONFIG_MM_TRACE_LVL ; idx++) {
102             print(" <- %p", b->trace[idx]);
103         }
104         print(")");
105     }
106 #endif
107 
108     print("\r\n");
109 }
110 
check_block(k_mm_list_t * b)111 void check_block(k_mm_list_t *b)
112 {
113     if (!b) {
114         return;
115     }
116 
117     if (b->buf_size & MM_BUFF_FREE) {
118         if (b->dye != MM_DYE_FREE) {
119             print("0x%p ", (void *)b);
120         }
121     } else {
122         if (b->dye != MM_DYE_USED) {
123             print("0x%p ", (void *)b);
124         }
125     }
126 }
127 
128 
dump_kmm_free_map(k_mm_head * mmhead)129 void dump_kmm_free_map(k_mm_head *mmhead)
130 {
131     int i;
132 
133     k_mm_list_t *next;
134     k_mm_list_t *tmp;
135 
136     if (!mmhead) {
137         return;
138     }
139 
140     print("freelist bitmap: 0x%x\r\n", (unsigned)mmhead->free_bitmap);
141     print("   Address  Stat     Len  Chk    Caller\r\n");
142 
143     for (i = 0; i < MM_BIT_LEVEL; i++) {
144         next = mmhead->freelist[i];
145         while (next) {
146             print_block(next);
147             tmp  = next->mbinfo.free_ptr.next;
148             next = tmp;
149         }
150     }
151 }
152 
dump_kmm_map(k_mm_head * mmhead)153 void dump_kmm_map(k_mm_head *mmhead)
154 {
155     k_mm_region_info_t *reginfo, *nextreg;
156     k_mm_list_t *next, *cur;
157 
158     if (!mmhead) {
159         return;
160     }
161 
162     print("ALL BLOCKS\r\n");
163     print("Blk_Addr    Stat     Len  Chk      Caller    Point\r\n");
164     reginfo = mmhead->regioninfo;
165     while (reginfo) {
166         cur = MM_GET_THIS_BLK(reginfo);
167         while (cur) {
168             print_block(cur);
169             if (MM_GET_BUF_SIZE(cur)) {
170                 next = MM_GET_NEXT_BLK(cur);
171             } else {
172                 next = NULL;
173             }
174             cur = next;
175         }
176         nextreg = reginfo->next;
177         reginfo = nextreg;
178     }
179 }
180 
dump_kmm_statistic_info(k_mm_head * mmhead)181 void dump_kmm_statistic_info(k_mm_head *mmhead)
182 {
183 #if (K_MM_STATISTIC > 0)
184     int i;
185 #endif
186 
187     if (!mmhead) {
188         return;
189     }
190 
191 #if (K_MM_STATISTIC > 0)
192     for (i = 0; i < MM_BIT_LEVEL; i++) {
193         if (i % 4 == 0 && i != 0) {
194             print("\r\n");
195         }
196         print("[2^%02d] bytes: %5d   |", (i + MM_MIN_BIT), mmhead->alloc_times[i]);
197     }
198     print("\r\n");
199 #endif
200 }
201 
202 #if (RHINO_CONFIG_MM_BLK > 0)
dump_kmm_mblk_info(k_mm_head * mmhead)203 void dump_kmm_mblk_info(k_mm_head *mmhead)
204 {
205     uint32_t idx;
206     uint32_t slice = 0;
207     mblk_list_t *blk_list;
208     mblk_pool_t *mm_pool;
209 
210     size_t UsedSize = 0;
211     size_t FreeSize = 0;
212     size_t MaxUsedSz = 0;
213     size_t AllocFail = 0;
214 
215     print(
216                 "---------------------------------------------------------------------------\r\n");
217     print(
218                 "[POOL]| BlkSize    | UsedSize   | FreeSize   | MaxUsedSz  | AllocFail  |\r\n");
219 
220     mm_pool = mmhead->fix_pool;
221     if (mm_pool != NULL) {
222         for (idx = 0 ; idx < MM_BLK_SLICE_BIT ; idx++) {
223             blk_list = &(mm_pool->blk_list[idx]);
224             if (blk_list->slice_cnt > 0) {
225                 print("      | %-10d | %-10d | %-10d | %-10d | %-10d |\r\n",
226                       blk_list->blk_size, \
227                       (int)blk_list->nofree_cnt * blk_list->blk_size,
228                       (int)blk_list->freelist_cnt * blk_list->blk_size,
229                       (blk_list->slice_cnt - 1)*MM_BLK_SLICE_SIZE + blk_list->slice_offset,
230                       (int)blk_list->fail_cnt);
231 
232                 UsedSize += blk_list->nofree_cnt * blk_list->blk_size;
233                 FreeSize += blk_list->freelist_cnt * blk_list->blk_size;
234                 MaxUsedSz += (blk_list->slice_cnt - 1) * MM_BLK_SLICE_SIZE + blk_list->slice_offset;
235                 AllocFail += blk_list->fail_cnt;
236 
237                 slice += blk_list->slice_cnt;
238             }
239         }
240         print("Total |            | %-10d | %-10d | %-10d | %-10d |\r\n",
241               UsedSize, FreeSize, MaxUsedSz, AllocFail);
242 
243         print("Pool Size %d, Free Slice size %p.\r\n",
244               mm_pool->pool_end - mm_pool->pool_start,
245               (intptr_t)(mm_pool->pool_end - mm_pool->pool_start - mm_pool->slice_cnt * MM_BLK_SLICE_SIZE));
246     }
247     print(
248                 "---------------------------------------------------------------------------\r\n");
249 }
250 #endif
251 
252 #if (RHINO_CONFIG_KOBJ_LIST > 0)
dump_kmm_task_info(k_mm_head * mmhead)253 void dump_kmm_task_info(k_mm_head *mmhead)
254 {
255     k_mm_region_info_t *reginfo;
256     k_mm_list_t *next, *cur;
257     ktask_t     *task_owner;
258     uint32_t     isr_alloc_size = 0;
259     uint32_t     unk_alloc_size = 0;
260     uint32_t     buff_size;
261 
262     klist_t     *listnode;
263     ktask_t     *task;
264 
265     if (!mmhead) {
266         return;
267     }
268 
269     reginfo = mmhead->regioninfo;
270     while (reginfo) {
271         cur = MM_GET_THIS_BLK(reginfo);
272         while (cur) {
273             buff_size = MM_GET_BUF_SIZE(cur);
274             if (cur->dye == MM_DYE_USED) {
275                 if (cur->owner_id == 0) {
276                     isr_alloc_size += buff_size;
277                 } else if (cur->owner_id != MM_OWNER_ID_SELF) {
278                     task_owner = debug_task_find_by_id(cur->owner_id);
279                     if (task_owner != NULL) {
280                         task_owner->task_alloc_size += buff_size;
281                     } else {
282                         unk_alloc_size += buff_size;
283                     }
284                 }
285             }
286 
287             if (buff_size) {
288                 next = MM_GET_NEXT_BLK(cur);
289             } else {
290                 next = NULL;
291             }
292             cur = next;
293         }
294         reginfo = reginfo->next;
295     }
296 
297     print("TaskName                 Prio  StackSize  HeapAllocSize\r\n");
298 
299     /* Traversing all task */
300     for (listnode = g_kobj_list.task_head.next;
301          listnode != &g_kobj_list.task_head; listnode = listnode->next) {
302 
303         task = krhino_list_entry(listnode, ktask_t, task_stats_item);
304 
305         if (task->task_alloc_size != 0) {
306             print("%-24s %-5d %-10d %-10d\r\n",
307                   task->task_name, task->prio, (int)task->stack_size, (int)task->task_alloc_size);
308             task->task_alloc_size = 0;
309         }
310     }
311 #if (RHINO_CONFIG_MM_BLK > 0)
312     isr_alloc_size -= (RHINO_CONFIG_MM_TLF_BLK_SIZE + MM_ALIGN_UP(sizeof(mblk_pool_t)));
313 #endif
314     print("Allocated in ISR %d, Allocated by deleted task %d\r\n", (int)isr_alloc_size, (int)unk_alloc_size);
315 }
316 #else
dump_kmm_task_info(k_mm_head * mmhead)317 void dump_kmm_task_info(k_mm_head *mmhead)
318 {
319     print("need config RHINO_CONFIG_KOBJ_LIST > 0\r\n");
320 }
321 #endif
322 
dumpsys_mm_info_func(uint32_t mm_status)323 uint32_t dumpsys_mm_info_func(uint32_t mm_status)
324 {
325     cpu_cpsr_t flags_cpsr = 0;
326 
327     if (mm_status != KMM_ERROR_LOCKED) {
328         KMM_CRITICAL_ENTER(g_kmm_head, flags_cpsr);
329     } else {
330         print = printk;
331     }
332 
333     print("\r\n");
334     print("------------------------------- all memory blocks --------------------------------- \r\n");
335     print("g_kmm_head = %8x\r\n", (unsigned int)g_kmm_head);
336     dump_kmm_map(g_kmm_head);
337 
338     print("\r\n");
339     print("----------------------------- all free memory blocks ------------------------------ \r\n");
340     dump_kmm_free_map(g_kmm_head);
341 
342     print("\r\n");
343     print("--------------------------- memory allocation statistic --------------------------- \r\n");
344     dump_kmm_statistic_info(g_kmm_head);
345 
346     print("\r\n");
347     print("-------------------------------[kernel] heap size overview -------------------------------- \r\n");
348     debug_mm_overview(print);
349 
350 #if (RHINO_CONFIG_MM_BLK > 0)
351     print("\r\n");
352     print("--------------------------- mmblk allocation statistic ---------------------------- \r\n");
353     dump_kmm_mblk_info(g_kmm_head);
354 #endif
355 
356     print("\r\n");
357     print("--------------------------- task allocation statistic ----------------------------- \r\n");
358     dump_kmm_task_info(g_kmm_head);
359 
360     print("\r\n");
361     print("----------------------------------------------------------------------------------- \r\n");
362 
363     if (mm_status != KMM_ERROR_LOCKED) {
364         KMM_CRITICAL_EXIT(g_kmm_head, flags_cpsr);
365     }
366 
367     return RHINO_SUCCESS;
368 }
369 
dumpsys_mm_overview_func(uint32_t len)370 uint32_t dumpsys_mm_overview_func(uint32_t len)
371 {
372     cpu_cpsr_t flags_cpsr = 0;
373 
374     KMM_CRITICAL_ENTER(g_kmm_head, flags_cpsr);
375 
376     print("\r\n");
377     print("-------------------------------[kernel] heap size overview -------------------------------- \r\n");
378     debug_mm_overview(print);
379 
380 #if (RHINO_CONFIG_MM_BLK > 0)
381     print("\r\n");
382     print("--------------------------- mmblk allocation statistic ---------------------------- \r\n");
383     dump_kmm_mblk_info(g_kmm_head);
384 #endif
385 
386     print("\r\n");
387     print("--------------------------- task allocation statistic ----------------------------- \r\n");
388     dump_kmm_task_info(g_kmm_head);
389 
390     KMM_CRITICAL_EXIT(g_kmm_head, flags_cpsr);
391 
392     print("\r\n");
393     print("----------------------------------------------------------------------------------- \r\n");
394 
395     return RHINO_SUCCESS;
396 }
397 
398 
399 
dump_kmm_chk(k_mm_head * mmhead,uint8_t care_cnt)400 void dump_kmm_chk(k_mm_head *mmhead, uint8_t care_cnt)
401 {
402     k_mm_region_info_t *reginfo, *nextreg;
403     k_mm_list_t *next, *cur;
404 
405     if (!mmhead || care_cnt == 0) {
406         return;
407     }
408 
409     reginfo = mmhead->regioninfo;
410     while (reginfo) {
411         cur = MM_GET_THIS_BLK(reginfo);
412         while (cur) {
413             if (cur->trace_id == care_cnt) {
414                 print_block(cur);
415             } else if (care_cnt == MM_CHK) {
416                 check_block(cur);
417             }
418             if (MM_GET_BUF_SIZE(cur)) {
419                 next = MM_GET_NEXT_BLK(cur);
420             } else {
421                 next = NULL;
422             }
423             cur = next;
424         }
425         nextreg = reginfo->next;
426         reginfo = nextreg;
427     }
428 }
429 
dumpsys_mm_leakcheck(uint32_t call_cnt,int32_t query_index)430 uint32_t dumpsys_mm_leakcheck(uint32_t call_cnt, int32_t query_index)
431 {
432     cpu_cpsr_t flags_cpsr = 0;
433     KMM_CRITICAL_ENTER(g_kmm_head, flags_cpsr);
434 
435     if (query_index < 0) {
436         query_index = g_mmlk_cnt;
437         g_mmlk_cnt = (uint8_t)call_cnt;
438     } else if (query_index > g_mmlk_cnt) {
439         printf("query_index should be less than %d\r\n", g_mmlk_cnt);
440         return -1;
441     }
442     print("-----------------All new alloced blocks:----------------\r\n");
443     print("Blk_Addr    Stat     Len  Chk      Caller    Point\r\n");
444 
445     dump_kmm_chk(g_kmm_head, query_index);
446 
447     print("--------------New alloced blocks info ends.-------------\r\n");
448     print("\r\n");
449 
450     KMM_CRITICAL_EXIT(g_kmm_head, flags_cpsr);
451     return RHINO_SUCCESS;
452 }
453 
dumpsys_mm_header_check(void)454 void dumpsys_mm_header_check(void)
455 {
456     cpu_cpsr_t flags_cpsr = 0;
457     KMM_CRITICAL_ENTER(g_kmm_head, flags_cpsr);
458 
459     print("-----------------All error blocks:----------------\r\n");
460 
461     dump_kmm_chk(g_kmm_head, MM_CHK);
462     print("\r\n");
463 
464     KMM_CRITICAL_EXIT(g_kmm_head, flags_cpsr);
465 }
466 
467 #endif /* #if (RHINO_CONFIG_MM_TLF > 0) */
468 
469 #endif /* #if (RHINO_CONFIG_MM_DEBUG > 0) */
470 
471