Extend page_owner_sort filtering and culling features to work with module names as well. The top most module is used. Fix regex error handling, failure labels were one step shifted. Signed-off-by: Petr Malat <oss@xxxxxxxxx> --- tools/mm/page_owner_sort.c | 96 ++++++++++++++++++++++++++++++-------- 1 file changed, 76 insertions(+), 20 deletions(-) diff --git a/tools/mm/page_owner_sort.c b/tools/mm/page_owner_sort.c index e1f264444342..a4d4d8528997 100644 --- a/tools/mm/page_owner_sort.c +++ b/tools/mm/page_owner_sort.c @@ -27,11 +27,13 @@ #define true 1 #define false 0 #define TASK_COMM_LEN 16 +#define MODULE_NAME_LEN 64 struct block_list { char *txt; char *comm; // task command name char *stacktrace; + char *module; __u64 ts_nsec; int len; int num; @@ -43,14 +45,16 @@ struct block_list { enum FILTER_BIT { FILTER_PID = 1<<1, FILTER_TGID = 1<<2, - FILTER_COMM = 1<<3 + FILTER_COMM = 1<<3, + FILTER_MODULE = 1<<4, }; enum CULL_BIT { CULL_PID = 1<<1, CULL_TGID = 1<<2, CULL_COMM = 1<<3, CULL_STACKTRACE = 1<<4, - CULL_ALLOCATOR = 1<<5 + CULL_ALLOCATOR = 1<<5, + CULL_MODULE = 1<<6, }; enum ALLOCATOR_BIT { ALLOCATOR_CMA = 1<<1, @@ -60,7 +64,8 @@ enum ALLOCATOR_BIT { }; enum ARG_TYPE { ARG_TXT, ARG_COMM, ARG_STACKTRACE, ARG_ALLOC_TS, ARG_CULL_TIME, - ARG_PAGE_NUM, ARG_PID, ARG_TGID, ARG_UNKNOWN, ARG_ALLOCATOR + ARG_PAGE_NUM, ARG_PID, ARG_TGID, ARG_UNKNOWN, ARG_ALLOCATOR, + ARG_MODULE }; enum SORT_ORDER { SORT_ASC = 1, @@ -80,9 +85,11 @@ struct filter_condition { pid_t *pids; pid_t *tgids; char **comms; + char **modules; int pids_size; int tgids_size; int comms_size; + int modules_size; }; struct sort_condition { int (**cmps)(const void *, const void *); @@ -95,6 +102,7 @@ static regex_t order_pattern; static regex_t pid_pattern; static regex_t tgid_pattern; static regex_t comm_pattern; +static regex_t module_pattern; static regex_t ts_nsec_pattern; static struct block_list *list; static int list_size; @@ -179,6 +187,13 @@ static int compare_comm(const void *p1, const void *p2) return strcmp(l1->comm, l2->comm); } +static int compare_module(const void *p1, const void *p2) +{ + const struct block_list *l1 = p1, *l2 = p2; + + return strcmp(l1->module, l2->module); +} + static int compare_ts(const void *p1, const void *p2) { const struct block_list *l1 = p1, *l2 = p2; @@ -200,6 +215,8 @@ static int compare_cull_condition(const void *p1, const void *p2) return compare_comm(p1, p2); if ((cull & CULL_ALLOCATOR) && compare_allocator(p1, p2)) return compare_allocator(p1, p2); + if ((cull & CULL_MODULE) && compare_module(p1, p2)) + return compare_module(p1, p2); return 0; } @@ -372,9 +389,7 @@ static char *get_comm(char *buf) memset(comm_str, 0, TASK_COMM_LEN); - search_pattern(&comm_pattern, comm_str, buf); - errno = 0; - if (errno != 0) { + if (search_pattern(&comm_pattern, comm_str, buf)) { if (debug_on) fprintf(stderr, "wrong comm in follow buf:\n%s\n", buf); return NULL; @@ -383,6 +398,16 @@ static char *get_comm(char *buf) return comm_str; } +static char *get_module(char *buf) +{ + char tmp[MODULE_NAME_LEN] = { 0 }; + + if (search_pattern(&module_pattern, tmp, buf)) + return strdup("vmlinux"); + + return strdup(tmp); +} + static int get_arg_type(const char *arg) { if (!strcmp(arg, "pid") || !strcmp(arg, "p")) @@ -399,6 +424,8 @@ static int get_arg_type(const char *arg) return ARG_ALLOC_TS; else if (!strcmp(arg, "allocator") || !strcmp(arg, "ator")) return ARG_ALLOCATOR; + else if (!strcmp(arg, "module")) + return ARG_MODULE; else { return ARG_UNKNOWN; } @@ -449,20 +476,30 @@ static bool match_str_list(const char *str, char **list, int list_size) static bool is_need(char *buf) { + bool match; + if ((filter & FILTER_PID) && !match_num_list(get_pid(buf), fc.pids, fc.pids_size)) return false; if ((filter & FILTER_TGID) && !match_num_list(get_tgid(buf), fc.tgids, fc.tgids_size)) return false; - char *comm = get_comm(buf); - - if ((filter & FILTER_COMM) && - !match_str_list(comm, fc.comms, fc.comms_size)) { + if (filter & FILTER_COMM) { + char *comm = get_comm(buf); + match = match_str_list(comm, fc.comms, fc.comms_size); free(comm); - return false; + if (!match) + return false; } - free(comm); + + if (filter & FILTER_MODULE) { + char *module = get_module(buf); + match = match_str_list(module, fc.modules, fc.modules_size); + free(module); + if (!match) + return false; + } + return true; } @@ -477,6 +514,7 @@ static bool add_list(char *buf, int len, char *ext_buf) list[list_size].pid = get_pid(buf); list[list_size].tgid = get_tgid(buf); list[list_size].comm = get_comm(buf); + list[list_size].module = get_module(buf); list[list_size].txt = malloc(len+1); if (!list[list_size].txt) { fprintf(stderr, "Out of memory\n"); @@ -522,6 +560,8 @@ static bool parse_cull_args(const char *arg_str) cull |= CULL_STACKTRACE; else if (arg_type == ARG_ALLOCATOR) cull |= CULL_ALLOCATOR; + else if (arg_type == ARG_MODULE) + cull |= CULL_MODULE; else { free_explode(args, size); return false; @@ -649,10 +689,14 @@ static void usage(void) "--name <cmdlist>\tSelect by command name. This selects the" " information\n\t\t\tof blocks whose command name appears in" " <cmdlist>.\n" + "--module <modlist>\tSelect by module name. This selects the" + " information\n\t\t\tof blocks whose stacktrace topmost module" + " appears in <modlist>.\n\t\t\t'vmlinux' is used if there isn't" + " module in the stacktrace\n" "--cull <rules>\t\tCull by user-defined rules. <rules> is a " "single\n\t\t\targument in the form of a comma-separated list " "with some\n\t\t\tcommon fields predefined (pid, tgid, comm, " - "stacktrace, allocator)\n" + "stacktrace, allocator,\n\t\t\tmodule)\n" "--sort <order>\t\tSpecify sort order as: [+|-]key[,[+|-]key[,...]]\n" ); } @@ -661,7 +705,7 @@ int main(int argc, char **argv) { FILE *fin, *fout; char *buf, *ext_buf; - int i, count, compare_flag; + int i, count, compare_flag, rtn = 1; struct stat st; int opt; struct option longopts[] = { @@ -670,6 +714,7 @@ int main(int argc, char **argv) { "name", required_argument, NULL, 3 }, { "cull", required_argument, NULL, 4 }, { "sort", required_argument, NULL, 5 }, + { "module", required_argument, NULL, 6 }, { 0, 0, 0, 0}, }; @@ -737,6 +782,10 @@ int main(int argc, char **argv) exit(1); } break; + case 6: + filter = filter | FILTER_MODULE; + fc.modules = explode(',', optarg, &fc.modules_size); + break; default: usage(); exit(1); @@ -796,6 +845,8 @@ int main(int argc, char **argv) goto out_tgid; if (!check_regcomp(&comm_pattern, "tgid\\s*[0-9]*\\s*\\((.*)\\),\\s*ts")) goto out_comm; + if (!check_regcomp(&module_pattern, "^ .*\\[(.*)\\]$")) + goto out_module; if (!check_regcomp(&ts_nsec_pattern, "ts\\s*([0-9]*)\\s*ns")) goto out_ts; @@ -858,12 +909,15 @@ int main(int argc, char **argv) fprintf(fout, ", "); print_allocator(fout, list[i].allocator); } + if (cull & CULL_MODULE) + fprintf(fout, ", module: %s", list[i].module); if (cull & CULL_STACKTRACE) fprintf(fout, ":\n%s", list[i].stacktrace); fprintf(fout, "\n"); } } + rtn = 0; out_free: if (ext_buf) free(ext_buf); @@ -871,16 +925,18 @@ int main(int argc, char **argv) free(buf); if (list) free(list); -out_ts: regfree(&ts_nsec_pattern); -out_comm: +out_ts: + regfree(&module_pattern); +out_module: regfree(&comm_pattern); -out_tgid: +out_comm: regfree(&tgid_pattern); -out_pid: +out_tgid: regfree(&pid_pattern); -out_order: +out_pid: regfree(&order_pattern); +out_order: - return 0; + return rtn; } -- 2.39.2