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