Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf fixes from Ingo Molnar: "No kernel side changes, all tooling fixes plus two tooling cleanups that were committed late in the merge window alongside the perf annotate fixes, delayed by Arnaldo's European trip" * 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (23 commits) perf annotate: Fix segfault with source toggle perf annotate: Align struct annotate_args perf annotate: Simplify disasm_line allocation and freeing code perf annotate: Remove privsize from symbol__annotate() args perf probe: Check return value of strlist__add() for -ENOMEM perf config: Document missing config options perf annotate: Fix perf config option description perf annotate: Prefer cmdline option over default config perf annotate: Make perf config effective perf config: Introduce perf_config_u8() perf annotate: Fix --show-nr-samples for tui/stdio2 perf annotate: Fix --show-total-period for tui/stdio2 perf annotate/tui: Re-render title bar after switching back from script browser tools headers UAPI: Update tools's copy of kvm.h headers tools arch x86: Sync the msr-index.h copy with the kernel sources perf arch powerpc: Sync powerpc syscall.tbl with the kernel sources perf auxtrace: Add auxtrace_record__read_finish() perf arm-spe: Fix endless record after being terminated perf cs-etm: Fix endless record after being terminated perf intel-bts: Fix endless record after being terminated ...
This commit is contained in:
commit
852fb4a728
|
@ -512,6 +512,8 @@
|
||||||
#define MSR_K7_HWCR 0xc0010015
|
#define MSR_K7_HWCR 0xc0010015
|
||||||
#define MSR_K7_HWCR_SMMLOCK_BIT 0
|
#define MSR_K7_HWCR_SMMLOCK_BIT 0
|
||||||
#define MSR_K7_HWCR_SMMLOCK BIT_ULL(MSR_K7_HWCR_SMMLOCK_BIT)
|
#define MSR_K7_HWCR_SMMLOCK BIT_ULL(MSR_K7_HWCR_SMMLOCK_BIT)
|
||||||
|
#define MSR_K7_HWCR_IRPERF_EN_BIT 30
|
||||||
|
#define MSR_K7_HWCR_IRPERF_EN BIT_ULL(MSR_K7_HWCR_IRPERF_EN_BIT)
|
||||||
#define MSR_K7_FID_VID_CTL 0xc0010041
|
#define MSR_K7_FID_VID_CTL 0xc0010041
|
||||||
#define MSR_K7_FID_VID_STATUS 0xc0010042
|
#define MSR_K7_FID_VID_STATUS 0xc0010042
|
||||||
|
|
||||||
|
|
|
@ -390,6 +390,7 @@ struct kvm_sync_regs {
|
||||||
#define KVM_STATE_NESTED_GUEST_MODE 0x00000001
|
#define KVM_STATE_NESTED_GUEST_MODE 0x00000001
|
||||||
#define KVM_STATE_NESTED_RUN_PENDING 0x00000002
|
#define KVM_STATE_NESTED_RUN_PENDING 0x00000002
|
||||||
#define KVM_STATE_NESTED_EVMCS 0x00000004
|
#define KVM_STATE_NESTED_EVMCS 0x00000004
|
||||||
|
#define KVM_STATE_NESTED_MTF_PENDING 0x00000008
|
||||||
|
|
||||||
#define KVM_STATE_NESTED_SMM_GUEST_MODE 0x00000001
|
#define KVM_STATE_NESTED_SMM_GUEST_MODE 0x00000001
|
||||||
#define KVM_STATE_NESTED_SMM_VMXON 0x00000002
|
#define KVM_STATE_NESTED_SMM_VMXON 0x00000002
|
||||||
|
|
|
@ -239,7 +239,6 @@ buildid.*::
|
||||||
set buildid.dir to /dev/null. The default is $HOME/.debug
|
set buildid.dir to /dev/null. The default is $HOME/.debug
|
||||||
|
|
||||||
annotate.*::
|
annotate.*::
|
||||||
These options work only for TUI.
|
|
||||||
These are in control of addresses, jump function, source code
|
These are in control of addresses, jump function, source code
|
||||||
in lines of assembly code from a specific program.
|
in lines of assembly code from a specific program.
|
||||||
|
|
||||||
|
@ -269,6 +268,8 @@ annotate.*::
|
||||||
│ mov (%rdi),%rdx
|
│ mov (%rdi),%rdx
|
||||||
│ return n;
|
│ return n;
|
||||||
|
|
||||||
|
This option works with tui, stdio2 browsers.
|
||||||
|
|
||||||
annotate.use_offset::
|
annotate.use_offset::
|
||||||
Basing on a first address of a loaded function, offset can be used.
|
Basing on a first address of a loaded function, offset can be used.
|
||||||
Instead of using original addresses of assembly code,
|
Instead of using original addresses of assembly code,
|
||||||
|
@ -287,6 +288,8 @@ annotate.*::
|
||||||
|
|
||||||
368:│ mov 0x8(%r14),%rdi
|
368:│ mov 0x8(%r14),%rdi
|
||||||
|
|
||||||
|
This option works with tui, stdio2 browsers.
|
||||||
|
|
||||||
annotate.jump_arrows::
|
annotate.jump_arrows::
|
||||||
There can be jump instruction among assembly code.
|
There can be jump instruction among assembly code.
|
||||||
Depending on a boolean value of jump_arrows,
|
Depending on a boolean value of jump_arrows,
|
||||||
|
@ -306,6 +309,8 @@ annotate.*::
|
||||||
│1330: mov %r15,%r10
|
│1330: mov %r15,%r10
|
||||||
│1333: cmp %r15,%r14
|
│1333: cmp %r15,%r14
|
||||||
|
|
||||||
|
This option works with tui browser.
|
||||||
|
|
||||||
annotate.show_linenr::
|
annotate.show_linenr::
|
||||||
When showing source code if this option is 'true',
|
When showing source code if this option is 'true',
|
||||||
line numbers are printed as below.
|
line numbers are printed as below.
|
||||||
|
@ -325,6 +330,8 @@ annotate.*::
|
||||||
│ array++;
|
│ array++;
|
||||||
│ }
|
│ }
|
||||||
|
|
||||||
|
This option works with tui, stdio2 browsers.
|
||||||
|
|
||||||
annotate.show_nr_jumps::
|
annotate.show_nr_jumps::
|
||||||
Let's see a part of assembly code.
|
Let's see a part of assembly code.
|
||||||
|
|
||||||
|
@ -335,6 +342,8 @@ annotate.*::
|
||||||
|
|
||||||
│1 1382: movb $0x1,-0x270(%rbp)
|
│1 1382: movb $0x1,-0x270(%rbp)
|
||||||
|
|
||||||
|
This option works with tui, stdio2 browsers.
|
||||||
|
|
||||||
annotate.show_total_period::
|
annotate.show_total_period::
|
||||||
To compare two records on an instruction base, with this option
|
To compare two records on an instruction base, with this option
|
||||||
provided, display total number of samples that belong to a line
|
provided, display total number of samples that belong to a line
|
||||||
|
@ -348,11 +357,30 @@ annotate.*::
|
||||||
|
|
||||||
99.93 │ mov %eax,%eax
|
99.93 │ mov %eax,%eax
|
||||||
|
|
||||||
|
This option works with tui, stdio2, stdio browsers.
|
||||||
|
|
||||||
|
annotate.show_nr_samples::
|
||||||
|
By default perf annotate shows percentage of samples. This option
|
||||||
|
can be used to print absolute number of samples. Ex, when set as
|
||||||
|
false:
|
||||||
|
|
||||||
|
Percent│
|
||||||
|
74.03 │ mov %fs:0x28,%rax
|
||||||
|
|
||||||
|
When set as true:
|
||||||
|
|
||||||
|
Samples│
|
||||||
|
6 │ mov %fs:0x28,%rax
|
||||||
|
|
||||||
|
This option works with tui, stdio2, stdio browsers.
|
||||||
|
|
||||||
annotate.offset_level::
|
annotate.offset_level::
|
||||||
Default is '1', meaning just jump targets will have offsets show right beside
|
Default is '1', meaning just jump targets will have offsets show right beside
|
||||||
the instruction. When set to '2' 'call' instructions will also have its offsets
|
the instruction. When set to '2' 'call' instructions will also have its offsets
|
||||||
shown, 3 or higher will show offsets for all instructions.
|
shown, 3 or higher will show offsets for all instructions.
|
||||||
|
|
||||||
|
This option works with tui, stdio2 browsers.
|
||||||
|
|
||||||
hist.*::
|
hist.*::
|
||||||
hist.percentage::
|
hist.percentage::
|
||||||
This option control the way to calculate overhead of filtered entries -
|
This option control the way to calculate overhead of filtered entries -
|
||||||
|
@ -490,6 +518,12 @@ top.*::
|
||||||
column by default.
|
column by default.
|
||||||
The default is 'true'.
|
The default is 'true'.
|
||||||
|
|
||||||
|
top.call-graph::
|
||||||
|
This is identical to 'call-graph.record-mode', except it is
|
||||||
|
applicable only for 'top' subcommand. This option ONLY setup
|
||||||
|
the unwind method. To enable 'perf top' to actually use it,
|
||||||
|
the command line option -g must be specified.
|
||||||
|
|
||||||
man.*::
|
man.*::
|
||||||
man.viewer::
|
man.viewer::
|
||||||
This option can assign a tool to view manual pages when 'help'
|
This option can assign a tool to view manual pages when 'help'
|
||||||
|
@ -517,6 +551,16 @@ record.*::
|
||||||
But if this option is 'no-cache', it will not update the build-id cache.
|
But if this option is 'no-cache', it will not update the build-id cache.
|
||||||
'skip' skips post-processing and does not update the cache.
|
'skip' skips post-processing and does not update the cache.
|
||||||
|
|
||||||
|
record.call-graph::
|
||||||
|
This is identical to 'call-graph.record-mode', except it is
|
||||||
|
applicable only for 'record' subcommand. This option ONLY setup
|
||||||
|
the unwind method. To enable 'perf record' to actually use it,
|
||||||
|
the command line option -g must be specified.
|
||||||
|
|
||||||
|
record.aio::
|
||||||
|
Use 'n' control blocks in asynchronous (Posix AIO) trace writing
|
||||||
|
mode ('n' default: 1, max: 4).
|
||||||
|
|
||||||
diff.*::
|
diff.*::
|
||||||
diff.order::
|
diff.order::
|
||||||
This option sets the number of columns to sort the result.
|
This option sets the number of columns to sort the result.
|
||||||
|
@ -566,6 +610,11 @@ trace.*::
|
||||||
"libbeauty", the default, to use the same argument beautifiers used in the
|
"libbeauty", the default, to use the same argument beautifiers used in the
|
||||||
strace-like sys_enter+sys_exit lines.
|
strace-like sys_enter+sys_exit lines.
|
||||||
|
|
||||||
|
ftrace.*::
|
||||||
|
ftrace.tracer::
|
||||||
|
Can be used to select the default tracer. Possible values are
|
||||||
|
'function' and 'function_graph'.
|
||||||
|
|
||||||
llvm.*::
|
llvm.*::
|
||||||
llvm.clang-path::
|
llvm.clang-path::
|
||||||
Path to clang. If omit, search it from $PATH.
|
Path to clang. If omit, search it from $PATH.
|
||||||
|
@ -610,6 +659,29 @@ scripts.*::
|
||||||
The script gets the same options passed as a full perf script,
|
The script gets the same options passed as a full perf script,
|
||||||
in particular -i perfdata file, --cpu, --tid
|
in particular -i perfdata file, --cpu, --tid
|
||||||
|
|
||||||
|
convert.*::
|
||||||
|
|
||||||
|
convert.queue-size::
|
||||||
|
Limit the size of ordered_events queue, so we could control
|
||||||
|
allocation size of perf data files without proper finished
|
||||||
|
round events.
|
||||||
|
|
||||||
|
intel-pt.*::
|
||||||
|
|
||||||
|
intel-pt.cache-divisor::
|
||||||
|
|
||||||
|
intel-pt.mispred-all::
|
||||||
|
If set, Intel PT decoder will set the mispred flag on all
|
||||||
|
branches.
|
||||||
|
|
||||||
|
auxtrace.*::
|
||||||
|
|
||||||
|
auxtrace.dumpdir::
|
||||||
|
s390 only. The directory to save the auxiliary trace buffer
|
||||||
|
can be changed using this option. Ex, auxtrace.dumpdir=/tmp.
|
||||||
|
If the directory does not exist or has the wrong file type,
|
||||||
|
the current directory is used.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
linkperf:perf[1]
|
linkperf:perf[1]
|
||||||
|
|
|
@ -858,21 +858,6 @@ static void cs_etm_recording_free(struct auxtrace_record *itr)
|
||||||
free(ptr);
|
free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cs_etm_read_finish(struct auxtrace_record *itr, int idx)
|
|
||||||
{
|
|
||||||
struct cs_etm_recording *ptr =
|
|
||||||
container_of(itr, struct cs_etm_recording, itr);
|
|
||||||
struct evsel *evsel;
|
|
||||||
|
|
||||||
evlist__for_each_entry(ptr->evlist, evsel) {
|
|
||||||
if (evsel->core.attr.type == ptr->cs_etm_pmu->type)
|
|
||||||
return perf_evlist__enable_event_idx(ptr->evlist,
|
|
||||||
evsel, idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct auxtrace_record *cs_etm_record_init(int *err)
|
struct auxtrace_record *cs_etm_record_init(int *err)
|
||||||
{
|
{
|
||||||
struct perf_pmu *cs_etm_pmu;
|
struct perf_pmu *cs_etm_pmu;
|
||||||
|
@ -892,6 +877,7 @@ struct auxtrace_record *cs_etm_record_init(int *err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr->cs_etm_pmu = cs_etm_pmu;
|
ptr->cs_etm_pmu = cs_etm_pmu;
|
||||||
|
ptr->itr.pmu = cs_etm_pmu;
|
||||||
ptr->itr.parse_snapshot_options = cs_etm_parse_snapshot_options;
|
ptr->itr.parse_snapshot_options = cs_etm_parse_snapshot_options;
|
||||||
ptr->itr.recording_options = cs_etm_recording_options;
|
ptr->itr.recording_options = cs_etm_recording_options;
|
||||||
ptr->itr.info_priv_size = cs_etm_info_priv_size;
|
ptr->itr.info_priv_size = cs_etm_info_priv_size;
|
||||||
|
@ -901,7 +887,7 @@ struct auxtrace_record *cs_etm_record_init(int *err)
|
||||||
ptr->itr.snapshot_finish = cs_etm_snapshot_finish;
|
ptr->itr.snapshot_finish = cs_etm_snapshot_finish;
|
||||||
ptr->itr.reference = cs_etm_reference;
|
ptr->itr.reference = cs_etm_reference;
|
||||||
ptr->itr.free = cs_etm_recording_free;
|
ptr->itr.free = cs_etm_recording_free;
|
||||||
ptr->itr.read_finish = cs_etm_read_finish;
|
ptr->itr.read_finish = auxtrace_record__read_finish;
|
||||||
|
|
||||||
*err = 0;
|
*err = 0;
|
||||||
return &ptr->itr;
|
return &ptr->itr;
|
||||||
|
|
|
@ -158,20 +158,6 @@ static void arm_spe_recording_free(struct auxtrace_record *itr)
|
||||||
free(sper);
|
free(sper);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int arm_spe_read_finish(struct auxtrace_record *itr, int idx)
|
|
||||||
{
|
|
||||||
struct arm_spe_recording *sper =
|
|
||||||
container_of(itr, struct arm_spe_recording, itr);
|
|
||||||
struct evsel *evsel;
|
|
||||||
|
|
||||||
evlist__for_each_entry(sper->evlist, evsel) {
|
|
||||||
if (evsel->core.attr.type == sper->arm_spe_pmu->type)
|
|
||||||
return perf_evlist__enable_event_idx(sper->evlist,
|
|
||||||
evsel, idx);
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct auxtrace_record *arm_spe_recording_init(int *err,
|
struct auxtrace_record *arm_spe_recording_init(int *err,
|
||||||
struct perf_pmu *arm_spe_pmu)
|
struct perf_pmu *arm_spe_pmu)
|
||||||
{
|
{
|
||||||
|
@ -189,12 +175,13 @@ struct auxtrace_record *arm_spe_recording_init(int *err,
|
||||||
}
|
}
|
||||||
|
|
||||||
sper->arm_spe_pmu = arm_spe_pmu;
|
sper->arm_spe_pmu = arm_spe_pmu;
|
||||||
|
sper->itr.pmu = arm_spe_pmu;
|
||||||
sper->itr.recording_options = arm_spe_recording_options;
|
sper->itr.recording_options = arm_spe_recording_options;
|
||||||
sper->itr.info_priv_size = arm_spe_info_priv_size;
|
sper->itr.info_priv_size = arm_spe_info_priv_size;
|
||||||
sper->itr.info_fill = arm_spe_info_fill;
|
sper->itr.info_fill = arm_spe_info_fill;
|
||||||
sper->itr.free = arm_spe_recording_free;
|
sper->itr.free = arm_spe_recording_free;
|
||||||
sper->itr.reference = arm_spe_reference;
|
sper->itr.reference = arm_spe_reference;
|
||||||
sper->itr.read_finish = arm_spe_read_finish;
|
sper->itr.read_finish = auxtrace_record__read_finish;
|
||||||
sper->itr.alignment = 0;
|
sper->itr.alignment = 0;
|
||||||
|
|
||||||
*err = 0;
|
*err = 0;
|
||||||
|
|
|
@ -517,3 +517,5 @@
|
||||||
433 common fspick sys_fspick
|
433 common fspick sys_fspick
|
||||||
434 common pidfd_open sys_pidfd_open
|
434 common pidfd_open sys_pidfd_open
|
||||||
435 nospu clone3 ppc_clone3
|
435 nospu clone3 ppc_clone3
|
||||||
|
437 common openat2 sys_openat2
|
||||||
|
438 common pidfd_getfd sys_pidfd_getfd
|
||||||
|
|
|
@ -413,20 +413,6 @@ out_err:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int intel_bts_read_finish(struct auxtrace_record *itr, int idx)
|
|
||||||
{
|
|
||||||
struct intel_bts_recording *btsr =
|
|
||||||
container_of(itr, struct intel_bts_recording, itr);
|
|
||||||
struct evsel *evsel;
|
|
||||||
|
|
||||||
evlist__for_each_entry(btsr->evlist, evsel) {
|
|
||||||
if (evsel->core.attr.type == btsr->intel_bts_pmu->type)
|
|
||||||
return perf_evlist__enable_event_idx(btsr->evlist,
|
|
||||||
evsel, idx);
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct auxtrace_record *intel_bts_recording_init(int *err)
|
struct auxtrace_record *intel_bts_recording_init(int *err)
|
||||||
{
|
{
|
||||||
struct perf_pmu *intel_bts_pmu = perf_pmu__find(INTEL_BTS_PMU_NAME);
|
struct perf_pmu *intel_bts_pmu = perf_pmu__find(INTEL_BTS_PMU_NAME);
|
||||||
|
@ -447,6 +433,7 @@ struct auxtrace_record *intel_bts_recording_init(int *err)
|
||||||
}
|
}
|
||||||
|
|
||||||
btsr->intel_bts_pmu = intel_bts_pmu;
|
btsr->intel_bts_pmu = intel_bts_pmu;
|
||||||
|
btsr->itr.pmu = intel_bts_pmu;
|
||||||
btsr->itr.recording_options = intel_bts_recording_options;
|
btsr->itr.recording_options = intel_bts_recording_options;
|
||||||
btsr->itr.info_priv_size = intel_bts_info_priv_size;
|
btsr->itr.info_priv_size = intel_bts_info_priv_size;
|
||||||
btsr->itr.info_fill = intel_bts_info_fill;
|
btsr->itr.info_fill = intel_bts_info_fill;
|
||||||
|
@ -456,7 +443,7 @@ struct auxtrace_record *intel_bts_recording_init(int *err)
|
||||||
btsr->itr.find_snapshot = intel_bts_find_snapshot;
|
btsr->itr.find_snapshot = intel_bts_find_snapshot;
|
||||||
btsr->itr.parse_snapshot_options = intel_bts_parse_snapshot_options;
|
btsr->itr.parse_snapshot_options = intel_bts_parse_snapshot_options;
|
||||||
btsr->itr.reference = intel_bts_reference;
|
btsr->itr.reference = intel_bts_reference;
|
||||||
btsr->itr.read_finish = intel_bts_read_finish;
|
btsr->itr.read_finish = auxtrace_record__read_finish;
|
||||||
btsr->itr.alignment = sizeof(struct branch);
|
btsr->itr.alignment = sizeof(struct branch);
|
||||||
return &btsr->itr;
|
return &btsr->itr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1166,20 +1166,6 @@ static u64 intel_pt_reference(struct auxtrace_record *itr __maybe_unused)
|
||||||
return rdtsc();
|
return rdtsc();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int intel_pt_read_finish(struct auxtrace_record *itr, int idx)
|
|
||||||
{
|
|
||||||
struct intel_pt_recording *ptr =
|
|
||||||
container_of(itr, struct intel_pt_recording, itr);
|
|
||||||
struct evsel *evsel;
|
|
||||||
|
|
||||||
evlist__for_each_entry(ptr->evlist, evsel) {
|
|
||||||
if (evsel->core.attr.type == ptr->intel_pt_pmu->type)
|
|
||||||
return perf_evlist__enable_event_idx(ptr->evlist, evsel,
|
|
||||||
idx);
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct auxtrace_record *intel_pt_recording_init(int *err)
|
struct auxtrace_record *intel_pt_recording_init(int *err)
|
||||||
{
|
{
|
||||||
struct perf_pmu *intel_pt_pmu = perf_pmu__find(INTEL_PT_PMU_NAME);
|
struct perf_pmu *intel_pt_pmu = perf_pmu__find(INTEL_PT_PMU_NAME);
|
||||||
|
@ -1200,6 +1186,7 @@ struct auxtrace_record *intel_pt_recording_init(int *err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr->intel_pt_pmu = intel_pt_pmu;
|
ptr->intel_pt_pmu = intel_pt_pmu;
|
||||||
|
ptr->itr.pmu = intel_pt_pmu;
|
||||||
ptr->itr.recording_options = intel_pt_recording_options;
|
ptr->itr.recording_options = intel_pt_recording_options;
|
||||||
ptr->itr.info_priv_size = intel_pt_info_priv_size;
|
ptr->itr.info_priv_size = intel_pt_info_priv_size;
|
||||||
ptr->itr.info_fill = intel_pt_info_fill;
|
ptr->itr.info_fill = intel_pt_info_fill;
|
||||||
|
@ -1209,7 +1196,7 @@ struct auxtrace_record *intel_pt_recording_init(int *err)
|
||||||
ptr->itr.find_snapshot = intel_pt_find_snapshot;
|
ptr->itr.find_snapshot = intel_pt_find_snapshot;
|
||||||
ptr->itr.parse_snapshot_options = intel_pt_parse_snapshot_options;
|
ptr->itr.parse_snapshot_options = intel_pt_parse_snapshot_options;
|
||||||
ptr->itr.reference = intel_pt_reference;
|
ptr->itr.reference = intel_pt_reference;
|
||||||
ptr->itr.read_finish = intel_pt_read_finish;
|
ptr->itr.read_finish = auxtrace_record__read_finish;
|
||||||
/*
|
/*
|
||||||
* Decoding starts at a PSB packet. Minimum PSB period is 2K so 4K
|
* Decoding starts at a PSB packet. Minimum PSB period is 2K so 4K
|
||||||
* should give at least 1 PSB per sample.
|
* should give at least 1 PSB per sample.
|
||||||
|
|
|
@ -566,6 +566,8 @@ int cmd_annotate(int argc, const char **argv)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
annotation_config__init(&annotate.opts);
|
||||||
|
|
||||||
argc = parse_options(argc, argv, options, annotate_usage, 0);
|
argc = parse_options(argc, argv, options, annotate_usage, 0);
|
||||||
if (argc) {
|
if (argc) {
|
||||||
/*
|
/*
|
||||||
|
@ -605,8 +607,6 @@ int cmd_annotate(int argc, const char **argv)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_delete;
|
goto out_delete;
|
||||||
|
|
||||||
annotation_config__init();
|
|
||||||
|
|
||||||
symbol_conf.try_vmlinux_path = true;
|
symbol_conf.try_vmlinux_path = true;
|
||||||
|
|
||||||
ret = symbol__init(&annotate.session->header.env);
|
ret = symbol__init(&annotate.session->header.env);
|
||||||
|
|
|
@ -449,7 +449,8 @@ static int perf_del_probe_events(struct strfilter *filter)
|
||||||
ret = probe_file__del_strlist(kfd, klist);
|
ret = probe_file__del_strlist(kfd, klist);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
} else if (ret == -ENOMEM)
|
||||||
|
goto error;
|
||||||
|
|
||||||
ret2 = probe_file__get_events(ufd, filter, ulist);
|
ret2 = probe_file__get_events(ufd, filter, ulist);
|
||||||
if (ret2 == 0) {
|
if (ret2 == 0) {
|
||||||
|
@ -459,7 +460,8 @@ static int perf_del_probe_events(struct strfilter *filter)
|
||||||
ret2 = probe_file__del_strlist(ufd, ulist);
|
ret2 = probe_file__del_strlist(ufd, ulist);
|
||||||
if (ret2 < 0)
|
if (ret2 < 0)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
} else if (ret2 == -ENOMEM)
|
||||||
|
goto error;
|
||||||
|
|
||||||
if (ret == -ENOENT && ret2 == -ENOENT)
|
if (ret == -ENOENT && ret2 == -ENOENT)
|
||||||
pr_warning("\"%s\" does not hit any event.\n", str);
|
pr_warning("\"%s\" does not hit any event.\n", str);
|
||||||
|
|
|
@ -1507,7 +1507,7 @@ repeat:
|
||||||
symbol_conf.priv_size += sizeof(u32);
|
symbol_conf.priv_size += sizeof(u32);
|
||||||
symbol_conf.sort_by_name = true;
|
symbol_conf.sort_by_name = true;
|
||||||
}
|
}
|
||||||
annotation_config__init();
|
annotation_config__init(&report.annotation_opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (symbol__init(&session->header.env) < 0)
|
if (symbol__init(&session->header.env) < 0)
|
||||||
|
|
|
@ -143,7 +143,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = symbol__annotate(&he->ms, evsel, 0, &top->annotation_opts, NULL);
|
err = symbol__annotate(&he->ms, evsel, &top->annotation_opts, NULL);
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
top->sym_filter_entry = he;
|
top->sym_filter_entry = he;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1683,7 +1683,7 @@ int cmd_top(int argc, const char **argv)
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
goto out_delete_evlist;
|
goto out_delete_evlist;
|
||||||
|
|
||||||
annotation_config__init();
|
annotation_config__init(&top.annotation_opts);
|
||||||
|
|
||||||
symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
|
symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
|
||||||
status = symbol__init(NULL);
|
status = symbol__init(NULL);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#ifndef _PERF_BPF_PID_FILTER_
|
#ifndef _PERF_BPF_PID_FILTER_
|
||||||
#define _PERF_BPF_PID_FILTER_
|
#define _PERF_BPF_PID_FILTER_
|
||||||
|
|
||||||
#include <bpf/bpf.h>
|
#include <bpf.h>
|
||||||
|
|
||||||
#define pid_filter(name) pid_map(name, bool)
|
#define pid_filter(name) pid_map(name, bool)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
#include <bpf/bpf.h>
|
#include <bpf.h>
|
||||||
|
|
||||||
struct bpf_map SEC("maps") __bpf_stdout__ = {
|
struct bpf_map SEC("maps") __bpf_stdout__ = {
|
||||||
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
|
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: LGPL-2.1
|
// SPDX-License-Identifier: LGPL-2.1
|
||||||
|
|
||||||
#include <bpf/bpf.h>
|
#include <bpf.h>
|
||||||
|
|
||||||
static int (*bpf_get_current_pid_tgid)(void) = (void *)BPF_FUNC_get_current_pid_tgid;
|
static int (*bpf_get_current_pid_tgid)(void) = (void *)BPF_FUNC_get_current_pid_tgid;
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ add_probe_vfs_getname() {
|
||||||
if [ $had_vfs_getname -eq 1 ] ; then
|
if [ $had_vfs_getname -eq 1 ] ; then
|
||||||
line=$(perf probe -L getname_flags 2>&1 | egrep 'result.*=.*filename;' | sed -r 's/[[:space:]]+([[:digit:]]+)[[:space:]]+result->uptr.*/\1/')
|
line=$(perf probe -L getname_flags 2>&1 | egrep 'result.*=.*filename;' | sed -r 's/[[:space:]]+([[:digit:]]+)[[:space:]]+result->uptr.*/\1/')
|
||||||
perf probe -q "vfs_getname=getname_flags:${line} pathname=result->name:string" || \
|
perf probe -q "vfs_getname=getname_flags:${line} pathname=result->name:string" || \
|
||||||
perf probe $verbose "vfs_getname=getname_flags:${line} pathname=filename:string"
|
perf probe $verbose "vfs_getname=getname_flags:${line} pathname=filename:ustring"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -754,10 +754,9 @@ static int annotate_browser__run(struct annotate_browser *browser,
|
||||||
"? Search string backwards\n");
|
"? Search string backwards\n");
|
||||||
continue;
|
continue;
|
||||||
case 'r':
|
case 'r':
|
||||||
{
|
script_browse(NULL, NULL);
|
||||||
script_browse(NULL, NULL);
|
annotate_browser__show(&browser->b, title, help);
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
case 'k':
|
case 'k':
|
||||||
notes->options->show_linenr = !notes->options->show_linenr;
|
notes->options->show_linenr = !notes->options->show_linenr;
|
||||||
break;
|
break;
|
||||||
|
@ -834,13 +833,13 @@ show_sup_ins:
|
||||||
map_symbol__annotation_dump(ms, evsel, browser->opts);
|
map_symbol__annotation_dump(ms, evsel, browser->opts);
|
||||||
continue;
|
continue;
|
||||||
case 't':
|
case 't':
|
||||||
if (notes->options->show_total_period) {
|
if (symbol_conf.show_total_period) {
|
||||||
notes->options->show_total_period = false;
|
symbol_conf.show_total_period = false;
|
||||||
notes->options->show_nr_samples = true;
|
symbol_conf.show_nr_samples = true;
|
||||||
} else if (notes->options->show_nr_samples)
|
} else if (symbol_conf.show_nr_samples)
|
||||||
notes->options->show_nr_samples = false;
|
symbol_conf.show_nr_samples = false;
|
||||||
else
|
else
|
||||||
notes->options->show_total_period = true;
|
symbol_conf.show_total_period = true;
|
||||||
annotation__update_column_widths(notes);
|
annotation__update_column_widths(notes);
|
||||||
continue;
|
continue;
|
||||||
case 'c':
|
case 'c':
|
||||||
|
|
|
@ -174,7 +174,7 @@ static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel,
|
||||||
if (ms->map->dso->annotate_warned)
|
if (ms->map->dso->annotate_warned)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
err = symbol__annotate(ms, evsel, 0, &annotation__default_options, NULL);
|
err = symbol__annotate(ms, evsel, &annotation__default_options, NULL);
|
||||||
if (err) {
|
if (err) {
|
||||||
char msg[BUFSIZ];
|
char msg[BUFSIZ];
|
||||||
symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
|
symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
|
||||||
|
|
|
@ -1143,93 +1143,70 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
struct annotate_args {
|
struct annotate_args {
|
||||||
size_t privsize;
|
struct arch *arch;
|
||||||
struct arch *arch;
|
struct map_symbol ms;
|
||||||
struct map_symbol ms;
|
struct evsel *evsel;
|
||||||
struct evsel *evsel;
|
|
||||||
struct annotation_options *options;
|
struct annotation_options *options;
|
||||||
s64 offset;
|
s64 offset;
|
||||||
char *line;
|
char *line;
|
||||||
int line_nr;
|
int line_nr;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void annotation_line__delete(struct annotation_line *al)
|
static void annotation_line__init(struct annotation_line *al,
|
||||||
|
struct annotate_args *args,
|
||||||
|
int nr)
|
||||||
{
|
{
|
||||||
void *ptr = (void *) al - al->privsize;
|
al->offset = args->offset;
|
||||||
|
al->line = strdup(args->line);
|
||||||
free_srcline(al->path);
|
al->line_nr = args->line_nr;
|
||||||
zfree(&al->line);
|
al->data_nr = nr;
|
||||||
free(ptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void annotation_line__exit(struct annotation_line *al)
|
||||||
* Allocating the annotation line data with following
|
{
|
||||||
* structure:
|
free_srcline(al->path);
|
||||||
*
|
zfree(&al->line);
|
||||||
* --------------------------------------
|
}
|
||||||
* private space | struct annotation_line
|
|
||||||
* --------------------------------------
|
static size_t disasm_line_size(int nr)
|
||||||
*
|
|
||||||
* Size of the private space is stored in 'struct annotation_line'.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static struct annotation_line *
|
|
||||||
annotation_line__new(struct annotate_args *args, size_t privsize)
|
|
||||||
{
|
{
|
||||||
struct annotation_line *al;
|
struct annotation_line *al;
|
||||||
struct evsel *evsel = args->evsel;
|
|
||||||
size_t size = privsize + sizeof(*al);
|
|
||||||
int nr = 1;
|
|
||||||
|
|
||||||
if (perf_evsel__is_group_event(evsel))
|
return (sizeof(struct disasm_line) + (sizeof(al->data[0]) * nr));
|
||||||
nr = evsel->core.nr_members;
|
|
||||||
|
|
||||||
size += sizeof(al->data[0]) * nr;
|
|
||||||
|
|
||||||
al = zalloc(size);
|
|
||||||
if (al) {
|
|
||||||
al = (void *) al + privsize;
|
|
||||||
al->privsize = privsize;
|
|
||||||
al->offset = args->offset;
|
|
||||||
al->line = strdup(args->line);
|
|
||||||
al->line_nr = args->line_nr;
|
|
||||||
al->data_nr = nr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return al;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocating the disasm annotation line data with
|
* Allocating the disasm annotation line data with
|
||||||
* following structure:
|
* following structure:
|
||||||
*
|
*
|
||||||
* ------------------------------------------------------------
|
* -------------------------------------------
|
||||||
* privsize space | struct disasm_line | struct annotation_line
|
* struct disasm_line | struct annotation_line
|
||||||
* ------------------------------------------------------------
|
* -------------------------------------------
|
||||||
*
|
*
|
||||||
* We have 'struct annotation_line' member as last member
|
* We have 'struct annotation_line' member as last member
|
||||||
* of 'struct disasm_line' to have an easy access.
|
* of 'struct disasm_line' to have an easy access.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
static struct disasm_line *disasm_line__new(struct annotate_args *args)
|
static struct disasm_line *disasm_line__new(struct annotate_args *args)
|
||||||
{
|
{
|
||||||
struct disasm_line *dl = NULL;
|
struct disasm_line *dl = NULL;
|
||||||
struct annotation_line *al;
|
int nr = 1;
|
||||||
size_t privsize = args->privsize + offsetof(struct disasm_line, al);
|
|
||||||
|
|
||||||
al = annotation_line__new(args, privsize);
|
if (perf_evsel__is_group_event(args->evsel))
|
||||||
if (al != NULL) {
|
nr = args->evsel->core.nr_members;
|
||||||
dl = disasm_line(al);
|
|
||||||
|
|
||||||
if (dl->al.line == NULL)
|
dl = zalloc(disasm_line_size(nr));
|
||||||
goto out_delete;
|
if (!dl)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (args->offset != -1) {
|
annotation_line__init(&dl->al, args, nr);
|
||||||
if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0)
|
if (dl->al.line == NULL)
|
||||||
goto out_free_line;
|
goto out_delete;
|
||||||
|
|
||||||
disasm_line__init_ins(dl, args->arch, &args->ms);
|
if (args->offset != -1) {
|
||||||
}
|
if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0)
|
||||||
|
goto out_free_line;
|
||||||
|
|
||||||
|
disasm_line__init_ins(dl, args->arch, &args->ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dl;
|
return dl;
|
||||||
|
@ -1248,7 +1225,8 @@ void disasm_line__free(struct disasm_line *dl)
|
||||||
else
|
else
|
||||||
ins__delete(&dl->ops);
|
ins__delete(&dl->ops);
|
||||||
zfree(&dl->ins.name);
|
zfree(&dl->ins.name);
|
||||||
annotation_line__delete(&dl->al);
|
annotation_line__exit(&dl->al);
|
||||||
|
free(dl);
|
||||||
}
|
}
|
||||||
|
|
||||||
int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name)
|
int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name)
|
||||||
|
@ -2149,13 +2127,12 @@ void symbol__calc_percent(struct symbol *sym, struct evsel *evsel)
|
||||||
annotation__calc_percent(notes, evsel, symbol__size(sym));
|
annotation__calc_percent(notes, evsel, symbol__size(sym));
|
||||||
}
|
}
|
||||||
|
|
||||||
int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, size_t privsize,
|
int symbol__annotate(struct map_symbol *ms, struct evsel *evsel,
|
||||||
struct annotation_options *options, struct arch **parch)
|
struct annotation_options *options, struct arch **parch)
|
||||||
{
|
{
|
||||||
struct symbol *sym = ms->sym;
|
struct symbol *sym = ms->sym;
|
||||||
struct annotation *notes = symbol__annotation(sym);
|
struct annotation *notes = symbol__annotation(sym);
|
||||||
struct annotate_args args = {
|
struct annotate_args args = {
|
||||||
.privsize = privsize,
|
|
||||||
.evsel = evsel,
|
.evsel = evsel,
|
||||||
.options = options,
|
.options = options,
|
||||||
};
|
};
|
||||||
|
@ -2644,6 +2621,8 @@ void annotation__set_offsets(struct annotation *notes, s64 size)
|
||||||
struct annotation_line *al;
|
struct annotation_line *al;
|
||||||
|
|
||||||
notes->max_line_len = 0;
|
notes->max_line_len = 0;
|
||||||
|
notes->nr_entries = 0;
|
||||||
|
notes->nr_asm_entries = 0;
|
||||||
|
|
||||||
list_for_each_entry(al, ¬es->src->source, node) {
|
list_for_each_entry(al, ¬es->src->source, node) {
|
||||||
size_t line_len = strlen(al->line);
|
size_t line_len = strlen(al->line);
|
||||||
|
@ -2790,7 +2769,7 @@ int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel,
|
||||||
struct symbol *sym = ms->sym;
|
struct symbol *sym = ms->sym;
|
||||||
struct rb_root source_line = RB_ROOT;
|
struct rb_root source_line = RB_ROOT;
|
||||||
|
|
||||||
if (symbol__annotate(ms, evsel, 0, opts, NULL) < 0)
|
if (symbol__annotate(ms, evsel, opts, NULL) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
symbol__calc_percent(sym, evsel);
|
symbol__calc_percent(sym, evsel);
|
||||||
|
@ -2915,9 +2894,9 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati
|
||||||
percent = annotation_data__percent(&al->data[i], percent_type);
|
percent = annotation_data__percent(&al->data[i], percent_type);
|
||||||
|
|
||||||
obj__set_percent_color(obj, percent, current_entry);
|
obj__set_percent_color(obj, percent, current_entry);
|
||||||
if (notes->options->show_total_period) {
|
if (symbol_conf.show_total_period) {
|
||||||
obj__printf(obj, "%11" PRIu64 " ", al->data[i].he.period);
|
obj__printf(obj, "%11" PRIu64 " ", al->data[i].he.period);
|
||||||
} else if (notes->options->show_nr_samples) {
|
} else if (symbol_conf.show_nr_samples) {
|
||||||
obj__printf(obj, "%6" PRIu64 " ",
|
obj__printf(obj, "%6" PRIu64 " ",
|
||||||
al->data[i].he.nr_samples);
|
al->data[i].he.nr_samples);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2931,8 +2910,8 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati
|
||||||
obj__printf(obj, "%-*s", pcnt_width, " ");
|
obj__printf(obj, "%-*s", pcnt_width, " ");
|
||||||
else {
|
else {
|
||||||
obj__printf(obj, "%-*s", pcnt_width,
|
obj__printf(obj, "%-*s", pcnt_width,
|
||||||
notes->options->show_total_period ? "Period" :
|
symbol_conf.show_total_period ? "Period" :
|
||||||
notes->options->show_nr_samples ? "Samples" : "Percent");
|
symbol_conf.show_nr_samples ? "Samples" : "Percent");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3070,7 +3049,7 @@ int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel,
|
||||||
if (perf_evsel__is_group_event(evsel))
|
if (perf_evsel__is_group_event(evsel))
|
||||||
nr_pcnt = evsel->core.nr_members;
|
nr_pcnt = evsel->core.nr_members;
|
||||||
|
|
||||||
err = symbol__annotate(ms, evsel, 0, options, parch);
|
err = symbol__annotate(ms, evsel, options, parch);
|
||||||
if (err)
|
if (err)
|
||||||
goto out_free_offsets;
|
goto out_free_offsets;
|
||||||
|
|
||||||
|
@ -3094,69 +3073,46 @@ out_free_offsets:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ANNOTATION__CFG(n) \
|
static int annotation__config(const char *var, const char *value, void *data)
|
||||||
{ .name = #n, .value = &annotation__default_options.n, }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Keep the entries sorted, they are bsearch'ed
|
|
||||||
*/
|
|
||||||
static struct annotation_config {
|
|
||||||
const char *name;
|
|
||||||
void *value;
|
|
||||||
} annotation__configs[] = {
|
|
||||||
ANNOTATION__CFG(hide_src_code),
|
|
||||||
ANNOTATION__CFG(jump_arrows),
|
|
||||||
ANNOTATION__CFG(offset_level),
|
|
||||||
ANNOTATION__CFG(show_linenr),
|
|
||||||
ANNOTATION__CFG(show_nr_jumps),
|
|
||||||
ANNOTATION__CFG(show_nr_samples),
|
|
||||||
ANNOTATION__CFG(show_total_period),
|
|
||||||
ANNOTATION__CFG(use_offset),
|
|
||||||
};
|
|
||||||
|
|
||||||
#undef ANNOTATION__CFG
|
|
||||||
|
|
||||||
static int annotation_config__cmp(const void *name, const void *cfgp)
|
|
||||||
{
|
{
|
||||||
const struct annotation_config *cfg = cfgp;
|
struct annotation_options *opt = data;
|
||||||
|
|
||||||
return strcmp(name, cfg->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int annotation__config(const char *var, const char *value,
|
|
||||||
void *data __maybe_unused)
|
|
||||||
{
|
|
||||||
struct annotation_config *cfg;
|
|
||||||
const char *name;
|
|
||||||
|
|
||||||
if (!strstarts(var, "annotate."))
|
if (!strstarts(var, "annotate."))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
name = var + 9;
|
if (!strcmp(var, "annotate.offset_level")) {
|
||||||
cfg = bsearch(name, annotation__configs, ARRAY_SIZE(annotation__configs),
|
perf_config_u8(&opt->offset_level, "offset_level", value);
|
||||||
sizeof(struct annotation_config), annotation_config__cmp);
|
|
||||||
|
|
||||||
if (cfg == NULL)
|
if (opt->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
|
||||||
pr_debug("%s variable unknown, ignoring...", var);
|
opt->offset_level = ANNOTATION__MAX_OFFSET_LEVEL;
|
||||||
else if (strcmp(var, "annotate.offset_level") == 0) {
|
else if (opt->offset_level < ANNOTATION__MIN_OFFSET_LEVEL)
|
||||||
perf_config_int(cfg->value, name, value);
|
opt->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
|
||||||
|
} else if (!strcmp(var, "annotate.hide_src_code")) {
|
||||||
if (*(int *)cfg->value > ANNOTATION__MAX_OFFSET_LEVEL)
|
opt->hide_src_code = perf_config_bool("hide_src_code", value);
|
||||||
*(int *)cfg->value = ANNOTATION__MAX_OFFSET_LEVEL;
|
} else if (!strcmp(var, "annotate.jump_arrows")) {
|
||||||
else if (*(int *)cfg->value < ANNOTATION__MIN_OFFSET_LEVEL)
|
opt->jump_arrows = perf_config_bool("jump_arrows", value);
|
||||||
*(int *)cfg->value = ANNOTATION__MIN_OFFSET_LEVEL;
|
} else if (!strcmp(var, "annotate.show_linenr")) {
|
||||||
|
opt->show_linenr = perf_config_bool("show_linenr", value);
|
||||||
|
} else if (!strcmp(var, "annotate.show_nr_jumps")) {
|
||||||
|
opt->show_nr_jumps = perf_config_bool("show_nr_jumps", value);
|
||||||
|
} else if (!strcmp(var, "annotate.show_nr_samples")) {
|
||||||
|
symbol_conf.show_nr_samples = perf_config_bool("show_nr_samples",
|
||||||
|
value);
|
||||||
|
} else if (!strcmp(var, "annotate.show_total_period")) {
|
||||||
|
symbol_conf.show_total_period = perf_config_bool("show_total_period",
|
||||||
|
value);
|
||||||
|
} else if (!strcmp(var, "annotate.use_offset")) {
|
||||||
|
opt->use_offset = perf_config_bool("use_offset", value);
|
||||||
} else {
|
} else {
|
||||||
*(bool *)cfg->value = perf_config_bool(name, value);
|
pr_debug("%s variable unknown, ignoring...", var);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void annotation_config__init(void)
|
void annotation_config__init(struct annotation_options *opt)
|
||||||
{
|
{
|
||||||
perf_config(annotation__config, NULL);
|
perf_config(annotation__config, opt);
|
||||||
|
|
||||||
annotation__default_options.show_total_period = symbol_conf.show_total_period;
|
|
||||||
annotation__default_options.show_nr_samples = symbol_conf.show_nr_samples;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int parse_percent_type(char *str1, char *str2)
|
static unsigned int parse_percent_type(char *str1, char *str2)
|
||||||
|
|
|
@ -83,8 +83,6 @@ struct annotation_options {
|
||||||
full_path,
|
full_path,
|
||||||
show_linenr,
|
show_linenr,
|
||||||
show_nr_jumps,
|
show_nr_jumps,
|
||||||
show_nr_samples,
|
|
||||||
show_total_period,
|
|
||||||
show_minmax_cycle,
|
show_minmax_cycle,
|
||||||
show_asm_raw,
|
show_asm_raw,
|
||||||
annotate_src;
|
annotate_src;
|
||||||
|
@ -141,7 +139,6 @@ struct annotation_line {
|
||||||
u64 cycles;
|
u64 cycles;
|
||||||
u64 cycles_max;
|
u64 cycles_max;
|
||||||
u64 cycles_min;
|
u64 cycles_min;
|
||||||
size_t privsize;
|
|
||||||
char *path;
|
char *path;
|
||||||
u32 idx;
|
u32 idx;
|
||||||
int idx_asm;
|
int idx_asm;
|
||||||
|
@ -309,7 +306,7 @@ static inline int annotation__cycles_width(struct annotation *notes)
|
||||||
|
|
||||||
static inline int annotation__pcnt_width(struct annotation *notes)
|
static inline int annotation__pcnt_width(struct annotation *notes)
|
||||||
{
|
{
|
||||||
return (notes->options->show_total_period ? 12 : 7) * notes->nr_events;
|
return (symbol_conf.show_total_period ? 12 : 7) * notes->nr_events;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool annotation_line__filter(struct annotation_line *al, struct annotation *notes)
|
static inline bool annotation_line__filter(struct annotation_line *al, struct annotation *notes)
|
||||||
|
@ -352,7 +349,7 @@ struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists);
|
||||||
void symbol__annotate_zero_histograms(struct symbol *sym);
|
void symbol__annotate_zero_histograms(struct symbol *sym);
|
||||||
|
|
||||||
int symbol__annotate(struct map_symbol *ms,
|
int symbol__annotate(struct map_symbol *ms,
|
||||||
struct evsel *evsel, size_t privsize,
|
struct evsel *evsel,
|
||||||
struct annotation_options *options,
|
struct annotation_options *options,
|
||||||
struct arch **parch);
|
struct arch **parch);
|
||||||
int symbol__annotate2(struct map_symbol *ms,
|
int symbol__annotate2(struct map_symbol *ms,
|
||||||
|
@ -413,7 +410,7 @@ static inline int symbol__tui_annotate(struct map_symbol *ms __maybe_unused,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void annotation_config__init(void);
|
void annotation_config__init(struct annotation_options *opt);
|
||||||
|
|
||||||
int annotate_parse_percent_type(const struct option *opt, const char *_str,
|
int annotate_parse_percent_type(const struct option *opt, const char *_str,
|
||||||
int unset);
|
int unset);
|
||||||
|
|
|
@ -629,8 +629,10 @@ int auxtrace_record__options(struct auxtrace_record *itr,
|
||||||
struct evlist *evlist,
|
struct evlist *evlist,
|
||||||
struct record_opts *opts)
|
struct record_opts *opts)
|
||||||
{
|
{
|
||||||
if (itr)
|
if (itr) {
|
||||||
|
itr->evlist = evlist;
|
||||||
return itr->recording_options(itr, evlist, opts);
|
return itr->recording_options(itr, evlist, opts);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,6 +666,24 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int auxtrace_record__read_finish(struct auxtrace_record *itr, int idx)
|
||||||
|
{
|
||||||
|
struct evsel *evsel;
|
||||||
|
|
||||||
|
if (!itr->evlist || !itr->pmu)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
evlist__for_each_entry(itr->evlist, evsel) {
|
||||||
|
if (evsel->core.attr.type == itr->pmu->type) {
|
||||||
|
if (evsel->disabled)
|
||||||
|
return 0;
|
||||||
|
return perf_evlist__enable_event_idx(itr->evlist, evsel,
|
||||||
|
idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Event record size is 16-bit which results in a maximum size of about 64KiB.
|
* Event record size is 16-bit which results in a maximum size of about 64KiB.
|
||||||
* Allow about 4KiB for the rest of the sample record, to give a maximum
|
* Allow about 4KiB for the rest of the sample record, to give a maximum
|
||||||
|
|
|
@ -29,6 +29,7 @@ struct record_opts;
|
||||||
struct perf_record_auxtrace_error;
|
struct perf_record_auxtrace_error;
|
||||||
struct perf_record_auxtrace_info;
|
struct perf_record_auxtrace_info;
|
||||||
struct events_stats;
|
struct events_stats;
|
||||||
|
struct perf_pmu;
|
||||||
|
|
||||||
enum auxtrace_error_type {
|
enum auxtrace_error_type {
|
||||||
PERF_AUXTRACE_ERROR_ITRACE = 1,
|
PERF_AUXTRACE_ERROR_ITRACE = 1,
|
||||||
|
@ -322,6 +323,8 @@ struct auxtrace_mmap_params {
|
||||||
* @read_finish: called after reading from an auxtrace mmap
|
* @read_finish: called after reading from an auxtrace mmap
|
||||||
* @alignment: alignment (if any) for AUX area data
|
* @alignment: alignment (if any) for AUX area data
|
||||||
* @default_aux_sample_size: default sample size for --aux sample option
|
* @default_aux_sample_size: default sample size for --aux sample option
|
||||||
|
* @pmu: associated pmu
|
||||||
|
* @evlist: selected events list
|
||||||
*/
|
*/
|
||||||
struct auxtrace_record {
|
struct auxtrace_record {
|
||||||
int (*recording_options)(struct auxtrace_record *itr,
|
int (*recording_options)(struct auxtrace_record *itr,
|
||||||
|
@ -346,6 +349,8 @@ struct auxtrace_record {
|
||||||
int (*read_finish)(struct auxtrace_record *itr, int idx);
|
int (*read_finish)(struct auxtrace_record *itr, int idx);
|
||||||
unsigned int alignment;
|
unsigned int alignment;
|
||||||
unsigned int default_aux_sample_size;
|
unsigned int default_aux_sample_size;
|
||||||
|
struct perf_pmu *pmu;
|
||||||
|
struct evlist *evlist;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -537,6 +542,7 @@ int auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx,
|
||||||
struct auxtrace_mmap *mm,
|
struct auxtrace_mmap *mm,
|
||||||
unsigned char *data, u64 *head, u64 *old);
|
unsigned char *data, u64 *head, u64 *old);
|
||||||
u64 auxtrace_record__reference(struct auxtrace_record *itr);
|
u64 auxtrace_record__reference(struct auxtrace_record *itr);
|
||||||
|
int auxtrace_record__read_finish(struct auxtrace_record *itr, int idx);
|
||||||
|
|
||||||
int auxtrace_index__auxtrace_event(struct list_head *head, union perf_event *event,
|
int auxtrace_index__auxtrace_event(struct list_head *head, union perf_event *event,
|
||||||
off_t file_offset);
|
off_t file_offset);
|
||||||
|
|
|
@ -374,6 +374,18 @@ int perf_config_int(int *dest, const char *name, const char *value)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int perf_config_u8(u8 *dest, const char *name, const char *value)
|
||||||
|
{
|
||||||
|
long ret = 0;
|
||||||
|
|
||||||
|
if (!perf_parse_long(value, &ret)) {
|
||||||
|
bad_config(name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*dest = ret;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
|
static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
|
@ -29,6 +29,7 @@ typedef int (*config_fn_t)(const char *, const char *, void *);
|
||||||
int perf_default_config(const char *, const char *, void *);
|
int perf_default_config(const char *, const char *, void *);
|
||||||
int perf_config(config_fn_t fn, void *);
|
int perf_config(config_fn_t fn, void *);
|
||||||
int perf_config_int(int *dest, const char *, const char *);
|
int perf_config_int(int *dest, const char *, const char *);
|
||||||
|
int perf_config_u8(u8 *dest, const char *name, const char *value);
|
||||||
int perf_config_u64(u64 *dest, const char *, const char *);
|
int perf_config_u64(u64 *dest, const char *, const char *);
|
||||||
int perf_config_bool(const char *, const char *);
|
int perf_config_bool(const char *, const char *);
|
||||||
int config_error_nonbool(const char *);
|
int config_error_nonbool(const char *);
|
||||||
|
|
|
@ -301,10 +301,15 @@ int probe_file__get_events(int fd, struct strfilter *filter,
|
||||||
p = strchr(ent->s, ':');
|
p = strchr(ent->s, ':');
|
||||||
if ((p && strfilter__compare(filter, p + 1)) ||
|
if ((p && strfilter__compare(filter, p + 1)) ||
|
||||||
strfilter__compare(filter, ent->s)) {
|
strfilter__compare(filter, ent->s)) {
|
||||||
strlist__add(plist, ent->s);
|
ret = strlist__add(plist, ent->s);
|
||||||
|
if (ret == -ENOMEM) {
|
||||||
|
pr_err("strlist__add failed with -ENOMEM\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
strlist__delete(namelist);
|
strlist__delete(namelist);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -511,7 +516,11 @@ static int probe_cache__load(struct probe_cache *pcache)
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
strlist__add(entry->tevlist, buf);
|
ret = strlist__add(entry->tevlist, buf);
|
||||||
|
if (ret == -ENOMEM) {
|
||||||
|
pr_err("strlist__add failed with -ENOMEM\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
@ -672,7 +681,12 @@ int probe_cache__add_entry(struct probe_cache *pcache,
|
||||||
command = synthesize_probe_trace_command(&tevs[i]);
|
command = synthesize_probe_trace_command(&tevs[i]);
|
||||||
if (!command)
|
if (!command)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
strlist__add(entry->tevlist, command);
|
ret = strlist__add(entry->tevlist, command);
|
||||||
|
if (ret == -ENOMEM) {
|
||||||
|
pr_err("strlist__add failed with -ENOMEM\n");
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
|
||||||
free(command);
|
free(command);
|
||||||
}
|
}
|
||||||
list_add_tail(&entry->node, &pcache->entries);
|
list_add_tail(&entry->node, &pcache->entries);
|
||||||
|
@ -853,9 +867,15 @@ int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
strlist__add(entry->tevlist, buf);
|
ret = strlist__add(entry->tevlist, buf);
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
entry = NULL;
|
entry = NULL;
|
||||||
|
|
||||||
|
if (ret == -ENOMEM) {
|
||||||
|
pr_err("strlist__add failed with -ENOMEM\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (entry) {
|
if (entry) {
|
||||||
list_del_init(&entry->node);
|
list_del_init(&entry->node);
|
||||||
|
|
Loading…
Reference in a new issue