1 /*
2 * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3 */
4
5 #if AOS_COMP_CLI
6 #include <string.h>
7 #include <stdio.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include "aos/cli.h"
11 #include "debug_api.h"
12
13 typedef struct {
14 char task_name[32];
15 uint32_t task_id;
16 uint32_t task_state;
17 uint32_t stack_size;
18 size_t free_size;
19 uint64_t time_total;
20 uint8_t task_prio;
21 char candidate;
22 #if (RHINO_CONFIG_CPU_NUM > 1)
23 uint8_t cpu_binded;
24 uint8_t cpu_num;
25 uint8_t cur_exc;
26 #endif
27 } dumpsys_task_info_t;
28
29
30 #define MM_LEAK_CHECK_ROUND_SCOND 10 * 1000
31 #define RHINO_BACKTRACE_DEPTH 10
32
33 ktimer_t g_mm_leak_check_timer;
34
dumpsys_task_func(char * buf,uint32_t len,int32_t detail)35 uint32_t dumpsys_task_func(char *buf, uint32_t len, int32_t detail)
36 {
37 kstat_t rst;
38 size_t free_size = 0;
39 uint64_t time_total = 0;
40 /* consistent with "task_stat_t" */
41 char *cpu_stat[] = { "ERROR", "RDY", "PEND", "SUS",
42 "PEND_SUS", "SLP", "SLP_SUS", "DELETED"
43 };
44 klist_t *taskhead = &g_kobj_list.task_head;
45 klist_t *taskend = taskhead;
46 klist_t *tmp;
47 ktask_t *task;
48 size_t corenum;
49 (void)corenum;
50
51 #if (RHINO_CONFIG_CPU_NUM > 1)
52 ktask_t *candidate[RHINO_CONFIG_CPU_NUM];
53 #else
54 ktask_t *candidate;
55 #endif
56 char yes = 'N';
57 int32_t taskstate = 0;
58 int32_t tasknum = 0;
59 int32_t taskindex = 0;
60
61 dumpsys_task_info_t *taskinfo;
62 dumpsys_task_info_t *taskinfoeach;
63
64 aos_cli_printf("-----------------------------------------------------------"
65 "---------------------\r\n");
66
67 krhino_sched_disable();
68
69 #if (RHINO_CONFIG_CPU_NUM > 1)
70 for (corenum = 0; corenum < RHINO_CONFIG_CPU_NUM; corenum++) {
71 preferred_cpu_ready_task_get(&g_ready_queue, corenum);
72 candidate[corenum] = g_preferred_ready_task[corenum];
73 }
74
75 #else
76 preferred_cpu_ready_task_get(&g_ready_queue, cpu_cur_get());
77 candidate = g_preferred_ready_task[cpu_cur_get()];
78 #endif
79
80 for (tmp = taskhead->next; tmp != taskend; tmp = tmp->next) {
81 tasknum ++;
82 }
83
84 taskinfo = malloc(tasknum * sizeof(dumpsys_task_info_t));
85 if (taskinfo == NULL) {
86 krhino_sched_enable();
87 return RHINO_NO_MEM;
88 }
89 memset(taskinfo, 0, tasknum * sizeof(dumpsys_task_info_t));
90
91 for (tmp = taskhead->next; tmp != taskend; tmp = tmp->next) {
92
93 char name_cut[19];
94 taskinfoeach = taskinfo + taskindex;
95 taskindex++;
96
97 task = krhino_list_entry(tmp, ktask_t, task_stats_item);
98 const name_t *task_name;
99 rst = krhino_task_stack_min_free(task, &free_size);
100
101 if (rst != RHINO_SUCCESS) {
102 free_size = 0;
103 }
104
105 #if (RHINO_CONFIG_SYS_STATS > 0)
106 time_total = task->task_time_total_run / 20;
107 #endif
108
109 if (task->task_name != NULL) {
110 task_name = task->task_name;
111 } else {
112 task_name = "anonym";
113 }
114 strncpy(taskinfoeach->task_name, task_name, sizeof(taskinfoeach->task_name) - 1);
115 taskinfoeach->task_id = task->task_id;
116
117 #if (RHINO_CONFIG_CPU_NUM > 1)
118 for (corenum = 0; corenum < RHINO_CONFIG_CPU_NUM; corenum++) {
119 if (candidate[corenum] == task) {
120 yes = 'Y';
121 } else {
122 yes = 'N';
123 }
124 }
125
126 #else
127 if (candidate == task) {
128 yes = 'Y';
129 } else {
130 yes = 'N';
131 }
132
133 #endif
134 taskstate = task->task_state >= sizeof(cpu_stat) / sizeof(cpu_stat[0])
135 ? 0
136 : task->task_state;
137 taskinfoeach->task_state = taskstate;
138 taskinfoeach->task_prio = task->prio;
139 taskinfoeach->stack_size = task->stack_size * sizeof(cpu_stack_t);
140 taskinfoeach->free_size = free_size * sizeof(cpu_stack_t);
141 taskinfoeach->time_total = time_total;
142 taskinfoeach->candidate = yes;
143 #if (RHINO_CONFIG_CPU_NUM > 1)
144 taskinfoeach->cpu_binded = task->cpu_binded;
145 taskinfoeach->cpu_num = task->cpu_num;
146 taskinfoeach->cur_exc = task->cur_exc;
147 #endif
148
149 /* if not support %-N.Ms,cut it manually */
150 if (strlen(task_name) > 18) {
151 memset(name_cut, 0, sizeof(name_cut));
152 memcpy(name_cut, task->task_name, 18);
153 task_name = name_cut;
154
155 strncpy(taskinfoeach->task_name, task_name, strlen(task_name));
156 }
157 }
158
159 krhino_sched_enable();
160
161 #if (RHINO_CONFIG_CPU_NUM > 1)
162 aos_cli_printf("Name ID State Prio StackSize MinFreesize "
163 "Runtime Candidate cpu_binded cpu_num cur_exc\r\n");
164 #else
165 aos_cli_printf("Name ID State Prio StackSize MinFreesize "
166 "Runtime Candidate\r\n");
167 #endif
168
169 aos_cli_printf("-----------------------------------------------------------"
170 "---------------------\r\n");
171
172 for (taskindex = 0; taskindex < tasknum; taskindex++) {
173 taskinfoeach = taskinfo + taskindex;
174
175 #if (RHINO_CONFIG_CPU_NUM > 1)
176 aos_cli_printf("%-19s%-6d%-9s%-5d%-10d%-12u%-9u %-11c%-10d%-10d%-10d\r\n",
177 taskinfoeach->task_name, taskinfoeach->task_id, cpu_stat[taskinfoeach->task_state],
178 taskinfoeach->task_prio, taskinfoeach->stack_size,
179 taskinfoeach->free_size, (uint32_t)taskinfoeach->time_total,
180 taskinfoeach->candidate, taskinfoeach->cpu_binded,
181 taskinfoeach->cpu_num, taskinfoeach->cur_exc);
182 #else
183 aos_cli_printf("%-19s%-6d%-9s%-5d%-10d%-12u%-9u %-11c \r\n",
184 taskinfoeach->task_name, taskinfoeach->task_id, cpu_stat[taskinfoeach->task_state],
185 taskinfoeach->task_prio, (int32_t)taskinfoeach->stack_size,
186 taskinfoeach->free_size, (uint32_t)taskinfoeach->time_total,
187 taskinfoeach->candidate);
188 #endif
189 }
190
191 free(taskinfo);
192 aos_cli_printf("-----------------------------------------------------------"
193 "---------------------\r\n");
194
195 return RHINO_SUCCESS;
196 }
197
task_cmd(char * buf,int32_t len,int32_t argc,char ** argv)198 static void task_cmd(char *buf, int32_t len, int32_t argc, char **argv)
199 {
200 dumpsys_task_func(NULL, 0, 1);
201 }
202
dumpsys_cmd(char * buf,int len,int argc,char ** argv)203 static void dumpsys_cmd(char *buf, int len, int argc, char **argv)
204 {
205 if (argc != 2) {
206 aos_cli_printf("dumpsys help:\r\n");
207 aos_cli_printf("dumpsys mm : show kernel memory status.\r\n");
208 #if (RHINO_CONFIG_MM_DEBUG > 0)
209 aos_cli_printf("dumpsys mm_info : show kernel memory has alloced.\r\n");
210 #endif
211 return;
212 }
213
214 if (0 == strcmp(argv[1], "mm")) {
215 debug_mm_overview(aos_cli_printf);
216 }
217 #if (RHINO_CONFIG_MM_DEBUG > 0)
218 else if (0 == strcmp(argv[1], "mm_info")) {
219 dumpsys_mm_info_func(0);
220 }
221 #endif
222 }
223
224
task_bt(char * buf,int32_t len,int32_t argc,char ** argv)225 static void task_bt(char *buf, int32_t len, int32_t argc, char **argv)
226 {
227 uint32_t task_id;
228 ktask_t *task;
229
230 switch (argc) {
231 case 2:
232 task_id = (uint32_t)strtoul(argv[1], 0, 10);
233 break;
234 default:
235 aos_cli_printf("task_bt <taskid>\r\n"
236 "taskid : task id\r\n");
237 return;
238 }
239
240 task = debug_task_find_by_id(task_id);
241 if (task == NULL) {
242 aos_cli_printf("taskid %d not exist\r\n", task_id);
243 return;
244 }
245
246 if (((ktask_t *)task)->task_name) {
247 aos_cli_printf("task name : %s\r\n", ((ktask_t *)task)->task_name);
248 debug_backtrace_task((char *)(((ktask_t *)task)->task_name), aos_cli_printf);
249 }
250 }
251
252
task_btn(char * buf,int32_t len,int32_t argc,char ** argv)253 static void task_btn(char *buf, int32_t len, int32_t argc, char **argv)
254 {
255 if (argc == 2) {
256 debug_backtrace_task(argv[1], aos_cli_printf);
257 } else {
258 aos_cli_printf("task_btn <taskname>\r\n");
259 }
260 }
261
262 #if (RHINO_CONFIG_MM_DEBUG > 0)
mem_leak(char * buf,int32_t len,int32_t argc,char ** argv)263 static void mem_leak(char *buf, int32_t len, int32_t argc, char **argv)
264 {
265 static int call_cnt = 0;
266 int query_index = -1;
267
268 if (call_cnt == 0) {
269 aos_cli_printf("memory leak check start.\r\n");
270 }
271 if (argc == 2) {
272 query_index = strtoul(argv[1], NULL, 0);
273 if (query_index > call_cnt) {
274 query_index = -1;
275 }
276 } else {
277 call_cnt++;
278 printf("\r\nAdd tag %d when malloc\r\n", call_cnt);
279 }
280
281 dumpsys_mm_leakcheck(call_cnt, query_index);
282 }
283 #endif
284
285 static const struct cli_command dumpsys_cli_cmd[] = {
286 { "tasklist", "list all thread info", task_cmd },
287 { "dumpsys", "dump system info", dumpsys_cmd },
288 { "taskbt", "list thread backtrace", task_bt },
289 { "taskbtn", "list thread backtrace by name", task_btn },
290 #if (RHINO_CONFIG_MM_DEBUG > 0)
291 { "mmlk", "memory leak info", mem_leak },
292 #endif
293 };
294
295
debug_dumpsys_cmds_register(void)296 void debug_dumpsys_cmds_register(void)
297 {
298 int32_t ret;
299
300 ret = aos_cli_register_commands(dumpsys_cli_cmd, sizeof(dumpsys_cli_cmd) / sizeof(struct cli_command));
301 if (ret) {
302 printf("%s %d failed, ret = %d\r\n", __func__, __LINE__, ret);
303 }
304 }
305 #endif /* AOS_COMP_CLI */
306