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