1 /*
2 * Copyright (C) 2015-2019 Alibaba Group Holding Limited
3 */
4
5 #if AOS_COMP_CLI
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <fcntl.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
13
14 #include "k_api.h"
15 #include "debug_api.h"
16 #include "aos/cli.h"
17
18 #if (RHINO_CONFIG_SYS_STATS > 0)
19
20 #define CPU_USAGE_DEFAULT_PRI 7
21 #define CPU_USAGE_STACK 4048
22
23 ktask_t *cpuusage_task;
24 int sync_mode = 0;
25 ksem_t sync_sem;
26
27 struct statistics_param {
28 uint32_t period;
29 uint32_t total;
30 uint32_t record_to_file;
31 };
32
33
34 typedef struct {
35 char task_name[32];
36 uint32_t task_cpu_usage;
37 } task_cpuusage_info;
38
39 static uint32_t task_cpu_usage_period = 0;
40
debug_task_cpu_usage_stats(void)41 void debug_task_cpu_usage_stats(void)
42 {
43 uint32_t i;
44 klist_t *taskhead = &g_kobj_list.task_head;
45 klist_t *taskend = taskhead;
46 klist_t *tmp;
47 ktask_t *task;
48 lr_timer_t cur_time;
49 lr_timer_t exec_time;
50
51 static lr_timer_t stats_start = 0;
52 lr_timer_t stats_end;
53
54 (void)i; /* to avoid compiler warning */
55
56 CPSR_ALLOC();
57 RHINO_CRITICAL_ENTER();
58 #if (RHINO_CONFIG_CPU_NUM > 1)
59 for (i = 0; i < RHINO_CONFIG_CPU_NUM; i++) {
60 cur_time = (lr_timer_t)LR_COUNT_GET();
61 exec_time = cur_time - g_active_task[i]->task_time_start;
62
63 g_active_task[i]->task_time_total_run += (sys_time_t)exec_time;
64 g_active_task[i]->task_time_start = cur_time;
65 }
66 #else
67 cur_time = (lr_timer_t)LR_COUNT_GET();
68 exec_time = cur_time - g_active_task[0]->task_time_start;
69
70 g_active_task[0]->task_time_total_run += (sys_time_t)exec_time;
71 g_active_task[0]->task_time_start = cur_time;
72 #endif
73
74 for (tmp = taskhead->next; tmp != taskend; tmp = tmp->next) {
75 task = krhino_list_entry(tmp, ktask_t, task_stats_item);
76 task->task_exec_time = task->task_time_total_run -
77 task->task_time_total_run_prev;
78 task->task_time_total_run_prev = task->task_time_total_run;
79 }
80 RHINO_CRITICAL_EXIT();
81
82 stats_end = (lr_timer_t)LR_COUNT_GET();
83 task_cpu_usage_period = stats_end - stats_start;
84 stats_start = stats_end;
85 }
86
debug_total_cpu_usage_show(struct cpuusage_data * cpuusage_record,int32_t record_len,int32_t index)87 void debug_total_cpu_usage_show(struct cpuusage_data * cpuusage_record, int32_t record_len,int32_t index)
88 {
89 uint32_t i, j;
90 klist_t *taskhead = &g_kobj_list.task_head;
91 klist_t *taskend = taskhead;
92 klist_t *tmp;
93 ktask_t *task;
94 const char *task_name;
95 lr_timer_t task_cpu_usage;
96 uint32_t total_cpu_usage[RHINO_CONFIG_CPU_NUM];
97
98 uint32_t tasknum = 0;
99 task_cpuusage_info *taskinfo;
100 task_cpuusage_info *taskinfoeach;
101
102 if (cpuusage_record == NULL) {
103 aos_cli_printf("-----------------------\r\n");
104 }
105
106 #if (RHINO_CONFIG_CPU_NUM > 1)
107 for (i = 0; i < RHINO_CONFIG_CPU_NUM; i++) {
108 total_cpu_usage[i] = debug_total_cpu_usage_get(i);
109 if (cpuusage_record != NULL) {
110 if (cpuusage_record[i].taskname[0] == 0) {
111 snprintf((char *)cpuusage_record[i].taskname, CPU_USAGE_MAX_TASKNAME_LEN, "CPU%d", (int)i);
112 }
113 cpuusage_record[i].cpuusage[index] = (float)total_cpu_usage[i] / 100;
114 } else {
115 aos_cli_printf("CPU%d usage :%3d.%02d%% \r\n", (int)i, (int)total_cpu_usage[i] / 100,
116 (int)total_cpu_usage[i] % 100);
117 }
118 }
119 #else
120 total_cpu_usage[0] = debug_total_cpu_usage_get(0);
121 if (cpuusage_record != NULL) {
122 if (cpuusage_record[0].taskname[0] == 0) {
123 snprintf(cpuusage_record[0].taskname, CPU_USAGE_MAX_TASKNAME_LEN, "CPU");
124 }
125 cpuusage_record[0].cpuusage[index] = (float)total_cpu_usage[0] / 100;
126 } else {
127 aos_cli_printf("CPU usage :%3d.%02d%% \r\n", (int)total_cpu_usage[0] / 100,
128 (int)total_cpu_usage[0] % 100);
129 }
130 #endif
131
132 if (cpuusage_record == NULL) {
133 aos_cli_printf("---------------------------\r\n");
134 aos_cli_printf("Name %%CPU\r\n");
135 aos_cli_printf("---------------------------\r\n");
136 }
137
138 krhino_sched_disable();
139 for (tmp = taskhead->next; tmp != taskend; tmp = tmp->next) {
140 tasknum ++;
141 }
142 taskinfo = krhino_mm_alloc(tasknum * sizeof(task_cpuusage_info));
143 if (taskinfo == NULL) {
144 krhino_sched_enable();
145 return;
146 }
147 memset(taskinfo, 0, tasknum * sizeof(task_cpuusage_info));
148
149 taskinfoeach = taskinfo;
150
151 for (tmp = taskhead->next; tmp != taskend; tmp = tmp->next) {
152 task = krhino_list_entry(tmp, ktask_t, task_stats_item);
153
154 if (task->task_name != NULL) {
155 task_name = task->task_name;
156 } else {
157 task_name = "anonym";
158 }
159 taskinfoeach->task_cpu_usage = debug_task_cpu_usage_get(task);
160 strncpy(taskinfoeach->task_name, task_name, sizeof(taskinfoeach->task_name) - 1);
161 taskinfoeach++;
162 }
163 krhino_sched_enable();
164
165 for (i = 0; i < tasknum; i++) {
166 taskinfoeach = taskinfo + i;
167 task_name = taskinfoeach->task_name;
168 task_cpu_usage = taskinfoeach->task_cpu_usage;
169
170 if (cpuusage_record != NULL) {
171 for (j = RHINO_CONFIG_CPU_NUM; j < record_len; j++) {
172 if (cpuusage_record[j].taskname[0] == 0) {
173 if (strlen(taskinfoeach->task_name) > CPU_USAGE_MAX_TASKNAME_LEN) {
174 aos_cli_printf("task name is longer than CPU_USAGE_MAX_TASKNAME_LEN\r\n");
175 break;
176 }
177 memcpy(cpuusage_record[j].taskname, taskinfoeach->task_name, strlen(taskinfoeach->task_name));
178 }
179
180 if (strcmp((char *)cpuusage_record[j].taskname, taskinfoeach->task_name) != 0) {
181 continue;
182 }
183
184 cpuusage_record[j].cpuusage[index] = (float)task_cpu_usage / 100;
185 break;
186 }
187 } else {
188 aos_cli_printf("%-19s%3d.%02d\r\n", task_name, (int)task_cpu_usage / 100,
189 (int)task_cpu_usage % 100);
190 }
191 }
192
193 krhino_mm_free(taskinfo);
194
195 if (cpuusage_record == NULL) {
196 aos_cli_printf("---------------------------\r\n");
197 }
198 }
199
200 /* one in ten thousand */
debug_task_cpu_usage_get(ktask_t * task)201 uint32_t debug_task_cpu_usage_get(ktask_t *task)
202 {
203 uint32_t task_cpu_usage = 0;
204
205 if (task_cpu_usage_period == 0) {
206 return 0;
207 }
208
209 task_cpu_usage = (uint64_t)(task->task_exec_time) * 10000 / task_cpu_usage_period;
210 if (task_cpu_usage > 10000) {
211 task_cpu_usage = 10000;
212 }
213
214 return task_cpu_usage;
215 }
216
217 /* one in ten thousand */
debug_total_cpu_usage_get(uint32_t cpuid)218 uint32_t debug_total_cpu_usage_get(uint32_t cpuid)
219 {
220 uint32_t total_cpu_usage = 0;
221 total_cpu_usage = 10000 - debug_task_cpu_usage_get(&g_idle_task[cpuid]);
222 return total_cpu_usage;
223 }
224
cpuusage_statistics(void * arg)225 void cpuusage_statistics(void *arg)
226 {
227 ktask_t *cur_task;
228 kstat_t status;
229 uint32_t period = 0;
230 uint32_t total = 0;
231 int32_t stat_count = 0;
232 int32_t index = 0;
233 struct statistics_param *param = (struct statistics_param *)arg;
234
235 /* used for record to file */
236 int fd = -1;
237 int i;
238
239 #if DEBUG_CPUUSAGE_RECODE_TO_FILE_ENABLE
240 int j;
241 int ret = -1;
242 char buf[CPU_USAGE_MAX_TASKNAME_LEN + 1];
243 #endif
244 struct cpuusage_data cpuusage_record[DEBUG_CPUUSAGE_MAX_TASK];
245
246 period = param->period;
247 total = param->total;
248 stat_count = total / period;
249
250 #if DEBUG_CPUUSAGE_RECODE_TO_FILE_ENABLE
251 if (param->record_to_file == 1) {
252 for (i = 0; i < DEBUG_CPUUSAGE_MAX_TASK; i++) {
253 memset(cpuusage_record[i].taskname, 0, CPU_USAGE_MAX_TASKNAME_LEN);
254 cpuusage_record[i].cpuusage = krhino_mm_alloc(stat_count * sizeof(float));
255 memset(cpuusage_record[i].cpuusage, 0, stat_count * sizeof(float));
256 }
257 }
258 #endif
259
260 aos_cli_printf("Start to statistics CPU utilization, period %d ms\r\n", (int)period);
261 if (total != 0) {
262 aos_cli_printf("Total statistical time %d ms\r\n", (int)total);
263 }
264
265 debug_task_cpu_usage_stats();
266 status = krhino_task_sleep(period * RHINO_CONFIG_TICKS_PER_SECOND / 1000);
267 if (status == RHINO_TASK_CANCELED) {
268 //krhino_task_cancel_clr();
269 }
270
271 /* If total is 0, it will run continuously */
272 while ((index < stat_count) || (total == 0)) {
273 if (krhino_task_cancel_chk() == RHINO_TRUE) {
274 cur_task = krhino_cur_task_get();
275 krhino_task_dyn_del(cur_task);
276 }
277
278 debug_task_cpu_usage_stats();
279 status = krhino_task_sleep(period * RHINO_CONFIG_TICKS_PER_SECOND / 1000);
280 if (status == RHINO_TASK_CANCELED) {
281 //krhino_task_cancel_clr();
282 break;
283 } else {
284 if (param->record_to_file == 1) {
285 #if DEBUG_CPUUSAGE_RECODE_TO_FILE_ENABLE
286 debug_total_cpu_usage_show(cpuusage_record, DEBUG_CPUUSAGE_MAX_TASK, index);
287 #endif
288 } else {
289 debug_total_cpu_usage_show(NULL, 0, 0);
290 }
291
292 index++;
293 }
294 }
295
296 #if DEBUG_CPUUSAGE_RECODE_TO_FILE_ENABLE
297 if (param->record_to_file == 1) {
298 fd = open(DEBUG_CPUUSAGE_FILE_NAME, O_CREAT | O_WRONLY | O_TRUNC, 0666);
299 if (fd < 0) {
300 aos_cli_printf("file open error %s, %d\r\n", __FILE__, __LINE__);
301 }
302
303 for (i = 0; i < DEBUG_CPUUSAGE_MAX_TASK; i++) {
304 if (cpuusage_record[i].taskname[0] == 0) {
305 break;
306 }
307 if (fd >= 0) {
308 ret = snprintf(buf, sizeof(buf), "%-30s", cpuusage_record[i].taskname);
309 if (ret > 0) {
310 write(fd, buf, ret);
311 }
312 } else {
313 aos_cli_printf("%-30s", cpuusage_record[i].taskname);
314 }
315 for (j = 0; j < stat_count; j++) {
316 if (fd >= 0) {
317 ret = snprintf(buf, sizeof(buf), "%7.2f", cpuusage_record[i].cpuusage[j]);
318 if (ret > 0) {
319 write(fd, buf, ret);
320 }
321 } else {
322 aos_cli_printf("%7.2f", cpuusage_record[i].cpuusage[j]);
323 }
324 }
325 if (fd >= 0) {
326 write(fd, "\r\n", sizeof("\r\n"));
327 } else {
328 aos_cli_printf("\r\n");
329 }
330 }
331
332 if (fd >= 0) {
333 close(fd);
334 }
335
336 for (i = 0; i < DEBUG_CPUUSAGE_MAX_TASK; i++) {
337 krhino_mm_free(cpuusage_record[i].cpuusage);
338 }
339 }
340 #endif
341
342 printf("====CPU utilization statistics end====\r\n");
343 if (sync_mode == 1) {
344 krhino_sem_give(&sync_sem);
345 }
346 }
347
cpuusage_cmd(char * buf,int32_t len,int32_t argc,char ** argv)348 void cpuusage_cmd(char *buf, int32_t len, int32_t argc, char **argv)
349 {
350 static struct statistics_param param = {.period = 0, .total = 0};
351
352 ktask_t *task_tmp = NULL;
353 int argv_index = 1;
354
355 memset(¶m, 0, sizeof(param));
356
357 while (argv_index < argc) {
358 if (0 == strcmp(argv[argv_index], "-d")) {
359 argv_index++;
360 if (argv_index < argc) {
361 param.period = atoi(argv[argv_index]);
362 if (param.period == 0) {
363 aos_cli_printf("warning -d parma is error\r\n");
364 } else {
365 argv_index++;
366 }
367 }
368 } else if (0 == strcmp(argv[argv_index], "-t")) {
369 argv_index++;
370 if (argv_index < argc) {
371 param.total = atoi(argv[argv_index]);
372 if (param.total == 0) {
373 aos_cli_printf("warning -t parma is error\r\n");
374 } else {
375 argv_index++;
376 }
377 }
378 } else if (0 == strcmp(argv[argv_index], "-f")) {
379 param.record_to_file = 1;
380 argv_index++;
381 } else if (0 == strcmp(argv[argv_index], "-e")) {
382 if (cpuusage_task != NULL) {
383 krhino_task_cancel(cpuusage_task);
384 }
385 cpuusage_task = NULL;
386 return;
387 } else if (0 == strcmp(argv[argv_index], "-s")) {
388 if (sync_mode == 0) {
389 if ((krhino_sem_create(&sync_sem, "cpuusage_sync", 0)) != RHINO_SUCCESS) {
390 aos_cli_printf("warning -s parma is error\r\n");
391 continue;
392 }
393 argv_index++;
394 sync_mode = 1;
395 }
396 } else {
397 /* unrecognized parameters */
398 argv_index++;
399 }
400 }
401
402 if (param.period == 0) {
403 param.period = 1000;
404 aos_cli_printf("use default param: period %dms\r\n", param.period);
405 }
406
407 if ((param.record_to_file == 1) && (param.total == 0)) {
408 param.total = 30000;
409 aos_cli_printf("use default param: total %dms\r\n", param.total);
410 }
411
412 task_tmp = debug_task_find("cpuusage");
413 if (task_tmp != NULL) {
414 return;
415 }
416
417 krhino_task_dyn_create(&cpuusage_task, "cpuusage", (void *)¶m, (uint8_t)CPU_USAGE_DEFAULT_PRI, 0, CPU_USAGE_STACK,
418 cpuusage_statistics, 1);
419
420 if (sync_mode == 1) {
421 krhino_sem_take(&sync_sem, RHINO_WAIT_FOREVER);
422
423 krhino_sem_del(&sync_sem);
424 sync_mode = 0;
425 }
426 }
427
428 static const struct cli_command dumpsys_cpuusage_cmd[] = {
429 {"cpuusage", "show cpu usage", cpuusage_cmd},
430 };
431
debug_cpuusage_cmds_register(void)432 void debug_cpuusage_cmds_register(void)
433 {
434 int32_t ret;
435
436 ret = aos_cli_register_commands(dumpsys_cpuusage_cmd, sizeof(dumpsys_cpuusage_cmd) / sizeof(struct cli_command));
437 if (ret) {
438 printf("%s %d failed, ret = %d\r\n", __func__, __LINE__, ret);
439 }
440 }
441
442 #endif /* #if (RHINO_CONFIG_SYS_STATS > 0) */
443 #endif /* AOS_COMP_CLI */
444