| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * intel-bts.c: Intel Processor Trace support |
|---|
| 3 | 4 | * Copyright (c) 2013-2015, Intel Corporation. |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 6 | | - * under the terms and conditions of the GNU General Public License, |
|---|
| 7 | | - * version 2, as published by the Free Software Foundation. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
|---|
| 10 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 11 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 12 | | - * more details. |
|---|
| 13 | | - * |
|---|
| 14 | 5 | */ |
|---|
| 15 | 6 | |
|---|
| 16 | 7 | #include <endian.h> |
|---|
| .. | .. |
|---|
| 21 | 12 | #include <linux/types.h> |
|---|
| 22 | 13 | #include <linux/bitops.h> |
|---|
| 23 | 14 | #include <linux/log2.h> |
|---|
| 15 | +#include <linux/zalloc.h> |
|---|
| 24 | 16 | |
|---|
| 25 | | -#include "cpumap.h" |
|---|
| 26 | 17 | #include "color.h" |
|---|
| 27 | 18 | #include "evsel.h" |
|---|
| 28 | 19 | #include "evlist.h" |
|---|
| 29 | 20 | #include "machine.h" |
|---|
| 21 | +#include "symbol.h" |
|---|
| 30 | 22 | #include "session.h" |
|---|
| 31 | | -#include "util.h" |
|---|
| 23 | +#include "tool.h" |
|---|
| 32 | 24 | #include "thread.h" |
|---|
| 33 | 25 | #include "thread-stack.h" |
|---|
| 34 | 26 | #include "debug.h" |
|---|
| .. | .. |
|---|
| 36 | 28 | #include "auxtrace.h" |
|---|
| 37 | 29 | #include "intel-pt-decoder/intel-pt-insn-decoder.h" |
|---|
| 38 | 30 | #include "intel-bts.h" |
|---|
| 31 | +#include "util/synthetic-events.h" |
|---|
| 39 | 32 | |
|---|
| 40 | 33 | #define MAX_TIMESTAMP (~0ULL) |
|---|
| 41 | 34 | |
|---|
| .. | .. |
|---|
| 142 | 135 | |
|---|
| 143 | 136 | auxtrace_synth_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE, |
|---|
| 144 | 137 | INTEL_BTS_ERR_LOST, sample->cpu, sample->pid, |
|---|
| 145 | | - sample->tid, 0, "Lost trace data"); |
|---|
| 138 | + sample->tid, 0, "Lost trace data", sample->time); |
|---|
| 146 | 139 | |
|---|
| 147 | 140 | err = perf_session__deliver_synth_event(bts->session, &event, NULL); |
|---|
| 148 | 141 | if (err) |
|---|
| .. | .. |
|---|
| 326 | 319 | { |
|---|
| 327 | 320 | struct machine *machine = btsq->bts->machine; |
|---|
| 328 | 321 | struct thread *thread; |
|---|
| 329 | | - struct addr_location al; |
|---|
| 330 | 322 | unsigned char buf[INTEL_PT_INSN_BUF_SZ]; |
|---|
| 331 | 323 | ssize_t len; |
|---|
| 332 | | - int x86_64; |
|---|
| 333 | | - uint8_t cpumode; |
|---|
| 324 | + bool x86_64; |
|---|
| 334 | 325 | int err = -1; |
|---|
| 335 | | - |
|---|
| 336 | | - if (machine__kernel_ip(machine, ip)) |
|---|
| 337 | | - cpumode = PERF_RECORD_MISC_KERNEL; |
|---|
| 338 | | - else |
|---|
| 339 | | - cpumode = PERF_RECORD_MISC_USER; |
|---|
| 340 | 326 | |
|---|
| 341 | 327 | thread = machine__find_thread(machine, -1, btsq->tid); |
|---|
| 342 | 328 | if (!thread) |
|---|
| 343 | 329 | return -1; |
|---|
| 344 | 330 | |
|---|
| 345 | | - if (!thread__find_map(thread, cpumode, ip, &al) || !al.map->dso) |
|---|
| 346 | | - goto out_put; |
|---|
| 347 | | - |
|---|
| 348 | | - len = dso__data_read_addr(al.map->dso, al.map, machine, ip, buf, |
|---|
| 349 | | - INTEL_PT_INSN_BUF_SZ); |
|---|
| 331 | + len = thread__memcpy(thread, machine, buf, ip, INTEL_PT_INSN_BUF_SZ, &x86_64); |
|---|
| 350 | 332 | if (len <= 0) |
|---|
| 351 | 333 | goto out_put; |
|---|
| 352 | | - |
|---|
| 353 | | - /* Load maps to ensure dso->is_64_bit has been updated */ |
|---|
| 354 | | - map__load(al.map); |
|---|
| 355 | | - |
|---|
| 356 | | - x86_64 = al.map->dso->is_64_bit; |
|---|
| 357 | 334 | |
|---|
| 358 | 335 | if (intel_pt_get_insn(buf, len, x86_64, &btsq->intel_pt_insn)) |
|---|
| 359 | 336 | goto out_put; |
|---|
| .. | .. |
|---|
| 372 | 349 | |
|---|
| 373 | 350 | auxtrace_synth_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE, |
|---|
| 374 | 351 | INTEL_BTS_ERR_NOINSN, cpu, pid, tid, ip, |
|---|
| 375 | | - "Failed to get instruction"); |
|---|
| 352 | + "Failed to get instruction", 0); |
|---|
| 376 | 353 | |
|---|
| 377 | 354 | err = perf_session__deliver_synth_event(bts->session, &event, NULL); |
|---|
| 378 | 355 | if (err) |
|---|
| .. | .. |
|---|
| 451 | 428 | continue; |
|---|
| 452 | 429 | intel_bts_get_branch_type(btsq, branch); |
|---|
| 453 | 430 | if (btsq->bts->synth_opts.thread_stack) |
|---|
| 454 | | - thread_stack__event(thread, btsq->sample_flags, |
|---|
| 431 | + thread_stack__event(thread, btsq->cpu, btsq->sample_flags, |
|---|
| 455 | 432 | le64_to_cpu(branch->from), |
|---|
| 456 | 433 | le64_to_cpu(branch->to), |
|---|
| 457 | 434 | btsq->intel_pt_insn.length, |
|---|
| 458 | | - buffer->buffer_nr + 1); |
|---|
| 435 | + buffer->buffer_nr + 1, true, 0, 0); |
|---|
| 459 | 436 | if (filter && !(filter & btsq->sample_flags)) |
|---|
| 460 | 437 | continue; |
|---|
| 461 | 438 | err = intel_bts_synth_branch_sample(btsq, branch); |
|---|
| .. | .. |
|---|
| 523 | 500 | !btsq->bts->synth_opts.thread_stack && thread && |
|---|
| 524 | 501 | (!old_buffer || btsq->bts->sampling_mode || |
|---|
| 525 | 502 | (btsq->bts->snapshot_mode && !buffer->consecutive))) |
|---|
| 526 | | - thread_stack__set_trace_nr(thread, buffer->buffer_nr + 1); |
|---|
| 503 | + thread_stack__set_trace_nr(thread, btsq->cpu, buffer->buffer_nr + 1); |
|---|
| 527 | 504 | |
|---|
| 528 | 505 | err = intel_bts_process_buffer(btsq, buffer, thread); |
|---|
| 529 | 506 | |
|---|
| .. | .. |
|---|
| 751 | 728 | free(bts); |
|---|
| 752 | 729 | } |
|---|
| 753 | 730 | |
|---|
| 731 | +static bool intel_bts_evsel_is_auxtrace(struct perf_session *session, |
|---|
| 732 | + struct evsel *evsel) |
|---|
| 733 | +{ |
|---|
| 734 | + struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts, |
|---|
| 735 | + auxtrace); |
|---|
| 736 | + |
|---|
| 737 | + return evsel->core.attr.type == bts->pmu_type; |
|---|
| 738 | +} |
|---|
| 739 | + |
|---|
| 754 | 740 | struct intel_bts_synth { |
|---|
| 755 | 741 | struct perf_tool dummy_tool; |
|---|
| 756 | 742 | struct perf_session *session; |
|---|
| .. | .. |
|---|
| 783 | 769 | static int intel_bts_synth_events(struct intel_bts *bts, |
|---|
| 784 | 770 | struct perf_session *session) |
|---|
| 785 | 771 | { |
|---|
| 786 | | - struct perf_evlist *evlist = session->evlist; |
|---|
| 787 | | - struct perf_evsel *evsel; |
|---|
| 772 | + struct evlist *evlist = session->evlist; |
|---|
| 773 | + struct evsel *evsel; |
|---|
| 788 | 774 | struct perf_event_attr attr; |
|---|
| 789 | 775 | bool found = false; |
|---|
| 790 | 776 | u64 id; |
|---|
| 791 | 777 | int err; |
|---|
| 792 | 778 | |
|---|
| 793 | 779 | evlist__for_each_entry(evlist, evsel) { |
|---|
| 794 | | - if (evsel->attr.type == bts->pmu_type && evsel->ids) { |
|---|
| 780 | + if (evsel->core.attr.type == bts->pmu_type && evsel->core.ids) { |
|---|
| 795 | 781 | found = true; |
|---|
| 796 | 782 | break; |
|---|
| 797 | 783 | } |
|---|
| .. | .. |
|---|
| 805 | 791 | memset(&attr, 0, sizeof(struct perf_event_attr)); |
|---|
| 806 | 792 | attr.size = sizeof(struct perf_event_attr); |
|---|
| 807 | 793 | attr.type = PERF_TYPE_HARDWARE; |
|---|
| 808 | | - attr.sample_type = evsel->attr.sample_type & PERF_SAMPLE_MASK; |
|---|
| 794 | + attr.sample_type = evsel->core.attr.sample_type & PERF_SAMPLE_MASK; |
|---|
| 809 | 795 | attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID | |
|---|
| 810 | 796 | PERF_SAMPLE_PERIOD; |
|---|
| 811 | 797 | attr.sample_type &= ~(u64)PERF_SAMPLE_TIME; |
|---|
| 812 | 798 | attr.sample_type &= ~(u64)PERF_SAMPLE_CPU; |
|---|
| 813 | | - attr.exclude_user = evsel->attr.exclude_user; |
|---|
| 814 | | - attr.exclude_kernel = evsel->attr.exclude_kernel; |
|---|
| 815 | | - attr.exclude_hv = evsel->attr.exclude_hv; |
|---|
| 816 | | - attr.exclude_host = evsel->attr.exclude_host; |
|---|
| 817 | | - attr.exclude_guest = evsel->attr.exclude_guest; |
|---|
| 818 | | - attr.sample_id_all = evsel->attr.sample_id_all; |
|---|
| 819 | | - attr.read_format = evsel->attr.read_format; |
|---|
| 799 | + attr.exclude_user = evsel->core.attr.exclude_user; |
|---|
| 800 | + attr.exclude_kernel = evsel->core.attr.exclude_kernel; |
|---|
| 801 | + attr.exclude_hv = evsel->core.attr.exclude_hv; |
|---|
| 802 | + attr.exclude_host = evsel->core.attr.exclude_host; |
|---|
| 803 | + attr.exclude_guest = evsel->core.attr.exclude_guest; |
|---|
| 804 | + attr.sample_id_all = evsel->core.attr.sample_id_all; |
|---|
| 805 | + attr.read_format = evsel->core.attr.read_format; |
|---|
| 820 | 806 | |
|---|
| 821 | | - id = evsel->id[0] + 1000000000; |
|---|
| 807 | + id = evsel->core.id[0] + 1000000000; |
|---|
| 822 | 808 | if (!id) |
|---|
| 823 | 809 | id = 1; |
|---|
| 824 | 810 | |
|---|
| .. | .. |
|---|
| 839 | 825 | bts->branches_id = id; |
|---|
| 840 | 826 | /* |
|---|
| 841 | 827 | * We only use sample types from PERF_SAMPLE_MASK so we can use |
|---|
| 842 | | - * __perf_evsel__sample_size() here. |
|---|
| 828 | + * __evsel__sample_size() here. |
|---|
| 843 | 829 | */ |
|---|
| 844 | | - bts->branches_event_size = sizeof(struct sample_event) + |
|---|
| 845 | | - __perf_evsel__sample_size(attr.sample_type); |
|---|
| 830 | + bts->branches_event_size = sizeof(struct perf_record_sample) + |
|---|
| 831 | + __evsel__sample_size(attr.sample_type); |
|---|
| 846 | 832 | } |
|---|
| 847 | 833 | |
|---|
| 848 | 834 | return 0; |
|---|
| .. | .. |
|---|
| 857 | 843 | [INTEL_BTS_SNAPSHOT_MODE] = " Snapshot mode %"PRId64"\n", |
|---|
| 858 | 844 | }; |
|---|
| 859 | 845 | |
|---|
| 860 | | -static void intel_bts_print_info(u64 *arr, int start, int finish) |
|---|
| 846 | +static void intel_bts_print_info(__u64 *arr, int start, int finish) |
|---|
| 861 | 847 | { |
|---|
| 862 | 848 | int i; |
|---|
| 863 | 849 | |
|---|
| .. | .. |
|---|
| 871 | 857 | int intel_bts_process_auxtrace_info(union perf_event *event, |
|---|
| 872 | 858 | struct perf_session *session) |
|---|
| 873 | 859 | { |
|---|
| 874 | | - struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info; |
|---|
| 860 | + struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; |
|---|
| 875 | 861 | size_t min_sz = sizeof(u64) * INTEL_BTS_SNAPSHOT_MODE; |
|---|
| 876 | 862 | struct intel_bts *bts; |
|---|
| 877 | 863 | int err; |
|---|
| 878 | 864 | |
|---|
| 879 | | - if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event) + |
|---|
| 865 | + if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) + |
|---|
| 880 | 866 | min_sz) |
|---|
| 881 | 867 | return -EINVAL; |
|---|
| 882 | 868 | |
|---|
| .. | .. |
|---|
| 906 | 892 | bts->auxtrace.flush_events = intel_bts_flush; |
|---|
| 907 | 893 | bts->auxtrace.free_events = intel_bts_free_events; |
|---|
| 908 | 894 | bts->auxtrace.free = intel_bts_free; |
|---|
| 895 | + bts->auxtrace.evsel_is_auxtrace = intel_bts_evsel_is_auxtrace; |
|---|
| 909 | 896 | session->auxtrace = &bts->auxtrace; |
|---|
| 910 | 897 | |
|---|
| 911 | 898 | intel_bts_print_info(&auxtrace_info->priv[0], INTEL_BTS_PMU_TYPE, |
|---|
| .. | .. |
|---|
| 914 | 901 | if (dump_trace) |
|---|
| 915 | 902 | return 0; |
|---|
| 916 | 903 | |
|---|
| 917 | | - if (session->itrace_synth_opts && session->itrace_synth_opts->set) { |
|---|
| 904 | + if (session->itrace_synth_opts->set) { |
|---|
| 918 | 905 | bts->synth_opts = *session->itrace_synth_opts; |
|---|
| 919 | 906 | } else { |
|---|
| 920 | | - itrace_synth_opts__set_default(&bts->synth_opts); |
|---|
| 921 | | - if (session->itrace_synth_opts) |
|---|
| 922 | | - bts->synth_opts.thread_stack = |
|---|
| 907 | + itrace_synth_opts__set_default(&bts->synth_opts, |
|---|
| 908 | + session->itrace_synth_opts->default_no_sample); |
|---|
| 909 | + bts->synth_opts.thread_stack = |
|---|
| 923 | 910 | session->itrace_synth_opts->thread_stack; |
|---|
| 924 | 911 | } |
|---|
| 925 | 912 | |
|---|