linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] tools/mm: allow filtering and culling by module in page_owner_sort
@ 2024-05-08  9:45 Petr Malat
  2024-05-08 18:10 ` Andrew Morton
  0 siblings, 1 reply; 3+ messages in thread
From: Petr Malat @ 2024-05-08  9:45 UTC (permalink / raw)
  To: linux-mm; +Cc: akpm, Petr Malat

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@malat.biz>
---
 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



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] tools/mm: allow filtering and culling by module in page_owner_sort
  2024-05-08  9:45 [PATCH] tools/mm: allow filtering and culling by module in page_owner_sort Petr Malat
@ 2024-05-08 18:10 ` Andrew Morton
  2024-05-13 10:01   ` Petr Malat
  0 siblings, 1 reply; 3+ messages in thread
From: Andrew Morton @ 2024-05-08 18:10 UTC (permalink / raw)
  To: Petr Malat; +Cc: linux-mm

On Wed,  8 May 2024 11:45:07 +0200 Petr Malat <oss@malat.biz> wrote:

> Extend page_owner_sort filtering and culling features to work with module
> names as well. The top most module is used.

I'm not sure what this means.  Perhaps providing some sample output
would be helpful.

> Fix regex error handling, failure labels were one step shifted.

Again, showing us the before and after effects would aid understanding.


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] tools/mm: allow filtering and culling by module in page_owner_sort
  2024-05-08 18:10 ` Andrew Morton
@ 2024-05-13 10:01   ` Petr Malat
  0 siblings, 0 replies; 3+ messages in thread
From: Petr Malat @ 2024-05-13 10:01 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-mm

Hi Andrew,

On Wed, May 08, 2024 at 11:10:07AM -0700, Andrew Morton wrote:
> On Wed,  8 May 2024 11:45:07 +0200 Petr Malat <oss@malat.biz> wrote:
> 
> > Extend page_owner_sort filtering and culling features to work with module
> > names as well. The top most module is used.
> 
> I'm not sure what this means.  Perhaps providing some sample output
> would be helpful.

page_owner_sort -m --cull module generates output like this:

  412434 times, 509515 pages, module: vmlinux
  56476 times, 325647 pages, module: rvu_nicpf
  4226 times, 4581 pages, module: nfsd
  2061 times, 2062 pages, module: mvcpss
  278 times, 874 pages, module: rvu_nicvf
  125 times, 854 pages, module: mmc_block
  473 times, 638 pages, module: dtbo_loader
  126 times, 588 pages, module: rvu_af
  185 times, 362 pages, module: rvu_cptvf
  74 times, 340 pages, module: clk_port
     ...

where one can see how much memory was allocated by every module,
for example rvu_nicpf (ethernet) allocated 325647 pages in total.

> 
> > Fix regex error handling, failure labels were one step shifted.
> 
> Again, showing us the before and after effects would aid understanding.

According to the regfree manual page, regfree takes "precompiled pattern
buffer" as its argument, so if regcomp(preg, pattern, flags) fails,
regfree(preg) should not be called, because preg doesn't contain "precompiled
pattern buffer".

BR,
  Petr


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2024-05-13 10:08 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-05-08  9:45 [PATCH] tools/mm: allow filtering and culling by module in page_owner_sort Petr Malat
2024-05-08 18:10 ` Andrew Morton
2024-05-13 10:01   ` Petr Malat

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox