| .. | .. |
|---|
| 8 | 8 | */ |
|---|
| 9 | 9 | #include "builtin.h" |
|---|
| 10 | 10 | |
|---|
| 11 | | -#include "perf.h" |
|---|
| 12 | 11 | #include "util/color.h" |
|---|
| 12 | +#include "util/dso.h" |
|---|
| 13 | +#include "util/vdso.h" |
|---|
| 13 | 14 | #include "util/evlist.h" |
|---|
| 14 | 15 | #include "util/evsel.h" |
|---|
| 16 | +#include "util/map.h" |
|---|
| 15 | 17 | #include "util/session.h" |
|---|
| 16 | 18 | #include "util/tool.h" |
|---|
| 17 | 19 | #include "util/debug.h" |
|---|
| .. | .. |
|---|
| 19 | 21 | #include "util/data.h" |
|---|
| 20 | 22 | #include "util/auxtrace.h" |
|---|
| 21 | 23 | #include "util/jit.h" |
|---|
| 24 | +#include "util/symbol.h" |
|---|
| 25 | +#include "util/synthetic-events.h" |
|---|
| 22 | 26 | #include "util/thread.h" |
|---|
| 27 | +#include "util/namespaces.h" |
|---|
| 23 | 28 | |
|---|
| 29 | +#include <linux/err.h> |
|---|
| 24 | 30 | #include <subcmd/parse-options.h> |
|---|
| 31 | +#include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ |
|---|
| 25 | 32 | |
|---|
| 26 | 33 | #include <linux/list.h> |
|---|
| 27 | 34 | #include <errno.h> |
|---|
| .. | .. |
|---|
| 31 | 38 | struct perf_tool tool; |
|---|
| 32 | 39 | struct perf_session *session; |
|---|
| 33 | 40 | bool build_ids; |
|---|
| 41 | + bool build_id_all; |
|---|
| 34 | 42 | bool sched_stat; |
|---|
| 35 | 43 | bool have_auxtrace; |
|---|
| 36 | 44 | bool strip; |
|---|
| .. | .. |
|---|
| 41 | 49 | u64 aux_id; |
|---|
| 42 | 50 | struct list_head samples; |
|---|
| 43 | 51 | struct itrace_synth_opts itrace_synth_opts; |
|---|
| 52 | + char event_copy[PERF_SAMPLE_MAX_SIZE]; |
|---|
| 44 | 53 | }; |
|---|
| 45 | 54 | |
|---|
| 46 | 55 | struct event_entry { |
|---|
| 47 | 56 | struct list_head node; |
|---|
| 48 | 57 | u32 tid; |
|---|
| 49 | | - union perf_event event[0]; |
|---|
| 58 | + union perf_event event[]; |
|---|
| 50 | 59 | }; |
|---|
| 60 | + |
|---|
| 61 | +static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool, |
|---|
| 62 | + struct machine *machine, u8 cpumode, u32 flags); |
|---|
| 51 | 63 | |
|---|
| 52 | 64 | static int output_bytes(struct perf_inject *inject, void *buf, size_t sz) |
|---|
| 53 | 65 | { |
|---|
| .. | .. |
|---|
| 86 | 98 | } |
|---|
| 87 | 99 | #endif |
|---|
| 88 | 100 | |
|---|
| 89 | | -static int perf_event__repipe_op2_synth(struct perf_tool *tool, |
|---|
| 90 | | - union perf_event *event, |
|---|
| 91 | | - struct perf_session *session |
|---|
| 92 | | - __maybe_unused) |
|---|
| 101 | +static int perf_event__repipe_op2_synth(struct perf_session *session, |
|---|
| 102 | + union perf_event *event) |
|---|
| 93 | 103 | { |
|---|
| 94 | | - return perf_event__repipe_synth(tool, event); |
|---|
| 104 | + return perf_event__repipe_synth(session->tool, event); |
|---|
| 105 | +} |
|---|
| 106 | + |
|---|
| 107 | +static int perf_event__repipe_op4_synth(struct perf_session *session, |
|---|
| 108 | + union perf_event *event, |
|---|
| 109 | + u64 data __maybe_unused) |
|---|
| 110 | +{ |
|---|
| 111 | + return perf_event__repipe_synth(session->tool, event); |
|---|
| 95 | 112 | } |
|---|
| 96 | 113 | |
|---|
| 97 | 114 | static int perf_event__repipe_attr(struct perf_tool *tool, |
|---|
| 98 | 115 | union perf_event *event, |
|---|
| 99 | | - struct perf_evlist **pevlist) |
|---|
| 116 | + struct evlist **pevlist) |
|---|
| 100 | 117 | { |
|---|
| 101 | 118 | struct perf_inject *inject = container_of(tool, struct perf_inject, |
|---|
| 102 | 119 | tool); |
|---|
| .. | .. |
|---|
| 109 | 126 | if (!inject->output.is_pipe) |
|---|
| 110 | 127 | return 0; |
|---|
| 111 | 128 | |
|---|
| 129 | + return perf_event__repipe_synth(tool, event); |
|---|
| 130 | +} |
|---|
| 131 | + |
|---|
| 132 | +static int perf_event__repipe_event_update(struct perf_tool *tool, |
|---|
| 133 | + union perf_event *event, |
|---|
| 134 | + struct evlist **pevlist __maybe_unused) |
|---|
| 135 | +{ |
|---|
| 112 | 136 | return perf_event__repipe_synth(tool, event); |
|---|
| 113 | 137 | } |
|---|
| 114 | 138 | |
|---|
| .. | .. |
|---|
| 133 | 157 | return 0; |
|---|
| 134 | 158 | } |
|---|
| 135 | 159 | |
|---|
| 136 | | -static s64 perf_event__repipe_auxtrace(struct perf_tool *tool, |
|---|
| 137 | | - union perf_event *event, |
|---|
| 138 | | - struct perf_session *session) |
|---|
| 160 | +static s64 perf_event__repipe_auxtrace(struct perf_session *session, |
|---|
| 161 | + union perf_event *event) |
|---|
| 139 | 162 | { |
|---|
| 163 | + struct perf_tool *tool = session->tool; |
|---|
| 140 | 164 | struct perf_inject *inject = container_of(tool, struct perf_inject, |
|---|
| 141 | 165 | tool); |
|---|
| 142 | 166 | int ret; |
|---|
| .. | .. |
|---|
| 174 | 198 | #else |
|---|
| 175 | 199 | |
|---|
| 176 | 200 | static s64 |
|---|
| 177 | | -perf_event__repipe_auxtrace(struct perf_tool *tool __maybe_unused, |
|---|
| 178 | | - union perf_event *event __maybe_unused, |
|---|
| 179 | | - struct perf_session *session __maybe_unused) |
|---|
| 201 | +perf_event__repipe_auxtrace(struct perf_session *session __maybe_unused, |
|---|
| 202 | + union perf_event *event __maybe_unused) |
|---|
| 180 | 203 | { |
|---|
| 181 | 204 | pr_err("AUX area tracing not supported\n"); |
|---|
| 182 | 205 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 213 | 236 | return 0; |
|---|
| 214 | 237 | } |
|---|
| 215 | 238 | |
|---|
| 239 | +static union perf_event * |
|---|
| 240 | +perf_inject__cut_auxtrace_sample(struct perf_inject *inject, |
|---|
| 241 | + union perf_event *event, |
|---|
| 242 | + struct perf_sample *sample) |
|---|
| 243 | +{ |
|---|
| 244 | + size_t sz1 = sample->aux_sample.data - (void *)event; |
|---|
| 245 | + size_t sz2 = event->header.size - sample->aux_sample.size - sz1; |
|---|
| 246 | + union perf_event *ev = (union perf_event *)inject->event_copy; |
|---|
| 247 | + |
|---|
| 248 | + if (sz1 > event->header.size || sz2 > event->header.size || |
|---|
| 249 | + sz1 + sz2 > event->header.size || |
|---|
| 250 | + sz1 < sizeof(struct perf_event_header) + sizeof(u64)) |
|---|
| 251 | + return event; |
|---|
| 252 | + |
|---|
| 253 | + memcpy(ev, event, sz1); |
|---|
| 254 | + memcpy((void *)ev + sz1, (void *)event + event->header.size - sz2, sz2); |
|---|
| 255 | + ev->header.size = sz1 + sz2; |
|---|
| 256 | + ((u64 *)((void *)ev + sz1))[-1] = 0; |
|---|
| 257 | + |
|---|
| 258 | + return ev; |
|---|
| 259 | +} |
|---|
| 260 | + |
|---|
| 216 | 261 | typedef int (*inject_handler)(struct perf_tool *tool, |
|---|
| 217 | 262 | union perf_event *event, |
|---|
| 218 | 263 | struct perf_sample *sample, |
|---|
| 219 | | - struct perf_evsel *evsel, |
|---|
| 264 | + struct evsel *evsel, |
|---|
| 220 | 265 | struct machine *machine); |
|---|
| 221 | 266 | |
|---|
| 222 | 267 | static int perf_event__repipe_sample(struct perf_tool *tool, |
|---|
| 223 | 268 | union perf_event *event, |
|---|
| 224 | 269 | struct perf_sample *sample, |
|---|
| 225 | | - struct perf_evsel *evsel, |
|---|
| 270 | + struct evsel *evsel, |
|---|
| 226 | 271 | struct machine *machine) |
|---|
| 227 | 272 | { |
|---|
| 228 | | - if (evsel->handler) { |
|---|
| 273 | + struct perf_inject *inject = container_of(tool, struct perf_inject, |
|---|
| 274 | + tool); |
|---|
| 275 | + |
|---|
| 276 | + if (evsel && evsel->handler) { |
|---|
| 229 | 277 | inject_handler f = evsel->handler; |
|---|
| 230 | 278 | return f(tool, event, sample, evsel, machine); |
|---|
| 231 | 279 | } |
|---|
| 232 | 280 | |
|---|
| 233 | 281 | build_id__mark_dso_hit(tool, event, sample, evsel, machine); |
|---|
| 282 | + |
|---|
| 283 | + if (inject->itrace_synth_opts.set && sample->aux_sample.size) |
|---|
| 284 | + event = perf_inject__cut_auxtrace_sample(inject, event, sample); |
|---|
| 234 | 285 | |
|---|
| 235 | 286 | return perf_event__repipe_synth(tool, event); |
|---|
| 236 | 287 | } |
|---|
| .. | .. |
|---|
| 262 | 313 | * if jit marker, then inject jit mmaps and generate ELF images |
|---|
| 263 | 314 | */ |
|---|
| 264 | 315 | ret = jit_process(inject->session, &inject->output, machine, |
|---|
| 265 | | - event->mmap.filename, sample->pid, &n); |
|---|
| 316 | + event->mmap.filename, event->mmap.pid, &n); |
|---|
| 266 | 317 | if (ret < 0) |
|---|
| 267 | 318 | return ret; |
|---|
| 268 | 319 | if (ret) { |
|---|
| .. | .. |
|---|
| 272 | 323 | return perf_event__repipe_mmap(tool, event, sample, machine); |
|---|
| 273 | 324 | } |
|---|
| 274 | 325 | #endif |
|---|
| 326 | + |
|---|
| 327 | +static struct dso *findnew_dso(int pid, int tid, const char *filename, |
|---|
| 328 | + struct dso_id *id, struct machine *machine) |
|---|
| 329 | +{ |
|---|
| 330 | + struct thread *thread; |
|---|
| 331 | + struct nsinfo *nsi = NULL; |
|---|
| 332 | + struct nsinfo *nnsi; |
|---|
| 333 | + struct dso *dso; |
|---|
| 334 | + bool vdso; |
|---|
| 335 | + |
|---|
| 336 | + thread = machine__findnew_thread(machine, pid, tid); |
|---|
| 337 | + if (thread == NULL) { |
|---|
| 338 | + pr_err("cannot find or create a task %d/%d.\n", tid, pid); |
|---|
| 339 | + return NULL; |
|---|
| 340 | + } |
|---|
| 341 | + |
|---|
| 342 | + vdso = is_vdso_map(filename); |
|---|
| 343 | + nsi = nsinfo__get(thread->nsinfo); |
|---|
| 344 | + |
|---|
| 345 | + if (vdso) { |
|---|
| 346 | + /* The vdso maps are always on the host and not the |
|---|
| 347 | + * container. Ensure that we don't use setns to look |
|---|
| 348 | + * them up. |
|---|
| 349 | + */ |
|---|
| 350 | + nnsi = nsinfo__copy(nsi); |
|---|
| 351 | + if (nnsi) { |
|---|
| 352 | + nsinfo__put(nsi); |
|---|
| 353 | + nnsi->need_setns = false; |
|---|
| 354 | + nsi = nnsi; |
|---|
| 355 | + } |
|---|
| 356 | + dso = machine__findnew_vdso(machine, thread); |
|---|
| 357 | + } else { |
|---|
| 358 | + dso = machine__findnew_dso_id(machine, filename, id); |
|---|
| 359 | + } |
|---|
| 360 | + |
|---|
| 361 | + if (dso) { |
|---|
| 362 | + nsinfo__put(dso->nsinfo); |
|---|
| 363 | + dso->nsinfo = nsi; |
|---|
| 364 | + } else |
|---|
| 365 | + nsinfo__put(nsi); |
|---|
| 366 | + |
|---|
| 367 | + thread__put(thread); |
|---|
| 368 | + return dso; |
|---|
| 369 | +} |
|---|
| 370 | + |
|---|
| 371 | +static int perf_event__repipe_buildid_mmap(struct perf_tool *tool, |
|---|
| 372 | + union perf_event *event, |
|---|
| 373 | + struct perf_sample *sample, |
|---|
| 374 | + struct machine *machine) |
|---|
| 375 | +{ |
|---|
| 376 | + struct dso *dso; |
|---|
| 377 | + |
|---|
| 378 | + dso = findnew_dso(event->mmap.pid, event->mmap.tid, |
|---|
| 379 | + event->mmap.filename, NULL, machine); |
|---|
| 380 | + |
|---|
| 381 | + if (dso && !dso->hit) { |
|---|
| 382 | + dso->hit = 1; |
|---|
| 383 | + dso__inject_build_id(dso, tool, machine, sample->cpumode, 0); |
|---|
| 384 | + dso__put(dso); |
|---|
| 385 | + } |
|---|
| 386 | + |
|---|
| 387 | + return perf_event__repipe(tool, event, sample, machine); |
|---|
| 388 | +} |
|---|
| 275 | 389 | |
|---|
| 276 | 390 | static int perf_event__repipe_mmap2(struct perf_tool *tool, |
|---|
| 277 | 391 | union perf_event *event, |
|---|
| .. | .. |
|---|
| 300 | 414 | * if jit marker, then inject jit mmaps and generate ELF images |
|---|
| 301 | 415 | */ |
|---|
| 302 | 416 | ret = jit_process(inject->session, &inject->output, machine, |
|---|
| 303 | | - event->mmap2.filename, sample->pid, &n); |
|---|
| 417 | + event->mmap2.filename, event->mmap2.pid, &n); |
|---|
| 304 | 418 | if (ret < 0) |
|---|
| 305 | 419 | return ret; |
|---|
| 306 | 420 | if (ret) { |
|---|
| .. | .. |
|---|
| 310 | 424 | return perf_event__repipe_mmap2(tool, event, sample, machine); |
|---|
| 311 | 425 | } |
|---|
| 312 | 426 | #endif |
|---|
| 427 | + |
|---|
| 428 | +static int perf_event__repipe_buildid_mmap2(struct perf_tool *tool, |
|---|
| 429 | + union perf_event *event, |
|---|
| 430 | + struct perf_sample *sample, |
|---|
| 431 | + struct machine *machine) |
|---|
| 432 | +{ |
|---|
| 433 | + struct dso_id dso_id = { |
|---|
| 434 | + .maj = event->mmap2.maj, |
|---|
| 435 | + .min = event->mmap2.min, |
|---|
| 436 | + .ino = event->mmap2.ino, |
|---|
| 437 | + .ino_generation = event->mmap2.ino_generation, |
|---|
| 438 | + }; |
|---|
| 439 | + struct dso *dso; |
|---|
| 440 | + |
|---|
| 441 | + dso = findnew_dso(event->mmap2.pid, event->mmap2.tid, |
|---|
| 442 | + event->mmap2.filename, &dso_id, machine); |
|---|
| 443 | + |
|---|
| 444 | + if (dso && !dso->hit) { |
|---|
| 445 | + dso->hit = 1; |
|---|
| 446 | + dso__inject_build_id(dso, tool, machine, sample->cpumode, |
|---|
| 447 | + event->mmap2.flags); |
|---|
| 448 | + dso__put(dso); |
|---|
| 449 | + } |
|---|
| 450 | + |
|---|
| 451 | + perf_event__repipe(tool, event, sample, machine); |
|---|
| 452 | + |
|---|
| 453 | + return 0; |
|---|
| 454 | +} |
|---|
| 313 | 455 | |
|---|
| 314 | 456 | static int perf_event__repipe_fork(struct perf_tool *tool, |
|---|
| 315 | 457 | union perf_event *event, |
|---|
| .. | .. |
|---|
| 362 | 504 | return err; |
|---|
| 363 | 505 | } |
|---|
| 364 | 506 | |
|---|
| 365 | | -static int perf_event__repipe_tracing_data(struct perf_tool *tool, |
|---|
| 366 | | - union perf_event *event, |
|---|
| 367 | | - struct perf_session *session) |
|---|
| 507 | +static int perf_event__repipe_tracing_data(struct perf_session *session, |
|---|
| 508 | + union perf_event *event) |
|---|
| 368 | 509 | { |
|---|
| 369 | 510 | int err; |
|---|
| 370 | 511 | |
|---|
| 371 | | - perf_event__repipe_synth(tool, event); |
|---|
| 372 | | - err = perf_event__process_tracing_data(tool, event, session); |
|---|
| 373 | | - |
|---|
| 374 | | - return err; |
|---|
| 375 | | -} |
|---|
| 376 | | - |
|---|
| 377 | | -static int perf_event__repipe_id_index(struct perf_tool *tool, |
|---|
| 378 | | - union perf_event *event, |
|---|
| 379 | | - struct perf_session *session) |
|---|
| 380 | | -{ |
|---|
| 381 | | - int err; |
|---|
| 382 | | - |
|---|
| 383 | | - perf_event__repipe_synth(tool, event); |
|---|
| 384 | | - err = perf_event__process_id_index(tool, event, session); |
|---|
| 512 | + perf_event__repipe_synth(session->tool, event); |
|---|
| 513 | + err = perf_event__process_tracing_data(session, event); |
|---|
| 385 | 514 | |
|---|
| 386 | 515 | return err; |
|---|
| 387 | 516 | } |
|---|
| 388 | 517 | |
|---|
| 389 | 518 | static int dso__read_build_id(struct dso *dso) |
|---|
| 390 | 519 | { |
|---|
| 520 | + struct nscookie nsc; |
|---|
| 521 | + |
|---|
| 391 | 522 | if (dso->has_build_id) |
|---|
| 392 | 523 | return 0; |
|---|
| 393 | 524 | |
|---|
| 394 | | - if (filename__read_build_id(dso->long_name, dso->build_id, |
|---|
| 395 | | - sizeof(dso->build_id)) > 0) { |
|---|
| 525 | + nsinfo__mountns_enter(dso->nsinfo, &nsc); |
|---|
| 526 | + if (filename__read_build_id(dso->long_name, &dso->bid) > 0) |
|---|
| 396 | 527 | dso->has_build_id = true; |
|---|
| 397 | | - return 0; |
|---|
| 398 | | - } |
|---|
| 528 | + nsinfo__mountns_exit(&nsc); |
|---|
| 399 | 529 | |
|---|
| 400 | | - return -1; |
|---|
| 530 | + return dso->has_build_id ? 0 : -1; |
|---|
| 401 | 531 | } |
|---|
| 402 | 532 | |
|---|
| 403 | 533 | static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool, |
|---|
| 404 | | - struct machine *machine) |
|---|
| 534 | + struct machine *machine, u8 cpumode, u32 flags) |
|---|
| 405 | 535 | { |
|---|
| 406 | | - u16 misc = PERF_RECORD_MISC_USER; |
|---|
| 407 | 536 | int err; |
|---|
| 537 | + |
|---|
| 538 | + if (is_anon_memory(dso->long_name) || flags & MAP_HUGETLB) |
|---|
| 539 | + return 0; |
|---|
| 540 | + if (is_no_dso_memory(dso->long_name)) |
|---|
| 541 | + return 0; |
|---|
| 408 | 542 | |
|---|
| 409 | 543 | if (dso__read_build_id(dso) < 0) { |
|---|
| 410 | 544 | pr_debug("no build_id found for %s\n", dso->long_name); |
|---|
| 411 | 545 | return -1; |
|---|
| 412 | 546 | } |
|---|
| 413 | 547 | |
|---|
| 414 | | - if (dso->kernel) |
|---|
| 415 | | - misc = PERF_RECORD_MISC_KERNEL; |
|---|
| 416 | | - |
|---|
| 417 | | - err = perf_event__synthesize_build_id(tool, dso, misc, perf_event__repipe, |
|---|
| 418 | | - machine); |
|---|
| 548 | + err = perf_event__synthesize_build_id(tool, dso, cpumode, |
|---|
| 549 | + perf_event__repipe, machine); |
|---|
| 419 | 550 | if (err) { |
|---|
| 420 | 551 | pr_err("Can't synthesize build_id event for %s\n", dso->long_name); |
|---|
| 421 | 552 | return -1; |
|---|
| .. | .. |
|---|
| 424 | 555 | return 0; |
|---|
| 425 | 556 | } |
|---|
| 426 | 557 | |
|---|
| 427 | | -static int perf_event__inject_buildid(struct perf_tool *tool, |
|---|
| 428 | | - union perf_event *event, |
|---|
| 429 | | - struct perf_sample *sample, |
|---|
| 430 | | - struct perf_evsel *evsel __maybe_unused, |
|---|
| 431 | | - struct machine *machine) |
|---|
| 558 | +int perf_event__inject_buildid(struct perf_tool *tool, union perf_event *event, |
|---|
| 559 | + struct perf_sample *sample, |
|---|
| 560 | + struct evsel *evsel __maybe_unused, |
|---|
| 561 | + struct machine *machine) |
|---|
| 432 | 562 | { |
|---|
| 433 | 563 | struct addr_location al; |
|---|
| 434 | 564 | struct thread *thread; |
|---|
| .. | .. |
|---|
| 443 | 573 | if (thread__find_map(thread, sample->cpumode, sample->ip, &al)) { |
|---|
| 444 | 574 | if (!al.map->dso->hit) { |
|---|
| 445 | 575 | al.map->dso->hit = 1; |
|---|
| 446 | | - if (map__load(al.map) >= 0) { |
|---|
| 447 | | - dso__inject_build_id(al.map->dso, tool, machine); |
|---|
| 448 | | - /* |
|---|
| 449 | | - * If this fails, too bad, let the other side |
|---|
| 450 | | - * account this as unresolved. |
|---|
| 451 | | - */ |
|---|
| 452 | | - } else { |
|---|
| 453 | | -#ifdef HAVE_LIBELF_SUPPORT |
|---|
| 454 | | - pr_warning("no symbols found in %s, maybe " |
|---|
| 455 | | - "install a debug package?\n", |
|---|
| 456 | | - al.map->dso->long_name); |
|---|
| 457 | | -#endif |
|---|
| 458 | | - } |
|---|
| 576 | + dso__inject_build_id(al.map->dso, tool, machine, |
|---|
| 577 | + sample->cpumode, al.map->flags); |
|---|
| 459 | 578 | } |
|---|
| 460 | 579 | } |
|---|
| 461 | 580 | |
|---|
| .. | .. |
|---|
| 468 | 587 | static int perf_inject__sched_process_exit(struct perf_tool *tool, |
|---|
| 469 | 588 | union perf_event *event __maybe_unused, |
|---|
| 470 | 589 | struct perf_sample *sample, |
|---|
| 471 | | - struct perf_evsel *evsel __maybe_unused, |
|---|
| 590 | + struct evsel *evsel __maybe_unused, |
|---|
| 472 | 591 | struct machine *machine __maybe_unused) |
|---|
| 473 | 592 | { |
|---|
| 474 | 593 | struct perf_inject *inject = container_of(tool, struct perf_inject, tool); |
|---|
| .. | .. |
|---|
| 488 | 607 | static int perf_inject__sched_switch(struct perf_tool *tool, |
|---|
| 489 | 608 | union perf_event *event, |
|---|
| 490 | 609 | struct perf_sample *sample, |
|---|
| 491 | | - struct perf_evsel *evsel, |
|---|
| 610 | + struct evsel *evsel, |
|---|
| 492 | 611 | struct machine *machine) |
|---|
| 493 | 612 | { |
|---|
| 494 | 613 | struct perf_inject *inject = container_of(tool, struct perf_inject, tool); |
|---|
| .. | .. |
|---|
| 512 | 631 | static int perf_inject__sched_stat(struct perf_tool *tool, |
|---|
| 513 | 632 | union perf_event *event __maybe_unused, |
|---|
| 514 | 633 | struct perf_sample *sample, |
|---|
| 515 | | - struct perf_evsel *evsel, |
|---|
| 634 | + struct evsel *evsel, |
|---|
| 516 | 635 | struct machine *machine) |
|---|
| 517 | 636 | { |
|---|
| 518 | 637 | struct event_entry *ent; |
|---|
| 519 | 638 | union perf_event *event_sw; |
|---|
| 520 | 639 | struct perf_sample sample_sw; |
|---|
| 521 | 640 | struct perf_inject *inject = container_of(tool, struct perf_inject, tool); |
|---|
| 522 | | - u32 pid = perf_evsel__intval(evsel, sample, "pid"); |
|---|
| 641 | + u32 pid = evsel__intval(evsel, sample, "pid"); |
|---|
| 523 | 642 | |
|---|
| 524 | 643 | list_for_each_entry(ent, &inject->samples, node) { |
|---|
| 525 | 644 | if (pid == ent->tid) |
|---|
| .. | .. |
|---|
| 529 | 648 | return 0; |
|---|
| 530 | 649 | found: |
|---|
| 531 | 650 | event_sw = &ent->event[0]; |
|---|
| 532 | | - perf_evsel__parse_sample(evsel, event_sw, &sample_sw); |
|---|
| 651 | + evsel__parse_sample(evsel, event_sw, &sample_sw); |
|---|
| 533 | 652 | |
|---|
| 534 | 653 | sample_sw.period = sample->period; |
|---|
| 535 | 654 | sample_sw.time = sample->time; |
|---|
| 536 | | - perf_event__synthesize_sample(event_sw, evsel->attr.sample_type, |
|---|
| 537 | | - evsel->attr.read_format, &sample_sw); |
|---|
| 655 | + perf_event__synthesize_sample(event_sw, evsel->core.attr.sample_type, |
|---|
| 656 | + evsel->core.attr.read_format, &sample_sw); |
|---|
| 538 | 657 | build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine); |
|---|
| 539 | 658 | return perf_event__repipe(tool, event_sw, &sample_sw, machine); |
|---|
| 540 | 659 | } |
|---|
| .. | .. |
|---|
| 544 | 663 | session_done = 1; |
|---|
| 545 | 664 | } |
|---|
| 546 | 665 | |
|---|
| 547 | | -static int perf_evsel__check_stype(struct perf_evsel *evsel, |
|---|
| 548 | | - u64 sample_type, const char *sample_msg) |
|---|
| 666 | +static int evsel__check_stype(struct evsel *evsel, u64 sample_type, const char *sample_msg) |
|---|
| 549 | 667 | { |
|---|
| 550 | | - struct perf_event_attr *attr = &evsel->attr; |
|---|
| 551 | | - const char *name = perf_evsel__name(evsel); |
|---|
| 668 | + struct perf_event_attr *attr = &evsel->core.attr; |
|---|
| 669 | + const char *name = evsel__name(evsel); |
|---|
| 552 | 670 | |
|---|
| 553 | 671 | if (!(attr->sample_type & sample_type)) { |
|---|
| 554 | 672 | pr_err("Samples for %s event do not have %s attribute set.", |
|---|
| .. | .. |
|---|
| 562 | 680 | static int drop_sample(struct perf_tool *tool __maybe_unused, |
|---|
| 563 | 681 | union perf_event *event __maybe_unused, |
|---|
| 564 | 682 | struct perf_sample *sample __maybe_unused, |
|---|
| 565 | | - struct perf_evsel *evsel __maybe_unused, |
|---|
| 683 | + struct evsel *evsel __maybe_unused, |
|---|
| 566 | 684 | struct machine *machine __maybe_unused) |
|---|
| 567 | 685 | { |
|---|
| 568 | 686 | return 0; |
|---|
| .. | .. |
|---|
| 570 | 688 | |
|---|
| 571 | 689 | static void strip_init(struct perf_inject *inject) |
|---|
| 572 | 690 | { |
|---|
| 573 | | - struct perf_evlist *evlist = inject->session->evlist; |
|---|
| 574 | | - struct perf_evsel *evsel; |
|---|
| 691 | + struct evlist *evlist = inject->session->evlist; |
|---|
| 692 | + struct evsel *evsel; |
|---|
| 575 | 693 | |
|---|
| 576 | 694 | inject->tool.context_switch = perf_event__drop; |
|---|
| 577 | 695 | |
|---|
| 578 | 696 | evlist__for_each_entry(evlist, evsel) |
|---|
| 579 | 697 | evsel->handler = drop_sample; |
|---|
| 580 | | -} |
|---|
| 581 | | - |
|---|
| 582 | | -static bool has_tracking(struct perf_evsel *evsel) |
|---|
| 583 | | -{ |
|---|
| 584 | | - return evsel->attr.mmap || evsel->attr.mmap2 || evsel->attr.comm || |
|---|
| 585 | | - evsel->attr.task; |
|---|
| 586 | | -} |
|---|
| 587 | | - |
|---|
| 588 | | -#define COMPAT_MASK (PERF_SAMPLE_ID | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | \ |
|---|
| 589 | | - PERF_SAMPLE_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER) |
|---|
| 590 | | - |
|---|
| 591 | | -/* |
|---|
| 592 | | - * In order that the perf.data file is parsable, tracking events like MMAP need |
|---|
| 593 | | - * their selected event to exist, except if there is only 1 selected event left |
|---|
| 594 | | - * and it has a compatible sample type. |
|---|
| 595 | | - */ |
|---|
| 596 | | -static bool ok_to_remove(struct perf_evlist *evlist, |
|---|
| 597 | | - struct perf_evsel *evsel_to_remove) |
|---|
| 598 | | -{ |
|---|
| 599 | | - struct perf_evsel *evsel; |
|---|
| 600 | | - int cnt = 0; |
|---|
| 601 | | - bool ok = false; |
|---|
| 602 | | - |
|---|
| 603 | | - if (!has_tracking(evsel_to_remove)) |
|---|
| 604 | | - return true; |
|---|
| 605 | | - |
|---|
| 606 | | - evlist__for_each_entry(evlist, evsel) { |
|---|
| 607 | | - if (evsel->handler != drop_sample) { |
|---|
| 608 | | - cnt += 1; |
|---|
| 609 | | - if ((evsel->attr.sample_type & COMPAT_MASK) == |
|---|
| 610 | | - (evsel_to_remove->attr.sample_type & COMPAT_MASK)) |
|---|
| 611 | | - ok = true; |
|---|
| 612 | | - } |
|---|
| 613 | | - } |
|---|
| 614 | | - |
|---|
| 615 | | - return ok && cnt == 1; |
|---|
| 616 | | -} |
|---|
| 617 | | - |
|---|
| 618 | | -static void strip_fini(struct perf_inject *inject) |
|---|
| 619 | | -{ |
|---|
| 620 | | - struct perf_evlist *evlist = inject->session->evlist; |
|---|
| 621 | | - struct perf_evsel *evsel, *tmp; |
|---|
| 622 | | - |
|---|
| 623 | | - /* Remove non-synthesized evsels if possible */ |
|---|
| 624 | | - evlist__for_each_entry_safe(evlist, tmp, evsel) { |
|---|
| 625 | | - if (evsel->handler == drop_sample && |
|---|
| 626 | | - ok_to_remove(evlist, evsel)) { |
|---|
| 627 | | - pr_debug("Deleting %s\n", perf_evsel__name(evsel)); |
|---|
| 628 | | - perf_evlist__remove(evlist, evsel); |
|---|
| 629 | | - perf_evsel__delete(evsel); |
|---|
| 630 | | - } |
|---|
| 631 | | - } |
|---|
| 632 | 698 | } |
|---|
| 633 | 699 | |
|---|
| 634 | 700 | static int __cmd_inject(struct perf_inject *inject) |
|---|
| .. | .. |
|---|
| 642 | 708 | signal(SIGINT, sig_handler); |
|---|
| 643 | 709 | |
|---|
| 644 | 710 | if (inject->build_ids || inject->sched_stat || |
|---|
| 645 | | - inject->itrace_synth_opts.set) { |
|---|
| 711 | + inject->itrace_synth_opts.set || inject->build_id_all) { |
|---|
| 646 | 712 | inject->tool.mmap = perf_event__repipe_mmap; |
|---|
| 647 | 713 | inject->tool.mmap2 = perf_event__repipe_mmap2; |
|---|
| 648 | 714 | inject->tool.fork = perf_event__repipe_fork; |
|---|
| .. | .. |
|---|
| 651 | 717 | |
|---|
| 652 | 718 | output_data_offset = session->header.data_offset; |
|---|
| 653 | 719 | |
|---|
| 654 | | - if (inject->build_ids) { |
|---|
| 720 | + if (inject->build_id_all) { |
|---|
| 721 | + inject->tool.mmap = perf_event__repipe_buildid_mmap; |
|---|
| 722 | + inject->tool.mmap2 = perf_event__repipe_buildid_mmap2; |
|---|
| 723 | + } else if (inject->build_ids) { |
|---|
| 655 | 724 | inject->tool.sample = perf_event__inject_buildid; |
|---|
| 656 | 725 | } else if (inject->sched_stat) { |
|---|
| 657 | | - struct perf_evsel *evsel; |
|---|
| 726 | + struct evsel *evsel; |
|---|
| 658 | 727 | |
|---|
| 659 | 728 | evlist__for_each_entry(session->evlist, evsel) { |
|---|
| 660 | | - const char *name = perf_evsel__name(evsel); |
|---|
| 729 | + const char *name = evsel__name(evsel); |
|---|
| 661 | 730 | |
|---|
| 662 | 731 | if (!strcmp(name, "sched:sched_switch")) { |
|---|
| 663 | | - if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID")) |
|---|
| 732 | + if (evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID")) |
|---|
| 664 | 733 | return -EINVAL; |
|---|
| 665 | 734 | |
|---|
| 666 | 735 | evsel->handler = perf_inject__sched_switch; |
|---|
| .. | .. |
|---|
| 675 | 744 | inject->tool.comm = perf_event__repipe_comm; |
|---|
| 676 | 745 | inject->tool.namespaces = perf_event__repipe_namespaces; |
|---|
| 677 | 746 | inject->tool.exit = perf_event__repipe_exit; |
|---|
| 678 | | - inject->tool.id_index = perf_event__repipe_id_index; |
|---|
| 747 | + inject->tool.id_index = perf_event__process_id_index; |
|---|
| 679 | 748 | inject->tool.auxtrace_info = perf_event__process_auxtrace_info; |
|---|
| 680 | 749 | inject->tool.auxtrace = perf_event__process_auxtrace; |
|---|
| 681 | 750 | inject->tool.aux = perf_event__drop_aux; |
|---|
| .. | .. |
|---|
| 683 | 752 | inject->tool.ordered_events = true; |
|---|
| 684 | 753 | inject->tool.ordering_requires_timestamps = true; |
|---|
| 685 | 754 | /* Allow space in the header for new attributes */ |
|---|
| 686 | | - output_data_offset = 4096; |
|---|
| 755 | + output_data_offset = roundup(8192 + session->header.data_offset, 4096); |
|---|
| 687 | 756 | if (inject->strip) |
|---|
| 688 | 757 | strip_init(inject); |
|---|
| 689 | 758 | } |
|---|
| .. | .. |
|---|
| 711 | 780 | dsos__hit_all(session); |
|---|
| 712 | 781 | /* |
|---|
| 713 | 782 | * The AUX areas have been removed and replaced with |
|---|
| 714 | | - * synthesized hardware events, so clear the feature flag and |
|---|
| 715 | | - * remove the evsel. |
|---|
| 783 | + * synthesized hardware events, so clear the feature flag. |
|---|
| 716 | 784 | */ |
|---|
| 717 | 785 | if (inject->itrace_synth_opts.set) { |
|---|
| 718 | | - struct perf_evsel *evsel; |
|---|
| 719 | | - |
|---|
| 720 | 786 | perf_header__clear_feat(&session->header, |
|---|
| 721 | 787 | HEADER_AUXTRACE); |
|---|
| 722 | | - if (inject->itrace_synth_opts.last_branch) |
|---|
| 788 | + if (inject->itrace_synth_opts.last_branch || |
|---|
| 789 | + inject->itrace_synth_opts.add_last_branch) |
|---|
| 723 | 790 | perf_header__set_feat(&session->header, |
|---|
| 724 | 791 | HEADER_BRANCH_STACK); |
|---|
| 725 | | - evsel = perf_evlist__id2evsel_strict(session->evlist, |
|---|
| 726 | | - inject->aux_id); |
|---|
| 727 | | - if (evsel) { |
|---|
| 728 | | - pr_debug("Deleting %s\n", |
|---|
| 729 | | - perf_evsel__name(evsel)); |
|---|
| 730 | | - perf_evlist__remove(session->evlist, evsel); |
|---|
| 731 | | - perf_evsel__delete(evsel); |
|---|
| 732 | | - } |
|---|
| 733 | | - if (inject->strip) |
|---|
| 734 | | - strip_fini(inject); |
|---|
| 735 | 792 | } |
|---|
| 736 | 793 | session->header.data_offset = output_data_offset; |
|---|
| 737 | 794 | session->header.data_size = inject->bytes_written; |
|---|
| .. | .. |
|---|
| 746 | 803 | struct perf_inject inject = { |
|---|
| 747 | 804 | .tool = { |
|---|
| 748 | 805 | .sample = perf_event__repipe_sample, |
|---|
| 806 | + .read = perf_event__repipe_sample, |
|---|
| 749 | 807 | .mmap = perf_event__repipe, |
|---|
| 750 | 808 | .mmap2 = perf_event__repipe, |
|---|
| 751 | 809 | .comm = perf_event__repipe, |
|---|
| 810 | + .namespaces = perf_event__repipe, |
|---|
| 811 | + .cgroup = perf_event__repipe, |
|---|
| 752 | 812 | .fork = perf_event__repipe, |
|---|
| 753 | 813 | .exit = perf_event__repipe, |
|---|
| 754 | 814 | .lost = perf_event__repipe, |
|---|
| .. | .. |
|---|
| 756 | 816 | .aux = perf_event__repipe, |
|---|
| 757 | 817 | .itrace_start = perf_event__repipe, |
|---|
| 758 | 818 | .context_switch = perf_event__repipe, |
|---|
| 759 | | - .read = perf_event__repipe_sample, |
|---|
| 760 | 819 | .throttle = perf_event__repipe, |
|---|
| 761 | 820 | .unthrottle = perf_event__repipe, |
|---|
| 821 | + .ksymbol = perf_event__repipe, |
|---|
| 822 | + .bpf = perf_event__repipe, |
|---|
| 823 | + .text_poke = perf_event__repipe, |
|---|
| 762 | 824 | .attr = perf_event__repipe_attr, |
|---|
| 825 | + .event_update = perf_event__repipe_event_update, |
|---|
| 763 | 826 | .tracing_data = perf_event__repipe_op2_synth, |
|---|
| 764 | | - .auxtrace_info = perf_event__repipe_op2_synth, |
|---|
| 765 | | - .auxtrace = perf_event__repipe_auxtrace, |
|---|
| 766 | | - .auxtrace_error = perf_event__repipe_op2_synth, |
|---|
| 767 | | - .time_conv = perf_event__repipe_op2_synth, |
|---|
| 768 | 827 | .finished_round = perf_event__repipe_oe_synth, |
|---|
| 769 | 828 | .build_id = perf_event__repipe_op2_synth, |
|---|
| 770 | 829 | .id_index = perf_event__repipe_op2_synth, |
|---|
| 830 | + .auxtrace_info = perf_event__repipe_op2_synth, |
|---|
| 831 | + .auxtrace_error = perf_event__repipe_op2_synth, |
|---|
| 832 | + .time_conv = perf_event__repipe_op2_synth, |
|---|
| 833 | + .thread_map = perf_event__repipe_op2_synth, |
|---|
| 834 | + .cpu_map = perf_event__repipe_op2_synth, |
|---|
| 835 | + .stat_config = perf_event__repipe_op2_synth, |
|---|
| 836 | + .stat = perf_event__repipe_op2_synth, |
|---|
| 837 | + .stat_round = perf_event__repipe_op2_synth, |
|---|
| 771 | 838 | .feature = perf_event__repipe_op2_synth, |
|---|
| 839 | + .compressed = perf_event__repipe_op4_synth, |
|---|
| 840 | + .auxtrace = perf_event__repipe_auxtrace, |
|---|
| 772 | 841 | }, |
|---|
| 773 | 842 | .input_name = "-", |
|---|
| 774 | 843 | .samples = LIST_HEAD_INIT(inject.samples), |
|---|
| 775 | 844 | .output = { |
|---|
| 776 | | - .file = { |
|---|
| 777 | | - .path = "-", |
|---|
| 778 | | - }, |
|---|
| 779 | | - .mode = PERF_DATA_MODE_WRITE, |
|---|
| 845 | + .path = "-", |
|---|
| 846 | + .mode = PERF_DATA_MODE_WRITE, |
|---|
| 780 | 847 | }, |
|---|
| 781 | 848 | }; |
|---|
| 782 | 849 | struct perf_data data = { |
|---|
| .. | .. |
|---|
| 787 | 854 | struct option options[] = { |
|---|
| 788 | 855 | OPT_BOOLEAN('b', "build-ids", &inject.build_ids, |
|---|
| 789 | 856 | "Inject build-ids into the output stream"), |
|---|
| 857 | + OPT_BOOLEAN(0, "buildid-all", &inject.build_id_all, |
|---|
| 858 | + "Inject build-ids of all DSOs into the output stream"), |
|---|
| 790 | 859 | OPT_STRING('i', "input", &inject.input_name, "file", |
|---|
| 791 | 860 | "input file name"), |
|---|
| 792 | | - OPT_STRING('o', "output", &inject.output.file.path, "file", |
|---|
| 861 | + OPT_STRING('o', "output", &inject.output.path, "file", |
|---|
| 793 | 862 | "output file name"), |
|---|
| 794 | 863 | OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat, |
|---|
| 795 | 864 | "Merge sched-stat and sched-switch for getting events " |
|---|
| .. | .. |
|---|
| 803 | 872 | "kallsyms pathname"), |
|---|
| 804 | 873 | OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"), |
|---|
| 805 | 874 | OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts, |
|---|
| 806 | | - NULL, "opts", "Instruction Tracing options", |
|---|
| 875 | + NULL, "opts", "Instruction Tracing options\n" |
|---|
| 876 | + ITRACE_HELP, |
|---|
| 807 | 877 | itrace_parse_synth_opts), |
|---|
| 808 | 878 | OPT_BOOLEAN(0, "strip", &inject.strip, |
|---|
| 809 | 879 | "strip non-synthesized events (use with --itrace)"), |
|---|
| .. | .. |
|---|
| 834 | 904 | return -1; |
|---|
| 835 | 905 | } |
|---|
| 836 | 906 | |
|---|
| 837 | | - inject.tool.ordered_events = inject.sched_stat; |
|---|
| 907 | + data.path = inject.input_name; |
|---|
| 908 | + inject.session = perf_session__new(&data, inject.output.is_pipe, &inject.tool); |
|---|
| 909 | + if (IS_ERR(inject.session)) { |
|---|
| 910 | + ret = PTR_ERR(inject.session); |
|---|
| 911 | + goto out_close_output; |
|---|
| 912 | + } |
|---|
| 838 | 913 | |
|---|
| 839 | | - data.file.path = inject.input_name; |
|---|
| 840 | | - inject.session = perf_session__new(&data, true, &inject.tool); |
|---|
| 841 | | - if (inject.session == NULL) |
|---|
| 842 | | - return -1; |
|---|
| 914 | + if (zstd_init(&(inject.session->zstd_data), 0) < 0) |
|---|
| 915 | + pr_warning("Decompression initialization failed.\n"); |
|---|
| 843 | 916 | |
|---|
| 844 | | - if (inject.build_ids) { |
|---|
| 917 | + if (inject.build_ids && !inject.build_id_all) { |
|---|
| 845 | 918 | /* |
|---|
| 846 | 919 | * to make sure the mmap records are ordered correctly |
|---|
| 847 | 920 | * and so that the correct especially due to jitted code |
|---|
| .. | .. |
|---|
| 851 | 924 | inject.tool.ordered_events = true; |
|---|
| 852 | 925 | inject.tool.ordering_requires_timestamps = true; |
|---|
| 853 | 926 | } |
|---|
| 927 | + |
|---|
| 928 | + if (inject.sched_stat) { |
|---|
| 929 | + inject.tool.ordered_events = true; |
|---|
| 930 | + } |
|---|
| 931 | + |
|---|
| 854 | 932 | #ifdef HAVE_JITDUMP |
|---|
| 855 | 933 | if (inject.jit_mode) { |
|---|
| 856 | 934 | inject.tool.mmap2 = perf_event__jit_repipe_mmap2; |
|---|
| .. | .. |
|---|
| 871 | 949 | ret = __cmd_inject(&inject); |
|---|
| 872 | 950 | |
|---|
| 873 | 951 | out_delete: |
|---|
| 952 | + zstd_fini(&(inject.session->zstd_data)); |
|---|
| 874 | 953 | perf_session__delete(inject.session); |
|---|
| 954 | +out_close_output: |
|---|
| 955 | + perf_data__close(&inject.output); |
|---|
| 875 | 956 | return ret; |
|---|
| 876 | 957 | } |
|---|