1 #include "builtin.h" 2 3 #include "util/util.h" 4 #include "util/cache.h" 5 #include "util/symbol.h" 6 #include "util/thread.h" 7 #include "util/header.h" 8 #include "util/exec_cmd.h" 9 #include "util/trace-event.h" 10 #include "util/session.h" 11 12 static char const *script_name; 13 static char const *generate_script_lang; 14 15 static int default_start_script(const char *script __unused, 16 int argc __unused, 17 const char **argv __unused) 18 { 19 return 0; 20 } 21 22 static int default_stop_script(void) 23 { 24 return 0; 25 } 26 27 static int default_generate_script(const char *outfile __unused) 28 { 29 return 0; 30 } 31 32 static struct scripting_ops default_scripting_ops = { 33 .start_script = default_start_script, 34 .stop_script = default_stop_script, 35 .process_event = print_event, 36 .generate_script = default_generate_script, 37 }; 38 39 static struct scripting_ops *scripting_ops; 40 41 static void setup_scripting(void) 42 { 43 /* make sure PERF_EXEC_PATH is set for scripts */ 44 perf_set_argv_exec_path(perf_exec_path()); 45 46 setup_perl_scripting(); 47 48 scripting_ops = &default_scripting_ops; 49 } 50 51 static int cleanup_scripting(void) 52 { 53 return scripting_ops->stop_script(); 54 } 55 56 #include "util/parse-options.h" 57 58 #include "perf.h" 59 #include "util/debug.h" 60 61 #include "util/trace-event.h" 62 #include "util/exec_cmd.h" 63 64 static char const *input_name = "perf.data"; 65 66 static int process_sample_event(event_t *event, struct perf_session *session) 67 { 68 struct sample_data data; 69 struct thread *thread; 70 71 memset(&data, 0, sizeof(data)); 72 data.time = -1; 73 data.cpu = -1; 74 data.period = 1; 75 76 event__parse_sample(event, session->sample_type, &data); 77 78 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 79 event->header.misc, 80 data.pid, data.tid, 81 (void *)(long)data.ip, 82 (long long)data.period); 83 84 thread = perf_session__findnew(session, event->ip.pid); 85 if (thread == NULL) { 86 pr_debug("problem processing %d event, skipping it.\n", 87 event->header.type); 88 return -1; 89 } 90 91 if (session->sample_type & PERF_SAMPLE_RAW) { 92 /* 93 * FIXME: better resolve from pid from the struct trace_entry 94 * field, although it should be the same than this perf 95 * event pid 96 */ 97 scripting_ops->process_event(data.cpu, data.raw_data, 98 data.raw_size, 99 data.time, thread->comm); 100 } 101 102 session->events_stats.total += data.period; 103 return 0; 104 } 105 106 static int sample_type_check(struct perf_session *session) 107 { 108 if (!(session->sample_type & PERF_SAMPLE_RAW)) { 109 fprintf(stderr, 110 "No trace sample to read. Did you call perf record " 111 "without -R?"); 112 return -1; 113 } 114 115 return 0; 116 } 117 118 static struct perf_event_ops event_ops = { 119 .process_sample_event = process_sample_event, 120 .process_comm_event = event__process_comm, 121 .sample_type_check = sample_type_check, 122 }; 123 124 static int __cmd_trace(struct perf_session *session) 125 { 126 return perf_session__process_events(session, &event_ops); 127 } 128 129 struct script_spec { 130 struct list_head node; 131 struct scripting_ops *ops; 132 char spec[0]; 133 }; 134 135 LIST_HEAD(script_specs); 136 137 static struct script_spec *script_spec__new(const char *spec, 138 struct scripting_ops *ops) 139 { 140 struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1); 141 142 if (s != NULL) { 143 strcpy(s->spec, spec); 144 s->ops = ops; 145 } 146 147 return s; 148 } 149 150 static void script_spec__delete(struct script_spec *s) 151 { 152 free(s->spec); 153 free(s); 154 } 155 156 static void script_spec__add(struct script_spec *s) 157 { 158 list_add_tail(&s->node, &script_specs); 159 } 160 161 static struct script_spec *script_spec__find(const char *spec) 162 { 163 struct script_spec *s; 164 165 list_for_each_entry(s, &script_specs, node) 166 if (strcasecmp(s->spec, spec) == 0) 167 return s; 168 return NULL; 169 } 170 171 static struct script_spec *script_spec__findnew(const char *spec, 172 struct scripting_ops *ops) 173 { 174 struct script_spec *s = script_spec__find(spec); 175 176 if (s) 177 return s; 178 179 s = script_spec__new(spec, ops); 180 if (!s) 181 goto out_delete_spec; 182 183 script_spec__add(s); 184 185 return s; 186 187 out_delete_spec: 188 script_spec__delete(s); 189 190 return NULL; 191 } 192 193 int script_spec_register(const char *spec, struct scripting_ops *ops) 194 { 195 struct script_spec *s; 196 197 s = script_spec__find(spec); 198 if (s) 199 return -1; 200 201 s = script_spec__findnew(spec, ops); 202 if (!s) 203 return -1; 204 205 return 0; 206 } 207 208 static struct scripting_ops *script_spec__lookup(const char *spec) 209 { 210 struct script_spec *s = script_spec__find(spec); 211 if (!s) 212 return NULL; 213 214 return s->ops; 215 } 216 217 static void list_available_languages(void) 218 { 219 struct script_spec *s; 220 221 fprintf(stderr, "\n"); 222 fprintf(stderr, "Scripting language extensions (used in " 223 "perf trace -s [spec:]script.[spec]):\n\n"); 224 225 list_for_each_entry(s, &script_specs, node) 226 fprintf(stderr, " %-42s [%s]\n", s->spec, s->ops->name); 227 228 fprintf(stderr, "\n"); 229 } 230 231 static int parse_scriptname(const struct option *opt __used, 232 const char *str, int unset __used) 233 { 234 char spec[PATH_MAX]; 235 const char *script, *ext; 236 int len; 237 238 if (strcmp(str, "list") == 0) { 239 list_available_languages(); 240 return 0; 241 } 242 243 script = strchr(str, ':'); 244 if (script) { 245 len = script - str; 246 if (len >= PATH_MAX) { 247 fprintf(stderr, "invalid language specifier"); 248 return -1; 249 } 250 strncpy(spec, str, len); 251 spec[len] = '\0'; 252 scripting_ops = script_spec__lookup(spec); 253 if (!scripting_ops) { 254 fprintf(stderr, "invalid language specifier"); 255 return -1; 256 } 257 script++; 258 } else { 259 script = str; 260 ext = strchr(script, '.'); 261 if (!ext) { 262 fprintf(stderr, "invalid script extension"); 263 return -1; 264 } 265 scripting_ops = script_spec__lookup(++ext); 266 if (!scripting_ops) { 267 fprintf(stderr, "invalid script extension"); 268 return -1; 269 } 270 } 271 272 script_name = strdup(script); 273 274 return 0; 275 } 276 277 static const char * const annotate_usage[] = { 278 "perf trace [<options>] <command>", 279 NULL 280 }; 281 282 static const struct option options[] = { 283 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 284 "dump raw trace in ASCII"), 285 OPT_BOOLEAN('v', "verbose", &verbose, 286 "be more verbose (show symbol address, etc)"), 287 OPT_BOOLEAN('l', "latency", &latency_format, 288 "show latency attributes (irqs/preemption disabled, etc)"), 289 OPT_CALLBACK('s', "script", NULL, "name", 290 "script file name (lang:script name, script name, or *)", 291 parse_scriptname), 292 OPT_STRING('g', "gen-script", &generate_script_lang, "lang", 293 "generate perf-trace.xx script in specified language"), 294 295 OPT_END() 296 }; 297 298 int cmd_trace(int argc, const char **argv, const char *prefix __used) 299 { 300 int err; 301 struct perf_session *session; 302 303 symbol__init(0); 304 305 setup_scripting(); 306 307 argc = parse_options(argc, argv, options, annotate_usage, 308 PARSE_OPT_STOP_AT_NON_OPTION); 309 310 setup_pager(); 311 312 session = perf_session__new(input_name, O_RDONLY, 0, NULL); 313 if (session == NULL) 314 return -ENOMEM; 315 316 if (generate_script_lang) { 317 struct stat perf_stat; 318 319 int input = open(input_name, O_RDONLY); 320 if (input < 0) { 321 perror("failed to open file"); 322 exit(-1); 323 } 324 325 err = fstat(input, &perf_stat); 326 if (err < 0) { 327 perror("failed to stat file"); 328 exit(-1); 329 } 330 331 if (!perf_stat.st_size) { 332 fprintf(stderr, "zero-sized file, nothing to do!\n"); 333 exit(0); 334 } 335 336 scripting_ops = script_spec__lookup(generate_script_lang); 337 if (!scripting_ops) { 338 fprintf(stderr, "invalid language specifier"); 339 return -1; 340 } 341 342 perf_header__read(&session->header, input); 343 err = scripting_ops->generate_script("perf-trace"); 344 goto out; 345 } 346 347 if (script_name) { 348 err = scripting_ops->start_script(script_name, argc, argv); 349 if (err) 350 goto out; 351 } 352 353 err = __cmd_trace(session); 354 355 perf_session__delete(session); 356 cleanup_scripting(); 357 out: 358 return err; 359 } 360