mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-28 23:24:50 +00:00
perf/core improvements and fixes:
- Optimize sample parsing for ordering events, where we don't need to parse all the PERF_SAMPLE_ bits, just the ones leading to the timestamp needed to reorder events (Jiri Olsa) - Use a dummy event to ask for PERF_RECORD_{MMAP,COMM,EXEC} with 'perf record --delay', when the events asked by the user will only be enabled after the workload is started and the requested delay passes, so we need to add the dummy event and have it .enabled_on_exec. This then allows us to resolve symbols for the DSO executable MMAPs setup while we wait for the delay (Arnaldo Carvalho de Melo) - Synchronize kcmp.h and prctl.h ABI headers wrt SPDX tags (Arnaldo Carvalho de Melo) - Generalize the annotation code to support other source information besides objdump/DWARF obtained ones, starting with python scripts, that will is slated to be merged soon (Jiri Olsa) - Advance the source code lines to right after the column with the address in asm lines (Jiri Olsa) - Fix terminal dimensions resizing signal handling in 'perf top --stdio' (Jiri Olsa) - Improve error messages for PMU events (Kim Phillips) - Fix 'perf record' -c/-F options for cpu event aliases (Andi Kleen) - Enable type checking for perf_evsel_config_term types (Andi Kleen) - Call machine__exit() at 'perf trace' exit, so as to remove temporary files related to VDSO (Andrei Vagin) - Add "reject" option to parse-events.l, fixing the build with newer flex releases. Noticed with flex 2.6.4 on Alpine Linux 3.6 and Edge (Jiri Olsa) - Document some missing perf.data headers (Andi Kleen) - Allow printing period for non freq mod groups (Andi Kleen) - Do not warn the user about kernel.kptr_restrict when not sampling the kernel (Arnaldo Carvalho de Melo) - Fix bug in 'perf help' introduced during conversion to strstart() (Namhyung Kim) - Do not truncate ASM instruction mnemonics at 6 characters in the annotation output, PowerPC has long ones (Ravi Bangoria) - Document some missing command line options (Sihyeon Jang) - Update POWER9 vendor event tables (Sukadev Bhattiprolu) - Fix 'perf test' shell entries on s390x, where the 'openat' syscall is used instead of 'open' in one of the tests and - No need to use overwrite mmap mode in 'perf test', those tests do not generate massive amount of events to fill the ring buffer (Wang Nan) - Add missing command line options (mostly --force/-f) to the man pages (Sihyeon Jang) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEELb9bqkb7Te0zijNb1lAW81NSqkAFAloPQT8ACgkQ1lAW81NS qkBJKxAAja4hN1lyyfF1Jeu+8XHxroRXRKN4jJcKN/O2egZDt+htPp712zOxL6rB hObOZkvhciaTxmmx1QlDlv68YPMa7P5QppdY17/HPOs/oJD0D3f1fHfNXpg9TilA 5IdWAJVHxTUm9IaNOqIpUP6fV37mR+z2wYd2sCyunJio9OZrm2lgQe9d9WzYOd5j C0pRfjfrS4cuMLxqvXEn8oNv/ITGcuVoRQ6h7AEL+g51iFhTbc61BrUVy9BhffZt eAjoKpkb50SGa4xnpFufSgT8pgKd/JJEY7Xi6eypmLhX28Uhpt880xQaE+5+7/d1 ktlpRfIdMvCz/+RyrZXUredy5pEz2QEY9RhI5cCiMHP6ppTJ9yp2/dU9EDLurqvm vj/cEz9/58OJMS+gmentXJjA06puSNhYzOsG/rcZb6uGELhDDu8qytxaN4diOFPd Kl7kuyryodNl9y/NYMbm3nNL+pwy9BXN8ktN2I6O1WT1aimmdp/UMW6S5YENZUb7 FRz8DyDlkeBaDh58U9iS5c8qQ1LA0fqNuJWBp9aK4iETgeofLViMXWrwaPl9vKeC 3Sk5j6GuAAavgdIuvU9QoAkM9pZClgBvVt00KXVzOGbBHFDNwU2igik4HPwsJtMf Quo/kOMawW9rSei5Q1RRZjLAMRsvb2ktCx9Xll/1faiIdROhnjc= =PVj/ -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo-4.15-20171117' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: - Optimize sample parsing for ordering events, where we don't need to parse all the PERF_SAMPLE_ bits, just the ones leading to the timestamp needed to reorder events (Jiri Olsa) - Use a dummy event to ask for PERF_RECORD_{MMAP,COMM,EXEC} with 'perf record --delay', when the events asked by the user will only be enabled after the workload is started and the requested delay passes, so we need to add the dummy event and have it .enabled_on_exec. This then allows us to resolve symbols for the DSO executable MMAPs setup while we wait for the delay (Arnaldo Carvalho de Melo) - Synchronize kcmp.h and prctl.h ABI headers wrt SPDX tags (Arnaldo Carvalho de Melo) - Generalize the annotation code to support other source information besides objdump/DWARF obtained ones, starting with python scripts, that will is slated to be merged soon (Jiri Olsa) - Advance the source code lines to right after the column with the address in asm lines (Jiri Olsa) - Fix terminal dimensions resizing signal handling in 'perf top --stdio' (Jiri Olsa) - Improve error messages for PMU events (Kim Phillips) - Fix 'perf record' -c/-F options for cpu event aliases (Andi Kleen) - Enable type checking for perf_evsel_config_term types (Andi Kleen) - Call machine__exit() at 'perf trace' exit, so as to remove temporary files related to VDSO (Andrei Vagin) - Add "reject" option to parse-events.l, fixing the build with newer flex releases. Noticed with flex 2.6.4 on Alpine Linux 3.6 and Edge (Jiri Olsa) - Document some missing perf.data headers (Andi Kleen) - Allow printing period for non freq mod groups (Andi Kleen) - Do not warn the user about kernel.kptr_restrict when not sampling the kernel (Arnaldo Carvalho de Melo) - Fix bug in 'perf help' introduced during conversion to strstart() (Namhyung Kim) - Do not truncate ASM instruction mnemonics at 6 characters in the annotation output, PowerPC has long ones (Ravi Bangoria) - Document some missing command line options (Sihyeon Jang) - Update POWER9 vendor event tables (Sukadev Bhattiprolu) - Fix 'perf test' shell entries on s390x, where the 'openat' syscall is used instead of 'open' in one of the tests and - No need to use overwrite mmap mode in 'perf test', those tests do not generate massive amount of events to fill the ring buffer (Wang Nan) - Add missing command line options (mostly --force/-f) to the man pages (Sihyeon Jang) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
754fe00fa6
52 changed files with 1028 additions and 920 deletions
|
@ -6640,6 +6640,7 @@ static void perf_event_namespaces_output(struct perf_event *event,
|
||||||
struct perf_namespaces_event *namespaces_event = data;
|
struct perf_namespaces_event *namespaces_event = data;
|
||||||
struct perf_output_handle handle;
|
struct perf_output_handle handle;
|
||||||
struct perf_sample_data sample;
|
struct perf_sample_data sample;
|
||||||
|
u16 header_size = namespaces_event->event_id.header.size;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!perf_event_namespaces_match(event))
|
if (!perf_event_namespaces_match(event))
|
||||||
|
@ -6650,7 +6651,7 @@ static void perf_event_namespaces_output(struct perf_event *event,
|
||||||
ret = perf_output_begin(&handle, event,
|
ret = perf_output_begin(&handle, event,
|
||||||
namespaces_event->event_id.header.size);
|
namespaces_event->event_id.header.size);
|
||||||
if (ret)
|
if (ret)
|
||||||
return;
|
goto out;
|
||||||
|
|
||||||
namespaces_event->event_id.pid = perf_event_pid(event,
|
namespaces_event->event_id.pid = perf_event_pid(event,
|
||||||
namespaces_event->task);
|
namespaces_event->task);
|
||||||
|
@ -6662,6 +6663,8 @@ static void perf_event_namespaces_output(struct perf_event *event,
|
||||||
perf_event__output_id_sample(event, &handle, &sample);
|
perf_event__output_id_sample(event, &handle, &sample);
|
||||||
|
|
||||||
perf_output_end(&handle);
|
perf_output_end(&handle);
|
||||||
|
out:
|
||||||
|
namespaces_event->event_id.header.size = header_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void perf_fill_ns_link_info(struct perf_ns_link_info *ns_link_info,
|
static void perf_fill_ns_link_info(struct perf_ns_link_info *ns_link_info,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||||
#ifndef _UAPI_LINUX_KCMP_H
|
#ifndef _UAPI_LINUX_KCMP_H
|
||||||
#define _UAPI_LINUX_KCMP_H
|
#define _UAPI_LINUX_KCMP_H
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||||
#ifndef _LINUX_PRCTL_H
|
#ifndef _LINUX_PRCTL_H
|
||||||
#define _LINUX_PRCTL_H
|
#define _LINUX_PRCTL_H
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,9 @@ OPTIONS
|
||||||
-a::
|
-a::
|
||||||
--add=::
|
--add=::
|
||||||
Add specified file to the cache.
|
Add specified file to the cache.
|
||||||
|
-f::
|
||||||
|
--force::
|
||||||
|
Don't complain, do it.
|
||||||
-k::
|
-k::
|
||||||
--kcore::
|
--kcore::
|
||||||
Add specified kcore file to the cache. For the current host that is
|
Add specified kcore file to the cache. For the current host that is
|
||||||
|
|
|
@ -20,6 +20,10 @@ OPTIONS
|
||||||
--input=::
|
--input=::
|
||||||
Input file name. (default: perf.data unless stdin is a fifo)
|
Input file name. (default: perf.data unless stdin is a fifo)
|
||||||
|
|
||||||
|
-f::
|
||||||
|
--force::
|
||||||
|
Don't complain, do it.
|
||||||
|
|
||||||
-F::
|
-F::
|
||||||
--freq=::
|
--freq=::
|
||||||
Show just the sample frequency used for each event.
|
Show just the sample frequency used for each event.
|
||||||
|
|
|
@ -60,6 +60,10 @@ include::itrace.txt[]
|
||||||
found in the jitdumps files captured in the input perf.data file. Use this option
|
found in the jitdumps files captured in the input perf.data file. Use this option
|
||||||
if you are monitoring environment using JIT runtimes, such as Java, DART or V8.
|
if you are monitoring environment using JIT runtimes, such as Java, DART or V8.
|
||||||
|
|
||||||
|
-f::
|
||||||
|
--force::
|
||||||
|
Don't complain, do it.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
|
linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
|
||||||
|
|
|
@ -42,6 +42,10 @@ COMMON OPTIONS
|
||||||
--dump-raw-trace::
|
--dump-raw-trace::
|
||||||
Dump raw trace in ASCII.
|
Dump raw trace in ASCII.
|
||||||
|
|
||||||
|
-f::
|
||||||
|
--force::
|
||||||
|
Don't complan, do it.
|
||||||
|
|
||||||
REPORT OPTIONS
|
REPORT OPTIONS
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,10 @@ OPTIONS
|
||||||
--dump-raw-trace=::
|
--dump-raw-trace=::
|
||||||
Display verbose dump of the sched data.
|
Display verbose dump of the sched data.
|
||||||
|
|
||||||
|
-f::
|
||||||
|
--force::
|
||||||
|
Don't complain, do it.
|
||||||
|
|
||||||
OPTIONS for 'perf sched map'
|
OPTIONS for 'perf sched map'
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,9 @@ TIMECHART OPTIONS
|
||||||
-p::
|
-p::
|
||||||
--process::
|
--process::
|
||||||
Select the processes to display, by name or PID
|
Select the processes to display, by name or PID
|
||||||
|
-f::
|
||||||
|
--force::
|
||||||
|
Don't complain, do it.
|
||||||
--symfs=<directory>::
|
--symfs=<directory>::
|
||||||
Look for files with symbols relative to this directory.
|
Look for files with symbols relative to this directory.
|
||||||
-n::
|
-n::
|
||||||
|
|
|
@ -268,6 +268,12 @@ INTERACTIVE PROMPTING KEYS
|
||||||
[S]::
|
[S]::
|
||||||
Stop annotation, return to full profile display.
|
Stop annotation, return to full profile display.
|
||||||
|
|
||||||
|
[K]::
|
||||||
|
Hide kernel symbols.
|
||||||
|
|
||||||
|
[U]::
|
||||||
|
Hide user symbols.
|
||||||
|
|
||||||
[z]::
|
[z]::
|
||||||
Toggle event count zeroing across display updates.
|
Toggle event count zeroing across display updates.
|
||||||
|
|
||||||
|
|
|
@ -86,18 +86,18 @@ comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-
|
||||||
In per-thread mode with inheritance mode on (default), Events are captured only when
|
In per-thread mode with inheritance mode on (default), Events are captured only when
|
||||||
the thread executes on the designated CPUs. Default is to monitor all CPUs.
|
the thread executes on the designated CPUs. Default is to monitor all CPUs.
|
||||||
|
|
||||||
--duration:
|
--duration::
|
||||||
Show only events that had a duration greater than N.M ms.
|
Show only events that had a duration greater than N.M ms.
|
||||||
|
|
||||||
--sched:
|
--sched::
|
||||||
Accrue thread runtime and provide a summary at the end of the session.
|
Accrue thread runtime and provide a summary at the end of the session.
|
||||||
|
|
||||||
-i
|
-i::
|
||||||
--input
|
--input::
|
||||||
Process events from a given perf data file.
|
Process events from a given perf data file.
|
||||||
|
|
||||||
-T
|
-T::
|
||||||
--time
|
--time::
|
||||||
Print full timestamp rather time relative to first sample.
|
Print full timestamp rather time relative to first sample.
|
||||||
|
|
||||||
--comm::
|
--comm::
|
||||||
|
@ -117,6 +117,10 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
|
||||||
Show tool stats such as number of times fd->pathname was discovered thru
|
Show tool stats such as number of times fd->pathname was discovered thru
|
||||||
hooking the open syscall return + vfs_getname or via reading /proc/pid/fd, etc.
|
hooking the open syscall return + vfs_getname or via reading /proc/pid/fd, etc.
|
||||||
|
|
||||||
|
-f::
|
||||||
|
--force::
|
||||||
|
Don't complain, do it.
|
||||||
|
|
||||||
-F=[all|min|maj]::
|
-F=[all|min|maj]::
|
||||||
--pf=[all|min|maj]::
|
--pf=[all|min|maj]::
|
||||||
Trace pagefaults. Optionally, you can specify whether you want minor,
|
Trace pagefaults. Optionally, you can specify whether you want minor,
|
||||||
|
|
|
@ -238,6 +238,29 @@ struct auxtrace_index {
|
||||||
struct auxtrace_index_entry entries[PERF_AUXTRACE_INDEX_ENTRY_COUNT];
|
struct auxtrace_index_entry entries[PERF_AUXTRACE_INDEX_ENTRY_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
HEADER_STAT = 19,
|
||||||
|
|
||||||
|
This is merely a flag signifying that the data section contains data
|
||||||
|
recorded from perf stat record.
|
||||||
|
|
||||||
|
HEADER_CACHE = 20,
|
||||||
|
|
||||||
|
Description of the cache hierarchy. Based on the Linux sysfs format
|
||||||
|
in /sys/devices/system/cpu/cpu*/cache/
|
||||||
|
|
||||||
|
u32 version Currently always 1
|
||||||
|
u32 number_of_cache_levels
|
||||||
|
|
||||||
|
struct {
|
||||||
|
u32 level;
|
||||||
|
u32 line_size;
|
||||||
|
u32 sets;
|
||||||
|
u32 ways;
|
||||||
|
struct perf_header_string type;
|
||||||
|
struct perf_header_string size;
|
||||||
|
struct perf_header_string map;
|
||||||
|
}[number_of_cache_levels];
|
||||||
|
|
||||||
other bits are reserved and should ignored for now
|
other bits are reserved and should ignored for now
|
||||||
HEADER_FEAT_BITS = 256,
|
HEADER_FEAT_BITS = 256,
|
||||||
|
|
||||||
|
|
|
@ -579,7 +579,7 @@ else
|
||||||
PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
|
PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
|
||||||
PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
|
PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
|
||||||
PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
|
PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
|
||||||
PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
|
PERL_EMBED_CCOPTS = $(shell perl -MExtUtils::Embed -e ccopts 2>/dev/null)
|
||||||
FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
|
FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
|
||||||
|
|
||||||
ifneq ($(feature-libperl), 1)
|
ifneq ($(feature-libperl), 1)
|
||||||
|
|
|
@ -325,8 +325,8 @@ int cmd_buildid_cache(int argc, const char **argv)
|
||||||
"file", "kcore file to add"),
|
"file", "kcore file to add"),
|
||||||
OPT_STRING('r', "remove", &remove_name_list_str, "file list",
|
OPT_STRING('r', "remove", &remove_name_list_str, "file list",
|
||||||
"file(s) to remove"),
|
"file(s) to remove"),
|
||||||
OPT_STRING('p', "purge", &purge_name_list_str, "path list",
|
OPT_STRING('p', "purge", &purge_name_list_str, "file list",
|
||||||
"path(s) to remove (remove old caches too)"),
|
"file(s) to remove (remove old caches too)"),
|
||||||
OPT_STRING('M', "missing", &missing_filename, "file",
|
OPT_STRING('M', "missing", &missing_filename, "file",
|
||||||
"to find missing build ids in the cache"),
|
"to find missing build ids in the cache"),
|
||||||
OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
|
OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
|
||||||
|
|
|
@ -2224,9 +2224,9 @@ static int perf_c2c__browse_cacheline(struct hist_entry *he)
|
||||||
struct hist_browser *browser;
|
struct hist_browser *browser;
|
||||||
int key = -1;
|
int key = -1;
|
||||||
const char help[] =
|
const char help[] =
|
||||||
" ENTER Togle callchains (if present) \n"
|
" ENTER Toggle callchains (if present) \n"
|
||||||
" n Togle Node details info \n"
|
" n Toggle Node details info \n"
|
||||||
" s Togle full lenght of symbol and source line columns \n"
|
" s Toggle full length of symbol and source line columns \n"
|
||||||
" q Return back to cacheline list \n";
|
" q Return back to cacheline list \n";
|
||||||
|
|
||||||
/* Display compact version first. */
|
/* Display compact version first. */
|
||||||
|
@ -2303,7 +2303,7 @@ static int perf_c2c__hists_browse(struct hists *hists)
|
||||||
int key = -1;
|
int key = -1;
|
||||||
const char help[] =
|
const char help[] =
|
||||||
" d Display cacheline details \n"
|
" d Display cacheline details \n"
|
||||||
" ENTER Togle callchains (if present) \n"
|
" ENTER Toggle callchains (if present) \n"
|
||||||
" q Quit \n";
|
" q Quit \n";
|
||||||
|
|
||||||
browser = perf_c2c_browser__new(hists);
|
browser = perf_c2c_browser__new(hists);
|
||||||
|
|
|
@ -284,7 +284,7 @@ static int perf_help_config(const char *var, const char *value, void *cb)
|
||||||
add_man_viewer(value);
|
add_man_viewer(value);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!strstarts(var, "man."))
|
if (strstarts(var, "man."))
|
||||||
return add_man_viewer_info(var, value);
|
return add_man_viewer_info(var, value);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -314,7 +314,7 @@ static const char *cmd_to_page(const char *perf_cmd)
|
||||||
|
|
||||||
if (!perf_cmd)
|
if (!perf_cmd)
|
||||||
return "perf";
|
return "perf";
|
||||||
else if (!strstarts(perf_cmd, "perf"))
|
else if (strstarts(perf_cmd, "perf"))
|
||||||
return perf_cmd;
|
return perf_cmd;
|
||||||
|
|
||||||
return asprintf(&s, "perf-%s", perf_cmd) < 0 ? NULL : s;
|
return asprintf(&s, "perf-%s", perf_cmd) < 0 ? NULL : s;
|
||||||
|
|
|
@ -741,20 +741,20 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx,
|
||||||
u64 *mmap_time)
|
u64 *mmap_time)
|
||||||
{
|
{
|
||||||
union perf_event *event;
|
union perf_event *event;
|
||||||
struct perf_sample sample;
|
u64 timestamp;
|
||||||
s64 n = 0;
|
s64 n = 0;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
*mmap_time = ULLONG_MAX;
|
*mmap_time = ULLONG_MAX;
|
||||||
while ((event = perf_evlist__mmap_read(kvm->evlist, idx)) != NULL) {
|
while ((event = perf_evlist__mmap_read(kvm->evlist, idx)) != NULL) {
|
||||||
err = perf_evlist__parse_sample(kvm->evlist, event, &sample);
|
err = perf_evlist__parse_sample_timestamp(kvm->evlist, event, ×tamp);
|
||||||
if (err) {
|
if (err) {
|
||||||
perf_evlist__mmap_consume(kvm->evlist, idx);
|
perf_evlist__mmap_consume(kvm->evlist, idx);
|
||||||
pr_err("Failed to parse sample\n");
|
pr_err("Failed to parse sample\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = perf_session__queue_event(kvm->session, event, &sample, 0);
|
err = perf_session__queue_event(kvm->session, event, timestamp, 0);
|
||||||
/*
|
/*
|
||||||
* FIXME: Here we can't consume the event, as perf_session__queue_event will
|
* FIXME: Here we can't consume the event, as perf_session__queue_event will
|
||||||
* point to it, and it'll get possibly overwritten by the kernel.
|
* point to it, and it'll get possibly overwritten by the kernel.
|
||||||
|
@ -768,7 +768,7 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx,
|
||||||
|
|
||||||
/* save time stamp of our first sample for this mmap */
|
/* save time stamp of our first sample for this mmap */
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
*mmap_time = sample.time;
|
*mmap_time = timestamp;
|
||||||
|
|
||||||
/* limit events per mmap handled all at once */
|
/* limit events per mmap handled all at once */
|
||||||
n++;
|
n++;
|
||||||
|
|
|
@ -339,6 +339,22 @@ static int record__open(struct record *rec)
|
||||||
struct perf_evsel_config_term *err_term;
|
struct perf_evsel_config_term *err_term;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For initial_delay we need to add a dummy event so that we can track
|
||||||
|
* PERF_RECORD_MMAP while we wait for the initial delay to enable the
|
||||||
|
* real events, the ones asked by the user.
|
||||||
|
*/
|
||||||
|
if (opts->initial_delay) {
|
||||||
|
if (perf_evlist__add_dummy(evlist))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
pos = perf_evlist__first(evlist);
|
||||||
|
pos->tracking = 0;
|
||||||
|
pos = perf_evlist__last(evlist);
|
||||||
|
pos->tracking = 1;
|
||||||
|
pos->attr.enable_on_exec = 1;
|
||||||
|
}
|
||||||
|
|
||||||
perf_evlist__config(evlist, opts, &callchain_param);
|
perf_evlist__config(evlist, opts, &callchain_param);
|
||||||
|
|
||||||
evlist__for_each_entry(evlist, pos) {
|
evlist__for_each_entry(evlist, pos) {
|
||||||
|
@ -749,17 +765,19 @@ static int record__synthesize(struct record *rec, bool tail)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
|
if (!perf_evlist__exclude_kernel(rec->evlist)) {
|
||||||
machine);
|
err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
|
||||||
WARN_ONCE(err < 0, "Couldn't record kernel reference relocation symbol\n"
|
machine);
|
||||||
"Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
|
WARN_ONCE(err < 0, "Couldn't record kernel reference relocation symbol\n"
|
||||||
"Check /proc/kallsyms permission or run as root.\n");
|
"Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
|
||||||
|
"Check /proc/kallsyms permission or run as root.\n");
|
||||||
|
|
||||||
err = perf_event__synthesize_modules(tool, process_synthesized_event,
|
err = perf_event__synthesize_modules(tool, process_synthesized_event,
|
||||||
machine);
|
machine);
|
||||||
WARN_ONCE(err < 0, "Couldn't record kernel module information.\n"
|
WARN_ONCE(err < 0, "Couldn't record kernel module information.\n"
|
||||||
"Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
|
"Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
|
||||||
"Check /proc/modules permission or run as root.\n");
|
"Check /proc/modules permission or run as root.\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (perf_guest) {
|
if (perf_guest) {
|
||||||
machines__process_guests(&session->machines,
|
machines__process_guests(&session->machines,
|
||||||
|
@ -1693,7 +1711,7 @@ int cmd_record(int argc, const char **argv)
|
||||||
|
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
|
|
||||||
if (symbol_conf.kptr_restrict)
|
if (symbol_conf.kptr_restrict && !perf_evlist__exclude_kernel(rec->evlist))
|
||||||
pr_warning(
|
pr_warning(
|
||||||
"WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
|
"WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
|
||||||
"check /proc/sys/kernel/kptr_restrict.\n\n"
|
"check /proc/sys/kernel/kptr_restrict.\n\n"
|
||||||
|
|
|
@ -441,6 +441,9 @@ static void report__warn_kptr_restrict(const struct report *rep)
|
||||||
struct map *kernel_map = machine__kernel_map(&rep->session->machines.host);
|
struct map *kernel_map = machine__kernel_map(&rep->session->machines.host);
|
||||||
struct kmap *kernel_kmap = kernel_map ? map__kmap(kernel_map) : NULL;
|
struct kmap *kernel_kmap = kernel_map ? map__kmap(kernel_map) : NULL;
|
||||||
|
|
||||||
|
if (perf_evlist__exclude_kernel(rep->session->evlist))
|
||||||
|
return;
|
||||||
|
|
||||||
if (kernel_map == NULL ||
|
if (kernel_map == NULL ||
|
||||||
(kernel_map->dso->hit &&
|
(kernel_map->dso->hit &&
|
||||||
(kernel_kmap->ref_reloc_sym == NULL ||
|
(kernel_kmap->ref_reloc_sym == NULL ||
|
||||||
|
|
|
@ -423,11 +423,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
|
||||||
PERF_OUTPUT_CPU, allow_user_set))
|
PERF_OUTPUT_CPU, allow_user_set))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (PRINT_FIELD(PERIOD) &&
|
|
||||||
perf_evsel__check_stype(evsel, PERF_SAMPLE_PERIOD, "PERIOD",
|
|
||||||
PERF_OUTPUT_PERIOD))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (PRINT_FIELD(IREGS) &&
|
if (PRINT_FIELD(IREGS) &&
|
||||||
perf_evsel__check_stype(evsel, PERF_SAMPLE_REGS_INTR, "IREGS",
|
perf_evsel__check_stype(evsel, PERF_SAMPLE_REGS_INTR, "IREGS",
|
||||||
PERF_OUTPUT_IREGS))
|
PERF_OUTPUT_IREGS))
|
||||||
|
@ -1955,6 +1950,16 @@ static int perf_script__fopen_per_event_dump(struct perf_script *script)
|
||||||
struct perf_evsel *evsel;
|
struct perf_evsel *evsel;
|
||||||
|
|
||||||
evlist__for_each_entry(script->session->evlist, evsel) {
|
evlist__for_each_entry(script->session->evlist, evsel) {
|
||||||
|
/*
|
||||||
|
* Already setup? I.e. we may be called twice in cases like
|
||||||
|
* Intel PT, one for the intel_pt// and dummy events, then
|
||||||
|
* for the evsels syntheized from the auxtrace info.
|
||||||
|
*
|
||||||
|
* Ses perf_script__process_auxtrace_info.
|
||||||
|
*/
|
||||||
|
if (evsel->priv != NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
evsel->priv = perf_evsel_script__new(evsel, script->session->data);
|
evsel->priv = perf_evsel_script__new(evsel, script->session->data);
|
||||||
if (evsel->priv == NULL)
|
if (evsel->priv == NULL)
|
||||||
goto out_err_fclose;
|
goto out_err_fclose;
|
||||||
|
@ -2838,6 +2843,25 @@ int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
|
||||||
return set_maps(script);
|
return set_maps(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_AUXTRACE_SUPPORT
|
||||||
|
static int perf_script__process_auxtrace_info(struct perf_tool *tool,
|
||||||
|
union perf_event *event,
|
||||||
|
struct perf_session *session)
|
||||||
|
{
|
||||||
|
int ret = perf_event__process_auxtrace_info(tool, event, session);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
struct perf_script *script = container_of(tool, struct perf_script, tool);
|
||||||
|
|
||||||
|
ret = perf_script__setup_per_event_dump(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define perf_script__process_auxtrace_info 0
|
||||||
|
#endif
|
||||||
|
|
||||||
int cmd_script(int argc, const char **argv)
|
int cmd_script(int argc, const char **argv)
|
||||||
{
|
{
|
||||||
bool show_full_info = false;
|
bool show_full_info = false;
|
||||||
|
@ -2866,7 +2890,7 @@ int cmd_script(int argc, const char **argv)
|
||||||
.feature = perf_event__process_feature,
|
.feature = perf_event__process_feature,
|
||||||
.build_id = perf_event__process_build_id,
|
.build_id = perf_event__process_build_id,
|
||||||
.id_index = perf_event__process_id_index,
|
.id_index = perf_event__process_id_index,
|
||||||
.auxtrace_info = perf_event__process_auxtrace_info,
|
.auxtrace_info = perf_script__process_auxtrace_info,
|
||||||
.auxtrace = perf_event__process_auxtrace,
|
.auxtrace = perf_event__process_auxtrace,
|
||||||
.auxtrace_error = perf_event__process_auxtrace_error,
|
.auxtrace_error = perf_event__process_auxtrace_error,
|
||||||
.stat = perf_event__process_stat_event,
|
.stat = perf_event__process_stat_event,
|
||||||
|
|
|
@ -77,6 +77,7 @@
|
||||||
#include "sane_ctype.h"
|
#include "sane_ctype.h"
|
||||||
|
|
||||||
static volatile int done;
|
static volatile int done;
|
||||||
|
static volatile int resize;
|
||||||
|
|
||||||
#define HEADER_LINE_NR 5
|
#define HEADER_LINE_NR 5
|
||||||
|
|
||||||
|
@ -85,17 +86,20 @@ static void perf_top__update_print_entries(struct perf_top *top)
|
||||||
top->print_entries = top->winsize.ws_row - HEADER_LINE_NR;
|
top->print_entries = top->winsize.ws_row - HEADER_LINE_NR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void perf_top__sig_winch(int sig __maybe_unused,
|
static void winch_sig(int sig __maybe_unused)
|
||||||
siginfo_t *info __maybe_unused, void *arg)
|
|
||||||
{
|
{
|
||||||
struct perf_top *top = arg;
|
resize = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void perf_top__resize(struct perf_top *top)
|
||||||
|
{
|
||||||
get_term_dimensions(&top->winsize);
|
get_term_dimensions(&top->winsize);
|
||||||
perf_top__update_print_entries(top);
|
perf_top__update_print_entries(top);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
|
static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
|
||||||
{
|
{
|
||||||
|
struct perf_evsel *evsel = hists_to_evsel(he->hists);
|
||||||
struct symbol *sym;
|
struct symbol *sym;
|
||||||
struct annotation *notes;
|
struct annotation *notes;
|
||||||
struct map *map;
|
struct map *map;
|
||||||
|
@ -134,7 +138,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = symbol__disassemble(sym, map, NULL, 0, NULL, NULL);
|
err = symbol__annotate(sym, map, evsel, 0, NULL, NULL);
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
out_assign:
|
out_assign:
|
||||||
top->sym_filter_entry = he;
|
top->sym_filter_entry = he;
|
||||||
|
@ -226,6 +230,7 @@ static void perf_top__record_precise_ip(struct perf_top *top,
|
||||||
static void perf_top__show_details(struct perf_top *top)
|
static void perf_top__show_details(struct perf_top *top)
|
||||||
{
|
{
|
||||||
struct hist_entry *he = top->sym_filter_entry;
|
struct hist_entry *he = top->sym_filter_entry;
|
||||||
|
struct perf_evsel *evsel = hists_to_evsel(he->hists);
|
||||||
struct annotation *notes;
|
struct annotation *notes;
|
||||||
struct symbol *symbol;
|
struct symbol *symbol;
|
||||||
int more;
|
int more;
|
||||||
|
@ -238,6 +243,8 @@ static void perf_top__show_details(struct perf_top *top)
|
||||||
|
|
||||||
pthread_mutex_lock(¬es->lock);
|
pthread_mutex_lock(¬es->lock);
|
||||||
|
|
||||||
|
symbol__calc_percent(symbol, evsel);
|
||||||
|
|
||||||
if (notes->src == NULL)
|
if (notes->src == NULL)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
|
@ -409,7 +416,7 @@ static void perf_top__print_mapped_keys(struct perf_top *top)
|
||||||
fprintf(stdout, "\t[S] stop annotation.\n");
|
fprintf(stdout, "\t[S] stop annotation.\n");
|
||||||
|
|
||||||
fprintf(stdout,
|
fprintf(stdout,
|
||||||
"\t[K] hide kernel_symbols symbols. \t(%s)\n",
|
"\t[K] hide kernel symbols. \t(%s)\n",
|
||||||
top->hide_kernel_symbols ? "yes" : "no");
|
top->hide_kernel_symbols ? "yes" : "no");
|
||||||
fprintf(stdout,
|
fprintf(stdout,
|
||||||
"\t[U] hide user symbols. \t(%s)\n",
|
"\t[U] hide user symbols. \t(%s)\n",
|
||||||
|
@ -473,12 +480,8 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
|
||||||
case 'e':
|
case 'e':
|
||||||
prompt_integer(&top->print_entries, "Enter display entries (lines)");
|
prompt_integer(&top->print_entries, "Enter display entries (lines)");
|
||||||
if (top->print_entries == 0) {
|
if (top->print_entries == 0) {
|
||||||
struct sigaction act = {
|
perf_top__resize(top);
|
||||||
.sa_sigaction = perf_top__sig_winch,
|
signal(SIGWINCH, winch_sig);
|
||||||
.sa_flags = SA_SIGINFO,
|
|
||||||
};
|
|
||||||
perf_top__sig_winch(SIGWINCH, NULL, top);
|
|
||||||
sigaction(SIGWINCH, &act, NULL);
|
|
||||||
} else {
|
} else {
|
||||||
signal(SIGWINCH, SIG_DFL);
|
signal(SIGWINCH, SIG_DFL);
|
||||||
}
|
}
|
||||||
|
@ -732,14 +735,16 @@ static void perf_event__process_sample(struct perf_tool *tool,
|
||||||
if (!machine->kptr_restrict_warned &&
|
if (!machine->kptr_restrict_warned &&
|
||||||
symbol_conf.kptr_restrict &&
|
symbol_conf.kptr_restrict &&
|
||||||
al.cpumode == PERF_RECORD_MISC_KERNEL) {
|
al.cpumode == PERF_RECORD_MISC_KERNEL) {
|
||||||
ui__warning(
|
if (!perf_evlist__exclude_kernel(top->session->evlist)) {
|
||||||
|
ui__warning(
|
||||||
"Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
|
"Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
|
||||||
"Check /proc/sys/kernel/kptr_restrict.\n\n"
|
"Check /proc/sys/kernel/kptr_restrict.\n\n"
|
||||||
"Kernel%s samples will not be resolved.\n",
|
"Kernel%s samples will not be resolved.\n",
|
||||||
al.map && !RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION]) ?
|
al.map && !RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION]) ?
|
||||||
" modules" : "");
|
" modules" : "");
|
||||||
if (use_browser <= 0)
|
if (use_browser <= 0)
|
||||||
sleep(5);
|
sleep(5);
|
||||||
|
}
|
||||||
machine->kptr_restrict_warned = true;
|
machine->kptr_restrict_warned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1030,6 +1035,11 @@ static int __cmd_top(struct perf_top *top)
|
||||||
|
|
||||||
if (hits == top->samples)
|
if (hits == top->samples)
|
||||||
ret = perf_evlist__poll(top->evlist, 100);
|
ret = perf_evlist__poll(top->evlist, 100);
|
||||||
|
|
||||||
|
if (resize) {
|
||||||
|
perf_top__resize(top);
|
||||||
|
resize = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -1352,12 +1362,8 @@ int cmd_top(int argc, const char **argv)
|
||||||
|
|
||||||
get_term_dimensions(&top.winsize);
|
get_term_dimensions(&top.winsize);
|
||||||
if (top.print_entries == 0) {
|
if (top.print_entries == 0) {
|
||||||
struct sigaction act = {
|
|
||||||
.sa_sigaction = perf_top__sig_winch,
|
|
||||||
.sa_flags = SA_SIGINFO,
|
|
||||||
};
|
|
||||||
perf_top__update_print_entries(&top);
|
perf_top__update_print_entries(&top);
|
||||||
sigaction(SIGWINCH, &act, NULL);
|
signal(SIGWINCH, winch_sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = __cmd_top(&top);
|
status = __cmd_top(&top);
|
||||||
|
|
|
@ -1152,12 +1152,14 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
|
||||||
if (trace->host == NULL)
|
if (trace->host == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
|
err = trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr);
|
||||||
return -errno;
|
if (err < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
|
err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
|
||||||
evlist->threads, trace__tool_process, false,
|
evlist->threads, trace__tool_process, false,
|
||||||
trace->opts.proc_map_timeout, 1);
|
trace->opts.proc_map_timeout, 1);
|
||||||
|
out:
|
||||||
if (err)
|
if (err)
|
||||||
symbol__exit();
|
symbol__exit();
|
||||||
|
|
||||||
|
|
|
@ -124,11 +124,6 @@
|
||||||
"EventName": "PM_CMPLU_STALL_LARX",
|
"EventName": "PM_CMPLU_STALL_LARX",
|
||||||
"BriefDescription": "Finish stall because the NTF instruction was a larx waiting to be satisfied"
|
"BriefDescription": "Finish stall because the NTF instruction was a larx waiting to be satisfied"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x3006C",
|
|
||||||
"EventName": "PM_RUN_CYC_SMT2_MODE",
|
|
||||||
"BriefDescription": "Cycles in which this thread's run latch is set and the core is in SMT2 mode"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x1C058",
|
"EventCode": "0x1C058",
|
||||||
"EventName": "PM_DTLB_MISS_16G",
|
"EventName": "PM_DTLB_MISS_16G",
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
[
|
[
|
||||||
{,
|
|
||||||
"EventCode": "0x3E15C",
|
|
||||||
"EventName": "PM_MRK_L2_TM_ST_ABORT_SISTER",
|
|
||||||
"BriefDescription": "TM marked store abort for this thread"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x25044",
|
"EventCode": "0x25044",
|
||||||
"EventName": "PM_IPTEG_FROM_L31_MOD",
|
"EventName": "PM_IPTEG_FROM_L31_MOD",
|
||||||
|
@ -369,4 +364,4 @@
|
||||||
"EventName": "PM_IPTEG_FROM_L31_ECO_MOD",
|
"EventName": "PM_IPTEG_FROM_L31_ECO_MOD",
|
||||||
"BriefDescription": "A Page Table Entry was loaded into the TLB with Modified (M) data from another core's ECO L3 on the same chip due to a instruction side request"
|
"BriefDescription": "A Page Table Entry was loaded into the TLB with Modified (M) data from another core's ECO L3 on the same chip due to a instruction side request"
|
||||||
}
|
}
|
||||||
]
|
]
|
|
@ -1,9 +1,4 @@
|
||||||
[
|
[
|
||||||
{,
|
|
||||||
"EventCode": "0x3C052",
|
|
||||||
"EventName": "PM_DATA_SYS_PUMP_MPRED",
|
|
||||||
"BriefDescription": "Final Pump Scope (system) mispredicted. Either the original scope was too small (Chip/Group) or the original scope was System and it should have been smaller. Counts for a demand load"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x3013E",
|
"EventCode": "0x3013E",
|
||||||
"EventName": "PM_MRK_STALL_CMPLU_CYC",
|
"EventName": "PM_MRK_STALL_CMPLU_CYC",
|
||||||
|
@ -254,6 +249,11 @@
|
||||||
"EventName": "PM_RADIX_PWC_L1_PDE_FROM_L3",
|
"EventName": "PM_RADIX_PWC_L1_PDE_FROM_L3",
|
||||||
"BriefDescription": "A Page Directory Entry was reloaded to a level 1 page walk cache from the core's L3 data cache"
|
"BriefDescription": "A Page Directory Entry was reloaded to a level 1 page walk cache from the core's L3 data cache"
|
||||||
},
|
},
|
||||||
|
{,
|
||||||
|
"EventCode": "0x3C052",
|
||||||
|
"EventName": "PM_DATA_SYS_PUMP_MPRED",
|
||||||
|
"BriefDescription": "Final Pump Scope (system) mispredicted. Either the original scope was too small (Chip/Group) or the original scope was System and it should have been smaller. Counts for a demand load"
|
||||||
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x4D142",
|
"EventCode": "0x4D142",
|
||||||
"EventName": "PM_MRK_DATA_FROM_L3",
|
"EventName": "PM_MRK_DATA_FROM_L3",
|
||||||
|
@ -434,21 +434,6 @@
|
||||||
"EventName": "PM_ITLB_MISS",
|
"EventName": "PM_ITLB_MISS",
|
||||||
"BriefDescription": "ITLB Reloaded. Counts 1 per ITLB miss for HPT but multiple for radix depending on number of levels traveresed"
|
"BriefDescription": "ITLB Reloaded. Counts 1 per ITLB miss for HPT but multiple for radix depending on number of levels traveresed"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x2D024",
|
|
||||||
"EventName": "PM_RADIX_PWC_L2_HIT",
|
|
||||||
"BriefDescription": "A radix translation attempt missed in the TLB but hit on both the first and second levels of page walk cache."
|
|
||||||
},
|
|
||||||
{,
|
|
||||||
"EventCode": "0x3F056",
|
|
||||||
"EventName": "PM_RADIX_PWC_L3_HIT",
|
|
||||||
"BriefDescription": "A radix translation attempt missed in the TLB but hit on the first, second, and third levels of page walk cache."
|
|
||||||
},
|
|
||||||
{,
|
|
||||||
"EventCode": "0x4E014",
|
|
||||||
"EventName": "PM_TM_TX_PASS_RUN_INST",
|
|
||||||
"BriefDescription": "Run instructions spent in successful transactions"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x1E044",
|
"EventCode": "0x1E044",
|
||||||
"EventName": "PM_DPTEG_FROM_L3_NO_CONFLICT",
|
"EventName": "PM_DPTEG_FROM_L3_NO_CONFLICT",
|
||||||
|
@ -644,4 +629,4 @@
|
||||||
"EventName": "PM_MRK_BR_MPRED_CMPL",
|
"EventName": "PM_MRK_BR_MPRED_CMPL",
|
||||||
"BriefDescription": "Marked Branch Mispredicted"
|
"BriefDescription": "Marked Branch Mispredicted"
|
||||||
}
|
}
|
||||||
]
|
]
|
|
@ -79,6 +79,11 @@
|
||||||
"EventName": "PM_RADIX_PWC_MISS",
|
"EventName": "PM_RADIX_PWC_MISS",
|
||||||
"BriefDescription": "A radix translation attempt missed in the TLB and all levels of page walk cache."
|
"BriefDescription": "A radix translation attempt missed in the TLB and all levels of page walk cache."
|
||||||
},
|
},
|
||||||
|
{,
|
||||||
|
"EventCode": "0x26882",
|
||||||
|
"EventName": "PM_L2_DC_INV",
|
||||||
|
"BriefDescription": "D-cache invalidates sent over the reload bus to the core"
|
||||||
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x24048",
|
"EventCode": "0x24048",
|
||||||
"EventName": "PM_INST_FROM_LMEM",
|
"EventName": "PM_INST_FROM_LMEM",
|
||||||
|
@ -94,11 +99,6 @@
|
||||||
"EventName": "PM_TM_PASSED",
|
"EventName": "PM_TM_PASSED",
|
||||||
"BriefDescription": "Number of TM transactions that passed"
|
"BriefDescription": "Number of TM transactions that passed"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0xD1A0",
|
|
||||||
"EventName": "PM_MRK_LSU_FLUSH_LHS",
|
|
||||||
"BriefDescription": "Effective Address alias flush : no EA match but Real Address match. If the data has not yet been returned for this load, the instruction will just be rejected, but if it has returned data, it will be flushed"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0xF088",
|
"EventCode": "0xF088",
|
||||||
"EventName": "PM_LSU0_STORE_REJECT",
|
"EventName": "PM_LSU0_STORE_REJECT",
|
||||||
|
@ -127,7 +127,7 @@
|
||||||
{,
|
{,
|
||||||
"EventCode": "0xD08C",
|
"EventCode": "0xD08C",
|
||||||
"EventName": "PM_LSU2_LDMX_FIN",
|
"EventName": "PM_LSU2_LDMX_FIN",
|
||||||
"BriefDescription": "New P9 instruction LDMX. The definition of this new PMU event is (from the ldmx RFC02491): The thread has executed an ldmx instruction that accessed a doubleword that contains an effective address within an enabled section of the Load Monitored region. This event, therefore, should not occur if the FSCR has disabled the load monitored facility (FSCR[52]) or disabled the EBB facility (FSCR[56])"
|
"BriefDescription": "New P9 instruction LDMX. The definition of this new PMU event is (from the ldmx RFC02491): The thread has executed an ldmx instruction that accessed a doubleword that contains an effective address within an enabled section of the Load Monitored region. This event, therefore, should not occur if the FSCR has disabled the load monitored facility (FSCR[52]) or disabled the EBB facility (FSCR[56])."
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x300F8",
|
"EventCode": "0x300F8",
|
||||||
|
@ -204,11 +204,6 @@
|
||||||
"EventName": "PM_MRK_DATA_FROM_L31_ECO_MOD_CYC",
|
"EventName": "PM_MRK_DATA_FROM_L31_ECO_MOD_CYC",
|
||||||
"BriefDescription": "Duration in cycles to reload with Modified (M) data from another core's ECO L3 on the same chip due to a marked load"
|
"BriefDescription": "Duration in cycles to reload with Modified (M) data from another core's ECO L3 on the same chip due to a marked load"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0xF0B4",
|
|
||||||
"EventName": "PM_DC_PREF_CONS_ALLOC",
|
|
||||||
"BriefDescription": "Prefetch stream allocated in the conservative phase by either the hardware prefetch mechanism or software prefetch"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0xF894",
|
"EventCode": "0xF894",
|
||||||
"EventName": "PM_LSU3_L1_CAM_CANCEL",
|
"EventName": "PM_LSU3_L1_CAM_CANCEL",
|
||||||
|
@ -219,21 +214,11 @@
|
||||||
"EventName": "PM_FLUSH_DISP_TLBIE",
|
"EventName": "PM_FLUSH_DISP_TLBIE",
|
||||||
"BriefDescription": "Dispatch Flush: TLBIE"
|
"BriefDescription": "Dispatch Flush: TLBIE"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0xD1A4",
|
|
||||||
"EventName": "PM_MRK_LSU_FLUSH_SAO",
|
|
||||||
"BriefDescription": "A load-hit-load condition with Strong Address Ordering will have address compare disabled and flush"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x4E11E",
|
"EventCode": "0x4E11E",
|
||||||
"EventName": "PM_MRK_DATA_FROM_DMEM_CYC",
|
"EventName": "PM_MRK_DATA_FROM_DMEM_CYC",
|
||||||
"BriefDescription": "Duration in cycles to reload from another chip's memory on the same Node or Group (Distant) due to a marked load"
|
"BriefDescription": "Duration in cycles to reload from another chip's memory on the same Node or Group (Distant) due to a marked load"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x5894",
|
|
||||||
"EventName": "PM_LWSYNC",
|
|
||||||
"BriefDescription": "Lwsync instruction decoded and transferred"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x14156",
|
"EventCode": "0x14156",
|
||||||
"EventName": "PM_MRK_DATA_FROM_L2_CYC",
|
"EventName": "PM_MRK_DATA_FROM_L2_CYC",
|
||||||
|
@ -244,11 +229,6 @@
|
||||||
"EventName": "PM_RD_CLEARING_SC",
|
"EventName": "PM_RD_CLEARING_SC",
|
||||||
"BriefDescription": "Read clearing SC"
|
"BriefDescription": "Read clearing SC"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x50A0",
|
|
||||||
"EventName": "PM_HWSYNC",
|
|
||||||
"BriefDescription": "Hwsync instruction decoded and transferred"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x168B0",
|
"EventCode": "0x168B0",
|
||||||
"EventName": "PM_L3_P1_NODE_PUMP",
|
"EventName": "PM_L3_P1_NODE_PUMP",
|
||||||
|
@ -264,6 +244,11 @@
|
||||||
"EventName": "PM_MRK_DATA_FROM_L2_DISP_CONFLICT_LDHITST",
|
"EventName": "PM_MRK_DATA_FROM_L2_DISP_CONFLICT_LDHITST",
|
||||||
"BriefDescription": "The processor's data cache was reloaded from local core's L2 with load hit store conflict due to a marked load"
|
"BriefDescription": "The processor's data cache was reloaded from local core's L2 with load hit store conflict due to a marked load"
|
||||||
},
|
},
|
||||||
|
{,
|
||||||
|
"EventCode": "0x468AE",
|
||||||
|
"EventName": "PM_L3_P3_CO_RTY",
|
||||||
|
"BriefDescription": "L3 CO received retry port 3 (memory only), every retry counted"
|
||||||
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x460A8",
|
"EventCode": "0x460A8",
|
||||||
"EventName": "PM_SN_HIT",
|
"EventName": "PM_SN_HIT",
|
||||||
|
@ -279,11 +264,6 @@
|
||||||
"EventName": "PM_DC_PREF_HW_ALLOC",
|
"EventName": "PM_DC_PREF_HW_ALLOC",
|
||||||
"BriefDescription": "Prefetch stream allocated by the hardware prefetch mechanism"
|
"BriefDescription": "Prefetch stream allocated by the hardware prefetch mechanism"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0xF0BC",
|
|
||||||
"EventName": "PM_LS2_UNALIGNED_ST",
|
|
||||||
"BriefDescription": "Store instructions whose data crosses a double-word boundary, which causes it to require an additional slice than than what normally would be required of the Store of that size. If the Store wraps from slice 3 to slice 0, thee is an additional 3-cycle penalty"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0xD0AC",
|
"EventCode": "0xD0AC",
|
||||||
"EventName": "PM_SRQ_SYNC_CYC",
|
"EventName": "PM_SRQ_SYNC_CYC",
|
||||||
|
@ -379,26 +359,11 @@
|
||||||
"EventName": "PM_RUN_CYC_SMT4_MODE",
|
"EventName": "PM_RUN_CYC_SMT4_MODE",
|
||||||
"BriefDescription": "Cycles in which this thread's run latch is set and the core is in SMT4 mode"
|
"BriefDescription": "Cycles in which this thread's run latch is set and the core is in SMT4 mode"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x5088",
|
|
||||||
"EventName": "PM_DECODE_FUSION_OP_PRESERV",
|
|
||||||
"BriefDescription": "Destructive op operand preservation"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x1D14E",
|
"EventCode": "0x1D14E",
|
||||||
"EventName": "PM_MRK_DATA_FROM_OFF_CHIP_CACHE_CYC",
|
"EventName": "PM_MRK_DATA_FROM_OFF_CHIP_CACHE_CYC",
|
||||||
"BriefDescription": "Duration in cycles to reload either shared or modified data from another core's L2/L3 on a different chip (remote or distant) due to a marked load"
|
"BriefDescription": "Duration in cycles to reload either shared or modified data from another core's L2/L3 on a different chip (remote or distant) due to a marked load"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x509C",
|
|
||||||
"EventName": "PM_FORCED_NOP",
|
|
||||||
"BriefDescription": "Instruction was forced to execute as a nop because it was found to behave like a nop (have no effect) at decode time"
|
|
||||||
},
|
|
||||||
{,
|
|
||||||
"EventCode": "0xC098",
|
|
||||||
"EventName": "PM_LS2_UNALIGNED_LD",
|
|
||||||
"BriefDescription": "Load instructions whose data crosses a double-word boundary, which causes it to require an additional slice than than what normally would be required of the load of that size. If the load wraps from slice 3 to slice 0, thee is an additional 3-cycle penalty"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x20058",
|
"EventCode": "0x20058",
|
||||||
"EventName": "PM_DARQ1_10_12_ENTRIES",
|
"EventName": "PM_DARQ1_10_12_ENTRIES",
|
||||||
|
@ -434,11 +399,6 @@
|
||||||
"EventName": "PM_LSU1_STORE_REJECT",
|
"EventName": "PM_LSU1_STORE_REJECT",
|
||||||
"BriefDescription": "All internal store rejects cause the instruction to go back to the SRQ and go to sleep until woken up to try again after the condition has been met"
|
"BriefDescription": "All internal store rejects cause the instruction to go back to the SRQ and go to sleep until woken up to try again after the condition has been met"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x4505E",
|
|
||||||
"EventName": "PM_FLOP_CMPL",
|
|
||||||
"BriefDescription": "Floating Point Operation Finished"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x1D144",
|
"EventCode": "0x1D144",
|
||||||
"EventName": "PM_MRK_DATA_FROM_L3_DISP_CONFLICT",
|
"EventName": "PM_MRK_DATA_FROM_L3_DISP_CONFLICT",
|
||||||
|
@ -480,14 +440,9 @@
|
||||||
"BriefDescription": "XL-form branch was mispredicted due to the predicted target address missing from EAT. The EAT forces a mispredict in this case since there is no predicated target to validate. This is a rare case that may occur when the EAT is full and a branch is issued"
|
"BriefDescription": "XL-form branch was mispredicted due to the predicted target address missing from EAT. The EAT forces a mispredict in this case since there is no predicated target to validate. This is a rare case that may occur when the EAT is full and a branch is issued"
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0xC094",
|
"EventCode": "0x460AE",
|
||||||
"EventName": "PM_LS0_UNALIGNED_LD",
|
"EventName": "PM_L3_P2_CO_RTY",
|
||||||
"BriefDescription": "Load instructions whose data crosses a double-word boundary, which causes it to require an additional slice than than what normally would be required of the load of that size. If the load wraps from slice 3 to slice 0, thee is an additional 3-cycle penalty"
|
"BriefDescription": "L3 CO received retry port 2 (memory only), every retry counted"
|
||||||
},
|
|
||||||
{,
|
|
||||||
"EventCode": "0xF8BC",
|
|
||||||
"EventName": "PM_LS3_UNALIGNED_ST",
|
|
||||||
"BriefDescription": "Store instructions whose data crosses a double-word boundary, which causes it to require an additional slice than than what normally would be required of the Store of that size. If the Store wraps from slice 3 to slice 0, thee is an additional 3-cycle penalty"
|
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x58B0",
|
"EventCode": "0x58B0",
|
||||||
|
@ -504,11 +459,6 @@
|
||||||
"EventName": "PM_TM_ST_CONF",
|
"EventName": "PM_TM_ST_CONF",
|
||||||
"BriefDescription": "TM Store (fav or non-fav) ran into conflict (failed)"
|
"BriefDescription": "TM Store (fav or non-fav) ran into conflict (failed)"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0xD998",
|
|
||||||
"EventName": "PM_MRK_LSU_FLUSH_EMSH",
|
|
||||||
"BriefDescription": "An ERAT miss was detected after a set-p hit. Erat tracker indicates fail due to tlbmiss and the instruction gets flushed because the instruction was working on the wrong address"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0xF8A0",
|
"EventCode": "0xF8A0",
|
||||||
"EventName": "PM_NON_DATA_STORE",
|
"EventName": "PM_NON_DATA_STORE",
|
||||||
|
@ -524,11 +474,6 @@
|
||||||
"EventName": "PM_BR_UNCOND",
|
"EventName": "PM_BR_UNCOND",
|
||||||
"BriefDescription": "Unconditional Branch Completed. HW branch prediction was not used for this branch. This can be an I-form branch, a B-form branch with BO-field set to branch always, or a B-form branch which was covenrted to a Resolve."
|
"BriefDescription": "Unconditional Branch Completed. HW branch prediction was not used for this branch. This can be an I-form branch, a B-form branch with BO-field set to branch always, or a B-form branch which was covenrted to a Resolve."
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x1F056",
|
|
||||||
"EventName": "PM_RADIX_PWC_L1_HIT",
|
|
||||||
"BriefDescription": "A radix translation attempt missed in the TLB and only the first level page walk cache was a hit."
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0xF8A8",
|
"EventCode": "0xF8A8",
|
||||||
"EventName": "PM_DC_PREF_FUZZY_CONF",
|
"EventName": "PM_DC_PREF_FUZZY_CONF",
|
||||||
|
@ -544,6 +489,11 @@
|
||||||
"EventName": "PM_LSU2_TM_L1_MISS",
|
"EventName": "PM_LSU2_TM_L1_MISS",
|
||||||
"BriefDescription": "Load tm L1 miss"
|
"BriefDescription": "Load tm L1 miss"
|
||||||
},
|
},
|
||||||
|
{,
|
||||||
|
"EventCode": "0xC880",
|
||||||
|
"EventName": "PM_LS1_LD_VECTOR_FIN",
|
||||||
|
"BriefDescription": ""
|
||||||
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x2894",
|
"EventCode": "0x2894",
|
||||||
"EventName": "PM_TM_OUTER_TEND",
|
"EventName": "PM_TM_OUTER_TEND",
|
||||||
|
@ -564,21 +514,11 @@
|
||||||
"EventName": "PM_MRK_LSU_DERAT_MISS",
|
"EventName": "PM_MRK_LSU_DERAT_MISS",
|
||||||
"BriefDescription": "Marked derat reload (miss) for any page size"
|
"BriefDescription": "Marked derat reload (miss) for any page size"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x160A0",
|
|
||||||
"EventName": "PM_L3_PF_MISS_L3",
|
|
||||||
"BriefDescription": "L3 PF missed in L3"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x1C04A",
|
"EventCode": "0x1C04A",
|
||||||
"EventName": "PM_DATA_FROM_RL2L3_SHR",
|
"EventName": "PM_DATA_FROM_RL2L3_SHR",
|
||||||
"BriefDescription": "The processor's data cache was reloaded with Shared (S) data from another chip's L2 or L3 on the same Node or Group (Remote), as this chip due to a demand load"
|
"BriefDescription": "The processor's data cache was reloaded with Shared (S) data from another chip's L2 or L3 on the same Node or Group (Remote), as this chip due to a demand load"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0xD99C",
|
|
||||||
"EventName": "PM_MRK_LSU_FLUSH_UE",
|
|
||||||
"BriefDescription": "Correctable ECC error on reload data, reported at critical data forward time"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x268B0",
|
"EventCode": "0x268B0",
|
||||||
"EventName": "PM_L3_P1_GRP_PUMP",
|
"EventName": "PM_L3_P1_GRP_PUMP",
|
||||||
|
@ -629,11 +569,6 @@
|
||||||
"EventName": "PM_TMA_REQ_L2",
|
"EventName": "PM_TMA_REQ_L2",
|
||||||
"BriefDescription": "addrs only req to L2 only on the first one,Indication that Load footprint is not expanding"
|
"BriefDescription": "addrs only req to L2 only on the first one,Indication that Load footprint is not expanding"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x5884",
|
|
||||||
"EventName": "PM_DECODE_LANES_NOT_AVAIL",
|
|
||||||
"BriefDescription": "Decode has something to transmit but dispatch lanes are not available"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x3C042",
|
"EventCode": "0x3C042",
|
||||||
"EventName": "PM_DATA_FROM_L3_DISP_CONFLICT",
|
"EventName": "PM_DATA_FROM_L3_DISP_CONFLICT",
|
||||||
|
@ -690,9 +625,9 @@
|
||||||
"BriefDescription": "False LHS match detected"
|
"BriefDescription": "False LHS match detected"
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0xD9A4",
|
"EventCode": "0xF0B0",
|
||||||
"EventName": "PM_MRK_LSU_FLUSH_LARX_STCX",
|
"EventName": "PM_L3_LD_PREF",
|
||||||
"BriefDescription": "A larx is flushed because an older larx has an LMQ reservation for the same thread. A stcx is flushed because an older stcx is in the LMQ. The flush happens when the older larx/stcx relaunches"
|
"BriefDescription": "L3 load prefetch, sourced from a hardware or software stream, was sent to the nest"
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x4D012",
|
"EventCode": "0x4D012",
|
||||||
|
@ -715,9 +650,9 @@
|
||||||
"BriefDescription": "All successful Ld/St dispatches for this thread that were an L2 miss (excludes i_l2mru_tch_reqs)"
|
"BriefDescription": "All successful Ld/St dispatches for this thread that were an L2 miss (excludes i_l2mru_tch_reqs)"
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0xF8B8",
|
"EventCode": "0x160A0",
|
||||||
"EventName": "PM_LS1_UNALIGNED_ST",
|
"EventName": "PM_L3_PF_MISS_L3",
|
||||||
"BriefDescription": "Store instructions whose data crosses a double-word boundary, which causes it to require an additional slice than than what normally would be required of the Store of that size. If the Store wraps from slice 3 to slice 0, thee is an additional 3-cycle penalty"
|
"BriefDescription": "L3 PF missed in L3"
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x408C",
|
"EventCode": "0x408C",
|
||||||
|
@ -764,11 +699,6 @@
|
||||||
"EventName": "PM_TM_NESTED_TEND",
|
"EventName": "PM_TM_NESTED_TEND",
|
||||||
"BriefDescription": "Completion time nested tend"
|
"BriefDescription": "Completion time nested tend"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x36084",
|
|
||||||
"EventName": "PM_L2_RCST_DISP",
|
|
||||||
"BriefDescription": "All D-side store dispatch attempts for this thread"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x368A0",
|
"EventCode": "0x368A0",
|
||||||
"EventName": "PM_L3_PF_OFF_CHIP_CACHE",
|
"EventName": "PM_L3_PF_OFF_CHIP_CACHE",
|
||||||
|
@ -829,11 +759,6 @@
|
||||||
"EventName": "PM_L3_SN_USAGE",
|
"EventName": "PM_L3_SN_USAGE",
|
||||||
"BriefDescription": "Rotating sample of 16 snoop valids"
|
"BriefDescription": "Rotating sample of 16 snoop valids"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x16084",
|
|
||||||
"EventName": "PM_L2_RCLD_DISP",
|
|
||||||
"BriefDescription": "All I-or-D side load dispatch attempts for this thread (excludes i_l2mru_tch_reqs)"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x1608C",
|
"EventCode": "0x1608C",
|
||||||
"EventName": "PM_RC0_BUSY",
|
"EventName": "PM_RC0_BUSY",
|
||||||
|
@ -842,7 +767,7 @@
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x36082",
|
"EventCode": "0x36082",
|
||||||
"EventName": "PM_L2_LD_DISP",
|
"EventName": "PM_L2_LD_DISP",
|
||||||
"BriefDescription": "All successful I-or-D side load dispatches for this thread (excludes i_l2mru_tch_reqs)."
|
"BriefDescription": "All successful I-or-D side load dispatches for this thread (excludes i_l2mru_tch_reqs)"
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0xF8B0",
|
"EventCode": "0xF8B0",
|
||||||
|
@ -904,11 +829,6 @@
|
||||||
"EventName": "PM_IC_PREF_REQ",
|
"EventName": "PM_IC_PREF_REQ",
|
||||||
"BriefDescription": "Instruction prefetch requests"
|
"BriefDescription": "Instruction prefetch requests"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0xC898",
|
|
||||||
"EventName": "PM_LS3_UNALIGNED_LD",
|
|
||||||
"BriefDescription": "Load instructions whose data crosses a double-word boundary, which causes it to require an additional slice than than what normally would be required of the load of that size. If the load wraps from slice 3 to slice 0, thee is an additional 3-cycle penalty"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x488C",
|
"EventCode": "0x488C",
|
||||||
"EventName": "PM_IC_PREF_WRITE",
|
"EventName": "PM_IC_PREF_WRITE",
|
||||||
|
@ -1017,7 +937,7 @@
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x3E05E",
|
"EventCode": "0x3E05E",
|
||||||
"EventName": "PM_L3_CO_MEPF",
|
"EventName": "PM_L3_CO_MEPF",
|
||||||
"BriefDescription": "L3 castouts in Mepf state for this thread"
|
"BriefDescription": "L3 CO of line in Mep state (includes casthrough to memory). The Mepf state indicates that a line was brought in to satisfy an L3 prefetch request"
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x460A2",
|
"EventCode": "0x460A2",
|
||||||
|
@ -1204,11 +1124,6 @@
|
||||||
"EventName": "PM_TM_FAIL_NON_TX_CONFLICT",
|
"EventName": "PM_TM_FAIL_NON_TX_CONFLICT",
|
||||||
"BriefDescription": "Non transactional conflict from LSU, gets reported to TEXASR"
|
"BriefDescription": "Non transactional conflict from LSU, gets reported to TEXASR"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0xD198",
|
|
||||||
"EventName": "PM_MRK_LSU_FLUSH_ATOMIC",
|
|
||||||
"BriefDescription": "Quad-word loads (lq) are considered atomic because they always span at least 2 slices. If a snoop or store from another thread changes the data the load is accessing between the 2 or 3 pieces of the lq instruction, the lq will be flushed"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x201E0",
|
"EventCode": "0x201E0",
|
||||||
"EventName": "PM_MRK_DATA_FROM_MEMORY",
|
"EventName": "PM_MRK_DATA_FROM_MEMORY",
|
||||||
|
@ -1294,11 +1209,6 @@
|
||||||
"EventName": "PM_ICT_NOSLOT_DISP_HELD_HB_FULL",
|
"EventName": "PM_ICT_NOSLOT_DISP_HELD_HB_FULL",
|
||||||
"BriefDescription": "Ict empty for this thread due to dispatch holds because the History Buffer was full. Could be GPR/VSR/VMR/FPR/CR/XVF; CR; XVF (XER/VSCR/FPSCR)"
|
"BriefDescription": "Ict empty for this thread due to dispatch holds because the History Buffer was full. Could be GPR/VSR/VMR/FPR/CR/XVF; CR; XVF (XER/VSCR/FPSCR)"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0xC894",
|
|
||||||
"EventName": "PM_LS1_UNALIGNED_LD",
|
|
||||||
"BriefDescription": "Load instructions whose data crosses a double-word boundary, which causes it to require an additional slice than than what normally would be required of the load of that size. If the load wraps from slice 3 to slice 0, thee is an additional 3-cycle penalty"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x360A2",
|
"EventCode": "0x360A2",
|
||||||
"EventName": "PM_L3_L2_CO_HIT",
|
"EventName": "PM_L3_L2_CO_HIT",
|
||||||
|
@ -1324,11 +1234,6 @@
|
||||||
"EventName": "PM_L2_CASTOUT_SHR",
|
"EventName": "PM_L2_CASTOUT_SHR",
|
||||||
"BriefDescription": "L2 Castouts - Shared (Tx,Sx)"
|
"BriefDescription": "L2 Castouts - Shared (Tx,Sx)"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0xD884",
|
|
||||||
"EventName": "PM_LSU3_SET_MPRED",
|
|
||||||
"BriefDescription": "Set prediction(set-p) miss. The entry was not found in the Set prediction table"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x26092",
|
"EventCode": "0x26092",
|
||||||
"EventName": "PM_L2_LD_MISS_64B",
|
"EventName": "PM_L2_LD_MISS_64B",
|
||||||
|
@ -1362,12 +1267,12 @@
|
||||||
{,
|
{,
|
||||||
"EventCode": "0xD8A8",
|
"EventCode": "0xD8A8",
|
||||||
"EventName": "PM_ISLB_MISS",
|
"EventName": "PM_ISLB_MISS",
|
||||||
"BriefDescription": "Instruction SLB miss - Total of all segment sizes"
|
"BriefDescription": "Instruction SLB Miss - Total of all segment sizes"
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0xD19C",
|
"EventCode": "0x368AE",
|
||||||
"EventName": "PM_MRK_LSU_FLUSH_RELAUNCH_MISS",
|
"EventName": "PM_L3_P1_CO_RTY",
|
||||||
"BriefDescription": "If a load that has already returned data and has to relaunch for any reason then gets a miss (erat, setp, data cache), it will often be flushed at relaunch time because the data might be inconsistent"
|
"BriefDescription": "L3 CO received retry port 1 (memory only), every retry counted"
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x260A2",
|
"EventCode": "0x260A2",
|
||||||
|
@ -1384,6 +1289,11 @@
|
||||||
"EventName": "PM_CMPLU_STALL_NESTED_TBEGIN",
|
"EventName": "PM_CMPLU_STALL_NESTED_TBEGIN",
|
||||||
"BriefDescription": "Completion stall because the ISU is updating the TEXASR to keep track of the nested tbegin. This is a short delay, and it includes ROT"
|
"BriefDescription": "Completion stall because the ISU is updating the TEXASR to keep track of the nested tbegin. This is a short delay, and it includes ROT"
|
||||||
},
|
},
|
||||||
|
{,
|
||||||
|
"EventCode": "0xC084",
|
||||||
|
"EventName": "PM_LS2_LD_VECTOR_FIN",
|
||||||
|
"BriefDescription": ""
|
||||||
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x1608E",
|
"EventCode": "0x1608E",
|
||||||
"EventName": "PM_ST_CAUSED_FAIL",
|
"EventName": "PM_ST_CAUSED_FAIL",
|
||||||
|
@ -1409,11 +1319,6 @@
|
||||||
"EventName": "PM_CO_USAGE",
|
"EventName": "PM_CO_USAGE",
|
||||||
"BriefDescription": "Continuous 16 cycle (2to1) window where this signals rotates thru sampling each CO machine busy. PMU uses this wave to then do 16 cyc count to sample total number of machs running"
|
"BriefDescription": "Continuous 16 cycle (2to1) window where this signals rotates thru sampling each CO machine busy. PMU uses this wave to then do 16 cyc count to sample total number of machs running"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0xD084",
|
|
||||||
"EventName": "PM_LSU2_SET_MPRED",
|
|
||||||
"BriefDescription": "Set prediction(set-p) miss. The entry was not found in the Set prediction table"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x48B8",
|
"EventCode": "0x48B8",
|
||||||
"EventName": "PM_BR_MPRED_TAKEN_TA",
|
"EventName": "PM_BR_MPRED_TAKEN_TA",
|
||||||
|
@ -1449,30 +1354,25 @@
|
||||||
"EventName": "PM_DC_PREF_STRIDED_CONF",
|
"EventName": "PM_DC_PREF_STRIDED_CONF",
|
||||||
"BriefDescription": "A demand load referenced a line in an active strided prefetch stream. The stream could have been allocated through the hardware prefetch mechanism or through software."
|
"BriefDescription": "A demand load referenced a line in an active strided prefetch stream. The stream could have been allocated through the hardware prefetch mechanism or through software."
|
||||||
},
|
},
|
||||||
|
{,
|
||||||
|
"EventCode": "0x36084",
|
||||||
|
"EventName": "PM_L2_RCST_DISP",
|
||||||
|
"BriefDescription": "All D-side store dispatch attempts for this thread"
|
||||||
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x45054",
|
"EventCode": "0x45054",
|
||||||
"EventName": "PM_FMA_CMPL",
|
"EventName": "PM_FMA_CMPL",
|
||||||
"BriefDescription": "two flops operation completed (fmadd, fnmadd, fmsub, fnmsub) Scalar instructions only. "
|
"BriefDescription": "two flops operation completed (fmadd, fnmadd, fmsub, fnmsub) Scalar instructions only. "
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x5090",
|
|
||||||
"EventName": "PM_SHL_ST_DISABLE",
|
|
||||||
"BriefDescription": "Store-Hit-Load Table Read Hit with entry Disabled (entry was disabled due to the entry shown to not prevent the flush)"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x201E8",
|
"EventCode": "0x201E8",
|
||||||
"EventName": "PM_THRESH_EXC_512",
|
"EventName": "PM_THRESH_EXC_512",
|
||||||
"BriefDescription": "Threshold counter exceeded a value of 512"
|
"BriefDescription": "Threshold counter exceeded a value of 512"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x5084",
|
|
||||||
"EventName": "PM_DECODE_FUSION_EXT_ADD",
|
|
||||||
"BriefDescription": "32-bit extended addition"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x36080",
|
"EventCode": "0x36080",
|
||||||
"EventName": "PM_L2_INST",
|
"EventName": "PM_L2_INST",
|
||||||
"BriefDescription": "All successful I-side dispatches for this thread (excludes i_l2mru_tch reqs)."
|
"BriefDescription": "All successful I-side dispatches for this thread (excludes i_l2mru_tch reqs)"
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x3504C",
|
"EventCode": "0x3504C",
|
||||||
|
@ -1554,21 +1454,11 @@
|
||||||
"EventName": "PM_MEM_RWITM",
|
"EventName": "PM_MEM_RWITM",
|
||||||
"BriefDescription": "Memory Read With Intent to Modify for this thread"
|
"BriefDescription": "Memory Read With Intent to Modify for this thread"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x26882",
|
|
||||||
"EventName": "PM_L2_DC_INV",
|
|
||||||
"BriefDescription": "D-cache invalidates sent over the reload bus to the core"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0xC090",
|
"EventCode": "0xC090",
|
||||||
"EventName": "PM_LSU_STCX",
|
"EventName": "PM_LSU_STCX",
|
||||||
"BriefDescription": "STCX sent to nest, i.e. total"
|
"BriefDescription": "STCX sent to nest, i.e. total"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0xD080",
|
|
||||||
"EventName": "PM_LSU0_SET_MPRED",
|
|
||||||
"BriefDescription": "Set prediction(set-p) miss. The entry was not found in the Set prediction table"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x2C120",
|
"EventCode": "0x2C120",
|
||||||
"EventName": "PM_MRK_DATA_FROM_L2_NO_CONFLICT",
|
"EventName": "PM_MRK_DATA_FROM_L2_NO_CONFLICT",
|
||||||
|
@ -1609,11 +1499,6 @@
|
||||||
"EventName": "PM_IPTEG_FROM_L2_NO_CONFLICT",
|
"EventName": "PM_IPTEG_FROM_L2_NO_CONFLICT",
|
||||||
"BriefDescription": "A Page Table Entry was loaded into the TLB from local core's L2 without conflict due to a instruction side request"
|
"BriefDescription": "A Page Table Entry was loaded into the TLB from local core's L2 without conflict due to a instruction side request"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0xD9A0",
|
|
||||||
"EventName": "PM_MRK_LSU_FLUSH_LHL_SHL",
|
|
||||||
"BriefDescription": "The instruction was flushed because of a sequential load/store consistency. If a load or store hits on an older load that has either been snooped (for loads) or has stale data (for stores)."
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x35042",
|
"EventCode": "0x35042",
|
||||||
"EventName": "PM_IPTEG_FROM_L3_DISP_CONFLICT",
|
"EventName": "PM_IPTEG_FROM_L3_DISP_CONFLICT",
|
||||||
|
@ -1692,7 +1577,7 @@
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x2001A",
|
"EventCode": "0x2001A",
|
||||||
"EventName": "PM_NTC_ALL_FIN",
|
"EventName": "PM_NTC_ALL_FIN",
|
||||||
"BriefDescription": "Cycles after all instructions have finished to group completed"
|
"BriefDescription": "Cycles after instruction finished to instruction completed."
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x3005A",
|
"EventCode": "0x3005A",
|
||||||
|
@ -1709,6 +1594,11 @@
|
||||||
"EventName": "PM_LSU1_L1_CAM_CANCEL",
|
"EventName": "PM_LSU1_L1_CAM_CANCEL",
|
||||||
"BriefDescription": "ls1 l1 tm cam cancel"
|
"BriefDescription": "ls1 l1 tm cam cancel"
|
||||||
},
|
},
|
||||||
|
{,
|
||||||
|
"EventCode": "0x268AE",
|
||||||
|
"EventName": "PM_L3_P3_PF_RTY",
|
||||||
|
"BriefDescription": "L3 PF received retry port 3, every retry counted"
|
||||||
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0xE884",
|
"EventCode": "0xE884",
|
||||||
"EventName": "PM_LS1_ERAT_MISS_PREF",
|
"EventName": "PM_LS1_ERAT_MISS_PREF",
|
||||||
|
@ -1742,7 +1632,7 @@
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x160B6",
|
"EventCode": "0x160B6",
|
||||||
"EventName": "PM_L3_WI0_BUSY",
|
"EventName": "PM_L3_WI0_BUSY",
|
||||||
"BriefDescription": "Rotating sample of 8 WI valid"
|
"BriefDescription": "Rotating sample of 8 WI valid (duplicate)"
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x368AC",
|
"EventCode": "0x368AC",
|
||||||
|
@ -1790,9 +1680,9 @@
|
||||||
"BriefDescription": "L2 guess system (VGS or RNS) and guess was correct (ie data beyond-group)"
|
"BriefDescription": "L2 guess system (VGS or RNS) and guess was correct (ie data beyond-group)"
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x589C",
|
"EventCode": "0x260AE",
|
||||||
"EventName": "PM_PTESYNC",
|
"EventName": "PM_L3_P2_PF_RTY",
|
||||||
"BriefDescription": "ptesync instruction counted when the instruction is decoded and transmitted"
|
"BriefDescription": "L3 PF received retry port 2, every retry counted"
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x26086",
|
"EventCode": "0x26086",
|
||||||
|
@ -1824,6 +1714,11 @@
|
||||||
"EventName": "PM_SHL_ST_DEP_CREATED",
|
"EventName": "PM_SHL_ST_DEP_CREATED",
|
||||||
"BriefDescription": "Store-Hit-Load Table Read Hit with entry Enabled"
|
"BriefDescription": "Store-Hit-Load Table Read Hit with entry Enabled"
|
||||||
},
|
},
|
||||||
|
{,
|
||||||
|
"EventCode": "0x46882",
|
||||||
|
"EventName": "PM_L2_ST_HIT",
|
||||||
|
"BriefDescription": "All successful D-side store dispatches for this thread that were L2 hits"
|
||||||
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x360AC",
|
"EventCode": "0x360AC",
|
||||||
"EventName": "PM_L3_SN0_BUSY",
|
"EventName": "PM_L3_SN0_BUSY",
|
||||||
|
@ -1844,11 +1739,6 @@
|
||||||
"EventName": "PM_L2_ST_MISS",
|
"EventName": "PM_L2_ST_MISS",
|
||||||
"BriefDescription": "All successful D-Side Store dispatches that were an L2 miss for this thread"
|
"BriefDescription": "All successful D-Side Store dispatches that were an L2 miss for this thread"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0xF8B4",
|
|
||||||
"EventName": "PM_DC_PREF_XCONS_ALLOC",
|
|
||||||
"BriefDescription": "Prefetch stream allocated in the Ultra conservative phase by either the hardware prefetch mechanism or software prefetch"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x35048",
|
"EventCode": "0x35048",
|
||||||
"EventName": "PM_IPTEG_FROM_DL2L3_SHR",
|
"EventName": "PM_IPTEG_FROM_DL2L3_SHR",
|
||||||
|
@ -1969,11 +1859,6 @@
|
||||||
"EventName": "PM_THRD_PRIO_2_3_CYC",
|
"EventName": "PM_THRD_PRIO_2_3_CYC",
|
||||||
"BriefDescription": "Cycles thread running at priority level 2 or 3"
|
"BriefDescription": "Cycles thread running at priority level 2 or 3"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x10134",
|
|
||||||
"EventName": "PM_MRK_ST_DONE_L2",
|
|
||||||
"BriefDescription": "marked store completed in L2 ( RC machine done)"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x368B2",
|
"EventCode": "0x368B2",
|
||||||
"EventName": "PM_L3_GRP_GUESS_WRONG_HIGH",
|
"EventName": "PM_L3_GRP_GUESS_WRONG_HIGH",
|
||||||
|
@ -2004,11 +1889,6 @@
|
||||||
"EventName": "PM_L2_GRP_GUESS_WRONG",
|
"EventName": "PM_L2_GRP_GUESS_WRONG",
|
||||||
"BriefDescription": "L2 guess grp (GS or NNS) and guess was not correct (ie data on-chip OR beyond-group)"
|
"BriefDescription": "L2 guess grp (GS or NNS) and guess was not correct (ie data on-chip OR beyond-group)"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x368AE",
|
|
||||||
"EventName": "PM_L3_P1_CO_RTY",
|
|
||||||
"BriefDescription": "L3 CO received retry port 1 (memory only), every retry counted"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0xC0AC",
|
"EventCode": "0xC0AC",
|
||||||
"EventName": "PM_LSU_FLUSH_EMSH",
|
"EventName": "PM_LSU_FLUSH_EMSH",
|
||||||
|
@ -2034,11 +1914,6 @@
|
||||||
"EventName": "PM_L2_GROUP_PUMP",
|
"EventName": "PM_L2_GROUP_PUMP",
|
||||||
"BriefDescription": "RC requests that were on group (aka nodel) pump attempts"
|
"BriefDescription": "RC requests that were on group (aka nodel) pump attempts"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0xF0B0",
|
|
||||||
"EventName": "PM_L3_LD_PREF",
|
|
||||||
"BriefDescription": "L3 load prefetch, sourced from a hardware or software stream, was sent to the nest"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x16080",
|
"EventCode": "0x16080",
|
||||||
"EventName": "PM_L2_LD",
|
"EventName": "PM_L2_LD",
|
||||||
|
@ -2049,6 +1924,11 @@
|
||||||
"EventName": "PM_MATH_FLOP_CMPL",
|
"EventName": "PM_MATH_FLOP_CMPL",
|
||||||
"BriefDescription": "Math flop instruction completed"
|
"BriefDescription": "Math flop instruction completed"
|
||||||
},
|
},
|
||||||
|
{,
|
||||||
|
"EventCode": "0xC080",
|
||||||
|
"EventName": "PM_LS0_LD_VECTOR_FIN",
|
||||||
|
"BriefDescription": ""
|
||||||
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x368B0",
|
"EventCode": "0x368B0",
|
||||||
"EventName": "PM_L3_P1_SYS_PUMP",
|
"EventName": "PM_L3_P1_SYS_PUMP",
|
||||||
|
@ -2119,11 +1999,6 @@
|
||||||
"EventName": "PM_BR_CORECT_PRED_TAKEN_CMPL",
|
"EventName": "PM_BR_CORECT_PRED_TAKEN_CMPL",
|
||||||
"BriefDescription": "Conditional Branch Completed in which the HW correctly predicted the direction as taken. Counted at completion time"
|
"BriefDescription": "Conditional Branch Completed in which the HW correctly predicted the direction as taken. Counted at completion time"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0xF0B8",
|
|
||||||
"EventName": "PM_LS0_UNALIGNED_ST",
|
|
||||||
"BriefDescription": "Store instructions whose data crosses a double-word boundary, which causes it to require an additional slice than than what normally would be required of the Store of that size. If the Store wraps from slice 3 to slice 0, thee is an additional 3-cycle penalty"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x20132",
|
"EventCode": "0x20132",
|
||||||
"EventName": "PM_MRK_DFU_FIN",
|
"EventName": "PM_MRK_DFU_FIN",
|
||||||
|
@ -2139,6 +2014,11 @@
|
||||||
"EventName": "PM_LSU_FLUSH_LHS",
|
"EventName": "PM_LSU_FLUSH_LHS",
|
||||||
"BriefDescription": "Effective Address alias flush : no EA match but Real Address match. If the data has not yet been returned for this load, the instruction will just be rejected, but if it has returned data, it will be flushed"
|
"BriefDescription": "Effective Address alias flush : no EA match but Real Address match. If the data has not yet been returned for this load, the instruction will just be rejected, but if it has returned data, it will be flushed"
|
||||||
},
|
},
|
||||||
|
{,
|
||||||
|
"EventCode": "0x16084",
|
||||||
|
"EventName": "PM_L2_RCLD_DISP",
|
||||||
|
"BriefDescription": "All I-or-D side load dispatch attempts for this thread (excludes i_l2mru_tch_reqs)"
|
||||||
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x3F150",
|
"EventCode": "0x3F150",
|
||||||
"EventName": "PM_MRK_ST_DRAIN_TO_L2DISP_CYC",
|
"EventName": "PM_MRK_ST_DRAIN_TO_L2DISP_CYC",
|
||||||
|
@ -2224,11 +2104,6 @@
|
||||||
"EventName": "PM_IC_PREF_CANCEL_PAGE",
|
"EventName": "PM_IC_PREF_CANCEL_PAGE",
|
||||||
"BriefDescription": "Prefetch Canceled due to page boundary"
|
"BriefDescription": "Prefetch Canceled due to page boundary"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0xF09C",
|
|
||||||
"EventName": "PM_SLB_TABLEWALK_CYC",
|
|
||||||
"BriefDescription": "Cycles when a tablewalk is pending on this thread on the SLB table"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x460AA",
|
"EventCode": "0x460AA",
|
||||||
"EventName": "PM_L3_P0_CO_L31",
|
"EventName": "PM_L3_P0_CO_L31",
|
||||||
|
@ -2247,10 +2122,10 @@
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x46082",
|
"EventCode": "0x46082",
|
||||||
"EventName": "PM_L2_ST_DISP",
|
"EventName": "PM_L2_ST_DISP",
|
||||||
"BriefDescription": "All successful D-side store dispatches for this thread "
|
"BriefDescription": "All successful D-side store dispatches for this thread (L2 miss + L2 hits)"
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x4609E",
|
"EventCode": "0x36880",
|
||||||
"EventName": "PM_L2_INST_MISS",
|
"EventName": "PM_L2_INST_MISS",
|
||||||
"BriefDescription": "All successful I-side dispatches that were an L2 miss for this thread (excludes i_l2mru_tch reqs)"
|
"BriefDescription": "All successful I-side dispatches that were an L2 miss for this thread (excludes i_l2mru_tch reqs)"
|
||||||
},
|
},
|
||||||
|
@ -2340,9 +2215,9 @@
|
||||||
"BriefDescription": "All ISU rejects"
|
"BriefDescription": "All ISU rejects"
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x46882",
|
"EventCode": "0xC884",
|
||||||
"EventName": "PM_L2_ST_HIT",
|
"EventName": "PM_LS3_LD_VECTOR_FIN",
|
||||||
"BriefDescription": "All successful D-side store dispatches for this thread that were L2 hits"
|
"BriefDescription": ""
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x360A8",
|
"EventCode": "0x360A8",
|
||||||
|
@ -2359,11 +2234,6 @@
|
||||||
"EventName": "PM_LSU_NCST",
|
"EventName": "PM_LSU_NCST",
|
||||||
"BriefDescription": "Asserts when a i=1 store op is sent to the nest. No record of issue pipe (LS0/LS1) is maintained so this is for both pipes. Probably don't need separate LS0 and LS1"
|
"BriefDescription": "Asserts when a i=1 store op is sent to the nest. No record of issue pipe (LS0/LS1) is maintained so this is for both pipes. Probably don't need separate LS0 and LS1"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0xD880",
|
|
||||||
"EventName": "PM_LSU1_SET_MPRED",
|
|
||||||
"BriefDescription": "Set prediction(set-p) miss. The entry was not found in the Set prediction table"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0xD0B8",
|
"EventCode": "0xD0B8",
|
||||||
"EventName": "PM_LSU_LMQ_FULL_CYC",
|
"EventName": "PM_LSU_LMQ_FULL_CYC",
|
||||||
|
@ -2389,4 +2259,4 @@
|
||||||
"EventName": "PM_L3_PF_USAGE",
|
"EventName": "PM_L3_PF_USAGE",
|
||||||
"BriefDescription": "Rotating sample of 32 PF actives"
|
"BriefDescription": "Rotating sample of 32 PF actives"
|
||||||
}
|
}
|
||||||
]
|
]
|
|
@ -124,6 +124,11 @@
|
||||||
"EventName": "PM_PMC5_OVERFLOW",
|
"EventName": "PM_PMC5_OVERFLOW",
|
||||||
"BriefDescription": "Overflow from counter 5"
|
"BriefDescription": "Overflow from counter 5"
|
||||||
},
|
},
|
||||||
|
{,
|
||||||
|
"EventCode": "0x4505E",
|
||||||
|
"EventName": "PM_FLOP_CMPL",
|
||||||
|
"BriefDescription": "Floating Point Operation Finished"
|
||||||
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x2C018",
|
"EventCode": "0x2C018",
|
||||||
"EventName": "PM_CMPLU_STALL_DMISS_L21_L31",
|
"EventName": "PM_CMPLU_STALL_DMISS_L21_L31",
|
||||||
|
@ -389,11 +394,6 @@
|
||||||
"EventName": "PM_ICT_NOSLOT_BR_MPRED",
|
"EventName": "PM_ICT_NOSLOT_BR_MPRED",
|
||||||
"BriefDescription": "Ict empty for this thread due to branch mispred"
|
"BriefDescription": "Ict empty for this thread due to branch mispred"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x3405E",
|
|
||||||
"EventName": "PM_IFETCH_THROTTLE",
|
|
||||||
"BriefDescription": "Cycles in which Instruction fetch throttle was active."
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x1F148",
|
"EventCode": "0x1F148",
|
||||||
"EventName": "PM_MRK_DPTEG_FROM_ON_CHIP_CACHE",
|
"EventName": "PM_MRK_DPTEG_FROM_ON_CHIP_CACHE",
|
||||||
|
@ -422,7 +422,7 @@
|
||||||
{,
|
{,
|
||||||
"EventCode": "0xD0A8",
|
"EventCode": "0xD0A8",
|
||||||
"EventName": "PM_DSLB_MISS",
|
"EventName": "PM_DSLB_MISS",
|
||||||
"BriefDescription": "Data SLB Miss - Total of all segment sizes"
|
"BriefDescription": "gate_and(sd_pc_c0_comp_valid AND sd_pc_c0_comp_thread(0:1)=tid,sd_pc_c0_comp_ppc_count(0:3)) + gate_and(sd_pc_c1_comp_valid AND sd_pc_c1_comp_thread(0:1)=tid,sd_pc_c1_comp_ppc_count(0:3))"
|
||||||
},
|
},
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x4C058",
|
"EventCode": "0x4C058",
|
||||||
|
@ -549,4 +549,4 @@
|
||||||
"EventName": "PM_MRK_DATA_FROM_L21_SHR_CYC",
|
"EventName": "PM_MRK_DATA_FROM_L21_SHR_CYC",
|
||||||
"BriefDescription": "Duration in cycles to reload with Shared (S) data from another core's L2 on the same chip due to a marked load"
|
"BriefDescription": "Duration in cycles to reload with Shared (S) data from another core's L2 on the same chip due to a marked load"
|
||||||
}
|
}
|
||||||
]
|
]
|
|
@ -119,4 +119,4 @@
|
||||||
"EventName": "PM_1FLOP_CMPL",
|
"EventName": "PM_1FLOP_CMPL",
|
||||||
"BriefDescription": "one flop (fadd, fmul, fsub, fcmp, fsel, fabs, fnabs, fres, fsqrte, fneg) operation completed"
|
"BriefDescription": "one flop (fadd, fmul, fsub, fcmp, fsel, fabs, fnabs, fres, fsqrte, fneg) operation completed"
|
||||||
}
|
}
|
||||||
]
|
]
|
|
@ -89,11 +89,6 @@
|
||||||
"EventName": "PM_STCX_FAIL",
|
"EventName": "PM_STCX_FAIL",
|
||||||
"BriefDescription": "stcx failed"
|
"BriefDescription": "stcx failed"
|
||||||
},
|
},
|
||||||
{,
|
|
||||||
"EventCode": "0x20112",
|
|
||||||
"EventName": "PM_MRK_NTF_FIN",
|
|
||||||
"BriefDescription": "Marked next to finish instruction finished"
|
|
||||||
},
|
|
||||||
{,
|
{,
|
||||||
"EventCode": "0x300F0",
|
"EventCode": "0x300F0",
|
||||||
"EventName": "PM_ST_MISS_L1",
|
"EventName": "PM_ST_MISS_L1",
|
||||||
|
|
|
@ -124,6 +124,12 @@ static int store_event(struct perf_event_attr *attr, pid_t pid, int cpu,
|
||||||
WRITE_ASS(exclude_guest, "d");
|
WRITE_ASS(exclude_guest, "d");
|
||||||
WRITE_ASS(exclude_callchain_kernel, "d");
|
WRITE_ASS(exclude_callchain_kernel, "d");
|
||||||
WRITE_ASS(exclude_callchain_user, "d");
|
WRITE_ASS(exclude_callchain_user, "d");
|
||||||
|
WRITE_ASS(mmap2, "d");
|
||||||
|
WRITE_ASS(comm_exec, "d");
|
||||||
|
WRITE_ASS(context_switch, "d");
|
||||||
|
WRITE_ASS(write_backward, "d");
|
||||||
|
WRITE_ASS(namespaces, "d");
|
||||||
|
WRITE_ASS(use_clockid, "d");
|
||||||
WRITE_ASS(wakeup_events, PRIu32);
|
WRITE_ASS(wakeup_events, PRIu32);
|
||||||
WRITE_ASS(bp_type, PRIu32);
|
WRITE_ASS(bp_type, PRIu32);
|
||||||
WRITE_ASS(config1, "llu");
|
WRITE_ASS(config1, "llu");
|
||||||
|
|
|
@ -59,7 +59,7 @@ static int do_test(struct perf_evlist *evlist, int mmap_pages,
|
||||||
int err;
|
int err;
|
||||||
char sbuf[STRERR_BUFSIZE];
|
char sbuf[STRERR_BUFSIZE];
|
||||||
|
|
||||||
err = perf_evlist__mmap(evlist, mmap_pages, true);
|
err = perf_evlist__mmap(evlist, mmap_pages, false);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
pr_debug("perf_evlist__mmap: %s\n",
|
pr_debug("perf_evlist__mmap: %s\n",
|
||||||
str_error_r(errno, sbuf, sizeof(sbuf)));
|
str_error_r(errno, sbuf, sizeof(sbuf)));
|
||||||
|
|
|
@ -94,7 +94,7 @@ int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unuse
|
||||||
expected_nr_events[i] = 1 + rand() % 127;
|
expected_nr_events[i] = 1 + rand() % 127;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (perf_evlist__mmap(evlist, 128, true) < 0) {
|
if (perf_evlist__mmap(evlist, 128, false) < 0) {
|
||||||
pr_debug("failed to mmap events: %d (%s)\n", errno,
|
pr_debug("failed to mmap events: %d (%s)\n", errno,
|
||||||
str_error_r(errno, sbuf, sizeof(sbuf)));
|
str_error_r(errno, sbuf, sizeof(sbuf)));
|
||||||
goto out_delete_evlist;
|
goto out_delete_evlist;
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
. $(dirname $0)/lib/probe.sh
|
. $(dirname $0)/lib/probe.sh
|
||||||
|
|
||||||
ld=$(realpath /lib64/ld*.so.* | uniq)
|
libc=$(grep -w libc /proc/self/maps | head -1 | sed -r 's/.*[[:space:]](\/.*)/\1/g')
|
||||||
libc=$(echo $ld | sed 's/ld/libc/g')
|
nm -g $libc 2>/dev/null | fgrep -q inet_pton || exit 254
|
||||||
|
|
||||||
trace_libc_inet_pton_backtrace() {
|
trace_libc_inet_pton_backtrace() {
|
||||||
idx=0
|
idx=0
|
||||||
|
@ -37,6 +37,9 @@ trace_libc_inet_pton_backtrace() {
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Check for IPv6 interface existence
|
||||||
|
ip a sh lo | fgrep -q inet6 || exit 2
|
||||||
|
|
||||||
skip_if_no_perf_probe && \
|
skip_if_no_perf_probe && \
|
||||||
perf probe -q $libc inet_pton && \
|
perf probe -q $libc inet_pton && \
|
||||||
trace_libc_inet_pton_backtrace
|
trace_libc_inet_pton_backtrace
|
||||||
|
|
|
@ -17,8 +17,10 @@ skip_if_no_perf_probe || exit 2
|
||||||
file=$(mktemp /tmp/temporary_file.XXXXX)
|
file=$(mktemp /tmp/temporary_file.XXXXX)
|
||||||
|
|
||||||
trace_open_vfs_getname() {
|
trace_open_vfs_getname() {
|
||||||
perf trace -e open touch $file 2>&1 | \
|
test "$(uname -m)" = s390x && { svc="openat"; txt="dfd: +CWD, +"; }
|
||||||
egrep " +[0-9]+\.[0-9]+ +\( +[0-9]+\.[0-9]+ ms\): +touch\/[0-9]+ open\(filename: +${file}, +flags: CREAT\|NOCTTY\|NONBLOCK\|WRONLY, +mode: +IRUGO\|IWUGO\) += +[0-9]+$"
|
|
||||||
|
perf trace -e ${svc:-open} touch $file 2>&1 | \
|
||||||
|
egrep " +[0-9]+\.[0-9]+ +\( +[0-9]+\.[0-9]+ ms\): +touch\/[0-9]+ ${svc:-open}\(${txt}filename: +${file}, +flags: CREAT\|NOCTTY\|NONBLOCK\|WRONLY, +mode: +IRUGO\|IWUGO\) += +[0-9]+$"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
|
||||||
goto out_delete_evlist;
|
goto out_delete_evlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = perf_evlist__mmap(evlist, 128, true);
|
err = perf_evlist__mmap(evlist, 128, false);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
pr_debug("failed to mmap event: %d (%s)\n", errno,
|
pr_debug("failed to mmap event: %d (%s)\n", errno,
|
||||||
str_error_r(errno, sbuf, sizeof(sbuf)));
|
str_error_r(errno, sbuf, sizeof(sbuf)));
|
||||||
|
|
|
@ -97,7 +97,7 @@ int test__task_exit(struct test *test __maybe_unused, int subtest __maybe_unused
|
||||||
goto out_delete_evlist;
|
goto out_delete_evlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (perf_evlist__mmap(evlist, 128, true) < 0) {
|
if (perf_evlist__mmap(evlist, 128, false) < 0) {
|
||||||
pr_debug("failed to mmap events: %d (%s)\n", errno,
|
pr_debug("failed to mmap events: %d (%s)\n", errno,
|
||||||
str_error_r(errno, sbuf, sizeof(sbuf)));
|
str_error_r(errno, sbuf, sizeof(sbuf)));
|
||||||
goto out_delete_evlist;
|
goto out_delete_evlist;
|
||||||
|
|
|
@ -25,16 +25,10 @@ struct disasm_line_samples {
|
||||||
#define IPC_WIDTH 6
|
#define IPC_WIDTH 6
|
||||||
#define CYCLES_WIDTH 6
|
#define CYCLES_WIDTH 6
|
||||||
|
|
||||||
struct browser_disasm_line {
|
struct browser_line {
|
||||||
struct rb_node rb_node;
|
u32 idx;
|
||||||
u32 idx;
|
int idx_asm;
|
||||||
int idx_asm;
|
int jump_sources;
|
||||||
int jump_sources;
|
|
||||||
/*
|
|
||||||
* actual length of this array is saved on the nr_events field
|
|
||||||
* of the struct annotate_browser
|
|
||||||
*/
|
|
||||||
struct disasm_line_samples samples[1];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct annotate_browser_opt {
|
static struct annotate_browser_opt {
|
||||||
|
@ -53,39 +47,43 @@ static struct annotate_browser_opt {
|
||||||
struct arch;
|
struct arch;
|
||||||
|
|
||||||
struct annotate_browser {
|
struct annotate_browser {
|
||||||
struct ui_browser b;
|
struct ui_browser b;
|
||||||
struct rb_root entries;
|
struct rb_root entries;
|
||||||
struct rb_node *curr_hot;
|
struct rb_node *curr_hot;
|
||||||
struct disasm_line *selection;
|
struct annotation_line *selection;
|
||||||
struct disasm_line **offsets;
|
struct annotation_line **offsets;
|
||||||
struct arch *arch;
|
struct arch *arch;
|
||||||
int nr_events;
|
int nr_events;
|
||||||
u64 start;
|
u64 start;
|
||||||
int nr_asm_entries;
|
int nr_asm_entries;
|
||||||
int nr_entries;
|
int nr_entries;
|
||||||
int max_jump_sources;
|
int max_jump_sources;
|
||||||
int nr_jumps;
|
int nr_jumps;
|
||||||
bool searching_backwards;
|
bool searching_backwards;
|
||||||
bool have_cycles;
|
bool have_cycles;
|
||||||
u8 addr_width;
|
u8 addr_width;
|
||||||
u8 jumps_width;
|
u8 jumps_width;
|
||||||
u8 target_width;
|
u8 target_width;
|
||||||
u8 min_addr_width;
|
u8 min_addr_width;
|
||||||
u8 max_addr_width;
|
u8 max_addr_width;
|
||||||
char search_bf[128];
|
char search_bf[128];
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
|
static inline struct browser_line *browser_line(struct annotation_line *al)
|
||||||
{
|
{
|
||||||
return (struct browser_disasm_line *)(dl + 1);
|
void *ptr = al;
|
||||||
|
|
||||||
|
ptr = container_of(al, struct disasm_line, al);
|
||||||
|
return ptr - sizeof(struct browser_line);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
|
static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
|
||||||
void *entry)
|
void *entry)
|
||||||
{
|
{
|
||||||
if (annotate_browser__opts.hide_src_code) {
|
if (annotate_browser__opts.hide_src_code) {
|
||||||
struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
|
struct annotation_line *al = list_entry(entry, struct annotation_line, node);
|
||||||
return dl->offset == -1;
|
|
||||||
|
return al->offset == -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -120,11 +118,37 @@ static int annotate_browser__cycles_width(struct annotate_browser *ab)
|
||||||
return ab->have_cycles ? IPC_WIDTH + CYCLES_WIDTH : 0;
|
return ab->have_cycles ? IPC_WIDTH + CYCLES_WIDTH : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void disasm_line__write(struct disasm_line *dl, struct ui_browser *browser,
|
||||||
|
char *bf, size_t size)
|
||||||
|
{
|
||||||
|
if (dl->ins.ops && dl->ins.ops->scnprintf) {
|
||||||
|
if (ins__is_jump(&dl->ins)) {
|
||||||
|
bool fwd = dl->ops.target.offset > dl->al.offset;
|
||||||
|
|
||||||
|
ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
|
||||||
|
SLSMG_UARROW_CHAR);
|
||||||
|
SLsmg_write_char(' ');
|
||||||
|
} else if (ins__is_call(&dl->ins)) {
|
||||||
|
ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
|
||||||
|
SLsmg_write_char(' ');
|
||||||
|
} else if (ins__is_ret(&dl->ins)) {
|
||||||
|
ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
|
||||||
|
SLsmg_write_char(' ');
|
||||||
|
} else {
|
||||||
|
ui_browser__write_nstring(browser, " ", 2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ui_browser__write_nstring(browser, " ", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
disasm_line__scnprintf(dl, bf, size, !annotate_browser__opts.use_offset);
|
||||||
|
}
|
||||||
|
|
||||||
static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
|
static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
|
||||||
{
|
{
|
||||||
struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
|
struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
|
||||||
struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
|
struct annotation_line *al = list_entry(entry, struct annotation_line, node);
|
||||||
struct browser_disasm_line *bdl = disasm_line__browser(dl);
|
struct browser_line *bl = browser_line(al);
|
||||||
bool current_entry = ui_browser__is_current_entry(browser, row);
|
bool current_entry = ui_browser__is_current_entry(browser, row);
|
||||||
bool change_color = (!annotate_browser__opts.hide_src_code &&
|
bool change_color = (!annotate_browser__opts.hide_src_code &&
|
||||||
(!current_entry || (browser->use_navkeypressed &&
|
(!current_entry || (browser->use_navkeypressed &&
|
||||||
|
@ -137,32 +161,32 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
|
||||||
bool show_title = false;
|
bool show_title = false;
|
||||||
|
|
||||||
for (i = 0; i < ab->nr_events; i++) {
|
for (i = 0; i < ab->nr_events; i++) {
|
||||||
if (bdl->samples[i].percent > percent_max)
|
if (al->samples[i].percent > percent_max)
|
||||||
percent_max = bdl->samples[i].percent;
|
percent_max = al->samples[i].percent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((row == 0) && (dl->offset == -1 || percent_max == 0.0)) {
|
if ((row == 0) && (al->offset == -1 || percent_max == 0.0)) {
|
||||||
if (ab->have_cycles) {
|
if (ab->have_cycles) {
|
||||||
if (dl->ipc == 0.0 && dl->cycles == 0)
|
if (al->ipc == 0.0 && al->cycles == 0)
|
||||||
show_title = true;
|
show_title = true;
|
||||||
} else
|
} else
|
||||||
show_title = true;
|
show_title = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dl->offset != -1 && percent_max != 0.0) {
|
if (al->offset != -1 && percent_max != 0.0) {
|
||||||
for (i = 0; i < ab->nr_events; i++) {
|
for (i = 0; i < ab->nr_events; i++) {
|
||||||
ui_browser__set_percent_color(browser,
|
ui_browser__set_percent_color(browser,
|
||||||
bdl->samples[i].percent,
|
al->samples[i].percent,
|
||||||
current_entry);
|
current_entry);
|
||||||
if (annotate_browser__opts.show_total_period) {
|
if (annotate_browser__opts.show_total_period) {
|
||||||
ui_browser__printf(browser, "%11" PRIu64 " ",
|
ui_browser__printf(browser, "%11" PRIu64 " ",
|
||||||
bdl->samples[i].he.period);
|
al->samples[i].he.period);
|
||||||
} else if (annotate_browser__opts.show_nr_samples) {
|
} else if (annotate_browser__opts.show_nr_samples) {
|
||||||
ui_browser__printf(browser, "%6" PRIu64 " ",
|
ui_browser__printf(browser, "%6" PRIu64 " ",
|
||||||
bdl->samples[i].he.nr_samples);
|
al->samples[i].he.nr_samples);
|
||||||
} else {
|
} else {
|
||||||
ui_browser__printf(browser, "%6.2f ",
|
ui_browser__printf(browser, "%6.2f ",
|
||||||
bdl->samples[i].percent);
|
al->samples[i].percent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -177,16 +201,16 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ab->have_cycles) {
|
if (ab->have_cycles) {
|
||||||
if (dl->ipc)
|
if (al->ipc)
|
||||||
ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc);
|
ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, al->ipc);
|
||||||
else if (!show_title)
|
else if (!show_title)
|
||||||
ui_browser__write_nstring(browser, " ", IPC_WIDTH);
|
ui_browser__write_nstring(browser, " ", IPC_WIDTH);
|
||||||
else
|
else
|
||||||
ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC");
|
ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC");
|
||||||
|
|
||||||
if (dl->cycles)
|
if (al->cycles)
|
||||||
ui_browser__printf(browser, "%*" PRIu64 " ",
|
ui_browser__printf(browser, "%*" PRIu64 " ",
|
||||||
CYCLES_WIDTH - 1, dl->cycles);
|
CYCLES_WIDTH - 1, al->cycles);
|
||||||
else if (!show_title)
|
else if (!show_title)
|
||||||
ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
|
ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
|
||||||
else
|
else
|
||||||
|
@ -199,19 +223,19 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
|
||||||
if (!browser->navkeypressed)
|
if (!browser->navkeypressed)
|
||||||
width += 1;
|
width += 1;
|
||||||
|
|
||||||
if (!*dl->line)
|
if (!*al->line)
|
||||||
ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width);
|
ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width);
|
||||||
else if (dl->offset == -1) {
|
else if (al->offset == -1) {
|
||||||
if (dl->line_nr && annotate_browser__opts.show_linenr)
|
if (al->line_nr && annotate_browser__opts.show_linenr)
|
||||||
printed = scnprintf(bf, sizeof(bf), "%-*d ",
|
printed = scnprintf(bf, sizeof(bf), "%-*d ",
|
||||||
ab->addr_width + 1, dl->line_nr);
|
ab->addr_width + 1, al->line_nr);
|
||||||
else
|
else
|
||||||
printed = scnprintf(bf, sizeof(bf), "%*s ",
|
printed = scnprintf(bf, sizeof(bf), "%*s ",
|
||||||
ab->addr_width, " ");
|
ab->addr_width, " ");
|
||||||
ui_browser__write_nstring(browser, bf, printed);
|
ui_browser__write_nstring(browser, bf, printed);
|
||||||
ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width - cycles_width + 1);
|
ui_browser__write_nstring(browser, al->line, width - printed - pcnt_width - cycles_width + 1);
|
||||||
} else {
|
} else {
|
||||||
u64 addr = dl->offset;
|
u64 addr = al->offset;
|
||||||
int color = -1;
|
int color = -1;
|
||||||
|
|
||||||
if (!annotate_browser__opts.use_offset)
|
if (!annotate_browser__opts.use_offset)
|
||||||
|
@ -220,13 +244,13 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
|
||||||
if (!annotate_browser__opts.use_offset) {
|
if (!annotate_browser__opts.use_offset) {
|
||||||
printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
|
printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
|
||||||
} else {
|
} else {
|
||||||
if (bdl->jump_sources) {
|
if (bl->jump_sources) {
|
||||||
if (annotate_browser__opts.show_nr_jumps) {
|
if (annotate_browser__opts.show_nr_jumps) {
|
||||||
int prev;
|
int prev;
|
||||||
printed = scnprintf(bf, sizeof(bf), "%*d ",
|
printed = scnprintf(bf, sizeof(bf), "%*d ",
|
||||||
ab->jumps_width,
|
ab->jumps_width,
|
||||||
bdl->jump_sources);
|
bl->jump_sources);
|
||||||
prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
|
prev = annotate_browser__set_jumps_percent_color(ab, bl->jump_sources,
|
||||||
current_entry);
|
current_entry);
|
||||||
ui_browser__write_nstring(browser, bf, printed);
|
ui_browser__write_nstring(browser, bf, printed);
|
||||||
ui_browser__set_color(browser, prev);
|
ui_browser__set_color(browser, prev);
|
||||||
|
@ -245,32 +269,14 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
|
||||||
ui_browser__write_nstring(browser, bf, printed);
|
ui_browser__write_nstring(browser, bf, printed);
|
||||||
if (change_color)
|
if (change_color)
|
||||||
ui_browser__set_color(browser, color);
|
ui_browser__set_color(browser, color);
|
||||||
if (dl->ins.ops && dl->ins.ops->scnprintf) {
|
|
||||||
if (ins__is_jump(&dl->ins)) {
|
|
||||||
bool fwd = dl->ops.target.offset > dl->offset;
|
|
||||||
|
|
||||||
ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
|
disasm_line__write(disasm_line(al), browser, bf, sizeof(bf));
|
||||||
SLSMG_UARROW_CHAR);
|
|
||||||
SLsmg_write_char(' ');
|
|
||||||
} else if (ins__is_call(&dl->ins)) {
|
|
||||||
ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
|
|
||||||
SLsmg_write_char(' ');
|
|
||||||
} else if (ins__is_ret(&dl->ins)) {
|
|
||||||
ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
|
|
||||||
SLsmg_write_char(' ');
|
|
||||||
} else {
|
|
||||||
ui_browser__write_nstring(browser, " ", 2);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ui_browser__write_nstring(browser, " ", 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
|
|
||||||
ui_browser__write_nstring(browser, bf, width - pcnt_width - cycles_width - 3 - printed);
|
ui_browser__write_nstring(browser, bf, width - pcnt_width - cycles_width - 3 - printed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current_entry)
|
if (current_entry)
|
||||||
ab->selection = dl;
|
ab->selection = al;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
|
static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
|
||||||
|
@ -286,7 +292,7 @@ static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sy
|
||||||
|
|
||||||
static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
|
static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
|
||||||
{
|
{
|
||||||
struct disasm_line *pos = list_prev_entry(cursor, node);
|
struct disasm_line *pos = list_prev_entry(cursor, al.node);
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
if (!pos)
|
if (!pos)
|
||||||
|
@ -306,8 +312,9 @@ static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
|
||||||
static void annotate_browser__draw_current_jump(struct ui_browser *browser)
|
static void annotate_browser__draw_current_jump(struct ui_browser *browser)
|
||||||
{
|
{
|
||||||
struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
|
struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
|
||||||
struct disasm_line *cursor = ab->selection, *target;
|
struct disasm_line *cursor = disasm_line(ab->selection);
|
||||||
struct browser_disasm_line *btarget, *bcursor;
|
struct annotation_line *target;
|
||||||
|
struct browser_line *btarget, *bcursor;
|
||||||
unsigned int from, to;
|
unsigned int from, to;
|
||||||
struct map_symbol *ms = ab->b.priv;
|
struct map_symbol *ms = ab->b.priv;
|
||||||
struct symbol *sym = ms->sym;
|
struct symbol *sym = ms->sym;
|
||||||
|
@ -321,11 +328,9 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
target = ab->offsets[cursor->ops.target.offset];
|
target = ab->offsets[cursor->ops.target.offset];
|
||||||
if (!target)
|
|
||||||
return;
|
|
||||||
|
|
||||||
bcursor = disasm_line__browser(cursor);
|
bcursor = browser_line(&cursor->al);
|
||||||
btarget = disasm_line__browser(target);
|
btarget = browser_line(target);
|
||||||
|
|
||||||
if (annotate_browser__opts.hide_src_code) {
|
if (annotate_browser__opts.hide_src_code) {
|
||||||
from = bcursor->idx_asm;
|
from = bcursor->idx_asm;
|
||||||
|
@ -361,12 +366,11 @@ static unsigned int annotate_browser__refresh(struct ui_browser *browser)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int disasm__cmp(struct browser_disasm_line *a,
|
static int disasm__cmp(struct annotation_line *a, struct annotation_line *b)
|
||||||
struct browser_disasm_line *b, int nr_pcnt)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < nr_pcnt; i++) {
|
for (i = 0; i < a->samples_nr; i++) {
|
||||||
if (a->samples[i].percent == b->samples[i].percent)
|
if (a->samples[i].percent == b->samples[i].percent)
|
||||||
continue;
|
continue;
|
||||||
return a->samples[i].percent < b->samples[i].percent;
|
return a->samples[i].percent < b->samples[i].percent;
|
||||||
|
@ -374,28 +378,27 @@ static int disasm__cmp(struct browser_disasm_line *a,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
|
static void disasm_rb_tree__insert(struct rb_root *root, struct annotation_line *al)
|
||||||
int nr_events)
|
|
||||||
{
|
{
|
||||||
struct rb_node **p = &root->rb_node;
|
struct rb_node **p = &root->rb_node;
|
||||||
struct rb_node *parent = NULL;
|
struct rb_node *parent = NULL;
|
||||||
struct browser_disasm_line *l;
|
struct annotation_line *l;
|
||||||
|
|
||||||
while (*p != NULL) {
|
while (*p != NULL) {
|
||||||
parent = *p;
|
parent = *p;
|
||||||
l = rb_entry(parent, struct browser_disasm_line, rb_node);
|
l = rb_entry(parent, struct annotation_line, rb_node);
|
||||||
|
|
||||||
if (disasm__cmp(bdl, l, nr_events))
|
if (disasm__cmp(al, l))
|
||||||
p = &(*p)->rb_left;
|
p = &(*p)->rb_left;
|
||||||
else
|
else
|
||||||
p = &(*p)->rb_right;
|
p = &(*p)->rb_right;
|
||||||
}
|
}
|
||||||
rb_link_node(&bdl->rb_node, parent, p);
|
rb_link_node(&al->rb_node, parent, p);
|
||||||
rb_insert_color(&bdl->rb_node, root);
|
rb_insert_color(&al->rb_node, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void annotate_browser__set_top(struct annotate_browser *browser,
|
static void annotate_browser__set_top(struct annotate_browser *browser,
|
||||||
struct disasm_line *pos, u32 idx)
|
struct annotation_line *pos, u32 idx)
|
||||||
{
|
{
|
||||||
unsigned back;
|
unsigned back;
|
||||||
|
|
||||||
|
@ -404,7 +407,7 @@ static void annotate_browser__set_top(struct annotate_browser *browser,
|
||||||
browser->b.top_idx = browser->b.index = idx;
|
browser->b.top_idx = browser->b.index = idx;
|
||||||
|
|
||||||
while (browser->b.top_idx != 0 && back != 0) {
|
while (browser->b.top_idx != 0 && back != 0) {
|
||||||
pos = list_entry(pos->node.prev, struct disasm_line, node);
|
pos = list_entry(pos->node.prev, struct annotation_line, node);
|
||||||
|
|
||||||
if (disasm_line__filter(&browser->b, &pos->node))
|
if (disasm_line__filter(&browser->b, &pos->node))
|
||||||
continue;
|
continue;
|
||||||
|
@ -420,12 +423,13 @@ static void annotate_browser__set_top(struct annotate_browser *browser,
|
||||||
static void annotate_browser__set_rb_top(struct annotate_browser *browser,
|
static void annotate_browser__set_rb_top(struct annotate_browser *browser,
|
||||||
struct rb_node *nd)
|
struct rb_node *nd)
|
||||||
{
|
{
|
||||||
struct browser_disasm_line *bpos;
|
struct browser_line *bpos;
|
||||||
struct disasm_line *pos;
|
struct annotation_line *pos;
|
||||||
u32 idx;
|
u32 idx;
|
||||||
|
|
||||||
bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
|
pos = rb_entry(nd, struct annotation_line, rb_node);
|
||||||
pos = ((struct disasm_line *)bpos) - 1;
|
bpos = browser_line(pos);
|
||||||
|
|
||||||
idx = bpos->idx;
|
idx = bpos->idx;
|
||||||
if (annotate_browser__opts.hide_src_code)
|
if (annotate_browser__opts.hide_src_code)
|
||||||
idx = bpos->idx_asm;
|
idx = bpos->idx_asm;
|
||||||
|
@ -439,46 +443,35 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
|
||||||
struct map_symbol *ms = browser->b.priv;
|
struct map_symbol *ms = browser->b.priv;
|
||||||
struct symbol *sym = ms->sym;
|
struct symbol *sym = ms->sym;
|
||||||
struct annotation *notes = symbol__annotation(sym);
|
struct annotation *notes = symbol__annotation(sym);
|
||||||
struct disasm_line *pos, *next;
|
struct disasm_line *pos;
|
||||||
s64 len = symbol__size(sym);
|
|
||||||
|
|
||||||
browser->entries = RB_ROOT;
|
browser->entries = RB_ROOT;
|
||||||
|
|
||||||
pthread_mutex_lock(¬es->lock);
|
pthread_mutex_lock(¬es->lock);
|
||||||
|
|
||||||
list_for_each_entry(pos, ¬es->src->source, node) {
|
symbol__calc_percent(sym, evsel);
|
||||||
struct browser_disasm_line *bpos = disasm_line__browser(pos);
|
|
||||||
const char *path = NULL;
|
list_for_each_entry(pos, ¬es->src->source, al.node) {
|
||||||
double max_percent = 0.0;
|
double max_percent = 0.0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (pos->offset == -1) {
|
if (pos->al.offset == -1) {
|
||||||
RB_CLEAR_NODE(&bpos->rb_node);
|
RB_CLEAR_NODE(&pos->al.rb_node);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
next = disasm__get_next_ip_line(¬es->src->source, pos);
|
for (i = 0; i < pos->al.samples_nr; i++) {
|
||||||
|
struct annotation_data *sample = &pos->al.samples[i];
|
||||||
|
|
||||||
for (i = 0; i < browser->nr_events; i++) {
|
if (max_percent < sample->percent)
|
||||||
struct sym_hist_entry sample;
|
max_percent = sample->percent;
|
||||||
|
|
||||||
bpos->samples[i].percent = disasm__calc_percent(notes,
|
|
||||||
evsel->idx + i,
|
|
||||||
pos->offset,
|
|
||||||
next ? next->offset : len,
|
|
||||||
&path, &sample);
|
|
||||||
bpos->samples[i].he = sample;
|
|
||||||
|
|
||||||
if (max_percent < bpos->samples[i].percent)
|
|
||||||
max_percent = bpos->samples[i].percent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_percent < 0.01 && pos->ipc == 0) {
|
if (max_percent < 0.01 && pos->al.ipc == 0) {
|
||||||
RB_CLEAR_NODE(&bpos->rb_node);
|
RB_CLEAR_NODE(&pos->al.rb_node);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
disasm_rb_tree__insert(&browser->entries, bpos,
|
disasm_rb_tree__insert(&browser->entries, &pos->al);
|
||||||
browser->nr_events);
|
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(¬es->lock);
|
pthread_mutex_unlock(¬es->lock);
|
||||||
|
|
||||||
|
@ -487,38 +480,38 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
|
||||||
|
|
||||||
static bool annotate_browser__toggle_source(struct annotate_browser *browser)
|
static bool annotate_browser__toggle_source(struct annotate_browser *browser)
|
||||||
{
|
{
|
||||||
struct disasm_line *dl;
|
struct annotation_line *al;
|
||||||
struct browser_disasm_line *bdl;
|
struct browser_line *bl;
|
||||||
off_t offset = browser->b.index - browser->b.top_idx;
|
off_t offset = browser->b.index - browser->b.top_idx;
|
||||||
|
|
||||||
browser->b.seek(&browser->b, offset, SEEK_CUR);
|
browser->b.seek(&browser->b, offset, SEEK_CUR);
|
||||||
dl = list_entry(browser->b.top, struct disasm_line, node);
|
al = list_entry(browser->b.top, struct annotation_line, node);
|
||||||
bdl = disasm_line__browser(dl);
|
bl = browser_line(al);
|
||||||
|
|
||||||
if (annotate_browser__opts.hide_src_code) {
|
if (annotate_browser__opts.hide_src_code) {
|
||||||
if (bdl->idx_asm < offset)
|
if (bl->idx_asm < offset)
|
||||||
offset = bdl->idx;
|
offset = bl->idx;
|
||||||
|
|
||||||
browser->b.nr_entries = browser->nr_entries;
|
browser->b.nr_entries = browser->nr_entries;
|
||||||
annotate_browser__opts.hide_src_code = false;
|
annotate_browser__opts.hide_src_code = false;
|
||||||
browser->b.seek(&browser->b, -offset, SEEK_CUR);
|
browser->b.seek(&browser->b, -offset, SEEK_CUR);
|
||||||
browser->b.top_idx = bdl->idx - offset;
|
browser->b.top_idx = bl->idx - offset;
|
||||||
browser->b.index = bdl->idx;
|
browser->b.index = bl->idx;
|
||||||
} else {
|
} else {
|
||||||
if (bdl->idx_asm < 0) {
|
if (bl->idx_asm < 0) {
|
||||||
ui_helpline__puts("Only available for assembly lines.");
|
ui_helpline__puts("Only available for assembly lines.");
|
||||||
browser->b.seek(&browser->b, -offset, SEEK_CUR);
|
browser->b.seek(&browser->b, -offset, SEEK_CUR);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdl->idx_asm < offset)
|
if (bl->idx_asm < offset)
|
||||||
offset = bdl->idx_asm;
|
offset = bl->idx_asm;
|
||||||
|
|
||||||
browser->b.nr_entries = browser->nr_asm_entries;
|
browser->b.nr_entries = browser->nr_asm_entries;
|
||||||
annotate_browser__opts.hide_src_code = true;
|
annotate_browser__opts.hide_src_code = true;
|
||||||
browser->b.seek(&browser->b, -offset, SEEK_CUR);
|
browser->b.seek(&browser->b, -offset, SEEK_CUR);
|
||||||
browser->b.top_idx = bdl->idx_asm - offset;
|
browser->b.top_idx = bl->idx_asm - offset;
|
||||||
browser->b.index = bdl->idx_asm;
|
browser->b.index = bl->idx_asm;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -543,7 +536,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
|
||||||
struct hist_browser_timer *hbt)
|
struct hist_browser_timer *hbt)
|
||||||
{
|
{
|
||||||
struct map_symbol *ms = browser->b.priv;
|
struct map_symbol *ms = browser->b.priv;
|
||||||
struct disasm_line *dl = browser->selection;
|
struct disasm_line *dl = disasm_line(browser->selection);
|
||||||
struct annotation *notes;
|
struct annotation *notes;
|
||||||
struct addr_map_symbol target = {
|
struct addr_map_symbol target = {
|
||||||
.map = ms->map,
|
.map = ms->map,
|
||||||
|
@ -589,10 +582,10 @@ struct disasm_line *annotate_browser__find_offset(struct annotate_browser *brows
|
||||||
struct disasm_line *pos;
|
struct disasm_line *pos;
|
||||||
|
|
||||||
*idx = 0;
|
*idx = 0;
|
||||||
list_for_each_entry(pos, ¬es->src->source, node) {
|
list_for_each_entry(pos, ¬es->src->source, al.node) {
|
||||||
if (pos->offset == offset)
|
if (pos->al.offset == offset)
|
||||||
return pos;
|
return pos;
|
||||||
if (!disasm_line__filter(&browser->b, &pos->node))
|
if (!disasm_line__filter(&browser->b, &pos->al.node))
|
||||||
++*idx;
|
++*idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -601,7 +594,7 @@ struct disasm_line *annotate_browser__find_offset(struct annotate_browser *brows
|
||||||
|
|
||||||
static bool annotate_browser__jump(struct annotate_browser *browser)
|
static bool annotate_browser__jump(struct annotate_browser *browser)
|
||||||
{
|
{
|
||||||
struct disasm_line *dl = browser->selection;
|
struct disasm_line *dl = disasm_line(browser->selection);
|
||||||
u64 offset;
|
u64 offset;
|
||||||
s64 idx;
|
s64 idx;
|
||||||
|
|
||||||
|
@ -615,29 +608,29 @@ static bool annotate_browser__jump(struct annotate_browser *browser)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
annotate_browser__set_top(browser, dl, idx);
|
annotate_browser__set_top(browser, &dl->al, idx);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
|
struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
|
||||||
char *s, s64 *idx)
|
char *s, s64 *idx)
|
||||||
{
|
{
|
||||||
struct map_symbol *ms = browser->b.priv;
|
struct map_symbol *ms = browser->b.priv;
|
||||||
struct symbol *sym = ms->sym;
|
struct symbol *sym = ms->sym;
|
||||||
struct annotation *notes = symbol__annotation(sym);
|
struct annotation *notes = symbol__annotation(sym);
|
||||||
struct disasm_line *pos = browser->selection;
|
struct annotation_line *al = browser->selection;
|
||||||
|
|
||||||
*idx = browser->b.index;
|
*idx = browser->b.index;
|
||||||
list_for_each_entry_continue(pos, ¬es->src->source, node) {
|
list_for_each_entry_continue(al, ¬es->src->source, node) {
|
||||||
if (disasm_line__filter(&browser->b, &pos->node))
|
if (disasm_line__filter(&browser->b, &al->node))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
++*idx;
|
++*idx;
|
||||||
|
|
||||||
if (pos->line && strstr(pos->line, s) != NULL)
|
if (al->line && strstr(al->line, s) != NULL)
|
||||||
return pos;
|
return al;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -645,38 +638,38 @@ struct disasm_line *annotate_browser__find_string(struct annotate_browser *brows
|
||||||
|
|
||||||
static bool __annotate_browser__search(struct annotate_browser *browser)
|
static bool __annotate_browser__search(struct annotate_browser *browser)
|
||||||
{
|
{
|
||||||
struct disasm_line *dl;
|
struct annotation_line *al;
|
||||||
s64 idx;
|
s64 idx;
|
||||||
|
|
||||||
dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
|
al = annotate_browser__find_string(browser, browser->search_bf, &idx);
|
||||||
if (dl == NULL) {
|
if (al == NULL) {
|
||||||
ui_helpline__puts("String not found!");
|
ui_helpline__puts("String not found!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
annotate_browser__set_top(browser, dl, idx);
|
annotate_browser__set_top(browser, al, idx);
|
||||||
browser->searching_backwards = false;
|
browser->searching_backwards = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
|
struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
|
||||||
char *s, s64 *idx)
|
char *s, s64 *idx)
|
||||||
{
|
{
|
||||||
struct map_symbol *ms = browser->b.priv;
|
struct map_symbol *ms = browser->b.priv;
|
||||||
struct symbol *sym = ms->sym;
|
struct symbol *sym = ms->sym;
|
||||||
struct annotation *notes = symbol__annotation(sym);
|
struct annotation *notes = symbol__annotation(sym);
|
||||||
struct disasm_line *pos = browser->selection;
|
struct annotation_line *al = browser->selection;
|
||||||
|
|
||||||
*idx = browser->b.index;
|
*idx = browser->b.index;
|
||||||
list_for_each_entry_continue_reverse(pos, ¬es->src->source, node) {
|
list_for_each_entry_continue_reverse(al, ¬es->src->source, node) {
|
||||||
if (disasm_line__filter(&browser->b, &pos->node))
|
if (disasm_line__filter(&browser->b, &al->node))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
--*idx;
|
--*idx;
|
||||||
|
|
||||||
if (pos->line && strstr(pos->line, s) != NULL)
|
if (al->line && strstr(al->line, s) != NULL)
|
||||||
return pos;
|
return al;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -684,16 +677,16 @@ struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browse
|
||||||
|
|
||||||
static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
|
static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
|
||||||
{
|
{
|
||||||
struct disasm_line *dl;
|
struct annotation_line *al;
|
||||||
s64 idx;
|
s64 idx;
|
||||||
|
|
||||||
dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
|
al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
|
||||||
if (dl == NULL) {
|
if (al == NULL) {
|
||||||
ui_helpline__puts("String not found!");
|
ui_helpline__puts("String not found!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
annotate_browser__set_top(browser, dl, idx);
|
annotate_browser__set_top(browser, al, idx);
|
||||||
browser->searching_backwards = true;
|
browser->searching_backwards = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -899,13 +892,16 @@ static int annotate_browser__run(struct annotate_browser *browser,
|
||||||
continue;
|
continue;
|
||||||
case K_ENTER:
|
case K_ENTER:
|
||||||
case K_RIGHT:
|
case K_RIGHT:
|
||||||
|
{
|
||||||
|
struct disasm_line *dl = disasm_line(browser->selection);
|
||||||
|
|
||||||
if (browser->selection == NULL)
|
if (browser->selection == NULL)
|
||||||
ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
|
ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
|
||||||
else if (browser->selection->offset == -1)
|
else if (browser->selection->offset == -1)
|
||||||
ui_helpline__puts("Actions are only available for assembly lines.");
|
ui_helpline__puts("Actions are only available for assembly lines.");
|
||||||
else if (!browser->selection->ins.ops)
|
else if (!dl->ins.ops)
|
||||||
goto show_sup_ins;
|
goto show_sup_ins;
|
||||||
else if (ins__is_ret(&browser->selection->ins))
|
else if (ins__is_ret(&dl->ins))
|
||||||
goto out;
|
goto out;
|
||||||
else if (!(annotate_browser__jump(browser) ||
|
else if (!(annotate_browser__jump(browser) ||
|
||||||
annotate_browser__callq(browser, evsel, hbt))) {
|
annotate_browser__callq(browser, evsel, hbt))) {
|
||||||
|
@ -913,6 +909,7 @@ static int annotate_browser__run(struct annotate_browser *browser,
|
||||||
ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
|
ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
case 't':
|
case 't':
|
||||||
if (annotate_browser__opts.show_total_period) {
|
if (annotate_browser__opts.show_total_period) {
|
||||||
annotate_browser__opts.show_total_period = false;
|
annotate_browser__opts.show_total_period = false;
|
||||||
|
@ -990,10 +987,10 @@ static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (offset = start; offset <= end; offset++) {
|
for (offset = start; offset <= end; offset++) {
|
||||||
struct disasm_line *dl = browser->offsets[offset];
|
struct annotation_line *al = browser->offsets[offset];
|
||||||
|
|
||||||
if (dl)
|
if (al)
|
||||||
dl->ipc = ipc;
|
al->ipc = ipc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1018,13 +1015,13 @@ static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
|
||||||
|
|
||||||
ch = ¬es->src->cycles_hist[offset];
|
ch = ¬es->src->cycles_hist[offset];
|
||||||
if (ch && ch->cycles) {
|
if (ch && ch->cycles) {
|
||||||
struct disasm_line *dl;
|
struct annotation_line *al;
|
||||||
|
|
||||||
if (ch->have_start)
|
if (ch->have_start)
|
||||||
count_and_fill(browser, ch->start, offset, ch);
|
count_and_fill(browser, ch->start, offset, ch);
|
||||||
dl = browser->offsets[offset];
|
al = browser->offsets[offset];
|
||||||
if (dl && ch->num_aggr)
|
if (al && ch->num_aggr)
|
||||||
dl->cycles = ch->cycles_aggr / ch->num_aggr;
|
al->cycles = ch->cycles_aggr / ch->num_aggr;
|
||||||
browser->have_cycles = true;
|
browser->have_cycles = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1043,23 +1040,27 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (offset = 0; offset < size; ++offset) {
|
for (offset = 0; offset < size; ++offset) {
|
||||||
struct disasm_line *dl = browser->offsets[offset], *dlt;
|
struct annotation_line *al = browser->offsets[offset];
|
||||||
struct browser_disasm_line *bdlt;
|
struct disasm_line *dl;
|
||||||
|
struct browser_line *blt;
|
||||||
|
|
||||||
|
dl = disasm_line(al);
|
||||||
|
|
||||||
if (!disasm_line__is_valid_jump(dl, sym))
|
if (!disasm_line__is_valid_jump(dl, sym))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
dlt = browser->offsets[dl->ops.target.offset];
|
al = browser->offsets[dl->ops.target.offset];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME: Oops, no jump target? Buggy disassembler? Or do we
|
* FIXME: Oops, no jump target? Buggy disassembler? Or do we
|
||||||
* have to adjust to the previous offset?
|
* have to adjust to the previous offset?
|
||||||
*/
|
*/
|
||||||
if (dlt == NULL)
|
if (al == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
bdlt = disasm_line__browser(dlt);
|
blt = browser_line(al);
|
||||||
if (++bdlt->jump_sources > browser->max_jump_sources)
|
if (++blt->jump_sources > browser->max_jump_sources)
|
||||||
browser->max_jump_sources = bdlt->jump_sources;
|
browser->max_jump_sources = blt->jump_sources;
|
||||||
|
|
||||||
++browser->nr_jumps;
|
++browser->nr_jumps;
|
||||||
}
|
}
|
||||||
|
@ -1078,7 +1079,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
|
||||||
struct perf_evsel *evsel,
|
struct perf_evsel *evsel,
|
||||||
struct hist_browser_timer *hbt)
|
struct hist_browser_timer *hbt)
|
||||||
{
|
{
|
||||||
struct disasm_line *pos, *n;
|
struct annotation_line *al;
|
||||||
struct annotation *notes;
|
struct annotation *notes;
|
||||||
size_t size;
|
size_t size;
|
||||||
struct map_symbol ms = {
|
struct map_symbol ms = {
|
||||||
|
@ -1097,7 +1098,6 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
|
||||||
};
|
};
|
||||||
int ret = -1, err;
|
int ret = -1, err;
|
||||||
int nr_pcnt = 1;
|
int nr_pcnt = 1;
|
||||||
size_t sizeof_bdl = sizeof(struct browser_disasm_line);
|
|
||||||
|
|
||||||
if (sym == NULL)
|
if (sym == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1107,21 +1107,18 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
|
||||||
if (map->dso->annotate_warned)
|
if (map->dso->annotate_warned)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
browser.offsets = zalloc(size * sizeof(struct disasm_line *));
|
browser.offsets = zalloc(size * sizeof(struct annotation_line *));
|
||||||
if (browser.offsets == NULL) {
|
if (browser.offsets == NULL) {
|
||||||
ui__error("Not enough memory!");
|
ui__error("Not enough memory!");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (perf_evsel__is_group_event(evsel)) {
|
if (perf_evsel__is_group_event(evsel))
|
||||||
nr_pcnt = evsel->nr_members;
|
nr_pcnt = evsel->nr_members;
|
||||||
sizeof_bdl += sizeof(struct disasm_line_samples) *
|
|
||||||
(nr_pcnt - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel),
|
err = symbol__annotate(sym, map, evsel,
|
||||||
sizeof_bdl, &browser.arch,
|
sizeof(struct browser_line), &browser.arch,
|
||||||
perf_evsel__env_cpuid(evsel));
|
perf_evsel__env_cpuid(evsel));
|
||||||
if (err) {
|
if (err) {
|
||||||
char msg[BUFSIZ];
|
char msg[BUFSIZ];
|
||||||
symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
|
symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
|
||||||
|
@ -1129,20 +1126,22 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
|
||||||
goto out_free_offsets;
|
goto out_free_offsets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
symbol__calc_percent(sym, evsel);
|
||||||
|
|
||||||
ui_helpline__push("Press ESC to exit");
|
ui_helpline__push("Press ESC to exit");
|
||||||
|
|
||||||
notes = symbol__annotation(sym);
|
notes = symbol__annotation(sym);
|
||||||
browser.start = map__rip_2objdump(map, sym->start);
|
browser.start = map__rip_2objdump(map, sym->start);
|
||||||
|
|
||||||
list_for_each_entry(pos, ¬es->src->source, node) {
|
list_for_each_entry(al, ¬es->src->source, node) {
|
||||||
struct browser_disasm_line *bpos;
|
struct browser_line *bpos;
|
||||||
size_t line_len = strlen(pos->line);
|
size_t line_len = strlen(al->line);
|
||||||
|
|
||||||
if (browser.b.width < line_len)
|
if (browser.b.width < line_len)
|
||||||
browser.b.width = line_len;
|
browser.b.width = line_len;
|
||||||
bpos = disasm_line__browser(pos);
|
bpos = browser_line(al);
|
||||||
bpos->idx = browser.nr_entries++;
|
bpos->idx = browser.nr_entries++;
|
||||||
if (pos->offset != -1) {
|
if (al->offset != -1) {
|
||||||
bpos->idx_asm = browser.nr_asm_entries++;
|
bpos->idx_asm = browser.nr_asm_entries++;
|
||||||
/*
|
/*
|
||||||
* FIXME: short term bandaid to cope with assembly
|
* FIXME: short term bandaid to cope with assembly
|
||||||
|
@ -1151,8 +1150,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
|
||||||
*
|
*
|
||||||
* E.g. copy_user_generic_unrolled
|
* E.g. copy_user_generic_unrolled
|
||||||
*/
|
*/
|
||||||
if (pos->offset < (s64)size)
|
if (al->offset < (s64)size)
|
||||||
browser.offsets[pos->offset] = pos;
|
browser.offsets[al->offset] = al;
|
||||||
} else
|
} else
|
||||||
bpos->idx_asm = -1;
|
bpos->idx_asm = -1;
|
||||||
}
|
}
|
||||||
|
@ -1174,10 +1173,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
|
||||||
annotate_browser__update_addr_width(&browser);
|
annotate_browser__update_addr_width(&browser);
|
||||||
|
|
||||||
ret = annotate_browser__run(&browser, evsel, hbt);
|
ret = annotate_browser__run(&browser, evsel, hbt);
|
||||||
list_for_each_entry_safe(pos, n, ¬es->src->source, node) {
|
|
||||||
list_del(&pos->node);
|
annotated_source__purge(notes->src);
|
||||||
disasm_line__free(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
out_free_offsets:
|
out_free_offsets:
|
||||||
free(browser.offsets);
|
free(browser.offsets);
|
||||||
|
|
|
@ -31,14 +31,14 @@ static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym,
|
||||||
|
|
||||||
strcpy(buf, "");
|
strcpy(buf, "");
|
||||||
|
|
||||||
if (dl->offset == (s64) -1)
|
if (dl->al.offset == (s64) -1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
symhist = annotation__histogram(symbol__annotation(sym), evidx);
|
symhist = annotation__histogram(symbol__annotation(sym), evidx);
|
||||||
if (!symbol_conf.event_group && !symhist->addr[dl->offset].nr_samples)
|
if (!symbol_conf.event_group && !symhist->addr[dl->al.offset].nr_samples)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
percent = 100.0 * symhist->addr[dl->offset].nr_samples / symhist->nr_samples;
|
percent = 100.0 * symhist->addr[dl->al.offset].nr_samples / symhist->nr_samples;
|
||||||
|
|
||||||
markup = perf_gtk__get_percent_color(percent);
|
markup = perf_gtk__get_percent_color(percent);
|
||||||
if (markup)
|
if (markup)
|
||||||
|
@ -57,16 +57,16 @@ static int perf_gtk__get_offset(char *buf, size_t size, struct symbol *sym,
|
||||||
|
|
||||||
strcpy(buf, "");
|
strcpy(buf, "");
|
||||||
|
|
||||||
if (dl->offset == (s64) -1)
|
if (dl->al.offset == (s64) -1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return scnprintf(buf, size, "%"PRIx64, start + dl->offset);
|
return scnprintf(buf, size, "%"PRIx64, start + dl->al.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int perf_gtk__get_line(char *buf, size_t size, struct disasm_line *dl)
|
static int perf_gtk__get_line(char *buf, size_t size, struct disasm_line *dl)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
char *line = g_markup_escape_text(dl->line, -1);
|
char *line = g_markup_escape_text(dl->al.line, -1);
|
||||||
const char *markup = "<span fgcolor='gray'>";
|
const char *markup = "<span fgcolor='gray'>";
|
||||||
|
|
||||||
strcpy(buf, "");
|
strcpy(buf, "");
|
||||||
|
@ -74,7 +74,7 @@ static int perf_gtk__get_line(char *buf, size_t size, struct disasm_line *dl)
|
||||||
if (!line)
|
if (!line)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (dl->offset != (s64) -1)
|
if (dl->al.offset != (s64) -1)
|
||||||
markup = NULL;
|
markup = NULL;
|
||||||
|
|
||||||
if (markup)
|
if (markup)
|
||||||
|
@ -119,7 +119,7 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym,
|
||||||
gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
|
gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
|
||||||
g_object_unref(GTK_TREE_MODEL(store));
|
g_object_unref(GTK_TREE_MODEL(store));
|
||||||
|
|
||||||
list_for_each_entry(pos, ¬es->src->source, node) {
|
list_for_each_entry(pos, ¬es->src->source, al.node) {
|
||||||
GtkTreeIter iter;
|
GtkTreeIter iter;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
@ -148,8 +148,8 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym,
|
||||||
|
|
||||||
gtk_container_add(GTK_CONTAINER(window), view);
|
gtk_container_add(GTK_CONTAINER(window), view);
|
||||||
|
|
||||||
list_for_each_entry_safe(pos, n, ¬es->src->source, node) {
|
list_for_each_entry_safe(pos, n, ¬es->src->source, al.node) {
|
||||||
list_del(&pos->node);
|
list_del(&pos->al.node);
|
||||||
disasm_line__free(pos);
|
disasm_line__free(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,8 +169,7 @@ static int symbol__gtk_annotate(struct symbol *sym, struct map *map,
|
||||||
if (map->dso->annotate_warned)
|
if (map->dso->annotate_warned)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel),
|
err = symbol__annotate(sym, map, evsel, 0, NULL, NULL);
|
||||||
0, NULL, NULL);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
char msg[BUFSIZ];
|
char msg[BUFSIZ];
|
||||||
symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
|
symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
|
||||||
|
@ -178,6 +177,8 @@ static int symbol__gtk_annotate(struct symbol *sym, struct map *map,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
symbol__calc_percent(sym, evsel);
|
||||||
|
|
||||||
if (perf_gtk__is_active_context(pgctx)) {
|
if (perf_gtk__is_active_context(pgctx)) {
|
||||||
window = pgctx->main_window;
|
window = pgctx->main_window;
|
||||||
notebook = pgctx->notebook;
|
notebook = pgctx->notebook;
|
||||||
|
|
|
@ -165,7 +165,7 @@ static void ins__delete(struct ins_operands *ops)
|
||||||
static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
|
static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
|
||||||
struct ins_operands *ops)
|
struct ins_operands *ops)
|
||||||
{
|
{
|
||||||
return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw);
|
return scnprintf(bf, size, "%-6s %s", ins->name, ops->raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ins__scnprintf(struct ins *ins, char *bf, size_t size,
|
int ins__scnprintf(struct ins *ins, char *bf, size_t size,
|
||||||
|
@ -230,12 +230,12 @@ static int call__scnprintf(struct ins *ins, char *bf, size_t size,
|
||||||
struct ins_operands *ops)
|
struct ins_operands *ops)
|
||||||
{
|
{
|
||||||
if (ops->target.name)
|
if (ops->target.name)
|
||||||
return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name);
|
return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.name);
|
||||||
|
|
||||||
if (ops->target.addr == 0)
|
if (ops->target.addr == 0)
|
||||||
return ins__raw_scnprintf(ins, bf, size, ops);
|
return ins__raw_scnprintf(ins, bf, size, ops);
|
||||||
|
|
||||||
return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr);
|
return scnprintf(bf, size, "%-6s *%" PRIx64, ins->name, ops->target.addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ins_ops call_ops = {
|
static struct ins_ops call_ops = {
|
||||||
|
@ -299,7 +299,7 @@ static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
|
||||||
c++;
|
c++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return scnprintf(bf, size, "%-6.6s %.*s%" PRIx64,
|
return scnprintf(bf, size, "%-6s %.*s%" PRIx64,
|
||||||
ins->name, c ? c - ops->raw : 0, ops->raw,
|
ins->name, c ? c - ops->raw : 0, ops->raw,
|
||||||
ops->target.offset);
|
ops->target.offset);
|
||||||
}
|
}
|
||||||
|
@ -372,7 +372,7 @@ static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
|
||||||
if (ops->locked.ins.ops == NULL)
|
if (ops->locked.ins.ops == NULL)
|
||||||
return ins__raw_scnprintf(ins, bf, size, ops);
|
return ins__raw_scnprintf(ins, bf, size, ops);
|
||||||
|
|
||||||
printed = scnprintf(bf, size, "%-6.6s ", ins->name);
|
printed = scnprintf(bf, size, "%-6s ", ins->name);
|
||||||
return printed + ins__scnprintf(&ops->locked.ins, bf + printed,
|
return printed + ins__scnprintf(&ops->locked.ins, bf + printed,
|
||||||
size - printed, ops->locked.ops);
|
size - printed, ops->locked.ops);
|
||||||
}
|
}
|
||||||
|
@ -448,7 +448,7 @@ static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map *m
|
||||||
static int mov__scnprintf(struct ins *ins, char *bf, size_t size,
|
static int mov__scnprintf(struct ins *ins, char *bf, size_t size,
|
||||||
struct ins_operands *ops)
|
struct ins_operands *ops)
|
||||||
{
|
{
|
||||||
return scnprintf(bf, size, "%-6.6s %s,%s", ins->name,
|
return scnprintf(bf, size, "%-6s %s,%s", ins->name,
|
||||||
ops->source.name ?: ops->source.raw,
|
ops->source.name ?: ops->source.raw,
|
||||||
ops->target.name ?: ops->target.raw);
|
ops->target.name ?: ops->target.raw);
|
||||||
}
|
}
|
||||||
|
@ -488,7 +488,7 @@ static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops
|
||||||
static int dec__scnprintf(struct ins *ins, char *bf, size_t size,
|
static int dec__scnprintf(struct ins *ins, char *bf, size_t size,
|
||||||
struct ins_operands *ops)
|
struct ins_operands *ops)
|
||||||
{
|
{
|
||||||
return scnprintf(bf, size, "%-6.6s %s", ins->name,
|
return scnprintf(bf, size, "%-6s %s", ins->name,
|
||||||
ops->target.name ?: ops->target.raw);
|
ops->target.name ?: ops->target.raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,7 +500,7 @@ static struct ins_ops dec_ops = {
|
||||||
static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size,
|
static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size,
|
||||||
struct ins_operands *ops __maybe_unused)
|
struct ins_operands *ops __maybe_unused)
|
||||||
{
|
{
|
||||||
return scnprintf(bf, size, "%-6.6s", "nop");
|
return scnprintf(bf, size, "%-6s", "nop");
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ins_ops nop_ops = {
|
static struct ins_ops nop_ops = {
|
||||||
|
@ -878,32 +878,99 @@ static int disasm_line__parse(char *line, const char **namep, char **rawp)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct disasm_line *disasm_line__new(s64 offset, char *line,
|
struct annotate_args {
|
||||||
size_t privsize, int line_nr,
|
size_t privsize;
|
||||||
struct arch *arch,
|
struct arch *arch;
|
||||||
struct map *map)
|
struct map *map;
|
||||||
{
|
struct perf_evsel *evsel;
|
||||||
struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
|
s64 offset;
|
||||||
|
char *line;
|
||||||
|
int line_nr;
|
||||||
|
};
|
||||||
|
|
||||||
if (dl != NULL) {
|
static void annotation_line__delete(struct annotation_line *al)
|
||||||
dl->offset = offset;
|
{
|
||||||
dl->line = strdup(line);
|
void *ptr = (void *) al - al->privsize;
|
||||||
dl->line_nr = line_nr;
|
|
||||||
if (dl->line == NULL)
|
free_srcline(al->path);
|
||||||
|
zfree(&al->line);
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocating the annotation line data with following
|
||||||
|
* structure:
|
||||||
|
*
|
||||||
|
* --------------------------------------
|
||||||
|
* private space | struct annotation_line
|
||||||
|
* --------------------------------------
|
||||||
|
*
|
||||||
|
* 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 perf_evsel *evsel = args->evsel;
|
||||||
|
size_t size = privsize + sizeof(*al);
|
||||||
|
int nr = 1;
|
||||||
|
|
||||||
|
if (perf_evsel__is_group_event(evsel))
|
||||||
|
nr = evsel->nr_members;
|
||||||
|
|
||||||
|
size += sizeof(al->samples[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->samples_nr = nr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return al;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocating the disasm annotation line data with
|
||||||
|
* following structure:
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------
|
||||||
|
* privsize space | struct disasm_line | struct annotation_line
|
||||||
|
* ------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* We have 'struct annotation_line' member as last member
|
||||||
|
* of 'struct disasm_line' to have an easy access.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static struct disasm_line *disasm_line__new(struct annotate_args *args)
|
||||||
|
{
|
||||||
|
struct disasm_line *dl = NULL;
|
||||||
|
struct annotation_line *al;
|
||||||
|
size_t privsize = args->privsize + offsetof(struct disasm_line, al);
|
||||||
|
|
||||||
|
al = annotation_line__new(args, privsize);
|
||||||
|
if (al != NULL) {
|
||||||
|
dl = disasm_line(al);
|
||||||
|
|
||||||
|
if (dl->al.line == NULL)
|
||||||
goto out_delete;
|
goto out_delete;
|
||||||
|
|
||||||
if (offset != -1) {
|
if (args->offset != -1) {
|
||||||
if (disasm_line__parse(dl->line, &dl->ins.name, &dl->ops.raw) < 0)
|
if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0)
|
||||||
goto out_free_line;
|
goto out_free_line;
|
||||||
|
|
||||||
disasm_line__init_ins(dl, arch, map);
|
disasm_line__init_ins(dl, args->arch, args->map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dl;
|
return dl;
|
||||||
|
|
||||||
out_free_line:
|
out_free_line:
|
||||||
zfree(&dl->line);
|
zfree(&dl->al.line);
|
||||||
out_delete:
|
out_delete:
|
||||||
free(dl);
|
free(dl);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -911,30 +978,30 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line,
|
||||||
|
|
||||||
void disasm_line__free(struct disasm_line *dl)
|
void disasm_line__free(struct disasm_line *dl)
|
||||||
{
|
{
|
||||||
zfree(&dl->line);
|
|
||||||
if (dl->ins.ops && dl->ins.ops->free)
|
if (dl->ins.ops && dl->ins.ops->free)
|
||||||
dl->ins.ops->free(&dl->ops);
|
dl->ins.ops->free(&dl->ops);
|
||||||
else
|
else
|
||||||
ins__delete(&dl->ops);
|
ins__delete(&dl->ops);
|
||||||
free((void *)dl->ins.name);
|
free((void *)dl->ins.name);
|
||||||
dl->ins.name = NULL;
|
dl->ins.name = NULL;
|
||||||
free(dl);
|
annotation_line__delete(&dl->al);
|
||||||
}
|
}
|
||||||
|
|
||||||
int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw)
|
int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw)
|
||||||
{
|
{
|
||||||
if (raw || !dl->ins.ops)
|
if (raw || !dl->ins.ops)
|
||||||
return scnprintf(bf, size, "%-6.6s %s", dl->ins.name, dl->ops.raw);
|
return scnprintf(bf, size, "%-6s %s", dl->ins.name, dl->ops.raw);
|
||||||
|
|
||||||
return ins__scnprintf(&dl->ins, bf, size, &dl->ops);
|
return ins__scnprintf(&dl->ins, bf, size, &dl->ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void disasm__add(struct list_head *head, struct disasm_line *line)
|
static void annotation_line__add(struct annotation_line *al, struct list_head *head)
|
||||||
{
|
{
|
||||||
list_add_tail(&line->node, head);
|
list_add_tail(&al->node, head);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos)
|
struct annotation_line *
|
||||||
|
annotation_line__next(struct annotation_line *pos, struct list_head *head)
|
||||||
{
|
{
|
||||||
list_for_each_entry_continue(pos, head, node)
|
list_for_each_entry_continue(pos, head, node)
|
||||||
if (pos->offset >= 0)
|
if (pos->offset >= 0)
|
||||||
|
@ -943,50 +1010,6 @@ struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disa
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,
|
|
||||||
s64 end, const char **path, struct sym_hist_entry *sample)
|
|
||||||
{
|
|
||||||
struct source_line *src_line = notes->src->lines;
|
|
||||||
double percent = 0.0;
|
|
||||||
|
|
||||||
sample->nr_samples = sample->period = 0;
|
|
||||||
|
|
||||||
if (src_line) {
|
|
||||||
size_t sizeof_src_line = sizeof(*src_line) +
|
|
||||||
sizeof(src_line->samples) * (src_line->nr_pcnt - 1);
|
|
||||||
|
|
||||||
while (offset < end) {
|
|
||||||
src_line = (void *)notes->src->lines +
|
|
||||||
(sizeof_src_line * offset);
|
|
||||||
|
|
||||||
if (*path == NULL)
|
|
||||||
*path = src_line->path;
|
|
||||||
|
|
||||||
percent += src_line->samples[evidx].percent;
|
|
||||||
sample->nr_samples += src_line->samples[evidx].nr;
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
struct sym_hist *h = annotation__histogram(notes, evidx);
|
|
||||||
unsigned int hits = 0;
|
|
||||||
u64 period = 0;
|
|
||||||
|
|
||||||
while (offset < end) {
|
|
||||||
hits += h->addr[offset].nr_samples;
|
|
||||||
period += h->addr[offset].period;
|
|
||||||
++offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (h->nr_samples) {
|
|
||||||
sample->period = period;
|
|
||||||
sample->nr_samples = hits;
|
|
||||||
percent = 100.0 * hits / h->nr_samples;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return percent;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *annotate__address_color(struct block_range *br)
|
static const char *annotate__address_color(struct block_range *br)
|
||||||
{
|
{
|
||||||
double cov = block_range__coverage(br);
|
double cov = block_range__coverage(br);
|
||||||
|
@ -1069,50 +1092,39 @@ static void annotate__branch_printf(struct block_range *br, u64 addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int disasm_line__print(struct disasm_line *dl, u64 start, int addr_fmt_width)
|
||||||
static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start,
|
|
||||||
struct perf_evsel *evsel, u64 len, int min_pcnt, int printed,
|
|
||||||
int max_lines, struct disasm_line *queue)
|
|
||||||
{
|
{
|
||||||
|
s64 offset = dl->al.offset;
|
||||||
|
const u64 addr = start + offset;
|
||||||
|
struct block_range *br;
|
||||||
|
|
||||||
|
br = block_range__find(addr);
|
||||||
|
color_fprintf(stdout, annotate__address_color(br), " %*" PRIx64 ":", addr_fmt_width, addr);
|
||||||
|
color_fprintf(stdout, annotate__asm_color(br), "%s", dl->al.line);
|
||||||
|
annotate__branch_printf(br, addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start,
|
||||||
|
struct perf_evsel *evsel, u64 len, int min_pcnt, int printed,
|
||||||
|
int max_lines, struct annotation_line *queue, int addr_fmt_width)
|
||||||
|
{
|
||||||
|
struct disasm_line *dl = container_of(al, struct disasm_line, al);
|
||||||
static const char *prev_line;
|
static const char *prev_line;
|
||||||
static const char *prev_color;
|
static const char *prev_color;
|
||||||
|
|
||||||
if (dl->offset != -1) {
|
if (al->offset != -1) {
|
||||||
const char *path = NULL;
|
double max_percent = 0.0;
|
||||||
double percent, max_percent = 0.0;
|
|
||||||
double *ppercents = &percent;
|
|
||||||
struct sym_hist_entry sample;
|
|
||||||
struct sym_hist_entry *psamples = &sample;
|
|
||||||
int i, nr_percent = 1;
|
int i, nr_percent = 1;
|
||||||
const char *color;
|
const char *color;
|
||||||
struct annotation *notes = symbol__annotation(sym);
|
struct annotation *notes = symbol__annotation(sym);
|
||||||
s64 offset = dl->offset;
|
|
||||||
const u64 addr = start + offset;
|
|
||||||
struct disasm_line *next;
|
|
||||||
struct block_range *br;
|
|
||||||
|
|
||||||
next = disasm__get_next_ip_line(¬es->src->source, dl);
|
for (i = 0; i < al->samples_nr; i++) {
|
||||||
|
struct annotation_data *sample = &al->samples[i];
|
||||||
|
|
||||||
if (perf_evsel__is_group_event(evsel)) {
|
if (sample->percent > max_percent)
|
||||||
nr_percent = evsel->nr_members;
|
max_percent = sample->percent;
|
||||||
ppercents = calloc(nr_percent, sizeof(double));
|
|
||||||
psamples = calloc(nr_percent, sizeof(struct sym_hist_entry));
|
|
||||||
if (ppercents == NULL || psamples == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < nr_percent; i++) {
|
|
||||||
percent = disasm__calc_percent(notes,
|
|
||||||
notes->src->lines ? i : evsel->idx + i,
|
|
||||||
offset,
|
|
||||||
next ? next->offset : (s64) len,
|
|
||||||
&path, &sample);
|
|
||||||
|
|
||||||
ppercents[i] = percent;
|
|
||||||
psamples[i] = sample;
|
|
||||||
if (percent > max_percent)
|
|
||||||
max_percent = percent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_percent < min_pcnt)
|
if (max_percent < min_pcnt)
|
||||||
|
@ -1123,10 +1135,10 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
|
||||||
|
|
||||||
if (queue != NULL) {
|
if (queue != NULL) {
|
||||||
list_for_each_entry_from(queue, ¬es->src->source, node) {
|
list_for_each_entry_from(queue, ¬es->src->source, node) {
|
||||||
if (queue == dl)
|
if (queue == al)
|
||||||
break;
|
break;
|
||||||
disasm_line__print(queue, sym, start, evsel, len,
|
annotation_line__print(queue, sym, start, evsel, len,
|
||||||
0, 0, 1, NULL);
|
0, 0, 1, NULL, addr_fmt_width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1137,44 +1149,34 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
|
||||||
* the same color than the percentage. Don't print it
|
* the same color than the percentage. Don't print it
|
||||||
* twice for close colored addr with the same filename:line
|
* twice for close colored addr with the same filename:line
|
||||||
*/
|
*/
|
||||||
if (path) {
|
if (al->path) {
|
||||||
if (!prev_line || strcmp(prev_line, path)
|
if (!prev_line || strcmp(prev_line, al->path)
|
||||||
|| color != prev_color) {
|
|| color != prev_color) {
|
||||||
color_fprintf(stdout, color, " %s", path);
|
color_fprintf(stdout, color, " %s", al->path);
|
||||||
prev_line = path;
|
prev_line = al->path;
|
||||||
prev_color = color;
|
prev_color = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < nr_percent; i++) {
|
for (i = 0; i < nr_percent; i++) {
|
||||||
percent = ppercents[i];
|
struct annotation_data *sample = &al->samples[i];
|
||||||
sample = psamples[i];
|
|
||||||
color = get_percent_color(percent);
|
color = get_percent_color(sample->percent);
|
||||||
|
|
||||||
if (symbol_conf.show_total_period)
|
if (symbol_conf.show_total_period)
|
||||||
color_fprintf(stdout, color, " %11" PRIu64,
|
color_fprintf(stdout, color, " %11" PRIu64,
|
||||||
sample.period);
|
sample->he.period);
|
||||||
else if (symbol_conf.show_nr_samples)
|
else if (symbol_conf.show_nr_samples)
|
||||||
color_fprintf(stdout, color, " %7" PRIu64,
|
color_fprintf(stdout, color, " %7" PRIu64,
|
||||||
sample.nr_samples);
|
sample->he.nr_samples);
|
||||||
else
|
else
|
||||||
color_fprintf(stdout, color, " %7.2f", percent);
|
color_fprintf(stdout, color, " %7.2f", sample->percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(" : ");
|
printf(" : ");
|
||||||
|
|
||||||
br = block_range__find(addr);
|
disasm_line__print(dl, start, addr_fmt_width);
|
||||||
color_fprintf(stdout, annotate__address_color(br), " %" PRIx64 ":", addr);
|
|
||||||
color_fprintf(stdout, annotate__asm_color(br), "%s", dl->line);
|
|
||||||
annotate__branch_printf(br, addr);
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
if (ppercents != &percent)
|
|
||||||
free(ppercents);
|
|
||||||
|
|
||||||
if (psamples != &sample)
|
|
||||||
free(psamples);
|
|
||||||
|
|
||||||
} else if (max_lines && printed >= max_lines)
|
} else if (max_lines && printed >= max_lines)
|
||||||
return 1;
|
return 1;
|
||||||
else {
|
else {
|
||||||
|
@ -1186,10 +1188,10 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
|
||||||
if (perf_evsel__is_group_event(evsel))
|
if (perf_evsel__is_group_event(evsel))
|
||||||
width *= evsel->nr_members;
|
width *= evsel->nr_members;
|
||||||
|
|
||||||
if (!*dl->line)
|
if (!*al->line)
|
||||||
printf(" %*s:\n", width, " ");
|
printf(" %*s:\n", width, " ");
|
||||||
else
|
else
|
||||||
printf(" %*s: %s\n", width, " ", dl->line);
|
printf(" %*s: %*s %s\n", width, " ", addr_fmt_width, " ", al->line);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1215,11 +1217,11 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
|
||||||
* means that it's not a disassembly line so should be treated differently.
|
* means that it's not a disassembly line so should be treated differently.
|
||||||
* The ops.raw part will be parsed further according to type of the instruction.
|
* The ops.raw part will be parsed further according to type of the instruction.
|
||||||
*/
|
*/
|
||||||
static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
|
static int symbol__parse_objdump_line(struct symbol *sym, FILE *file,
|
||||||
struct arch *arch,
|
struct annotate_args *args,
|
||||||
FILE *file, size_t privsize,
|
|
||||||
int *line_nr)
|
int *line_nr)
|
||||||
{
|
{
|
||||||
|
struct map *map = args->map;
|
||||||
struct annotation *notes = symbol__annotation(sym);
|
struct annotation *notes = symbol__annotation(sym);
|
||||||
struct disasm_line *dl;
|
struct disasm_line *dl;
|
||||||
char *line = NULL, *parsed_line, *tmp, *tmp2;
|
char *line = NULL, *parsed_line, *tmp, *tmp2;
|
||||||
|
@ -1263,7 +1265,11 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
|
||||||
parsed_line = tmp2 + 1;
|
parsed_line = tmp2 + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
dl = disasm_line__new(offset, parsed_line, privsize, *line_nr, arch, map);
|
args->offset = offset;
|
||||||
|
args->line = parsed_line;
|
||||||
|
args->line_nr = *line_nr;
|
||||||
|
|
||||||
|
dl = disasm_line__new(args);
|
||||||
free(line);
|
free(line);
|
||||||
(*line_nr)++;
|
(*line_nr)++;
|
||||||
|
|
||||||
|
@ -1288,7 +1294,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
|
||||||
dl->ops.target.name = strdup(target.sym->name);
|
dl->ops.target.name = strdup(target.sym->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
disasm__add(¬es->src->source, dl);
|
annotation_line__add(&dl->al, ¬es->src->source);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1305,19 +1311,19 @@ static void delete_last_nop(struct symbol *sym)
|
||||||
struct disasm_line *dl;
|
struct disasm_line *dl;
|
||||||
|
|
||||||
while (!list_empty(list)) {
|
while (!list_empty(list)) {
|
||||||
dl = list_entry(list->prev, struct disasm_line, node);
|
dl = list_entry(list->prev, struct disasm_line, al.node);
|
||||||
|
|
||||||
if (dl->ins.ops) {
|
if (dl->ins.ops) {
|
||||||
if (dl->ins.ops != &nop_ops)
|
if (dl->ins.ops != &nop_ops)
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (!strstr(dl->line, " nop ") &&
|
if (!strstr(dl->al.line, " nop ") &&
|
||||||
!strstr(dl->line, " nopl ") &&
|
!strstr(dl->al.line, " nopl ") &&
|
||||||
!strstr(dl->line, " nopw "))
|
!strstr(dl->al.line, " nopw "))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_del(&dl->node);
|
list_del(&dl->al.node);
|
||||||
disasm_line__free(dl);
|
disasm_line__free(dl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1424,13 +1430,11 @@ static const char *annotate__norm_arch(const char *arch_name)
|
||||||
return normalize_arch((char *)arch_name);
|
return normalize_arch((char *)arch_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
int symbol__disassemble(struct symbol *sym, struct map *map,
|
static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
|
||||||
const char *arch_name, size_t privsize,
|
|
||||||
struct arch **parch, char *cpuid)
|
|
||||||
{
|
{
|
||||||
|
struct map *map = args->map;
|
||||||
struct dso *dso = map->dso;
|
struct dso *dso = map->dso;
|
||||||
char command[PATH_MAX * 2];
|
char command[PATH_MAX * 2];
|
||||||
struct arch *arch = NULL;
|
|
||||||
FILE *file;
|
FILE *file;
|
||||||
char symfs_filename[PATH_MAX];
|
char symfs_filename[PATH_MAX];
|
||||||
struct kcore_extract kce;
|
struct kcore_extract kce;
|
||||||
|
@ -1444,25 +1448,6 @@ int symbol__disassemble(struct symbol *sym, struct map *map,
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
arch_name = annotate__norm_arch(arch_name);
|
|
||||||
if (!arch_name)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
arch = arch__find(arch_name);
|
|
||||||
if (arch == NULL)
|
|
||||||
return -ENOTSUP;
|
|
||||||
|
|
||||||
if (parch)
|
|
||||||
*parch = arch;
|
|
||||||
|
|
||||||
if (arch->init) {
|
|
||||||
err = arch->init(arch, cpuid);
|
|
||||||
if (err) {
|
|
||||||
pr_err("%s: failed to initialize %s arch priv area\n", __func__, arch->name);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
|
pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
|
||||||
symfs_filename, sym->name, map->unmap_ip(map, sym->start),
|
symfs_filename, sym->name, map->unmap_ip(map, sym->start),
|
||||||
map->unmap_ip(map, sym->end));
|
map->unmap_ip(map, sym->end));
|
||||||
|
@ -1546,8 +1531,7 @@ int symbol__disassemble(struct symbol *sym, struct map *map,
|
||||||
* can associate it with the instructions till the next one.
|
* can associate it with the instructions till the next one.
|
||||||
* See disasm_line__new() and struct disasm_line::line_nr.
|
* See disasm_line__new() and struct disasm_line::line_nr.
|
||||||
*/
|
*/
|
||||||
if (symbol__parse_objdump_line(sym, map, arch, file, privsize,
|
if (symbol__parse_objdump_line(sym, file, args, &lineno) < 0)
|
||||||
&lineno) < 0)
|
|
||||||
break;
|
break;
|
||||||
nline++;
|
nline++;
|
||||||
}
|
}
|
||||||
|
@ -1580,21 +1564,113 @@ int symbol__disassemble(struct symbol *sym, struct map *map,
|
||||||
goto out_remove_tmp;
|
goto out_remove_tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void insert_source_line(struct rb_root *root, struct source_line *src_line)
|
static void calc_percent(struct sym_hist *hist,
|
||||||
|
struct annotation_data *sample,
|
||||||
|
s64 offset, s64 end)
|
||||||
{
|
{
|
||||||
struct source_line *iter;
|
unsigned int hits = 0;
|
||||||
|
u64 period = 0;
|
||||||
|
|
||||||
|
while (offset < end) {
|
||||||
|
hits += hist->addr[offset].nr_samples;
|
||||||
|
period += hist->addr[offset].period;
|
||||||
|
++offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hist->nr_samples) {
|
||||||
|
sample->he.period = period;
|
||||||
|
sample->he.nr_samples = hits;
|
||||||
|
sample->percent = 100.0 * hits / hist->nr_samples;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void annotation__calc_percent(struct annotation *notes,
|
||||||
|
struct perf_evsel *evsel, s64 len)
|
||||||
|
{
|
||||||
|
struct annotation_line *al, *next;
|
||||||
|
|
||||||
|
list_for_each_entry(al, ¬es->src->source, node) {
|
||||||
|
s64 end;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (al->offset == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
next = annotation_line__next(al, ¬es->src->source);
|
||||||
|
end = next ? next->offset : len;
|
||||||
|
|
||||||
|
for (i = 0; i < al->samples_nr; i++) {
|
||||||
|
struct annotation_data *sample;
|
||||||
|
struct sym_hist *hist;
|
||||||
|
|
||||||
|
hist = annotation__histogram(notes, evsel->idx + i);
|
||||||
|
sample = &al->samples[i];
|
||||||
|
|
||||||
|
calc_percent(hist, sample, al->offset, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel)
|
||||||
|
{
|
||||||
|
struct annotation *notes = symbol__annotation(sym);
|
||||||
|
|
||||||
|
annotation__calc_percent(notes, evsel, symbol__size(sym));
|
||||||
|
}
|
||||||
|
|
||||||
|
int symbol__annotate(struct symbol *sym, struct map *map,
|
||||||
|
struct perf_evsel *evsel, size_t privsize,
|
||||||
|
struct arch **parch, char *cpuid)
|
||||||
|
{
|
||||||
|
struct annotate_args args = {
|
||||||
|
.privsize = privsize,
|
||||||
|
.map = map,
|
||||||
|
.evsel = evsel,
|
||||||
|
};
|
||||||
|
const char *arch_name = NULL;
|
||||||
|
struct arch *arch;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (evsel)
|
||||||
|
arch_name = perf_evsel__env_arch(evsel);
|
||||||
|
|
||||||
|
arch_name = annotate__norm_arch(arch_name);
|
||||||
|
if (!arch_name)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
args.arch = arch = arch__find(arch_name);
|
||||||
|
if (arch == NULL)
|
||||||
|
return -ENOTSUP;
|
||||||
|
|
||||||
|
if (parch)
|
||||||
|
*parch = arch;
|
||||||
|
|
||||||
|
if (arch->init) {
|
||||||
|
err = arch->init(arch, cpuid);
|
||||||
|
if (err) {
|
||||||
|
pr_err("%s: failed to initialize %s arch priv area\n", __func__, arch->name);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return symbol__disassemble(sym, &args);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void insert_source_line(struct rb_root *root, struct annotation_line *al)
|
||||||
|
{
|
||||||
|
struct annotation_line *iter;
|
||||||
struct rb_node **p = &root->rb_node;
|
struct rb_node **p = &root->rb_node;
|
||||||
struct rb_node *parent = NULL;
|
struct rb_node *parent = NULL;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
while (*p != NULL) {
|
while (*p != NULL) {
|
||||||
parent = *p;
|
parent = *p;
|
||||||
iter = rb_entry(parent, struct source_line, node);
|
iter = rb_entry(parent, struct annotation_line, rb_node);
|
||||||
|
|
||||||
ret = strcmp(iter->path, src_line->path);
|
ret = strcmp(iter->path, al->path);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
for (i = 0; i < src_line->nr_pcnt; i++)
|
for (i = 0; i < al->samples_nr; i++)
|
||||||
iter->samples[i].percent_sum += src_line->samples[i].percent;
|
iter->samples[i].percent_sum += al->samples[i].percent;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1604,18 +1680,18 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
|
||||||
p = &(*p)->rb_right;
|
p = &(*p)->rb_right;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < src_line->nr_pcnt; i++)
|
for (i = 0; i < al->samples_nr; i++)
|
||||||
src_line->samples[i].percent_sum = src_line->samples[i].percent;
|
al->samples[i].percent_sum = al->samples[i].percent;
|
||||||
|
|
||||||
rb_link_node(&src_line->node, parent, p);
|
rb_link_node(&al->rb_node, parent, p);
|
||||||
rb_insert_color(&src_line->node, root);
|
rb_insert_color(&al->rb_node, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmp_source_line(struct source_line *a, struct source_line *b)
|
static int cmp_source_line(struct annotation_line *a, struct annotation_line *b)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < a->nr_pcnt; i++) {
|
for (i = 0; i < a->samples_nr; i++) {
|
||||||
if (a->samples[i].percent_sum == b->samples[i].percent_sum)
|
if (a->samples[i].percent_sum == b->samples[i].percent_sum)
|
||||||
continue;
|
continue;
|
||||||
return a->samples[i].percent_sum > b->samples[i].percent_sum;
|
return a->samples[i].percent_sum > b->samples[i].percent_sum;
|
||||||
|
@ -1624,135 +1700,47 @@ static int cmp_source_line(struct source_line *a, struct source_line *b)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __resort_source_line(struct rb_root *root, struct source_line *src_line)
|
static void __resort_source_line(struct rb_root *root, struct annotation_line *al)
|
||||||
{
|
{
|
||||||
struct source_line *iter;
|
struct annotation_line *iter;
|
||||||
struct rb_node **p = &root->rb_node;
|
struct rb_node **p = &root->rb_node;
|
||||||
struct rb_node *parent = NULL;
|
struct rb_node *parent = NULL;
|
||||||
|
|
||||||
while (*p != NULL) {
|
while (*p != NULL) {
|
||||||
parent = *p;
|
parent = *p;
|
||||||
iter = rb_entry(parent, struct source_line, node);
|
iter = rb_entry(parent, struct annotation_line, rb_node);
|
||||||
|
|
||||||
if (cmp_source_line(src_line, iter))
|
if (cmp_source_line(al, iter))
|
||||||
p = &(*p)->rb_left;
|
p = &(*p)->rb_left;
|
||||||
else
|
else
|
||||||
p = &(*p)->rb_right;
|
p = &(*p)->rb_right;
|
||||||
}
|
}
|
||||||
|
|
||||||
rb_link_node(&src_line->node, parent, p);
|
rb_link_node(&al->rb_node, parent, p);
|
||||||
rb_insert_color(&src_line->node, root);
|
rb_insert_color(&al->rb_node, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root)
|
static void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root)
|
||||||
{
|
{
|
||||||
struct source_line *src_line;
|
struct annotation_line *al;
|
||||||
struct rb_node *node;
|
struct rb_node *node;
|
||||||
|
|
||||||
node = rb_first(src_root);
|
node = rb_first(src_root);
|
||||||
while (node) {
|
while (node) {
|
||||||
struct rb_node *next;
|
struct rb_node *next;
|
||||||
|
|
||||||
src_line = rb_entry(node, struct source_line, node);
|
al = rb_entry(node, struct annotation_line, rb_node);
|
||||||
next = rb_next(node);
|
next = rb_next(node);
|
||||||
rb_erase(node, src_root);
|
rb_erase(node, src_root);
|
||||||
|
|
||||||
__resort_source_line(dest_root, src_line);
|
__resort_source_line(dest_root, al);
|
||||||
node = next;
|
node = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void symbol__free_source_line(struct symbol *sym, int len)
|
|
||||||
{
|
|
||||||
struct annotation *notes = symbol__annotation(sym);
|
|
||||||
struct source_line *src_line = notes->src->lines;
|
|
||||||
size_t sizeof_src_line;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
sizeof_src_line = sizeof(*src_line) +
|
|
||||||
(sizeof(src_line->samples) * (src_line->nr_pcnt - 1));
|
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
free_srcline(src_line->path);
|
|
||||||
src_line = (void *)src_line + sizeof_src_line;
|
|
||||||
}
|
|
||||||
|
|
||||||
zfree(¬es->src->lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the filename:line for the colored entries */
|
|
||||||
static int symbol__get_source_line(struct symbol *sym, struct map *map,
|
|
||||||
struct perf_evsel *evsel,
|
|
||||||
struct rb_root *root, int len)
|
|
||||||
{
|
|
||||||
u64 start;
|
|
||||||
int i, k;
|
|
||||||
int evidx = evsel->idx;
|
|
||||||
struct source_line *src_line;
|
|
||||||
struct annotation *notes = symbol__annotation(sym);
|
|
||||||
struct sym_hist *h = annotation__histogram(notes, evidx);
|
|
||||||
struct rb_root tmp_root = RB_ROOT;
|
|
||||||
int nr_pcnt = 1;
|
|
||||||
u64 nr_samples = h->nr_samples;
|
|
||||||
size_t sizeof_src_line = sizeof(struct source_line);
|
|
||||||
|
|
||||||
if (perf_evsel__is_group_event(evsel)) {
|
|
||||||
for (i = 1; i < evsel->nr_members; i++) {
|
|
||||||
h = annotation__histogram(notes, evidx + i);
|
|
||||||
nr_samples += h->nr_samples;
|
|
||||||
}
|
|
||||||
nr_pcnt = evsel->nr_members;
|
|
||||||
sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->samples);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nr_samples)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
src_line = notes->src->lines = calloc(len, sizeof_src_line);
|
|
||||||
if (!notes->src->lines)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
start = map__rip_2objdump(map, sym->start);
|
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
u64 offset;
|
|
||||||
double percent_max = 0.0;
|
|
||||||
|
|
||||||
src_line->nr_pcnt = nr_pcnt;
|
|
||||||
|
|
||||||
for (k = 0; k < nr_pcnt; k++) {
|
|
||||||
double percent = 0.0;
|
|
||||||
|
|
||||||
h = annotation__histogram(notes, evidx + k);
|
|
||||||
nr_samples = h->addr[i].nr_samples;
|
|
||||||
if (h->nr_samples)
|
|
||||||
percent = 100.0 * nr_samples / h->nr_samples;
|
|
||||||
|
|
||||||
if (percent > percent_max)
|
|
||||||
percent_max = percent;
|
|
||||||
src_line->samples[k].percent = percent;
|
|
||||||
src_line->samples[k].nr = nr_samples;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (percent_max <= 0.5)
|
|
||||||
goto next;
|
|
||||||
|
|
||||||
offset = start + i;
|
|
||||||
src_line->path = get_srcline(map->dso, offset, NULL,
|
|
||||||
false, true);
|
|
||||||
insert_source_line(&tmp_root, src_line);
|
|
||||||
|
|
||||||
next:
|
|
||||||
src_line = (void *)src_line + sizeof_src_line;
|
|
||||||
}
|
|
||||||
|
|
||||||
resort_source_line(root, &tmp_root);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_summary(struct rb_root *root, const char *filename)
|
static void print_summary(struct rb_root *root, const char *filename)
|
||||||
{
|
{
|
||||||
struct source_line *src_line;
|
struct annotation_line *al;
|
||||||
struct rb_node *node;
|
struct rb_node *node;
|
||||||
|
|
||||||
printf("\nSorted summary for file %s\n", filename);
|
printf("\nSorted summary for file %s\n", filename);
|
||||||
|
@ -1770,9 +1758,9 @@ static void print_summary(struct rb_root *root, const char *filename)
|
||||||
char *path;
|
char *path;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
src_line = rb_entry(node, struct source_line, node);
|
al = rb_entry(node, struct annotation_line, rb_node);
|
||||||
for (i = 0; i < src_line->nr_pcnt; i++) {
|
for (i = 0; i < al->samples_nr; i++) {
|
||||||
percent = src_line->samples[i].percent_sum;
|
percent = al->samples[i].percent_sum;
|
||||||
color = get_percent_color(percent);
|
color = get_percent_color(percent);
|
||||||
color_fprintf(stdout, color, " %7.2f", percent);
|
color_fprintf(stdout, color, " %7.2f", percent);
|
||||||
|
|
||||||
|
@ -1780,7 +1768,7 @@ static void print_summary(struct rb_root *root, const char *filename)
|
||||||
percent_max = percent;
|
percent_max = percent;
|
||||||
}
|
}
|
||||||
|
|
||||||
path = src_line->path;
|
path = al->path;
|
||||||
color = get_percent_color(percent_max);
|
color = get_percent_color(percent_max);
|
||||||
color_fprintf(stdout, color, " %s\n", path);
|
color_fprintf(stdout, color, " %s\n", path);
|
||||||
|
|
||||||
|
@ -1801,6 +1789,19 @@ static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel)
|
||||||
printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->nr_samples", h->nr_samples);
|
printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->nr_samples", h->nr_samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int annotated_source__addr_fmt_width(struct list_head *lines, u64 start)
|
||||||
|
{
|
||||||
|
char bf[32];
|
||||||
|
struct annotation_line *line;
|
||||||
|
|
||||||
|
list_for_each_entry_reverse(line, lines, node) {
|
||||||
|
if (line->offset != -1)
|
||||||
|
return scnprintf(bf, sizeof(bf), "%" PRIx64, start + line->offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int symbol__annotate_printf(struct symbol *sym, struct map *map,
|
int symbol__annotate_printf(struct symbol *sym, struct map *map,
|
||||||
struct perf_evsel *evsel, bool full_paths,
|
struct perf_evsel *evsel, bool full_paths,
|
||||||
int min_pcnt, int max_lines, int context)
|
int min_pcnt, int max_lines, int context)
|
||||||
|
@ -1811,9 +1812,9 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
|
||||||
const char *evsel_name = perf_evsel__name(evsel);
|
const char *evsel_name = perf_evsel__name(evsel);
|
||||||
struct annotation *notes = symbol__annotation(sym);
|
struct annotation *notes = symbol__annotation(sym);
|
||||||
struct sym_hist *h = annotation__histogram(notes, evsel->idx);
|
struct sym_hist *h = annotation__histogram(notes, evsel->idx);
|
||||||
struct disasm_line *pos, *queue = NULL;
|
struct annotation_line *pos, *queue = NULL;
|
||||||
u64 start = map__rip_2objdump(map, sym->start);
|
u64 start = map__rip_2objdump(map, sym->start);
|
||||||
int printed = 2, queue_len = 0;
|
int printed = 2, queue_len = 0, addr_fmt_width;
|
||||||
int more = 0;
|
int more = 0;
|
||||||
u64 len;
|
u64 len;
|
||||||
int width = symbol_conf.show_total_period ? 12 : 8;
|
int width = symbol_conf.show_total_period ? 12 : 8;
|
||||||
|
@ -1844,15 +1845,21 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
|
||||||
if (verbose > 0)
|
if (verbose > 0)
|
||||||
symbol__annotate_hits(sym, evsel);
|
symbol__annotate_hits(sym, evsel);
|
||||||
|
|
||||||
|
addr_fmt_width = annotated_source__addr_fmt_width(¬es->src->source, start);
|
||||||
|
|
||||||
list_for_each_entry(pos, ¬es->src->source, node) {
|
list_for_each_entry(pos, ¬es->src->source, node) {
|
||||||
|
int err;
|
||||||
|
|
||||||
if (context && queue == NULL) {
|
if (context && queue == NULL) {
|
||||||
queue = pos;
|
queue = pos;
|
||||||
queue_len = 0;
|
queue_len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (disasm_line__print(pos, sym, start, evsel, len,
|
err = annotation_line__print(pos, sym, start, evsel, len,
|
||||||
min_pcnt, printed, max_lines,
|
min_pcnt, printed, max_lines,
|
||||||
queue)) {
|
queue, addr_fmt_width);
|
||||||
|
|
||||||
|
switch (err) {
|
||||||
case 0:
|
case 0:
|
||||||
++printed;
|
++printed;
|
||||||
if (context) {
|
if (context) {
|
||||||
|
@ -1907,13 +1914,13 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void disasm__purge(struct list_head *head)
|
void annotated_source__purge(struct annotated_source *as)
|
||||||
{
|
{
|
||||||
struct disasm_line *pos, *n;
|
struct annotation_line *al, *n;
|
||||||
|
|
||||||
list_for_each_entry_safe(pos, n, head, node) {
|
list_for_each_entry_safe(al, n, &as->source, node) {
|
||||||
list_del(&pos->node);
|
list_del(&al->node);
|
||||||
disasm_line__free(pos);
|
disasm_line__free(disasm_line(al));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1921,10 +1928,10 @@ static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
|
||||||
{
|
{
|
||||||
size_t printed;
|
size_t printed;
|
||||||
|
|
||||||
if (dl->offset == -1)
|
if (dl->al.offset == -1)
|
||||||
return fprintf(fp, "%s\n", dl->line);
|
return fprintf(fp, "%s\n", dl->al.line);
|
||||||
|
|
||||||
printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->ins.name);
|
printed = fprintf(fp, "%#" PRIx64 " %s", dl->al.offset, dl->ins.name);
|
||||||
|
|
||||||
if (dl->ops.raw[0] != '\0') {
|
if (dl->ops.raw[0] != '\0') {
|
||||||
printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
|
printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
|
||||||
|
@ -1939,38 +1946,72 @@ size_t disasm__fprintf(struct list_head *head, FILE *fp)
|
||||||
struct disasm_line *pos;
|
struct disasm_line *pos;
|
||||||
size_t printed = 0;
|
size_t printed = 0;
|
||||||
|
|
||||||
list_for_each_entry(pos, head, node)
|
list_for_each_entry(pos, head, al.node)
|
||||||
printed += disasm_line__fprintf(pos, fp);
|
printed += disasm_line__fprintf(pos, fp);
|
||||||
|
|
||||||
return printed;
|
return printed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void annotation__calc_lines(struct annotation *notes, struct map *map,
|
||||||
|
struct rb_root *root, u64 start)
|
||||||
|
{
|
||||||
|
struct annotation_line *al;
|
||||||
|
struct rb_root tmp_root = RB_ROOT;
|
||||||
|
|
||||||
|
list_for_each_entry(al, ¬es->src->source, node) {
|
||||||
|
double percent_max = 0.0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < al->samples_nr; i++) {
|
||||||
|
struct annotation_data *sample;
|
||||||
|
|
||||||
|
sample = &al->samples[i];
|
||||||
|
|
||||||
|
if (sample->percent > percent_max)
|
||||||
|
percent_max = sample->percent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (percent_max <= 0.5)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
al->path = get_srcline(map->dso, start + al->offset, NULL, false, true);
|
||||||
|
insert_source_line(&tmp_root, al);
|
||||||
|
}
|
||||||
|
|
||||||
|
resort_source_line(root, &tmp_root);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void symbol__calc_lines(struct symbol *sym, struct map *map,
|
||||||
|
struct rb_root *root)
|
||||||
|
{
|
||||||
|
struct annotation *notes = symbol__annotation(sym);
|
||||||
|
u64 start = map__rip_2objdump(map, sym->start);
|
||||||
|
|
||||||
|
annotation__calc_lines(notes, map, root, start);
|
||||||
|
}
|
||||||
|
|
||||||
int symbol__tty_annotate(struct symbol *sym, struct map *map,
|
int symbol__tty_annotate(struct symbol *sym, struct map *map,
|
||||||
struct perf_evsel *evsel, bool print_lines,
|
struct perf_evsel *evsel, bool print_lines,
|
||||||
bool full_paths, int min_pcnt, int max_lines)
|
bool full_paths, int min_pcnt, int max_lines)
|
||||||
{
|
{
|
||||||
struct dso *dso = map->dso;
|
struct dso *dso = map->dso;
|
||||||
struct rb_root source_line = RB_ROOT;
|
struct rb_root source_line = RB_ROOT;
|
||||||
u64 len;
|
|
||||||
|
|
||||||
if (symbol__disassemble(sym, map, perf_evsel__env_arch(evsel),
|
if (symbol__annotate(sym, map, evsel, 0, NULL, NULL) < 0)
|
||||||
0, NULL, NULL) < 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
len = symbol__size(sym);
|
symbol__calc_percent(sym, evsel);
|
||||||
|
|
||||||
if (print_lines) {
|
if (print_lines) {
|
||||||
srcline_full_filename = full_paths;
|
srcline_full_filename = full_paths;
|
||||||
symbol__get_source_line(sym, map, evsel, &source_line, len);
|
symbol__calc_lines(sym, map, &source_line);
|
||||||
print_summary(&source_line, dso->long_name);
|
print_summary(&source_line, dso->long_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol__annotate_printf(sym, map, evsel, full_paths,
|
symbol__annotate_printf(sym, map, evsel, full_paths,
|
||||||
min_pcnt, max_lines, 0);
|
min_pcnt, max_lines, 0);
|
||||||
if (print_lines)
|
|
||||||
symbol__free_source_line(sym, len);
|
|
||||||
|
|
||||||
disasm__purge(&symbol__annotation(sym)->src->source);
|
annotated_source__purge(symbol__annotation(sym)->src);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,33 +59,55 @@ bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2);
|
||||||
|
|
||||||
struct annotation;
|
struct annotation;
|
||||||
|
|
||||||
struct disasm_line {
|
struct sym_hist_entry {
|
||||||
struct list_head node;
|
u64 nr_samples;
|
||||||
s64 offset;
|
u64 period;
|
||||||
char *line;
|
|
||||||
struct ins ins;
|
|
||||||
int line_nr;
|
|
||||||
float ipc;
|
|
||||||
u64 cycles;
|
|
||||||
struct ins_operands ops;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct annotation_data {
|
||||||
|
double percent;
|
||||||
|
double percent_sum;
|
||||||
|
struct sym_hist_entry he;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct annotation_line {
|
||||||
|
struct list_head node;
|
||||||
|
struct rb_node rb_node;
|
||||||
|
s64 offset;
|
||||||
|
char *line;
|
||||||
|
int line_nr;
|
||||||
|
float ipc;
|
||||||
|
u64 cycles;
|
||||||
|
size_t privsize;
|
||||||
|
char *path;
|
||||||
|
int samples_nr;
|
||||||
|
struct annotation_data samples[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct disasm_line {
|
||||||
|
struct ins ins;
|
||||||
|
struct ins_operands ops;
|
||||||
|
|
||||||
|
/* This needs to be at the end. */
|
||||||
|
struct annotation_line al;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct disasm_line *disasm_line(struct annotation_line *al)
|
||||||
|
{
|
||||||
|
return al ? container_of(al, struct disasm_line, al) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool disasm_line__has_offset(const struct disasm_line *dl)
|
static inline bool disasm_line__has_offset(const struct disasm_line *dl)
|
||||||
{
|
{
|
||||||
return dl->ops.target.offset_avail;
|
return dl->ops.target.offset_avail;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sym_hist_entry {
|
|
||||||
u64 nr_samples;
|
|
||||||
u64 period;
|
|
||||||
};
|
|
||||||
|
|
||||||
void disasm_line__free(struct disasm_line *dl);
|
void disasm_line__free(struct disasm_line *dl);
|
||||||
struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos);
|
struct annotation_line *
|
||||||
|
annotation_line__next(struct annotation_line *pos, struct list_head *head);
|
||||||
int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw);
|
int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw);
|
||||||
size_t disasm__fprintf(struct list_head *head, FILE *fp);
|
size_t disasm__fprintf(struct list_head *head, FILE *fp);
|
||||||
double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,
|
void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel);
|
||||||
s64 end, const char **path, struct sym_hist_entry *sample);
|
|
||||||
|
|
||||||
struct sym_hist {
|
struct sym_hist {
|
||||||
u64 nr_samples;
|
u64 nr_samples;
|
||||||
|
@ -104,19 +126,6 @@ struct cyc_hist {
|
||||||
u16 reset;
|
u16 reset;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct source_line_samples {
|
|
||||||
double percent;
|
|
||||||
double percent_sum;
|
|
||||||
u64 nr;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct source_line {
|
|
||||||
struct rb_node node;
|
|
||||||
char *path;
|
|
||||||
int nr_pcnt;
|
|
||||||
struct source_line_samples samples[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
/** struct annotated_source - symbols with hits have this attached as in sannotation
|
/** struct annotated_source - symbols with hits have this attached as in sannotation
|
||||||
*
|
*
|
||||||
* @histogram: Array of addr hit histograms per event being monitored
|
* @histogram: Array of addr hit histograms per event being monitored
|
||||||
|
@ -132,7 +141,6 @@ struct source_line {
|
||||||
*/
|
*/
|
||||||
struct annotated_source {
|
struct annotated_source {
|
||||||
struct list_head source;
|
struct list_head source;
|
||||||
struct source_line *lines;
|
|
||||||
int nr_histograms;
|
int nr_histograms;
|
||||||
size_t sizeof_sym_hist;
|
size_t sizeof_sym_hist;
|
||||||
struct cyc_hist *cycles_hist;
|
struct cyc_hist *cycles_hist;
|
||||||
|
@ -169,9 +177,9 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *samp
|
||||||
int symbol__alloc_hist(struct symbol *sym);
|
int symbol__alloc_hist(struct symbol *sym);
|
||||||
void symbol__annotate_zero_histograms(struct symbol *sym);
|
void symbol__annotate_zero_histograms(struct symbol *sym);
|
||||||
|
|
||||||
int symbol__disassemble(struct symbol *sym, struct map *map,
|
int symbol__annotate(struct symbol *sym, struct map *map,
|
||||||
const char *arch_name, size_t privsize,
|
struct perf_evsel *evsel, size_t privsize,
|
||||||
struct arch **parch, char *cpuid);
|
struct arch **parch, char *cpuid);
|
||||||
|
|
||||||
enum symbol_disassemble_errno {
|
enum symbol_disassemble_errno {
|
||||||
SYMBOL_ANNOTATE_ERRNO__SUCCESS = 0,
|
SYMBOL_ANNOTATE_ERRNO__SUCCESS = 0,
|
||||||
|
@ -198,7 +206,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
|
||||||
int min_pcnt, int max_lines, int context);
|
int min_pcnt, int max_lines, int context);
|
||||||
void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
|
void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
|
||||||
void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
|
void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
|
||||||
void disasm__purge(struct list_head *head);
|
void annotated_source__purge(struct annotated_source *as);
|
||||||
|
|
||||||
bool ui__has_annotation(void);
|
bool ui__has_annotation(void);
|
||||||
|
|
||||||
|
|
|
@ -257,7 +257,7 @@ int perf_evlist__add_dummy(struct perf_evlist *evlist)
|
||||||
.config = PERF_COUNT_SW_DUMMY,
|
.config = PERF_COUNT_SW_DUMMY,
|
||||||
.size = sizeof(attr), /* to capture ABI version */
|
.size = sizeof(attr), /* to capture ABI version */
|
||||||
};
|
};
|
||||||
struct perf_evsel *evsel = perf_evsel__new(&attr);
|
struct perf_evsel *evsel = perf_evsel__new_idx(&attr, evlist->nr_entries);
|
||||||
|
|
||||||
if (evsel == NULL)
|
if (evsel == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -1582,6 +1582,17 @@ int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *even
|
||||||
return perf_evsel__parse_sample(evsel, event, sample);
|
return perf_evsel__parse_sample(evsel, event, sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int perf_evlist__parse_sample_timestamp(struct perf_evlist *evlist,
|
||||||
|
union perf_event *event,
|
||||||
|
u64 *timestamp)
|
||||||
|
{
|
||||||
|
struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event);
|
||||||
|
|
||||||
|
if (!evsel)
|
||||||
|
return -EFAULT;
|
||||||
|
return perf_evsel__parse_sample_timestamp(evsel, event, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp)
|
size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp)
|
||||||
{
|
{
|
||||||
struct perf_evsel *evsel;
|
struct perf_evsel *evsel;
|
||||||
|
@ -1786,3 +1797,15 @@ void perf_evlist__toggle_bkw_mmap(struct perf_evlist *evlist,
|
||||||
state_err:
|
state_err:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool perf_evlist__exclude_kernel(struct perf_evlist *evlist)
|
||||||
|
{
|
||||||
|
struct perf_evsel *evsel;
|
||||||
|
|
||||||
|
evlist__for_each_entry(evlist, evsel) {
|
||||||
|
if (!evsel->attr.exclude_kernel)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -205,6 +205,10 @@ u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist);
|
||||||
int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
|
int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
|
||||||
struct perf_sample *sample);
|
struct perf_sample *sample);
|
||||||
|
|
||||||
|
int perf_evlist__parse_sample_timestamp(struct perf_evlist *evlist,
|
||||||
|
union perf_event *event,
|
||||||
|
u64 *timestamp);
|
||||||
|
|
||||||
bool perf_evlist__valid_sample_type(struct perf_evlist *evlist);
|
bool perf_evlist__valid_sample_type(struct perf_evlist *evlist);
|
||||||
bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist);
|
bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist);
|
||||||
bool perf_evlist__valid_read_format(struct perf_evlist *evlist);
|
bool perf_evlist__valid_read_format(struct perf_evlist *evlist);
|
||||||
|
@ -312,4 +316,6 @@ perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, const char *str);
|
||||||
|
|
||||||
struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist,
|
struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist,
|
||||||
union perf_event *event);
|
union perf_event *event);
|
||||||
|
|
||||||
|
bool perf_evlist__exclude_kernel(struct perf_evlist *evlist);
|
||||||
#endif /* __PERF_EVLIST_H */
|
#endif /* __PERF_EVLIST_H */
|
||||||
|
|
|
@ -733,12 +733,16 @@ static void apply_config_terms(struct perf_evsel *evsel,
|
||||||
list_for_each_entry(term, config_terms, list) {
|
list_for_each_entry(term, config_terms, list) {
|
||||||
switch (term->type) {
|
switch (term->type) {
|
||||||
case PERF_EVSEL__CONFIG_TERM_PERIOD:
|
case PERF_EVSEL__CONFIG_TERM_PERIOD:
|
||||||
attr->sample_period = term->val.period;
|
if (!(term->weak && opts->user_interval != ULLONG_MAX)) {
|
||||||
attr->freq = 0;
|
attr->sample_period = term->val.period;
|
||||||
|
attr->freq = 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case PERF_EVSEL__CONFIG_TERM_FREQ:
|
case PERF_EVSEL__CONFIG_TERM_FREQ:
|
||||||
attr->sample_freq = term->val.freq;
|
if (!(term->weak && opts->user_freq != UINT_MAX)) {
|
||||||
attr->freq = 1;
|
attr->sample_freq = term->val.freq;
|
||||||
|
attr->freq = 1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case PERF_EVSEL__CONFIG_TERM_TIME:
|
case PERF_EVSEL__CONFIG_TERM_TIME:
|
||||||
if (term->val.time)
|
if (term->val.time)
|
||||||
|
@ -775,6 +779,8 @@ static void apply_config_terms(struct perf_evsel *evsel,
|
||||||
case PERF_EVSEL__CONFIG_TERM_OVERWRITE:
|
case PERF_EVSEL__CONFIG_TERM_OVERWRITE:
|
||||||
attr->write_backward = term->val.overwrite ? 1 : 0;
|
attr->write_backward = term->val.overwrite ? 1 : 0;
|
||||||
break;
|
break;
|
||||||
|
case PERF_EVSEL__CONFIG_TERM_DRV_CFG:
|
||||||
|
BUG_ON(1);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1371,7 +1377,7 @@ perf_evsel__process_group_data(struct perf_evsel *leader,
|
||||||
static int
|
static int
|
||||||
perf_evsel__read_group(struct perf_evsel *leader, int cpu, int thread)
|
perf_evsel__read_group(struct perf_evsel *leader, int cpu, int thread)
|
||||||
{
|
{
|
||||||
struct perf_stat_evsel *ps = leader->priv;
|
struct perf_stat_evsel *ps = leader->stats;
|
||||||
u64 read_format = leader->attr.read_format;
|
u64 read_format = leader->attr.read_format;
|
||||||
int size = perf_evsel__read_size(leader);
|
int size = perf_evsel__read_size(leader);
|
||||||
u64 *data = ps->group_data;
|
u64 *data = ps->group_data;
|
||||||
|
@ -1956,6 +1962,20 @@ static inline bool overflow(const void *endp, u16 max_size, const void *offset,
|
||||||
#define OVERFLOW_CHECK_u64(offset) \
|
#define OVERFLOW_CHECK_u64(offset) \
|
||||||
OVERFLOW_CHECK(offset, sizeof(u64), sizeof(u64))
|
OVERFLOW_CHECK(offset, sizeof(u64), sizeof(u64))
|
||||||
|
|
||||||
|
static int
|
||||||
|
perf_event__check_size(union perf_event *event, unsigned int sample_size)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The evsel's sample_size is based on PERF_SAMPLE_MASK which includes
|
||||||
|
* up to PERF_SAMPLE_PERIOD. After that overflow() must be used to
|
||||||
|
* check the format does not go past the end of the event.
|
||||||
|
*/
|
||||||
|
if (sample_size + sizeof(event->header) > event->header.size)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
|
int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
|
||||||
struct perf_sample *data)
|
struct perf_sample *data)
|
||||||
{
|
{
|
||||||
|
@ -1977,6 +1997,8 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
|
||||||
data->stream_id = data->id = data->time = -1ULL;
|
data->stream_id = data->id = data->time = -1ULL;
|
||||||
data->period = evsel->attr.sample_period;
|
data->period = evsel->attr.sample_period;
|
||||||
data->cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
|
data->cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
|
||||||
|
data->id = -1ULL;
|
||||||
|
data->data_src = PERF_MEM_DATA_SRC_NONE;
|
||||||
|
|
||||||
if (event->header.type != PERF_RECORD_SAMPLE) {
|
if (event->header.type != PERF_RECORD_SAMPLE) {
|
||||||
if (!evsel->attr.sample_id_all)
|
if (!evsel->attr.sample_id_all)
|
||||||
|
@ -1986,15 +2008,9 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
|
||||||
|
|
||||||
array = event->sample.array;
|
array = event->sample.array;
|
||||||
|
|
||||||
/*
|
if (perf_event__check_size(event, evsel->sample_size))
|
||||||
* The evsel's sample_size is based on PERF_SAMPLE_MASK which includes
|
|
||||||
* up to PERF_SAMPLE_PERIOD. After that overflow() must be used to
|
|
||||||
* check the format does not go past the end of the event.
|
|
||||||
*/
|
|
||||||
if (evsel->sample_size + sizeof(event->header) > event->header.size)
|
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
data->id = -1ULL;
|
|
||||||
if (type & PERF_SAMPLE_IDENTIFIER) {
|
if (type & PERF_SAMPLE_IDENTIFIER) {
|
||||||
data->id = *array;
|
data->id = *array;
|
||||||
array++;
|
array++;
|
||||||
|
@ -2024,7 +2040,6 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
|
||||||
array++;
|
array++;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->addr = 0;
|
|
||||||
if (type & PERF_SAMPLE_ADDR) {
|
if (type & PERF_SAMPLE_ADDR) {
|
||||||
data->addr = *array;
|
data->addr = *array;
|
||||||
array++;
|
array++;
|
||||||
|
@ -2188,14 +2203,12 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
|
||||||
array++;
|
array++;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->data_src = PERF_MEM_DATA_SRC_NONE;
|
|
||||||
if (type & PERF_SAMPLE_DATA_SRC) {
|
if (type & PERF_SAMPLE_DATA_SRC) {
|
||||||
OVERFLOW_CHECK_u64(array);
|
OVERFLOW_CHECK_u64(array);
|
||||||
data->data_src = *array;
|
data->data_src = *array;
|
||||||
array++;
|
array++;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->transaction = 0;
|
|
||||||
if (type & PERF_SAMPLE_TRANSACTION) {
|
if (type & PERF_SAMPLE_TRANSACTION) {
|
||||||
OVERFLOW_CHECK_u64(array);
|
OVERFLOW_CHECK_u64(array);
|
||||||
data->transaction = *array;
|
data->transaction = *array;
|
||||||
|
@ -2228,6 +2241,50 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int perf_evsel__parse_sample_timestamp(struct perf_evsel *evsel,
|
||||||
|
union perf_event *event,
|
||||||
|
u64 *timestamp)
|
||||||
|
{
|
||||||
|
u64 type = evsel->attr.sample_type;
|
||||||
|
const u64 *array;
|
||||||
|
|
||||||
|
if (!(type & PERF_SAMPLE_TIME))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (event->header.type != PERF_RECORD_SAMPLE) {
|
||||||
|
struct perf_sample data = {
|
||||||
|
.time = -1ULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!evsel->attr.sample_id_all)
|
||||||
|
return -1;
|
||||||
|
if (perf_evsel__parse_id_sample(evsel, event, &data))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*timestamp = data.time;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
array = event->sample.array;
|
||||||
|
|
||||||
|
if (perf_event__check_size(event, evsel->sample_size))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (type & PERF_SAMPLE_IDENTIFIER)
|
||||||
|
array++;
|
||||||
|
|
||||||
|
if (type & PERF_SAMPLE_IP)
|
||||||
|
array++;
|
||||||
|
|
||||||
|
if (type & PERF_SAMPLE_TID)
|
||||||
|
array++;
|
||||||
|
|
||||||
|
if (type & PERF_SAMPLE_TIME)
|
||||||
|
*timestamp = *array;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
|
size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
|
||||||
u64 read_format)
|
u64 read_format)
|
||||||
{
|
{
|
||||||
|
@ -2739,8 +2796,9 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
|
||||||
break;
|
break;
|
||||||
case EOPNOTSUPP:
|
case EOPNOTSUPP:
|
||||||
if (evsel->attr.sample_period != 0)
|
if (evsel->attr.sample_period != 0)
|
||||||
return scnprintf(msg, size, "%s",
|
return scnprintf(msg, size,
|
||||||
"PMU Hardware doesn't support sampling/overflow-interrupts.");
|
"%s: PMU Hardware doesn't support sampling/overflow-interrupts. Try 'perf stat'",
|
||||||
|
perf_evsel__name(evsel));
|
||||||
if (evsel->attr.precise_ip)
|
if (evsel->attr.precise_ip)
|
||||||
return scnprintf(msg, size, "%s",
|
return scnprintf(msg, size, "%s",
|
||||||
"\'precise\' request may not be supported. Try removing 'p' modifier.");
|
"\'precise\' request may not be supported. Try removing 'p' modifier.");
|
||||||
|
|
|
@ -38,7 +38,7 @@ struct cgroup_sel;
|
||||||
* It is allocated within event parsing and attached to
|
* It is allocated within event parsing and attached to
|
||||||
* perf_evsel::config_terms list head.
|
* perf_evsel::config_terms list head.
|
||||||
*/
|
*/
|
||||||
enum {
|
enum term_type {
|
||||||
PERF_EVSEL__CONFIG_TERM_PERIOD,
|
PERF_EVSEL__CONFIG_TERM_PERIOD,
|
||||||
PERF_EVSEL__CONFIG_TERM_FREQ,
|
PERF_EVSEL__CONFIG_TERM_FREQ,
|
||||||
PERF_EVSEL__CONFIG_TERM_TIME,
|
PERF_EVSEL__CONFIG_TERM_TIME,
|
||||||
|
@ -49,12 +49,11 @@ enum {
|
||||||
PERF_EVSEL__CONFIG_TERM_OVERWRITE,
|
PERF_EVSEL__CONFIG_TERM_OVERWRITE,
|
||||||
PERF_EVSEL__CONFIG_TERM_DRV_CFG,
|
PERF_EVSEL__CONFIG_TERM_DRV_CFG,
|
||||||
PERF_EVSEL__CONFIG_TERM_BRANCH,
|
PERF_EVSEL__CONFIG_TERM_BRANCH,
|
||||||
PERF_EVSEL__CONFIG_TERM_MAX,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct perf_evsel_config_term {
|
struct perf_evsel_config_term {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
int type;
|
enum term_type type;
|
||||||
union {
|
union {
|
||||||
u64 period;
|
u64 period;
|
||||||
u64 freq;
|
u64 freq;
|
||||||
|
@ -67,6 +66,7 @@ struct perf_evsel_config_term {
|
||||||
bool overwrite;
|
bool overwrite;
|
||||||
char *branch;
|
char *branch;
|
||||||
} val;
|
} val;
|
||||||
|
bool weak;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct perf_stat_evsel;
|
struct perf_stat_evsel;
|
||||||
|
@ -338,6 +338,10 @@ static inline int perf_evsel__read_on_cpu_scaled(struct perf_evsel *evsel,
|
||||||
int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
|
int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
|
||||||
struct perf_sample *sample);
|
struct perf_sample *sample);
|
||||||
|
|
||||||
|
int perf_evsel__parse_sample_timestamp(struct perf_evsel *evsel,
|
||||||
|
union perf_event *event,
|
||||||
|
u64 *timestamp);
|
||||||
|
|
||||||
static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel)
|
static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel)
|
||||||
{
|
{
|
||||||
return list_entry(evsel->node.next, struct perf_evsel, node);
|
return list_entry(evsel->node.next, struct perf_evsel, node);
|
||||||
|
|
|
@ -172,6 +172,9 @@ void machine__exit(struct machine *machine)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (machine == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
machine__destroy_kernel_maps(machine);
|
machine__destroy_kernel_maps(machine);
|
||||||
map_groups__exit(&machine->kmaps);
|
map_groups__exit(&machine->kmaps);
|
||||||
dsos__exit(&machine->dsos);
|
dsos__exit(&machine->dsos);
|
||||||
|
@ -2201,7 +2204,7 @@ int thread__resolve_callchain(struct thread *thread,
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
callchain_cursor_reset(&callchain_cursor);
|
callchain_cursor_reset(cursor);
|
||||||
|
|
||||||
if (callchain_param.order == ORDER_CALLEE) {
|
if (callchain_param.order == ORDER_CALLEE) {
|
||||||
ret = thread__resolve_callchain_sample(thread, cursor,
|
ret = thread__resolve_callchain_sample(thread, cursor,
|
||||||
|
|
|
@ -157,9 +157,8 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *eve
|
||||||
}
|
}
|
||||||
|
|
||||||
int ordered_events__queue(struct ordered_events *oe, union perf_event *event,
|
int ordered_events__queue(struct ordered_events *oe, union perf_event *event,
|
||||||
struct perf_sample *sample, u64 file_offset)
|
u64 timestamp, u64 file_offset)
|
||||||
{
|
{
|
||||||
u64 timestamp = sample->time;
|
|
||||||
struct ordered_event *oevent;
|
struct ordered_event *oevent;
|
||||||
|
|
||||||
if (!timestamp || timestamp == ~0ULL)
|
if (!timestamp || timestamp == ~0ULL)
|
||||||
|
|
|
@ -45,7 +45,7 @@ struct ordered_events {
|
||||||
};
|
};
|
||||||
|
|
||||||
int ordered_events__queue(struct ordered_events *oe, union perf_event *event,
|
int ordered_events__queue(struct ordered_events *oe, union perf_event *event,
|
||||||
struct perf_sample *sample, u64 file_offset);
|
u64 timestamp, u64 file_offset);
|
||||||
void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event);
|
void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event);
|
||||||
int ordered_events__flush(struct ordered_events *oe, enum oe_flush how);
|
int ordered_events__flush(struct ordered_events *oe, enum oe_flush how);
|
||||||
void ordered_events__init(struct ordered_events *oe, ordered_events__deliver_t deliver);
|
void ordered_events__init(struct ordered_events *oe, ordered_events__deliver_t deliver);
|
||||||
|
|
|
@ -1116,6 +1116,7 @@ do { \
|
||||||
INIT_LIST_HEAD(&__t->list); \
|
INIT_LIST_HEAD(&__t->list); \
|
||||||
__t->type = PERF_EVSEL__CONFIG_TERM_ ## __type; \
|
__t->type = PERF_EVSEL__CONFIG_TERM_ ## __type; \
|
||||||
__t->val.__name = __val; \
|
__t->val.__name = __val; \
|
||||||
|
__t->weak = term->weak; \
|
||||||
list_add_tail(&__t->list, head_terms); \
|
list_add_tail(&__t->list, head_terms); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@ -2410,6 +2411,7 @@ static int new_term(struct parse_events_term **_term,
|
||||||
|
|
||||||
*term = *temp;
|
*term = *temp;
|
||||||
INIT_LIST_HEAD(&term->list);
|
INIT_LIST_HEAD(&term->list);
|
||||||
|
term->weak = false;
|
||||||
|
|
||||||
switch (term->type_val) {
|
switch (term->type_val) {
|
||||||
case PARSE_EVENTS__TERM_TYPE_NUM:
|
case PARSE_EVENTS__TERM_TYPE_NUM:
|
||||||
|
|
|
@ -101,6 +101,9 @@ struct parse_events_term {
|
||||||
/* error string indexes for within parsed string */
|
/* error string indexes for within parsed string */
|
||||||
int err_term;
|
int err_term;
|
||||||
int err_val;
|
int err_val;
|
||||||
|
|
||||||
|
/* Coming from implicit alias */
|
||||||
|
bool weak;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct parse_events_error {
|
struct parse_events_error {
|
||||||
|
|
|
@ -405,6 +405,11 @@ static int pmu_alias_terms(struct perf_pmu_alias *alias,
|
||||||
parse_events_terms__purge(&list);
|
parse_events_terms__purge(&list);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* Weak terms don't override command line options,
|
||||||
|
* which we don't want for implicit terms in aliases.
|
||||||
|
*/
|
||||||
|
cloned->weak = true;
|
||||||
list_add_tail(&cloned->list, &list);
|
list_add_tail(&cloned->list, &list);
|
||||||
}
|
}
|
||||||
list_splice(&list, terms);
|
list_splice(&list, terms);
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
|
|
||||||
static int perf_session__deliver_event(struct perf_session *session,
|
static int perf_session__deliver_event(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event,
|
||||||
struct perf_sample *sample,
|
|
||||||
struct perf_tool *tool,
|
struct perf_tool *tool,
|
||||||
u64 file_offset);
|
u64 file_offset);
|
||||||
|
|
||||||
|
@ -107,17 +106,10 @@ static void perf_session__set_comm_exec(struct perf_session *session)
|
||||||
static int ordered_events__deliver_event(struct ordered_events *oe,
|
static int ordered_events__deliver_event(struct ordered_events *oe,
|
||||||
struct ordered_event *event)
|
struct ordered_event *event)
|
||||||
{
|
{
|
||||||
struct perf_sample sample;
|
|
||||||
struct perf_session *session = container_of(oe, struct perf_session,
|
struct perf_session *session = container_of(oe, struct perf_session,
|
||||||
ordered_events);
|
ordered_events);
|
||||||
int ret = perf_evlist__parse_sample(session->evlist, event->event, &sample);
|
|
||||||
|
|
||||||
if (ret) {
|
return perf_session__deliver_event(session, event->event,
|
||||||
pr_err("Can't parse sample, err = %d\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return perf_session__deliver_event(session, event->event, &sample,
|
|
||||||
session->tool, event->file_offset);
|
session->tool, event->file_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -873,9 +865,9 @@ static int process_finished_round(struct perf_tool *tool __maybe_unused,
|
||||||
}
|
}
|
||||||
|
|
||||||
int perf_session__queue_event(struct perf_session *s, union perf_event *event,
|
int perf_session__queue_event(struct perf_session *s, union perf_event *event,
|
||||||
struct perf_sample *sample, u64 file_offset)
|
u64 timestamp, u64 file_offset)
|
||||||
{
|
{
|
||||||
return ordered_events__queue(&s->ordered_events, event, sample, file_offset);
|
return ordered_events__queue(&s->ordered_events, event, timestamp, file_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void callchain__lbr_callstack_printf(struct perf_sample *sample)
|
static void callchain__lbr_callstack_printf(struct perf_sample *sample)
|
||||||
|
@ -1328,20 +1320,26 @@ static int machines__deliver_event(struct machines *machines,
|
||||||
|
|
||||||
static int perf_session__deliver_event(struct perf_session *session,
|
static int perf_session__deliver_event(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event,
|
||||||
struct perf_sample *sample,
|
|
||||||
struct perf_tool *tool,
|
struct perf_tool *tool,
|
||||||
u64 file_offset)
|
u64 file_offset)
|
||||||
{
|
{
|
||||||
|
struct perf_sample sample;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = auxtrace__process_event(session, event, sample, tool);
|
ret = perf_evlist__parse_sample(session->evlist, event, &sample);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("Can't parse sample, err = %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = auxtrace__process_event(session, event, &sample, tool);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return machines__deliver_event(&session->machines, session->evlist,
|
return machines__deliver_event(&session->machines, session->evlist,
|
||||||
event, sample, tool, file_offset);
|
event, &sample, tool, file_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static s64 perf_session__process_user_event(struct perf_session *session,
|
static s64 perf_session__process_user_event(struct perf_session *session,
|
||||||
|
@ -1495,7 +1493,6 @@ static s64 perf_session__process_event(struct perf_session *session,
|
||||||
{
|
{
|
||||||
struct perf_evlist *evlist = session->evlist;
|
struct perf_evlist *evlist = session->evlist;
|
||||||
struct perf_tool *tool = session->tool;
|
struct perf_tool *tool = session->tool;
|
||||||
struct perf_sample sample;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (session->header.needs_swap)
|
if (session->header.needs_swap)
|
||||||
|
@ -1509,21 +1506,19 @@ static s64 perf_session__process_event(struct perf_session *session,
|
||||||
if (event->header.type >= PERF_RECORD_USER_TYPE_START)
|
if (event->header.type >= PERF_RECORD_USER_TYPE_START)
|
||||||
return perf_session__process_user_event(session, event, file_offset);
|
return perf_session__process_user_event(session, event, file_offset);
|
||||||
|
|
||||||
/*
|
|
||||||
* For all kernel events we get the sample data
|
|
||||||
*/
|
|
||||||
ret = perf_evlist__parse_sample(evlist, event, &sample);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (tool->ordered_events) {
|
if (tool->ordered_events) {
|
||||||
ret = perf_session__queue_event(session, event, &sample, file_offset);
|
u64 timestamp;
|
||||||
|
|
||||||
|
ret = perf_evlist__parse_sample_timestamp(evlist, event, ×tamp);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = perf_session__queue_event(session, event, timestamp, file_offset);
|
||||||
if (ret != -ETIME)
|
if (ret != -ETIME)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return perf_session__deliver_event(session, event, &sample, tool,
|
return perf_session__deliver_event(session, event, tool, file_offset);
|
||||||
file_offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void perf_event_header__bswap(struct perf_event_header *hdr)
|
void perf_event_header__bswap(struct perf_event_header *hdr)
|
||||||
|
|
|
@ -53,7 +53,7 @@ int perf_session__peek_event(struct perf_session *session, off_t file_offset,
|
||||||
int perf_session__process_events(struct perf_session *session);
|
int perf_session__process_events(struct perf_session *session);
|
||||||
|
|
||||||
int perf_session__queue_event(struct perf_session *s, union perf_event *event,
|
int perf_session__queue_event(struct perf_session *s, union perf_event *event,
|
||||||
struct perf_sample *sample, u64 file_offset);
|
u64 timestamp, u64 file_offset);
|
||||||
|
|
||||||
void perf_tool__fill_defaults(struct perf_tool *tool);
|
void perf_tool__fill_defaults(struct perf_tool *tool);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue