summaryrefslogtreecommitdiffstats
path: root/tools/vm
diff options
context:
space:
mode:
authorJiajian Ye <yejiajian2018@email.szu.edu.cn>2022-04-28 23:15:56 -0700
committerakpm <akpm@linux-foundation.org>2022-04-28 23:15:56 -0700
commit75382a2dca0e9e9e57e88b479cf537549461a934 (patch)
tree55ad5eb926ca518f47e6add87d6cbceed5857db6 /tools/vm
parent329687a03d18143f491b535d22be1cccc291bb58 (diff)
downloadlinux-75382a2dca0e9e9e57e88b479cf537549461a934.tar.bz2
tools/vm/page_owner_sort.c: support for multi-value selection in single argument
When viewing page owner information, we may want to select blocks whose PID/TGID/TASK_COMM_NAME appears in a user-specified list for data analysis and aggregation. But currently page_owner_sort only supports selecting blocks associated with only one specified PID/TGID/TASK_COMM_NAME. Therefore, following adjustments are made to fix the problem: 1. Enhance selecting function to support the selection of multiple PIDs/TGIDs/TASK_COMM_NAMEs. The enhanced usages are as follows: --pid <pidlist> Select by pid. This selects the blocks whose PID numbers appear in <pidlist>. --tgid <tgidlist> Select by tgid. This selects the blocks whose TGID numbers appear in <tgidlist>. --name <cmdlist> Select by task command name. This selects the blocks whose task command name appear in <cmdlist>. Where <pidlist>, <tgidlist>, <cmdlist> are single arguments in the form of a comma-separated list,which offers a way to specify individual selecting rules. For example, if you want to select blocks whose tgids are 1, 2 or 3, you have to use 4 commands as follows: ./page_owner_sort <input> <output1> --tgid=1 ./page_owner_sort <input> <output2> --tgid=2 ./page_owner_sort <input> <output3> --tgid=3 cat <output1> <output2> <output3> > <output> With this patch, you can use only 1 command to obtain the same result as above: ./page_owner_sort <input> <output1> --tgid=1,2,3 2. Update explanations of --pid, --tgid and --name in the function usage() and the document(Documents/vm/page_owner.rst). This work is coauthored by Yixuan Cao Shenghong Han Yinan Zhang Chongxi Zhao Yuhong Feng Yongqiang Liu Link: https://lkml.kernel.org/r/20220401024856.767-2-yejiajian2018@email.szu.edu.cn Signed-off-by: Jiajian Ye <yejiajian2018@email.szu.edu.cn> Cc: Chongxi Zhao <zhaochongxi2019@email.szu.edu.cn> Cc: Shenghong Han <hanshenghong2019@email.szu.edu.cn> Cc: Yinan Zhang <zhangyinan2019@email.szu.edu.cn> Cc: Yixuan Cao <caoyixuan2019@email.szu.edu.cn> Cc: Yongqiang Liu <liuyongqiang13@huawei.com> Cc: Yuhong Feng <yuhongf@szu.edu.cn> Cc: Haowen Bai <baihaowen@meizu.com> Cc: Sean Anderson <seanga2@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Diffstat (limited to 'tools/vm')
-rw-r--r--tools/vm/page_owner_sort.c78
1 files changed, 57 insertions, 21 deletions
diff --git a/tools/vm/page_owner_sort.c b/tools/vm/page_owner_sort.c
index 6771003ed5f1..16fb034c6a4e 100644
--- a/tools/vm/page_owner_sort.c
+++ b/tools/vm/page_owner_sort.c
@@ -54,9 +54,12 @@ enum CULL_BIT {
CULL_STACKTRACE = 1<<5
};
struct filter_condition {
- pid_t tgid;
- pid_t pid;
- char comm[TASK_COMM_LEN];
+ pid_t *tgids;
+ int tgids_size;
+ pid_t *pids;
+ int pids_size;
+ char **comms;
+ int comms_size;
};
static struct filter_condition fc;
static regex_t order_pattern;
@@ -149,7 +152,6 @@ static int compare_free_ts(const void *p1, const void *p2)
return l1->free_ts_nsec < l2->free_ts_nsec ? -1 : 1;
}
-
static int compare_release(const void *p1, const void *p2)
{
const struct block_list *l1 = p1, *l2 = p2;
@@ -161,7 +163,6 @@ static int compare_release(const void *p1, const void *p2)
return l1->free_ts_nsec ? 1 : -1;
}
-
static int compare_cull_condition(const void *p1, const void *p2)
{
if (cull == 0)
@@ -344,22 +345,40 @@ static char *get_comm(char *buf)
return comm_str;
}
+static bool match_num_list(int num, int *list, int list_size)
+{
+ for (int i = 0; i < list_size; ++i)
+ if (list[i] == num)
+ return true;
+ return false;
+}
+
+static bool match_str_list(const char *str, char **list, int list_size)
+{
+ for (int i = 0; i < list_size; ++i)
+ if (!strcmp(list[i], str))
+ return true;
+ return false;
+}
+
static bool is_need(char *buf)
{
if ((filter & FILTER_UNRELEASE) && get_free_ts_nsec(buf) != 0)
return false;
- if ((filter & FILTER_PID) && get_pid(buf) != fc.pid)
+ if ((filter & FILTER_PID) && !match_num_list(get_pid(buf), fc.pids, fc.pids_size))
return false;
- if ((filter & FILTER_TGID) && get_tgid(buf) != fc.tgid)
+ 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) &&
- strncmp(comm, fc.comm, TASK_COMM_LEN) != 0) {
+ !match_str_list(comm, fc.comms, fc.comms_size)) {
free(comm);
return false;
}
+ free(comm);
return true;
}
@@ -428,6 +447,27 @@ static bool parse_cull_args(const char *arg_str)
return true;
}
+static int *parse_nums_list(char *arg_str, int *list_size)
+{
+ int size = 0;
+ char **args = explode(',', arg_str, &size);
+ int *list = calloc(size, sizeof(int));
+
+ errno = 0;
+ for (int i = 0; i < size; ++i) {
+ char *endptr = NULL;
+
+ list[i] = strtol(args[i], &endptr, 10);
+ if (errno != 0 || endptr == args[i] || *endptr != '\0') {
+ free(list);
+ return NULL;
+ }
+ }
+ *list_size = size;
+ free_explode(args, size);
+ return list;
+}
+
#define BUF_SIZE (128 * 1024)
static void usage(void)
@@ -442,9 +482,9 @@ static void usage(void)
"-a\t\tSort by memory allocate time.\n"
"-r\t\tSort by memory release time.\n"
"-f\t\tFilter out the information of blocks whose memory has been released.\n"
- "--pid <PID>\tSelect by pid. This selects the information of blocks whose process ID number equals to <PID>.\n"
- "--tgid <TGID>\tSelect by tgid. This selects the information of blocks whose Thread Group ID number equals to <TGID>.\n"
- "--name <command>\n\t\tSelect by command name. This selects the information of blocks whose command name identical to <command>.\n"
+ "--pid <pidlist>\tSelect by pid. This selects the information of blocks whose process ID numbers appear in <pidlist>.\n"
+ "--tgid <tgidlist>\tSelect by tgid. This selects the information of blocks whose Thread Group ID numbers appear in <tgidlist>.\n"
+ "--name <cmdlist>\n\t\tSelect by command name. This selects the information of blocks whose command name appears in <cmdlist>.\n"
"--cull <rules>\tCull by user-defined rules. <rules> is a single argument in the form of a comma-separated list with some common fields predefined\n"
);
}
@@ -453,7 +493,7 @@ int main(int argc, char **argv)
{
int (*cmp)(const void *, const void *) = compare_num;
FILE *fin, *fout;
- char *buf, *endptr;
+ char *buf;
int ret, i, count;
struct stat st;
int opt;
@@ -496,9 +536,8 @@ int main(int argc, char **argv)
break;
case 1:
filter = filter | FILTER_PID;
- errno = 0;
- fc.pid = strtol(optarg, &endptr, 10);
- if (errno != 0 || endptr == optarg || *endptr != '\0') {
+ fc.pids = parse_nums_list(optarg, &fc.pids_size);
+ if (fc.pids == NULL) {
fprintf(stderr, "wrong/invalid pid in from the command line:%s\n",
optarg);
exit(1);
@@ -506,9 +545,8 @@ int main(int argc, char **argv)
break;
case 2:
filter = filter | FILTER_TGID;
- errno = 0;
- fc.tgid = strtol(optarg, &endptr, 10);
- if (errno != 0 || endptr == optarg || *endptr != '\0') {
+ fc.tgids = parse_nums_list(optarg, &fc.tgids_size);
+ if (fc.tgids == NULL) {
fprintf(stderr, "wrong/invalid tgid in from the command line:%s\n",
optarg);
exit(1);
@@ -516,8 +554,7 @@ int main(int argc, char **argv)
break;
case 3:
filter = filter | FILTER_COMM;
- strncpy(fc.comm, optarg, TASK_COMM_LEN);
- fc.comm[TASK_COMM_LEN-1] = '\0';
+ fc.comms = explode(',', optarg, &fc.comms_size);
break;
case 4:
if (!parse_cull_args(optarg)) {
@@ -564,7 +601,6 @@ int main(int argc, char **argv)
ret = read_block(buf, BUF_SIZE, fin);
if (ret < 0)
break;
-
add_list(buf, ret);
}