xref: /openbmc/linux/tools/perf/builtin-kwork.c (revision 4f8ae962)
10f70d8e9SYang Jihong // SPDX-License-Identifier: GPL-2.0
20f70d8e9SYang Jihong /*
30f70d8e9SYang Jihong  * builtin-kwork.c
40f70d8e9SYang Jihong  *
50f70d8e9SYang Jihong  * Copyright (c) 2022  Huawei Inc,  Yang Jihong <yangjihong1@huawei.com>
60f70d8e9SYang Jihong  */
70f70d8e9SYang Jihong 
80f70d8e9SYang Jihong #include "builtin.h"
90f70d8e9SYang Jihong 
100f70d8e9SYang Jihong #include "util/data.h"
110f70d8e9SYang Jihong #include "util/kwork.h"
120f70d8e9SYang Jihong #include "util/debug.h"
130f70d8e9SYang Jihong #include "util/symbol.h"
140f70d8e9SYang Jihong #include "util/thread.h"
150f70d8e9SYang Jihong #include "util/string2.h"
160f70d8e9SYang Jihong #include "util/callchain.h"
170f70d8e9SYang Jihong #include "util/evsel_fprintf.h"
180f70d8e9SYang Jihong 
190f70d8e9SYang Jihong #include <subcmd/pager.h>
200f70d8e9SYang Jihong #include <subcmd/parse-options.h>
210f70d8e9SYang Jihong 
220f70d8e9SYang Jihong #include <errno.h>
230f70d8e9SYang Jihong #include <inttypes.h>
240f70d8e9SYang Jihong #include <linux/err.h>
250f70d8e9SYang Jihong #include <linux/time64.h>
260f70d8e9SYang Jihong #include <linux/zalloc.h>
270f70d8e9SYang Jihong 
28*4f8ae962SYang Jihong const struct evsel_str_handler irq_tp_handlers[] = {
29*4f8ae962SYang Jihong 	{ "irq:irq_handler_entry", NULL, },
30*4f8ae962SYang Jihong 	{ "irq:irq_handler_exit",  NULL, },
31*4f8ae962SYang Jihong };
32*4f8ae962SYang Jihong 
33*4f8ae962SYang Jihong static struct kwork_class kwork_irq = {
34*4f8ae962SYang Jihong 	.name           = "irq",
35*4f8ae962SYang Jihong 	.type           = KWORK_CLASS_IRQ,
36*4f8ae962SYang Jihong 	.nr_tracepoints = 2,
37*4f8ae962SYang Jihong 	.tp_handlers    = irq_tp_handlers,
38*4f8ae962SYang Jihong };
39*4f8ae962SYang Jihong 
400f70d8e9SYang Jihong static struct kwork_class *kwork_class_supported_list[KWORK_CLASS_MAX] = {
41*4f8ae962SYang Jihong 	[KWORK_CLASS_IRQ]       = &kwork_irq,
420f70d8e9SYang Jihong };
430f70d8e9SYang Jihong 
440f70d8e9SYang Jihong static void setup_event_list(struct perf_kwork *kwork,
450f70d8e9SYang Jihong 			     const struct option *options,
460f70d8e9SYang Jihong 			     const char * const usage_msg[])
470f70d8e9SYang Jihong {
480f70d8e9SYang Jihong 	int i;
490f70d8e9SYang Jihong 	struct kwork_class *class;
500f70d8e9SYang Jihong 	char *tmp, *tok, *str;
510f70d8e9SYang Jihong 
520f70d8e9SYang Jihong 	if (kwork->event_list_str == NULL)
530f70d8e9SYang Jihong 		goto null_event_list_str;
540f70d8e9SYang Jihong 
550f70d8e9SYang Jihong 	str = strdup(kwork->event_list_str);
560f70d8e9SYang Jihong 	for (tok = strtok_r(str, ", ", &tmp);
570f70d8e9SYang Jihong 	     tok; tok = strtok_r(NULL, ", ", &tmp)) {
580f70d8e9SYang Jihong 		for (i = 0; i < KWORK_CLASS_MAX; i++) {
590f70d8e9SYang Jihong 			class = kwork_class_supported_list[i];
600f70d8e9SYang Jihong 			if (strcmp(tok, class->name) == 0) {
610f70d8e9SYang Jihong 				list_add_tail(&class->list, &kwork->class_list);
620f70d8e9SYang Jihong 				break;
630f70d8e9SYang Jihong 			}
640f70d8e9SYang Jihong 		}
650f70d8e9SYang Jihong 		if (i == KWORK_CLASS_MAX) {
660f70d8e9SYang Jihong 			usage_with_options_msg(usage_msg, options,
670f70d8e9SYang Jihong 					       "Unknown --event key: `%s'", tok);
680f70d8e9SYang Jihong 		}
690f70d8e9SYang Jihong 	}
700f70d8e9SYang Jihong 	free(str);
710f70d8e9SYang Jihong 
720f70d8e9SYang Jihong null_event_list_str:
730f70d8e9SYang Jihong 	/*
740f70d8e9SYang Jihong 	 * config all kwork events if not specified
750f70d8e9SYang Jihong 	 */
760f70d8e9SYang Jihong 	if (list_empty(&kwork->class_list)) {
770f70d8e9SYang Jihong 		for (i = 0; i < KWORK_CLASS_MAX; i++) {
780f70d8e9SYang Jihong 			list_add_tail(&kwork_class_supported_list[i]->list,
790f70d8e9SYang Jihong 				      &kwork->class_list);
800f70d8e9SYang Jihong 		}
810f70d8e9SYang Jihong 	}
820f70d8e9SYang Jihong 
830f70d8e9SYang Jihong 	pr_debug("Config event list:");
840f70d8e9SYang Jihong 	list_for_each_entry(class, &kwork->class_list, list)
850f70d8e9SYang Jihong 		pr_debug(" %s", class->name);
860f70d8e9SYang Jihong 	pr_debug("\n");
870f70d8e9SYang Jihong }
880f70d8e9SYang Jihong 
890f70d8e9SYang Jihong static int perf_kwork__record(struct perf_kwork *kwork,
900f70d8e9SYang Jihong 			      int argc, const char **argv)
910f70d8e9SYang Jihong {
920f70d8e9SYang Jihong 	const char **rec_argv;
930f70d8e9SYang Jihong 	unsigned int rec_argc, i, j;
940f70d8e9SYang Jihong 	struct kwork_class *class;
950f70d8e9SYang Jihong 
960f70d8e9SYang Jihong 	const char *const record_args[] = {
970f70d8e9SYang Jihong 		"record",
980f70d8e9SYang Jihong 		"-a",
990f70d8e9SYang Jihong 		"-R",
1000f70d8e9SYang Jihong 		"-m", "1024",
1010f70d8e9SYang Jihong 		"-c", "1",
1020f70d8e9SYang Jihong 	};
1030f70d8e9SYang Jihong 
1040f70d8e9SYang Jihong 	rec_argc = ARRAY_SIZE(record_args) + argc - 1;
1050f70d8e9SYang Jihong 
1060f70d8e9SYang Jihong 	list_for_each_entry(class, &kwork->class_list, list)
1070f70d8e9SYang Jihong 		rec_argc += 2 * class->nr_tracepoints;
1080f70d8e9SYang Jihong 
1090f70d8e9SYang Jihong 	rec_argv = calloc(rec_argc + 1, sizeof(char *));
1100f70d8e9SYang Jihong 	if (rec_argv == NULL)
1110f70d8e9SYang Jihong 		return -ENOMEM;
1120f70d8e9SYang Jihong 
1130f70d8e9SYang Jihong 	for (i = 0; i < ARRAY_SIZE(record_args); i++)
1140f70d8e9SYang Jihong 		rec_argv[i] = strdup(record_args[i]);
1150f70d8e9SYang Jihong 
1160f70d8e9SYang Jihong 	list_for_each_entry(class, &kwork->class_list, list) {
1170f70d8e9SYang Jihong 		for (j = 0; j < class->nr_tracepoints; j++) {
1180f70d8e9SYang Jihong 			rec_argv[i++] = strdup("-e");
1190f70d8e9SYang Jihong 			rec_argv[i++] = strdup(class->tp_handlers[j].name);
1200f70d8e9SYang Jihong 		}
1210f70d8e9SYang Jihong 	}
1220f70d8e9SYang Jihong 
1230f70d8e9SYang Jihong 	for (j = 1; j < (unsigned int)argc; j++, i++)
1240f70d8e9SYang Jihong 		rec_argv[i] = argv[j];
1250f70d8e9SYang Jihong 
1260f70d8e9SYang Jihong 	BUG_ON(i != rec_argc);
1270f70d8e9SYang Jihong 
1280f70d8e9SYang Jihong 	pr_debug("record comm: ");
1290f70d8e9SYang Jihong 	for (j = 0; j < rec_argc; j++)
1300f70d8e9SYang Jihong 		pr_debug("%s ", rec_argv[j]);
1310f70d8e9SYang Jihong 	pr_debug("\n");
1320f70d8e9SYang Jihong 
1330f70d8e9SYang Jihong 	return cmd_record(i, rec_argv);
1340f70d8e9SYang Jihong }
1350f70d8e9SYang Jihong 
1360f70d8e9SYang Jihong int cmd_kwork(int argc, const char **argv)
1370f70d8e9SYang Jihong {
1380f70d8e9SYang Jihong 	static struct perf_kwork kwork = {
1390f70d8e9SYang Jihong 		.class_list          = LIST_HEAD_INIT(kwork.class_list),
1400f70d8e9SYang Jihong 		.force               = false,
1410f70d8e9SYang Jihong 		.event_list_str      = NULL,
1420f70d8e9SYang Jihong 	};
1430f70d8e9SYang Jihong 	const struct option kwork_options[] = {
1440f70d8e9SYang Jihong 	OPT_INCR('v', "verbose", &verbose,
1450f70d8e9SYang Jihong 		 "be more verbose (show symbol address, etc)"),
1460f70d8e9SYang Jihong 	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1470f70d8e9SYang Jihong 		    "dump raw trace in ASCII"),
1480f70d8e9SYang Jihong 	OPT_STRING('k', "kwork", &kwork.event_list_str, "kwork",
149*4f8ae962SYang Jihong 		   "list of kwork to profile (irq, etc)"),
1500f70d8e9SYang Jihong 	OPT_BOOLEAN('f', "force", &kwork.force, "don't complain, do it"),
1510f70d8e9SYang Jihong 	OPT_END()
1520f70d8e9SYang Jihong 	};
1530f70d8e9SYang Jihong 	const char *kwork_usage[] = {
1540f70d8e9SYang Jihong 		NULL,
1550f70d8e9SYang Jihong 		NULL
1560f70d8e9SYang Jihong 	};
1570f70d8e9SYang Jihong 	const char *const kwork_subcommands[] = {
1580f70d8e9SYang Jihong 		"record", NULL
1590f70d8e9SYang Jihong 	};
1600f70d8e9SYang Jihong 
1610f70d8e9SYang Jihong 	argc = parse_options_subcommand(argc, argv, kwork_options,
1620f70d8e9SYang Jihong 					kwork_subcommands, kwork_usage,
1630f70d8e9SYang Jihong 					PARSE_OPT_STOP_AT_NON_OPTION);
1640f70d8e9SYang Jihong 	if (!argc)
1650f70d8e9SYang Jihong 		usage_with_options(kwork_usage, kwork_options);
1660f70d8e9SYang Jihong 
1670f70d8e9SYang Jihong 	setup_event_list(&kwork, kwork_options, kwork_usage);
1680f70d8e9SYang Jihong 
1690f70d8e9SYang Jihong 	if (strlen(argv[0]) > 2 && strstarts("record", argv[0]))
1700f70d8e9SYang Jihong 		return perf_kwork__record(&kwork, argc, argv);
1710f70d8e9SYang Jihong 	else
1720f70d8e9SYang Jihong 		usage_with_options(kwork_usage, kwork_options);
1730f70d8e9SYang Jihong 
1740f70d8e9SYang Jihong 	return 0;
1750f70d8e9SYang Jihong }
176