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