diff -drupN a/tools/vm/slabinfo.c b/tools/vm/slabinfo.c --- a/tools/vm/slabinfo.c 2018-08-06 17:23:04.000000000 +0300 +++ b/tools/vm/slabinfo.c 2022-06-12 05:28:14.000000000 +0300 @@ -75,6 +75,9 @@ int show_inverted; int show_single_ref; int show_totals; int sort_size; +int sort_func; +int sort_by_size; +int sort_by_char; int sort_active; int set_debug; int show_ops; @@ -122,7 +125,9 @@ static void usage(void) "-o|--ops Show kmem_cache_ops\n" "-s|--shrink Shrink slabs\n" "-r|--report Detailed report on single slabs\n" - "-S|--Size Sort by size\n" + "-S|--Size Sort slab by size\n" + "-F|--Func Sort func by size\n" + "-C|--Char Sort func by first character of func\n" "-t|--tracking Show alloc/free information\n" "-T|--Totals Show summary information\n" "-v|--validate Validate slabs\n" @@ -1337,6 +1342,8 @@ struct option opts[] = { { "shrink", no_argument, NULL, 's' }, { "report", no_argument, NULL, 'r' }, { "Size", no_argument, NULL, 'S'}, + { "Func", no_argument, NULL, 'F'}, + { "Char", no_argument, NULL, 'C'}, { "tracking", no_argument, NULL, 't'}, { "Totals", no_argument, NULL, 'T'}, { "validate", no_argument, NULL, 'v' }, @@ -1349,6 +1356,256 @@ struct option opts[] = { { NULL, 0, NULL, 0 } }; +/* + * Output format: + * Total_size slab_type object_size objects slab_size alloc_calls_info + * */ +struct slab_func_info{ + char slab_name[64]; //slab type + int slab_total_size; //total slab size alloc by func + int slab_object_size; //object size + int slab_size; //slab size + int slab_cnt; //objects num + char *slab_alloc_info; //slab alloc func info + struct slab_func_info *pNext; +}; + +static void swap_slab_func_info(struct slab_func_info *A, struct slab_func_info *B) +{ + char slab_name[64]; + int slab_total_size; + int slab_object_size; + int slab_size; + int slab_cnt; + char *slab_alloc_info = NULL; + + slab_total_size = (A)->slab_total_size; + (A)->slab_total_size = (B)->slab_total_size; + (B)->slab_total_size = slab_total_size; + + slab_object_size = (A)->slab_object_size; + (A)->slab_object_size = (B)->slab_object_size; + (B)->slab_object_size = slab_object_size; + + slab_size = (A)->slab_size; + (A)->slab_size = (B)->slab_size; + (B)->slab_size = slab_size; + + slab_cnt = (A)->slab_cnt; + (A)->slab_cnt = (B)->slab_cnt; + (B)->slab_cnt = slab_cnt; + + strcpy(slab_name, (A)->slab_name); + strcpy((A)->slab_name, (B)->slab_name); + strcpy((B)->slab_name, slab_name); + + slab_alloc_info = (A)->slab_alloc_info; + (A)->slab_alloc_info = (B)->slab_alloc_info; + (B)->slab_alloc_info = slab_alloc_info; +} + +//#define SAVE_RESULT_FILE + +static void sort_func_by_size(struct slab_func_info *info_head, FILE *fp) +{ + struct slab_func_info *info_p = NULL; + struct slab_func_info *tmp_p = NULL; + struct slab_func_info *tgt_p = NULL; + int total_size = 0; + + info_p = info_head; + for (; info_p != NULL; info_p = info_p->pNext) { + total_size = info_p->slab_total_size; + tgt_p = info_p; + for (tmp_p = info_p->pNext; tmp_p != NULL; tmp_p = tmp_p->pNext) { + if (total_size < tmp_p->slab_total_size) { + total_size = tmp_p->slab_total_size; + tgt_p = tmp_p; + } + } + + printf("%-12d %-24s %-9d %-7d %-10d %s\n", tgt_p->slab_total_size, + tgt_p->slab_name, tgt_p->slab_object_size, tgt_p->slab_cnt, tgt_p->slab_size, tgt_p->slab_alloc_info); +#ifdef SAVE_RESULT_FILE + fprintf(fp, "%-12d %-24s %-10d %-7d %-10d %s\n", tgt_p->slab_total_size, + tgt_p->slab_name, tgt_p->slab_size, tgt_p->slab_cnt, tgt_p->slab_object_size, tgt_p->slab_alloc_info); +#endif + + swap_slab_func_info(tgt_p, info_p); + } +} + +static void sort_func_by_char(struct slab_func_info *info_head, FILE *fp) +{ + int i = 0, j = 0; + int had_sort_num = 0; + char *func_char_p = NULL; + struct slab_func_info *info_p = NULL; + struct slab_func_info *had_sort_p = NULL; + char *func_first_char = "abcdefghijklmnopqrstuvwxyzADCDEFGHIJKLMNOPQRSTUVWXYZ_<"; + int func_char_len = strlen(func_first_char); + + for (i = 0; i < func_char_len; i++, func_first_char++) { + info_p = info_head; + for (j = 0; j < had_sort_num; j++) + info_p = info_p->pNext; + had_sort_p = info_p; + for (; info_p != NULL; info_p = info_p->pNext) { + if (!strncmp(info_p->slab_alloc_info, func_first_char, 1)) { + swap_slab_func_info(had_sort_p, info_p); + + printf("%-12d %-24s %-9d %-7d %-10d %s\n", had_sort_p->slab_total_size, had_sort_p->slab_name, + had_sort_p->slab_object_size, had_sort_p->slab_cnt, had_sort_p->slab_size, had_sort_p->slab_alloc_info); +#ifdef SAVE_RESULT_FILE + fprintf(fp, "%-12d %-24s %-9d %-7d %-10d %s\n", had_sort_p->slab_total_size, had_sort_p->slab_name, + had_sort_p->slab_object_size, had_sort_p->slab_cnt, had_sort_p->slab_size, had_sort_p->slab_alloc_info); +#endif + + had_sort_p = had_sort_p->pNext; + had_sort_num++; + } + } + } +} + +static int sort_and_show_func(void) +{ + FILE *fp = NULL; + FILE *fp_output = NULL; + char *str_p = NULL; + struct slabinfo *s = NULL; + char slab_name[64]; + char str_one_line[1024]; + int slab_size = 0; + int object_size = 0; + struct slab_func_info *info_head = NULL; + struct slab_func_info *info_p = NULL; + + info_head = (struct slab_func_info *)malloc(sizeof(struct slab_func_info)); + info_head->pNext = NULL; + info_p = info_head; + +#ifdef SAVE_RESULT_FILE + system("rm /tmp/slab_func_info > /dev/null 2>&1"); +#endif + /* collect alloc_calls messages and save them in tempfile*/ + fp = fopen("/tmp/tempfile", "arw+"); + if (fp == NULL) { + printf("open %s file fail!\n", "/tmp/tempfile"); + return -1; + } + for (s = slabinfo; s < slabinfo + slabs; s++) { + if (read_slab_obj(s, "alloc_calls")) { + fprintf(fp, "slabname: %s, object_size: %d, slab_size: %d\n", + s->name, s->object_size, s->slab_size); + fwrite(buffer, 1, strlen(buffer), fp); + } + } + + rewind(fp); + while (!feof(fp)) { + fgets(str_one_line, 1024, fp); + if (strlen(str_one_line) == 0) + break; + + if (!strncmp(str_one_line, "slabname", 8)) { /*get one slab type info*/ + /* format: slabname: %s, object_size: %d, slab_size: %d */ + str_p = NULL; + str_p = strtok(str_one_line, " "); + str_p = strtok(NULL, ","); + strcpy(slab_name, str_p); /*get slab type*/ + str_p = strtok(NULL, " "); + str_p = strtok(NULL, ","); + object_size = atoi(str_p); /*get object size*/ + str_p = strtok(NULL, " "); + str_p = strtok(NULL, " "); + slab_size = atoi(str_p); /*get slab size*/ + } else if (!strncmp(str_one_line, "No data", 7)) { + /*some of the loss parts*/ + continue; + } else if (strlen(str_one_line) < 16) { // wait for fix + continue; + } else { + /*one slab object one time*/ + if (info_head->pNext == NULL) { + info_p = info_head; + info_head->pNext = (struct slab_func_info *)malloc(sizeof(struct slab_func_info)); + } else { + info_p->pNext = (struct slab_func_info *)malloc(sizeof(struct slab_func_info)); + if (info_p->pNext == NULL) { + printf("In %s line %d: malloc fail!\n", __func__, __LINE__); + fclose(fp); + return -1; + } + info_p = info_p->pNext; + } + strcpy(info_p->slab_name, slab_name); + info_p->slab_object_size = object_size; + info_p->slab_size = slab_size; + /*format: objs alloc_func_info*/ + str_p = NULL; + str_p = strtok(str_one_line, " "); + info_p->slab_cnt = atoi(str_p); /*get objests num*/ + info_p->slab_total_size = info_p->slab_object_size * info_p->slab_cnt; + str_p = strtok(NULL, " "); /*get alloc func info*/ + info_p->slab_alloc_info = (char *)malloc(strlen(str_p) + 4); + //info_p->slab_alloc_info = (char *)malloc(strlen(str_p) + 1); //malloc may fail? + if (info_p->slab_alloc_info == NULL) { + printf("In %s line %d: malloc fail!\n", __func__, __LINE__); + fclose(fp); + return -1; + } + strcpy(info_p->slab_alloc_info, str_p); +#if 0 + printf("In %d line %d: alloc_info = %s\n", __func__, __LINE__, info_p->slab_alloc_info); + printf("In %d line %d: total_size= %d, slab_name %s, alloc_info %s\n", __func__, __LINE__, + info_p->slab_total_size, info_p->slab_name, info_p->slab_alloc_info); +#endif + } + } + +#ifdef SAVE_RESULT_FILE + fp_output = fopen("/tmp/slab_func_info", "arw+"); + if (fp_output == NULL) { + printf("open %s file fail!\n", "/data/slab_func_info"); + fclose(fp); + return -1; + } + fprintf(fp_output, "Total(byte) Slab_type Obj_size Objs Slab_size Alloc_func\n"); +#endif + + printf("Total(byte) Slab_type Obj_size Objs Slab_size Alloc_func\n"); + if (sort_by_size) { + /*sort by size*/ + sort_func_by_size(info_head, fp_output); + } else if (sort_func_by_char) { + /*sort by the first character of alloc func name*/ + sort_func_by_char(info_head, fp_output); + } + + /*free sources!*/ + /*must free malloc buffer*/ + info_p = info_head; + for (; info_p != NULL; info_p = info_p->pNext) { + if (info_p->slab_alloc_info != NULL) { + free(info_p->slab_alloc_info); + info_p->slab_alloc_info = NULL; + } + if (info_p != NULL) { + free(info_p); + // info_p = NULL; /*segmemtation fault!*/ + } + } + + fclose(fp); +#ifdef SAVE_RESULT_FILE + fclose(fp_output); +#endif + system("rm /tmp/tempfile > /dev/null 2>&1"); + + return 1; +} + int main(int argc, char *argv[]) { int c; @@ -1357,7 +1614,7 @@ int main(int argc, char *argv[]) page_size = getpagesize(); - while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTSN:LXB", + while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTSFCN:LXB", opts, NULL)) != -1) switch (c) { case '1': @@ -1419,6 +1676,16 @@ int main(int argc, char *argv[]) case 'S': sort_size = 1; break; + case 'F': + sort_size = 1; + sort_func = 1; + sort_by_size = 1; + break; + case 'C': + sort_size = 1; + sort_func = 1; + sort_by_char = 1; + break; case 'N': if (optarg) { output_lines = atoi(optarg); @@ -1463,6 +1730,11 @@ int main(int argc, char *argv[]) xtotals(); } else if (show_totals) { totals(); + } else if (sort_func) { + link_slabs(); + rename_slabs(); + sort_slabs(); + sort_and_show_func(); } else { link_slabs(); rename_slabs();