xref: /openbmc/linux/tools/perf/builtin-kwork.c (revision 0f70d8e9)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * builtin-kwork.c
4  *
5  * Copyright (c) 2022  Huawei Inc,  Yang Jihong <yangjihong1@huawei.com>
6  */
7 
8 #include "builtin.h"
9 
10 #include "util/data.h"
11 #include "util/kwork.h"
12 #include "util/debug.h"
13 #include "util/symbol.h"
14 #include "util/thread.h"
15 #include "util/string2.h"
16 #include "util/callchain.h"
17 #include "util/evsel_fprintf.h"
18 
19 #include <subcmd/pager.h>
20 #include <subcmd/parse-options.h>
21 
22 #include <errno.h>
23 #include <inttypes.h>
24 #include <linux/err.h>
25 #include <linux/time64.h>
26 #include <linux/zalloc.h>
27 
28 static struct kwork_class *kwork_class_supported_list[KWORK_CLASS_MAX] = {
29 };
30 
31 static void setup_event_list(struct perf_kwork *kwork,
32 			     const struct option *options,
33 			     const char * const usage_msg[])
34 {
35 	int i;
36 	struct kwork_class *class;
37 	char *tmp, *tok, *str;
38 
39 	if (kwork->event_list_str == NULL)
40 		goto null_event_list_str;
41 
42 	str = strdup(kwork->event_list_str);
43 	for (tok = strtok_r(str, ", ", &tmp);
44 	     tok; tok = strtok_r(NULL, ", ", &tmp)) {
45 		for (i = 0; i < KWORK_CLASS_MAX; i++) {
46 			class = kwork_class_supported_list[i];
47 			if (strcmp(tok, class->name) == 0) {
48 				list_add_tail(&class->list, &kwork->class_list);
49 				break;
50 			}
51 		}
52 		if (i == KWORK_CLASS_MAX) {
53 			usage_with_options_msg(usage_msg, options,
54 					       "Unknown --event key: `%s'", tok);
55 		}
56 	}
57 	free(str);
58 
59 null_event_list_str:
60 	/*
61 	 * config all kwork events if not specified
62 	 */
63 	if (list_empty(&kwork->class_list)) {
64 		for (i = 0; i < KWORK_CLASS_MAX; i++) {
65 			list_add_tail(&kwork_class_supported_list[i]->list,
66 				      &kwork->class_list);
67 		}
68 	}
69 
70 	pr_debug("Config event list:");
71 	list_for_each_entry(class, &kwork->class_list, list)
72 		pr_debug(" %s", class->name);
73 	pr_debug("\n");
74 }
75 
76 static int perf_kwork__record(struct perf_kwork *kwork,
77 			      int argc, const char **argv)
78 {
79 	const char **rec_argv;
80 	unsigned int rec_argc, i, j;
81 	struct kwork_class *class;
82 
83 	const char *const record_args[] = {
84 		"record",
85 		"-a",
86 		"-R",
87 		"-m", "1024",
88 		"-c", "1",
89 	};
90 
91 	rec_argc = ARRAY_SIZE(record_args) + argc - 1;
92 
93 	list_for_each_entry(class, &kwork->class_list, list)
94 		rec_argc += 2 * class->nr_tracepoints;
95 
96 	rec_argv = calloc(rec_argc + 1, sizeof(char *));
97 	if (rec_argv == NULL)
98 		return -ENOMEM;
99 
100 	for (i = 0; i < ARRAY_SIZE(record_args); i++)
101 		rec_argv[i] = strdup(record_args[i]);
102 
103 	list_for_each_entry(class, &kwork->class_list, list) {
104 		for (j = 0; j < class->nr_tracepoints; j++) {
105 			rec_argv[i++] = strdup("-e");
106 			rec_argv[i++] = strdup(class->tp_handlers[j].name);
107 		}
108 	}
109 
110 	for (j = 1; j < (unsigned int)argc; j++, i++)
111 		rec_argv[i] = argv[j];
112 
113 	BUG_ON(i != rec_argc);
114 
115 	pr_debug("record comm: ");
116 	for (j = 0; j < rec_argc; j++)
117 		pr_debug("%s ", rec_argv[j]);
118 	pr_debug("\n");
119 
120 	return cmd_record(i, rec_argv);
121 }
122 
123 int cmd_kwork(int argc, const char **argv)
124 {
125 	static struct perf_kwork kwork = {
126 		.class_list          = LIST_HEAD_INIT(kwork.class_list),
127 		.force               = false,
128 		.event_list_str      = NULL,
129 	};
130 	const struct option kwork_options[] = {
131 	OPT_INCR('v', "verbose", &verbose,
132 		 "be more verbose (show symbol address, etc)"),
133 	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
134 		    "dump raw trace in ASCII"),
135 	OPT_STRING('k', "kwork", &kwork.event_list_str, "kwork",
136 		   "list of kwork to profile"),
137 	OPT_BOOLEAN('f', "force", &kwork.force, "don't complain, do it"),
138 	OPT_END()
139 	};
140 	const char *kwork_usage[] = {
141 		NULL,
142 		NULL
143 	};
144 	const char *const kwork_subcommands[] = {
145 		"record", NULL
146 	};
147 
148 	argc = parse_options_subcommand(argc, argv, kwork_options,
149 					kwork_subcommands, kwork_usage,
150 					PARSE_OPT_STOP_AT_NON_OPTION);
151 	if (!argc)
152 		usage_with_options(kwork_usage, kwork_options);
153 
154 	setup_event_list(&kwork, kwork_options, kwork_usage);
155 
156 	if (strlen(argv[0]) > 2 && strstarts("record", argv[0]))
157 		return perf_kwork__record(&kwork, argc, argv);
158 	else
159 		usage_with_options(kwork_usage, kwork_options);
160 
161 	return 0;
162 }
163