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 284f8ae962SYang Jihong const struct evsel_str_handler irq_tp_handlers[] = { 294f8ae962SYang Jihong { "irq:irq_handler_entry", NULL, }, 304f8ae962SYang Jihong { "irq:irq_handler_exit", NULL, }, 314f8ae962SYang Jihong }; 324f8ae962SYang Jihong 334f8ae962SYang Jihong static struct kwork_class kwork_irq = { 344f8ae962SYang Jihong .name = "irq", 354f8ae962SYang Jihong .type = KWORK_CLASS_IRQ, 364f8ae962SYang Jihong .nr_tracepoints = 2, 374f8ae962SYang Jihong .tp_handlers = irq_tp_handlers, 384f8ae962SYang Jihong }; 394f8ae962SYang Jihong 40*e6439321SYang Jihong const struct evsel_str_handler softirq_tp_handlers[] = { 41*e6439321SYang Jihong { "irq:softirq_raise", NULL, }, 42*e6439321SYang Jihong { "irq:softirq_entry", NULL, }, 43*e6439321SYang Jihong { "irq:softirq_exit", NULL, }, 44*e6439321SYang Jihong }; 45*e6439321SYang Jihong 46*e6439321SYang Jihong static struct kwork_class kwork_softirq = { 47*e6439321SYang Jihong .name = "softirq", 48*e6439321SYang Jihong .type = KWORK_CLASS_SOFTIRQ, 49*e6439321SYang Jihong .nr_tracepoints = 3, 50*e6439321SYang Jihong .tp_handlers = softirq_tp_handlers, 51*e6439321SYang Jihong }; 52*e6439321SYang Jihong 530f70d8e9SYang Jihong static struct kwork_class *kwork_class_supported_list[KWORK_CLASS_MAX] = { 544f8ae962SYang Jihong [KWORK_CLASS_IRQ] = &kwork_irq, 55*e6439321SYang Jihong [KWORK_CLASS_SOFTIRQ] = &kwork_softirq, 560f70d8e9SYang Jihong }; 570f70d8e9SYang Jihong 580f70d8e9SYang Jihong static void setup_event_list(struct perf_kwork *kwork, 590f70d8e9SYang Jihong const struct option *options, 600f70d8e9SYang Jihong const char * const usage_msg[]) 610f70d8e9SYang Jihong { 620f70d8e9SYang Jihong int i; 630f70d8e9SYang Jihong struct kwork_class *class; 640f70d8e9SYang Jihong char *tmp, *tok, *str; 650f70d8e9SYang Jihong 660f70d8e9SYang Jihong if (kwork->event_list_str == NULL) 670f70d8e9SYang Jihong goto null_event_list_str; 680f70d8e9SYang Jihong 690f70d8e9SYang Jihong str = strdup(kwork->event_list_str); 700f70d8e9SYang Jihong for (tok = strtok_r(str, ", ", &tmp); 710f70d8e9SYang Jihong tok; tok = strtok_r(NULL, ", ", &tmp)) { 720f70d8e9SYang Jihong for (i = 0; i < KWORK_CLASS_MAX; i++) { 730f70d8e9SYang Jihong class = kwork_class_supported_list[i]; 740f70d8e9SYang Jihong if (strcmp(tok, class->name) == 0) { 750f70d8e9SYang Jihong list_add_tail(&class->list, &kwork->class_list); 760f70d8e9SYang Jihong break; 770f70d8e9SYang Jihong } 780f70d8e9SYang Jihong } 790f70d8e9SYang Jihong if (i == KWORK_CLASS_MAX) { 800f70d8e9SYang Jihong usage_with_options_msg(usage_msg, options, 810f70d8e9SYang Jihong "Unknown --event key: `%s'", tok); 820f70d8e9SYang Jihong } 830f70d8e9SYang Jihong } 840f70d8e9SYang Jihong free(str); 850f70d8e9SYang Jihong 860f70d8e9SYang Jihong null_event_list_str: 870f70d8e9SYang Jihong /* 880f70d8e9SYang Jihong * config all kwork events if not specified 890f70d8e9SYang Jihong */ 900f70d8e9SYang Jihong if (list_empty(&kwork->class_list)) { 910f70d8e9SYang Jihong for (i = 0; i < KWORK_CLASS_MAX; i++) { 920f70d8e9SYang Jihong list_add_tail(&kwork_class_supported_list[i]->list, 930f70d8e9SYang Jihong &kwork->class_list); 940f70d8e9SYang Jihong } 950f70d8e9SYang Jihong } 960f70d8e9SYang Jihong 970f70d8e9SYang Jihong pr_debug("Config event list:"); 980f70d8e9SYang Jihong list_for_each_entry(class, &kwork->class_list, list) 990f70d8e9SYang Jihong pr_debug(" %s", class->name); 1000f70d8e9SYang Jihong pr_debug("\n"); 1010f70d8e9SYang Jihong } 1020f70d8e9SYang Jihong 1030f70d8e9SYang Jihong static int perf_kwork__record(struct perf_kwork *kwork, 1040f70d8e9SYang Jihong int argc, const char **argv) 1050f70d8e9SYang Jihong { 1060f70d8e9SYang Jihong const char **rec_argv; 1070f70d8e9SYang Jihong unsigned int rec_argc, i, j; 1080f70d8e9SYang Jihong struct kwork_class *class; 1090f70d8e9SYang Jihong 1100f70d8e9SYang Jihong const char *const record_args[] = { 1110f70d8e9SYang Jihong "record", 1120f70d8e9SYang Jihong "-a", 1130f70d8e9SYang Jihong "-R", 1140f70d8e9SYang Jihong "-m", "1024", 1150f70d8e9SYang Jihong "-c", "1", 1160f70d8e9SYang Jihong }; 1170f70d8e9SYang Jihong 1180f70d8e9SYang Jihong rec_argc = ARRAY_SIZE(record_args) + argc - 1; 1190f70d8e9SYang Jihong 1200f70d8e9SYang Jihong list_for_each_entry(class, &kwork->class_list, list) 1210f70d8e9SYang Jihong rec_argc += 2 * class->nr_tracepoints; 1220f70d8e9SYang Jihong 1230f70d8e9SYang Jihong rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1240f70d8e9SYang Jihong if (rec_argv == NULL) 1250f70d8e9SYang Jihong return -ENOMEM; 1260f70d8e9SYang Jihong 1270f70d8e9SYang Jihong for (i = 0; i < ARRAY_SIZE(record_args); i++) 1280f70d8e9SYang Jihong rec_argv[i] = strdup(record_args[i]); 1290f70d8e9SYang Jihong 1300f70d8e9SYang Jihong list_for_each_entry(class, &kwork->class_list, list) { 1310f70d8e9SYang Jihong for (j = 0; j < class->nr_tracepoints; j++) { 1320f70d8e9SYang Jihong rec_argv[i++] = strdup("-e"); 1330f70d8e9SYang Jihong rec_argv[i++] = strdup(class->tp_handlers[j].name); 1340f70d8e9SYang Jihong } 1350f70d8e9SYang Jihong } 1360f70d8e9SYang Jihong 1370f70d8e9SYang Jihong for (j = 1; j < (unsigned int)argc; j++, i++) 1380f70d8e9SYang Jihong rec_argv[i] = argv[j]; 1390f70d8e9SYang Jihong 1400f70d8e9SYang Jihong BUG_ON(i != rec_argc); 1410f70d8e9SYang Jihong 1420f70d8e9SYang Jihong pr_debug("record comm: "); 1430f70d8e9SYang Jihong for (j = 0; j < rec_argc; j++) 1440f70d8e9SYang Jihong pr_debug("%s ", rec_argv[j]); 1450f70d8e9SYang Jihong pr_debug("\n"); 1460f70d8e9SYang Jihong 1470f70d8e9SYang Jihong return cmd_record(i, rec_argv); 1480f70d8e9SYang Jihong } 1490f70d8e9SYang Jihong 1500f70d8e9SYang Jihong int cmd_kwork(int argc, const char **argv) 1510f70d8e9SYang Jihong { 1520f70d8e9SYang Jihong static struct perf_kwork kwork = { 1530f70d8e9SYang Jihong .class_list = LIST_HEAD_INIT(kwork.class_list), 1540f70d8e9SYang Jihong .force = false, 1550f70d8e9SYang Jihong .event_list_str = NULL, 1560f70d8e9SYang Jihong }; 1570f70d8e9SYang Jihong const struct option kwork_options[] = { 1580f70d8e9SYang Jihong OPT_INCR('v', "verbose", &verbose, 1590f70d8e9SYang Jihong "be more verbose (show symbol address, etc)"), 1600f70d8e9SYang Jihong OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1610f70d8e9SYang Jihong "dump raw trace in ASCII"), 1620f70d8e9SYang Jihong OPT_STRING('k', "kwork", &kwork.event_list_str, "kwork", 163*e6439321SYang Jihong "list of kwork to profile (irq, softirq, etc)"), 1640f70d8e9SYang Jihong OPT_BOOLEAN('f', "force", &kwork.force, "don't complain, do it"), 1650f70d8e9SYang Jihong OPT_END() 1660f70d8e9SYang Jihong }; 1670f70d8e9SYang Jihong const char *kwork_usage[] = { 1680f70d8e9SYang Jihong NULL, 1690f70d8e9SYang Jihong NULL 1700f70d8e9SYang Jihong }; 1710f70d8e9SYang Jihong const char *const kwork_subcommands[] = { 1720f70d8e9SYang Jihong "record", NULL 1730f70d8e9SYang Jihong }; 1740f70d8e9SYang Jihong 1750f70d8e9SYang Jihong argc = parse_options_subcommand(argc, argv, kwork_options, 1760f70d8e9SYang Jihong kwork_subcommands, kwork_usage, 1770f70d8e9SYang Jihong PARSE_OPT_STOP_AT_NON_OPTION); 1780f70d8e9SYang Jihong if (!argc) 1790f70d8e9SYang Jihong usage_with_options(kwork_usage, kwork_options); 1800f70d8e9SYang Jihong 1810f70d8e9SYang Jihong setup_event_list(&kwork, kwork_options, kwork_usage); 1820f70d8e9SYang Jihong 1830f70d8e9SYang Jihong if (strlen(argv[0]) > 2 && strstarts("record", argv[0])) 1840f70d8e9SYang Jihong return perf_kwork__record(&kwork, argc, argv); 1850f70d8e9SYang Jihong else 1860f70d8e9SYang Jihong usage_with_options(kwork_usage, kwork_options); 1870f70d8e9SYang Jihong 1880f70d8e9SYang Jihong return 0; 1890f70d8e9SYang Jihong } 190