Add filtering capability for page_owner to allow filtering by memory cgroup path. Filter page_owner output by cgroup path: ./page_owner_filter -g / ./page_owner_filter -g /user.slice ./page_owner_filter -g /user.slice -c systemd Signed-off-by: Zhen Ni --- tools/mm/page_owner_filter.c | 56 ++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/tools/mm/page_owner_filter.c b/tools/mm/page_owner_filter.c index 9256ffad4939..1ffbe4387854 100644 --- a/tools/mm/page_owner_filter.c +++ b/tools/mm/page_owner_filter.c @@ -20,7 +20,7 @@ #include #include -#define MAX_CMD_LEN 512 +#define MAX_CMD_LEN 2048 #define TASK_COMM_LEN 16 static void usage(const char *prog) @@ -33,12 +33,13 @@ static void usage(const char *prog) fprintf(stderr, " -t, --tgid TGID_LIST : Thread Group IDs (comma-separated, max 16)\n"); fprintf(stderr, " -c, --comm COMM_LIST : Process names (comma-separated, max 8)\n"); fprintf(stderr, " Supports wildcards: * ? [a-z]\n"); + fprintf(stderr, " -g, --cgroup PATH : Memory cgroup path\n"); fprintf(stderr, " -o, --output FILE : output file (default: stdout)\n"); fprintf(stderr, " -h, --help : show this help message\n"); fprintf(stderr, "\nExamples:\n"); fprintf(stderr, " %s -m handle -o output.txt\n", prog); fprintf(stderr, " %s -n 0,1 -c bash\n", prog); - fprintf(stderr, " %s -c \"python*\" -t 1\n", prog); + fprintf(stderr, " %s -c \"python*\" -g user.slice\n", prog); } static int validate_mode(const char *mode) @@ -221,6 +222,38 @@ static int validate_comm_list(const char *comm_list) return 0; } +static int validate_cgroup_path(const char *path) +{ + char cgroup_path[512]; + const char *input_path = path; + int is_cgroup_v2 = 0; + + if (!path || strlen(path) == 0) + return -1; + + if (path[0] == '/') + input_path++; + + /* Check if v1 memory controller exists */ + if (access("/sys/fs/cgroup/memory", F_OK) != 0) + is_cgroup_v2 = 1; + + if (is_cgroup_v2) + snprintf(cgroup_path, sizeof(cgroup_path), + "/sys/fs/cgroup/%s/memory.stat", input_path); + else + snprintf(cgroup_path, sizeof(cgroup_path), + "/sys/fs/cgroup/memory/%s/memory.stat", input_path); + + if (access(cgroup_path, F_OK) != 0) { + fprintf(stderr, "Error: Cgroup path '%s': not found or no memory controller\n", + path); + return -1; + } + + return 0; +} + int main(int argc, char *argv[]) { const char *output_file = NULL; @@ -240,6 +273,7 @@ int main(int argc, char *argv[]) {"pid", required_argument, 0, 'p'}, {"tgid", required_argument, 0, 't'}, {"comm", required_argument, 0, 'c'}, + {"cgroup", required_argument, 0, 'g'}, {"output", required_argument, 0, 'o'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} @@ -266,7 +300,7 @@ int main(int argc, char *argv[]) return 1; } - while ((opt = getopt_long(argc, argv, "m:n:p:t:c:o:h", long_options, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "m:n:p:t:c:g:o:h", long_options, NULL)) != -1) { int len; switch (opt) { @@ -340,6 +374,22 @@ int main(int argc, char *argv[]) cmd_len += len; break; } + case 'g': { + const char *cgroup_path = optarg; + + if (validate_cgroup_path(cgroup_path) < 0) + return 1; + const char *path = (cgroup_path[0] == '/') ? cgroup_path + 1 : cgroup_path; + + len = snprintf(filter_cmd + cmd_len, MAX_CMD_LEN - cmd_len, + "%smemcg=/%s", cmd_len > 0 ? " " : "", path); + if (len < 0 || cmd_len + len >= MAX_CMD_LEN) { + fprintf(stderr, "Error: Command too long\n"); + return 1; + } + cmd_len += len; + break; + } case 'o': output_file = optarg; break; -- 2.20.1