* [PATCH V8 0/7] Freq/CPU%/CORE_BUSY% support
@ 2015-09-03 12:30 kan.liang
2015-09-03 12:30 ` [PATCH V8 1/7] perf,tools: introduce generic FEAT for CPU attributes kan.liang
` (7 more replies)
0 siblings, 8 replies; 13+ messages in thread
From: kan.liang @ 2015-09-03 12:30 UTC (permalink / raw)
To: acme, jolsa
Cc: a.p.zijlstra, luto, mingo, eranian, ak, mark.rutland,
adrian.hunter, namhyung, linux-kernel, Kan Liang
From: Kan Liang <kan.liang@intel.com>
This patch set supports per-sample freq/CPU%/CORE_BUSY% print in perf
report -D and --stdio.
For printing these information, the perf.data file must have been obtained
by group read and using special events cycles, ref-cycles, msr/tsc/,
msr/aperf/ or msr/mperf/.
- Freq (MHz): The frequency during the sample interval. Needs cycles
ref-cycles event.
- CPU%: CPU utilization during the sample interval. Needs ref-cycles and
msr/tsc/ events.
- CORE_BUSY%: actual percent performance (APERF/MPERF%) during the
sample interval. Needs msr/aperf/ and msr/mperf/ events.
Here is an example:
$ perf record --freq-perf ~/tchain_edit
$ perf report --stdio --group --show-freq-perf
Overhead FREQ MHz CPU% CORE_BUSY%
Command Shared Object Symbol
........................................ ......... ..... ..........
........... ................ ......................
99.54% 99.54% 99.53% 99.53% 99.53% 2301 96 99
tchain_edit tchain_edit [.] f3
0.20% 0.20% 0.20% 0.20% 0.20% 2301 98 99
tchain_edit tchain_edit [.] f2
0.05% 0.05% 0.05% 0.05% 0.05% 2300 98 99
tchain_edit [kernel.vmlinux] [k] read_tsc
Changes since V1:
- Save cpu max freq to header when recording
- Read cpu max freq and msr type from header when reporting
Changes since V2:
- Introduce generic FEAT for CPU related data stored
- Make cpu max freq and msr type part of perf_session_env
- rename cpu_u to cpu_util
- Don't save sample value in perf_sample and discards new iterator.
Calculating the freq_perf_info in add_entry_cb callback
- Introduce symbol_conf.freq_perf_type for related hpp column visibility
Changes since V3:
- add a identifier 'tag' for CPU attributes, max frequency.
- add backpointers to evlist for env, and evsel for evlist.
- Use bitmask for freq_perf_type
- Replace macros by functions to caculate freq, cpu_util and core_busy
- Move all caculation codes under symbol_conf.show_freq_perf condition.
Changes since V4:
- Store cpu attributes id as tag and more readable cpu_attr
Changes since V5:
- Rename freq to max_freq and use it
- Add a loop in process_cpu_attributes to facility future extension
Changes since V6:
- Split rename perf_session_env and add backpointer to evlist patches
Changes since V7:
- Introduce --freq-perf option for perf record
- Factor out fix for dump_sample
Kan Liang (7):
perf,tools: introduce generic FEAT for CPU attributes
perf,tools: read msr pmu type from header.
perf,record: introduce --freq-perf option
perf,tools: fix dump_sample crash when evsel is NULL.
perf,tools: Dump per-sample freq/CPU%/CORE_BUSY% in report -D
perf,tools: caculate and save freq/CPU%/CORE_BUSY% in he_stat
perf,tools: Show freq/CPU%/CORE_BUSY% in perf report --stdio
tools/perf/Documentation/perf-record.txt | 4 ++
tools/perf/Documentation/perf-report.txt | 12 ++++++
tools/perf/builtin-record.c | 39 +++++++++++++++++-
tools/perf/builtin-report.c | 56 +++++++++++++++++++++++++
tools/perf/ui/hist.c | 71 +++++++++++++++++++++++++++++---
tools/perf/util/cpumap.c | 32 ++++++++++++++
tools/perf/util/cpumap.h | 1 +
tools/perf/util/header.c | 62 ++++++++++++++++++++++++++++
tools/perf/util/header.h | 13 ++++++
tools/perf/util/hist.h | 3 ++
tools/perf/util/session.c | 33 +++++++++++++--
tools/perf/util/session.h | 64 ++++++++++++++++++++++++++++
tools/perf/util/sort.c | 3 ++
tools/perf/util/sort.h | 3 ++
tools/perf/util/symbol.h | 12 +++++-
15 files changed, 397 insertions(+), 11 deletions(-)
--
1.8.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH V8 1/7] perf,tools: introduce generic FEAT for CPU attributes
2015-09-03 12:30 [PATCH V8 0/7] Freq/CPU%/CORE_BUSY% support kan.liang
@ 2015-09-03 12:30 ` kan.liang
2015-09-03 12:30 ` [PATCH V8 2/7] perf,tools: read msr pmu type from header kan.liang
` (6 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: kan.liang @ 2015-09-03 12:30 UTC (permalink / raw)
To: acme, jolsa
Cc: a.p.zijlstra, luto, mingo, eranian, ak, mark.rutland,
adrian.hunter, namhyung, linux-kernel, Kan Liang
From: Kan Liang <kan.liang@intel.com>
This patch introduces generic FEAT for CPU attributes. For the patch
set, we only need cpu max frequency. But it can be easily extented to
support more other CPU attributes.
The cpu max frequency is from the first online cpu.
Signed-off-by: Kan Liang <kan.liang@intel.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
---
tools/perf/util/cpumap.c | 32 ++++++++++++++++++++++++++
tools/perf/util/cpumap.h | 1 +
| 59 ++++++++++++++++++++++++++++++++++++++++++++++++
| 12 ++++++++++
4 files changed, 104 insertions(+)
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index a05d76a..671ee83 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -514,3 +514,35 @@ int cpu__setup_cpunode_map(void)
closedir(dir1);
return 0;
}
+
+u64 get_cpu_max_freq(void)
+{
+ const char *mnt;
+ char path[PATH_MAX], tmp;
+ FILE *fp;
+ u64 freq;
+ int cpu = 0;
+ int ret;
+
+ mnt = sysfs__mountpoint();
+ if (!mnt)
+ return 0;
+
+ snprintf(path, PATH_MAX, "%s/devices/system/cpu/online", mnt);
+ fp = fopen(path, "r");
+ if (fp) {
+ ret = fscanf(fp, "%u%c", &cpu, &tmp);
+ fclose(fp);
+ if (ret < 1)
+ return 0;
+ }
+
+ snprintf(path, PATH_MAX, "%s/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", mnt, cpu);
+ fp = fopen(path, "r");
+ if (!fp)
+ return 0;
+ ret = fscanf(fp, "%lu", &freq);
+ fclose(fp);
+
+ return (ret == 1) ? freq : 0;
+}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 8982d53..06cd2c4 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -60,6 +60,7 @@ int max_node_num;
int *cpunode_map;
int cpu__setup_cpunode_map(void);
+u64 get_cpu_max_freq(void);
static inline int cpu__max_node(void)
{
--git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 8fd7b7d..3535dcb 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -885,6 +885,23 @@ write_it:
return do_write_string(fd, buffer);
}
+static int write_cpu_attributes(int fd, struct perf_header *h __maybe_unused,
+ struct perf_evlist *evlist __maybe_unused)
+{
+ u32 tag_id;
+ u64 max_freq;
+ int ret;
+
+ tag_id = PERF_HEADER_CPU_MAX_FREQ;
+ ret = do_write(fd, &tag_id, sizeof(tag_id));
+ if (ret < 0)
+ return ret;
+
+ max_freq = get_cpu_max_freq();
+
+ return do_write(fd, &max_freq, sizeof(max_freq));
+}
+
static int write_branch_stack(int fd __maybe_unused,
struct perf_header *h __maybe_unused,
struct perf_evlist *evlist __maybe_unused)
@@ -1185,6 +1202,11 @@ static void print_cpuid(struct perf_header *ph, int fd __maybe_unused, FILE *fp)
fprintf(fp, "# cpuid : %s\n", ph->env.cpuid);
}
+static void print_cpu_attributes(struct perf_header *ph, int fd __maybe_unused, FILE *fp)
+{
+ fprintf(fp, "# CPU attributes: max frequency = %lu KHz\n", ph->env.cpuattr.max_freq);
+}
+
static void print_branch_stack(struct perf_header *ph __maybe_unused,
int fd __maybe_unused, FILE *fp)
{
@@ -1498,6 +1520,42 @@ static int process_cpuid(struct perf_file_section *section __maybe_unused,
return ph->env.cpuid ? 0 : -ENOMEM;
}
+static int process_cpu_attributes(struct perf_file_section *section __maybe_unused,
+ struct perf_header *ph, int fd,
+ void *data __maybe_unused)
+{
+ ssize_t ret;
+ u32 i, tag_id;
+ u64 nr;
+
+ for (i = 0; i < PERF_HEADER_CPU_ATTR_MAX; i++) {
+
+ ret = readn(fd, &tag_id, sizeof(tag_id));
+ if (ret != sizeof(tag_id))
+ return -1;
+
+ if (ph->needs_swap)
+ nr = bswap_32(tag_id);
+
+ if (tag_id >= PERF_HEADER_CPU_ATTR_MAX) {
+ pr_debug("The number of cpu attributes is not expected. "
+ "You may need to upgrade the perf tool.\n");
+ return -1;
+ }
+
+ ret = readn(fd, &nr, sizeof(nr));
+ if (ret != sizeof(nr))
+ return -1;
+
+ if (ph->needs_swap)
+ nr = bswap_64(nr);
+
+ ph->env.cpu_attr[tag_id] = nr;
+ }
+
+ return 0;
+}
+
static int process_total_mem(struct perf_file_section *section __maybe_unused,
struct perf_header *ph, int fd,
void *data __maybe_unused)
@@ -1983,6 +2041,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings),
FEAT_OPP(HEADER_GROUP_DESC, group_desc),
FEAT_OPP(HEADER_AUXTRACE, auxtrace),
+ FEAT_OPP(HEADER_CPU_ATTR, cpu_attributes),
};
struct header_print_data {
--git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 975d803..dd9f6b0 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -31,6 +31,7 @@ enum {
HEADER_PMU_MAPPINGS,
HEADER_GROUP_DESC,
HEADER_AUXTRACE,
+ HEADER_CPU_ATTR,
HEADER_LAST_FEATURE,
HEADER_FEAT_BITS = 256,
};
@@ -71,6 +72,11 @@ struct cpu_topology_map {
int core_id;
};
+enum perf_header_cpu_attr {
+ PERF_HEADER_CPU_MAX_FREQ = 0,
+ PERF_HEADER_CPU_ATTR_MAX,
+};
+
struct perf_env {
char *hostname;
char *os_release;
@@ -95,6 +101,12 @@ struct perf_env {
char *numa_nodes;
char *pmu_mappings;
struct cpu_topology_map *cpu;
+ union {
+ u64 cpu_attr[PERF_HEADER_CPU_ATTR_MAX];
+ struct {
+ u64 max_freq;
+ } cpuattr;
+ };
};
struct perf_header {
--
1.8.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH V8 2/7] perf,tools: read msr pmu type from header.
2015-09-03 12:30 [PATCH V8 0/7] Freq/CPU%/CORE_BUSY% support kan.liang
2015-09-03 12:30 ` [PATCH V8 1/7] perf,tools: introduce generic FEAT for CPU attributes kan.liang
@ 2015-09-03 12:30 ` kan.liang
2015-09-03 12:30 ` [PATCH V8 3/7] perf, record: introduce --freq-perf option kan.liang
` (5 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: kan.liang @ 2015-09-03 12:30 UTC (permalink / raw)
To: acme, jolsa
Cc: a.p.zijlstra, luto, mingo, eranian, ak, mark.rutland,
adrian.hunter, namhyung, linux-kernel, Kan Liang
From: Kan Liang <kan.liang@intel.com>
Get msr pmu type when processing pmu_mappings
Signed-off-by: Kan Liang <kan.liang@intel.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
---
| 3 +++
| 1 +
2 files changed, 4 insertions(+)
--git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 3535dcb..04f415d 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1879,6 +1879,9 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
/* include a NULL character at the end */
strbuf_add(&sb, "", 1);
+ if (!strcmp(name, "msr"))
+ ph->env.msr_pmu_type = type;
+
free(name);
pmu_num--;
}
--git a/tools/perf/util/header.h b/tools/perf/util/header.h
index dd9f6b0..d9034e8 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -107,6 +107,7 @@ struct perf_env {
u64 max_freq;
} cpuattr;
};
+ unsigned int msr_pmu_type;
};
struct perf_header {
--
1.8.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH V8 3/7] perf, record: introduce --freq-perf option
2015-09-03 12:30 [PATCH V8 0/7] Freq/CPU%/CORE_BUSY% support kan.liang
2015-09-03 12:30 ` [PATCH V8 1/7] perf,tools: introduce generic FEAT for CPU attributes kan.liang
2015-09-03 12:30 ` [PATCH V8 2/7] perf,tools: read msr pmu type from header kan.liang
@ 2015-09-03 12:30 ` kan.liang
2015-09-07 10:57 ` Jiri Olsa
2015-09-03 12:31 ` [PATCH V8 4/7] perf,tools: fix dump_sample crash when evsel is NULL kan.liang
` (4 subsequent siblings)
7 siblings, 1 reply; 13+ messages in thread
From: kan.liang @ 2015-09-03 12:30 UTC (permalink / raw)
To: acme, jolsa
Cc: a.p.zijlstra, luto, mingo, eranian, ak, mark.rutland,
adrian.hunter, namhyung, linux-kernel, Kan Liang
From: Kan Liang <kan.liang@intel.com>
To generate the frequency and performance output, perf must sample read
special events like cycles, ref-cycles, msr/tsc/, msr/aperf/ or
msr/mperf/.
With the --freq-perf option, perf record can automatically check and add
those event into evlist for sampling read.
Signed-off-by: Kan Liang <kan.liang@intel.com>
---
tools/perf/Documentation/perf-record.txt | 4 ++++
tools/perf/builtin-record.c | 39 +++++++++++++++++++++++++++++++-
tools/perf/util/session.h | 10 ++++++++
3 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 2e9ce77..3f40712 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -308,6 +308,10 @@ This option sets the time out limit. The default value is 500 ms.
Record context switch events i.e. events of type PERF_RECORD_SWITCH or
PERF_RECORD_SWITCH_CPU_WIDE.
+--freq-perf::
+Add frequency and performance related events to do sample read.
+These events include cycles, ref-cycles, msr/tsc/, msr/aperf/ and msr/mperf/.
+
SEE ALSO
--------
linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 142eeb3..e87dda3 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -13,7 +13,7 @@
#include "util/util.h"
#include "util/parse-options.h"
#include "util/parse-events.h"
-
+#include "util/pmu.h"
#include "util/callchain.h"
#include "util/cgroup.h"
#include "util/header.h"
@@ -50,6 +50,7 @@ struct record {
bool no_buildid;
bool no_buildid_cache;
long samples;
+ bool freq_perf;
};
static int record__write(struct record *rec, void *bf, size_t size)
@@ -948,6 +949,35 @@ out_free:
return ret;
}
+const char *freq_perf_events[FREQ_PERF_MAX][3] = {
+ { "msr", "tsc", "msr/tsc/" },
+ { "msr", "aperf", "msr/aperf/" },
+ { "msr", "mperf", "msr/mperf/" },
+ { NULL, "cycles", "cycles" },
+ { NULL, "ref-cycles", "ref-cycles" },
+};
+
+static int
+record_add_freq_perf_events(struct perf_evlist *evlist)
+{
+ int i;
+ char freq_perf_attrs[100];
+
+ strcpy(freq_perf_attrs, "{cycles,ref-cycles");
+ for (i = 0; i < FREQ_PERF_MAX; i++) {
+ if ((i == FREQ_PERF_CYCLES) ||
+ (i == FREQ_PERF_REF_CYCLES))
+ continue;
+ if (pmu_have_event(freq_perf_events[i][0], freq_perf_events[i][1])) {
+ strcat(freq_perf_attrs, ",");
+ strcat(freq_perf_attrs, freq_perf_events[i][2]);
+ }
+ }
+ strcat(freq_perf_attrs, "}:S");
+
+ return parse_events(evlist, freq_perf_attrs, NULL);
+}
+
static const char * const __record_usage[] = {
"perf record [<options>] [<command>]",
"perf record [<options>] -- <command> [<options>]",
@@ -1096,6 +1126,8 @@ struct option __record_options[] = {
"per thread proc mmap processing timeout in ms"),
OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
"Record context switch events"),
+ OPT_BOOLEAN(0, "freq-perf", &record.freq_perf,
+ "Add frequency and performance related events to do sample read."),
OPT_END()
};
@@ -1157,6 +1189,11 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
if (rec->no_buildid_cache || rec->no_buildid)
disable_buildid_cache();
+ if (rec->freq_perf && record_add_freq_perf_events(rec->evlist)) {
+ pr_err("Cannot set up freq and performance events\n");
+ goto out_symbol_exit;
+ }
+
if (rec->evlist->nr_entries == 0 &&
perf_evlist__add_default(rec->evlist) < 0) {
pr_err("Not enough memory for event selector list\n");
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index b44afc7..3915be7 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -42,6 +42,16 @@ struct perf_session {
#define PRINT_IP_OPT_ONELINE (1<<4)
#define PRINT_IP_OPT_SRCLINE (1<<5)
+enum perf_freq_perf_index {
+ FREQ_PERF_TSC = 0,
+ FREQ_PERF_APERF = 1,
+ FREQ_PERF_MPERF = 2,
+ FREQ_PERF_CYCLES = 3,
+ FREQ_PERF_REF_CYCLES = 4,
+
+ FREQ_PERF_MAX
+};
+
struct perf_tool;
struct perf_session *perf_session__new(struct perf_data_file *file,
--
1.8.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH V8 4/7] perf,tools: fix dump_sample crash when evsel is NULL.
2015-09-03 12:30 [PATCH V8 0/7] Freq/CPU%/CORE_BUSY% support kan.liang
` (2 preceding siblings ...)
2015-09-03 12:30 ` [PATCH V8 3/7] perf, record: introduce --freq-perf option kan.liang
@ 2015-09-03 12:31 ` kan.liang
2015-09-08 14:38 ` [tip:perf/core] perf session: Don't call dump_sample() " tip-bot for Kan Liang
2015-09-03 12:31 ` [PATCH V8 5/7] perf,tools: Dump per-sample freq/CPU%/CORE_BUSY% in report -D kan.liang
` (3 subsequent siblings)
7 siblings, 1 reply; 13+ messages in thread
From: kan.liang @ 2015-09-03 12:31 UTC (permalink / raw)
To: acme, jolsa
Cc: a.p.zijlstra, luto, mingo, eranian, ak, mark.rutland,
adrian.hunter, namhyung, linux-kernel, Kan Liang
From: Kan Liang <kan.liang@intel.com>
Need to check evsel before using in dump_sample.
Signed-off-by: Kan Liang <kan.liang@intel.com>
---
tools/perf/util/session.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 61669be..23fed17 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1080,11 +1080,11 @@ static int machines__deliver_event(struct machines *machines,
switch (event->header.type) {
case PERF_RECORD_SAMPLE:
- dump_sample(evsel, event, sample);
if (evsel == NULL) {
++evlist->stats.nr_unknown_id;
return 0;
}
+ dump_sample(evsel, event, sample);
if (machine == NULL) {
++evlist->stats.nr_unprocessable_samples;
return 0;
--
1.8.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH V8 5/7] perf,tools: Dump per-sample freq/CPU%/CORE_BUSY% in report -D
2015-09-03 12:30 [PATCH V8 0/7] Freq/CPU%/CORE_BUSY% support kan.liang
` (3 preceding siblings ...)
2015-09-03 12:31 ` [PATCH V8 4/7] perf,tools: fix dump_sample crash when evsel is NULL kan.liang
@ 2015-09-03 12:31 ` kan.liang
2015-09-03 12:31 ` [PATCH V8 6/7] perf,tools: caculate and save freq/CPU%/CORE_BUSY% in he_stat kan.liang
` (2 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: kan.liang @ 2015-09-03 12:31 UTC (permalink / raw)
To: acme, jolsa
Cc: a.p.zijlstra, luto, mingo, eranian, ak, mark.rutland,
adrian.hunter, namhyung, linux-kernel, Kan Liang
From: Kan Liang <kan.liang@intel.com>
The group read results from cycles/ref-cycles/TSC/ASTATE/MSTATE event
can be used to calculate the frequency, CPU Utilization and percent
performance during each sampling period.
This patch shows them in report -D.
Here is an example:
$ perf record --freq-perf ~/tchain_edit
Here is one sample from perf report -D
1972044565107 0x3498 [0x88]: PERF_RECORD_SAMPLE(IP, 0x2): 10608/10608:
0x4005fd period: 564686 addr: 0
... sample_read:
.... group nr 5
..... id 0000000000000012, value 0000000002143901
..... id 0000000000000052, value 0000000002143896
..... id 0000000000000094, value 00000000021e443d
..... id 00000000000000d4, value 00000000021db984
..... id 0000000000000114, value 00000000021db964
..... Freq 2301 MHz
..... CPU% 98%
..... CORE_BUSY% 99%
Signed-off-by: Kan Liang <kan.liang@intel.com>
---
tools/perf/util/session.c | 28 +++++++++++++++++++++---
tools/perf/util/session.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 79 insertions(+), 3 deletions(-)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 23fed17..ba763f7 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -7,7 +7,6 @@
#include <sys/mman.h>
#include "evlist.h"
-#include "evsel.h"
#include "session.h"
#include "tool.h"
#include "sort.h"
@@ -878,8 +877,15 @@ static void perf_evlist__print_tstamp(struct perf_evlist *evlist,
printf("%" PRIu64 " ", sample->time);
}
-static void sample_read__printf(struct perf_sample *sample, u64 read_format)
+static void sample_read__printf(struct perf_sample *sample,
+ struct perf_evsel *evsel)
{
+ u64 read_format = evsel->attr.read_format;
+ struct perf_evlist *evlist = evsel->evlist;
+ struct perf_sample_id *sid;
+ perf_freq_t data = { 0 };
+ u64 cpu_max_freq = evlist->env->cpuattr.max_freq;
+
printf("... sample_read:\n");
if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
@@ -902,10 +908,26 @@ static void sample_read__printf(struct perf_sample *sample, u64 read_format)
printf("..... id %016" PRIx64
", value %016" PRIx64 "\n",
value->id, value->value);
+
+ sid = perf_evlist__id2sid(evlist, value->id);
+ evsel = sid->evsel;
+ if (evsel != NULL)
+ perf_freq__init(evlist->env->msr_pmu_type,
+ evsel, data, value->value);
}
} else
printf("..... id %016" PRIx64 ", value %016" PRIx64 "\n",
sample->read.one.id, sample->read.one.value);
+
+ if (perf_freq__has_freq(data))
+ printf("..... Freq %lu MHz\n",
+ perf_freq__get_freq(data, cpu_max_freq/1000));
+ if (perf_freq__has_cpu_util(data))
+ printf("..... CPU%% %lu%%\n",
+ perf_freq__get_cpu_util(data));
+ if (perf_freq__has_core_busy(data))
+ printf("..... CORE_BUSY%% %lu%%\n",
+ perf_freq__get_core_busy(data));
}
static void dump_event(struct perf_evlist *evlist, union perf_event *event,
@@ -965,7 +987,7 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
printf("... transaction: %" PRIx64 "\n", sample->transaction);
if (sample_type & PERF_SAMPLE_READ)
- sample_read__printf(sample, evsel->attr.read_format);
+ sample_read__printf(sample, evsel);
}
static struct machine *machines__find_for_cpumode(struct machines *machines,
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 3915be7..83bf4a9 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -11,6 +11,7 @@
#include "ordered-events.h"
#include <linux/rbtree.h>
#include <linux/perf_event.h>
+#include "evsel.h"
struct ip_callchain;
struct thread;
@@ -42,6 +43,10 @@ struct perf_session {
#define PRINT_IP_OPT_ONELINE (1<<4)
#define PRINT_IP_OPT_SRCLINE (1<<5)
+#define PERF_MSR_TSC 0
+#define PERF_MSR_APERF 1
+#define PERF_MSR_MPERF 2
+
enum perf_freq_perf_index {
FREQ_PERF_TSC = 0,
FREQ_PERF_APERF = 1,
@@ -52,6 +57,55 @@ enum perf_freq_perf_index {
FREQ_PERF_MAX
};
+typedef u64 perf_freq_t[FREQ_PERF_MAX];
+
+static inline void perf_freq__init(unsigned int msr_pmu_type,
+ struct perf_evsel *evsel,
+ perf_freq_t array,
+ u64 value)
+{
+ if (evsel->attr.type == msr_pmu_type) {
+ if (evsel->attr.config == PERF_MSR_TSC)
+ array[FREQ_PERF_TSC] = value;
+ if (evsel->attr.config == PERF_MSR_APERF)
+ array[FREQ_PERF_APERF] = value;
+ if (evsel->attr.config == PERF_MSR_MPERF)
+ array[FREQ_PERF_MPERF] = value;
+ }
+ if (evsel->attr.type == PERF_TYPE_HARDWARE) {
+ if (evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES)
+ array[FREQ_PERF_CYCLES] = value;
+ if (evsel->attr.config == PERF_COUNT_HW_REF_CPU_CYCLES)
+ array[FREQ_PERF_REF_CYCLES] = value;
+ }
+}
+
+static inline bool perf_freq__has_freq(perf_freq_t array)
+{
+ return ((array[FREQ_PERF_CYCLES] > 0) && (array[FREQ_PERF_REF_CYCLES] > 0));
+}
+static inline u64 perf_freq__get_freq(perf_freq_t array, u64 cpu_max_freq)
+{
+ return ((array[FREQ_PERF_CYCLES] * cpu_max_freq) / array[FREQ_PERF_REF_CYCLES]);
+}
+static inline bool perf_freq__has_cpu_util(perf_freq_t array)
+{
+ return ((array[FREQ_PERF_TSC] > 0) && (array[FREQ_PERF_REF_CYCLES] > 0));
+}
+static inline u64 perf_freq__get_cpu_util(perf_freq_t array)
+{
+ return ((100 * array[FREQ_PERF_REF_CYCLES]) / array[FREQ_PERF_TSC]);
+}
+
+static inline bool perf_freq__has_core_busy(perf_freq_t array)
+{
+ return ((array[FREQ_PERF_APERF] > 0) && (array[FREQ_PERF_MPERF] > 0));
+}
+static inline u64 perf_freq__get_core_busy(perf_freq_t array)
+{
+ return ((100 * array[FREQ_PERF_APERF]) / array[FREQ_PERF_MPERF]);
+}
+
struct perf_tool;
struct perf_session *perf_session__new(struct perf_data_file *file,
--
1.8.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH V8 6/7] perf,tools: caculate and save freq/CPU%/CORE_BUSY% in he_stat
2015-09-03 12:30 [PATCH V8 0/7] Freq/CPU%/CORE_BUSY% support kan.liang
` (4 preceding siblings ...)
2015-09-03 12:31 ` [PATCH V8 5/7] perf,tools: Dump per-sample freq/CPU%/CORE_BUSY% in report -D kan.liang
@ 2015-09-03 12:31 ` kan.liang
2015-09-03 12:31 ` [PATCH V8 7/7] perf,tools: Show freq/CPU%/CORE_BUSY% in perf report --stdio kan.liang
2015-09-07 11:36 ` [PATCH V8 0/7] Freq/CPU%/CORE_BUSY% support Jiri Olsa
7 siblings, 0 replies; 13+ messages in thread
From: kan.liang @ 2015-09-03 12:31 UTC (permalink / raw)
To: acme, jolsa
Cc: a.p.zijlstra, luto, mingo, eranian, ak, mark.rutland,
adrian.hunter, namhyung, linux-kernel, Kan Liang
From: Kan Liang <kan.liang@intel.com>
Caculate freq/CPU%/CORE_BUSY% in add_entry_cb, and update the value in
he_stat.
Signed-off-by: Kan Liang <kan.liang@intel.com>
---
tools/perf/builtin-report.c | 36 ++++++++++++++++++++++++++++++++++++
tools/perf/util/sort.h | 3 +++
2 files changed, 39 insertions(+)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 62b285e..7673f1c 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -89,6 +89,38 @@ static int report__config(const char *var, const char *value, void *cb)
return perf_default_config(var, value, cb);
}
+static void set_he_freq_perf(struct perf_session *session,
+ struct hist_entry_iter *iter)
+{
+ struct hist_entry *he = iter->he;
+ struct perf_evsel *evsel = iter->evsel;
+ struct perf_evsel *leader = evsel;
+ struct perf_sample *sample = iter->sample;
+ struct perf_evlist *evlist = session->evlist;
+ u64 cpu_max_freq = session->header.env.cpuattr.max_freq;
+ perf_freq_t data = { 0 };
+ u64 nr = 0;
+
+ perf_freq__init(session->header.env.msr_pmu_type,
+ evsel, data,
+ sample->read.group.values[nr].value);
+ evlist__for_each_continue(evlist, evsel) {
+ if ((evsel->leader != leader) ||
+ (++nr >= sample->read.group.nr))
+ break;
+ perf_freq__init(session->header.env.msr_pmu_type,
+ evsel, data,
+ sample->read.group.values[nr].value);
+ }
+
+ if (perf_freq__has_freq(data))
+ he->stat.freq = perf_freq__get_freq(data, cpu_max_freq/1000);
+ if (perf_freq__has_cpu_util(data))
+ he->stat.cpu_util = perf_freq__get_cpu_util(data);
+ if (perf_freq__has_core_busy(data))
+ he->stat.core_busy = perf_freq__get_core_busy(data);
+}
+
static int hist_iter__report_callback(struct hist_entry_iter *iter,
struct addr_location *al, bool single,
void *arg)
@@ -100,6 +132,10 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter,
struct mem_info *mi;
struct branch_info *bi;
+ if ((iter->ops == &hist_iter_normal) &&
+ perf_evsel__is_group_leader(evsel))
+ set_he_freq_perf(rep->session, iter);
+
if (!ui__has_annotation())
return 0;
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 3c2a399..9ed52e6 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -54,6 +54,9 @@ struct he_stat {
u64 period_guest_us;
u64 weight;
u32 nr_events;
+ u64 freq;
+ u64 cpu_util;
+ u64 core_busy;
};
struct hist_entry_diff {
--
1.8.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH V8 7/7] perf,tools: Show freq/CPU%/CORE_BUSY% in perf report --stdio
2015-09-03 12:30 [PATCH V8 0/7] Freq/CPU%/CORE_BUSY% support kan.liang
` (5 preceding siblings ...)
2015-09-03 12:31 ` [PATCH V8 6/7] perf,tools: caculate and save freq/CPU%/CORE_BUSY% in he_stat kan.liang
@ 2015-09-03 12:31 ` kan.liang
2015-09-07 11:17 ` Jiri Olsa
2015-09-07 11:36 ` [PATCH V8 0/7] Freq/CPU%/CORE_BUSY% support Jiri Olsa
7 siblings, 1 reply; 13+ messages in thread
From: kan.liang @ 2015-09-03 12:31 UTC (permalink / raw)
To: acme, jolsa
Cc: a.p.zijlstra, luto, mingo, eranian, ak, mark.rutland,
adrian.hunter, namhyung, linux-kernel, Kan Liang
From: Kan Liang <kan.liang@intel.com>
Show frequency, CPU Utilization and percent performance for each symbol
in perf report by --stdio --show-freq-perf
In sampling group, only group leader do sampling. So only need to print
group leader's freq in --group.
Here is an example.
$ perf report --stdio --group --show-freq-perf
Overhead FREQ MHz CPU% CORE_BUSY%
Command Shared Object Symbol
........................................ ......... ..... ..........
........... ................ ......................
99.54% 99.54% 99.53% 99.53% 99.53% 2301 96 99
tchain_edit tchain_edit [.] f3
0.20% 0.20% 0.20% 0.20% 0.20% 2301 98 99
tchain_edit tchain_edit [.] f2
0.05% 0.05% 0.05% 0.05% 0.05% 2300 98 99
tchain_edit [kernel.vmlinux] [k] read_tsc
Signed-off-by: Kan Liang <kan.liang@intel.com>
---
tools/perf/Documentation/perf-report.txt | 12 ++++++
tools/perf/builtin-report.c | 22 +++++++++-
tools/perf/ui/hist.c | 71 +++++++++++++++++++++++++++++---
tools/perf/util/hist.h | 3 ++
tools/perf/util/session.c | 33 ++++++++-------
tools/perf/util/sort.c | 3 ++
tools/perf/util/symbol.h | 12 +++++-
7 files changed, 134 insertions(+), 22 deletions(-)
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 9c7981b..6280e22 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -306,6 +306,18 @@ OPTIONS
special event -e cpu/mem-loads/ or -e cpu/mem-stores/. See
'perf mem' for simpler access.
+--show-freq-perf::
+ Show CPU frequency and performance result from sample read.
+ To generate the frequency and performance output, the perf.data file
+ must have been obtained by group read and using special events cycles,
+ ref-cycles, msr/tsc/, msr/aperf/ or msr/mperf/
+ Freq MHz: The frequency during the sample interval. Needs cycles and
+ ref-cycles event.
+ CPU%: CPU utilization during the sample interval. Needs ref-cycles and
+ msr/tsc/ events.
+ CORE_BUSY%: actual percent performance (APERF/MPERF%) during the
+ sample interval. Needs msr/aperf/ and msr/mperf/ events.
+
--percent-limit::
Do not show entries which have an overhead under that percent.
(Default: 0).
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 7673f1c..ebcbe4c 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -133,7 +133,8 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter,
struct branch_info *bi;
if ((iter->ops == &hist_iter_normal) &&
- perf_evsel__is_group_leader(evsel))
+ perf_evsel__is_group_leader(evsel) &&
+ symbol_conf.show_freq_perf)
set_he_freq_perf(rep->session, iter);
if (!ui__has_annotation())
@@ -772,6 +773,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
"Enable kernel symbol demangling"),
OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
+ OPT_BOOLEAN(0, "show-freq-perf", &symbol_conf.show_freq_perf,
+ "show CPU freqency and performance info"),
OPT_CALLBACK(0, "percent-limit", &report, "percent",
"Don't show entries under that percent", parse_percent_limit),
OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
@@ -788,7 +791,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
struct perf_data_file file = {
.mode = PERF_DATA_MODE_READ,
};
+ struct perf_evsel *pos;
int ret = hists__init();
+ perf_freq_t freq_data_status = { 0 };
if (ret < 0)
return ret;
@@ -873,6 +878,21 @@ repeat:
symbol_conf.cumulate_callchain = false;
}
+
+ if (symbol_conf.show_freq_perf) {
+ symbol_conf.freq_perf_type = 0;
+ evlist__for_each(session->evlist, pos) {
+ perf_freq__init(session->header.env.msr_pmu_type,
+ pos, freq_data_status, 1);
+ }
+ if (perf_freq__has_freq(freq_data_status))
+ symbol_conf.freq_perf_type |= 1U << DISPLAY_FREQ;
+ if (perf_freq__has_cpu_util(freq_data_status))
+ symbol_conf.freq_perf_type |= 1U << DISPLAY_CPU_UTIL;
+ if (perf_freq__has_core_busy(freq_data_status))
+ symbol_conf.freq_perf_type |= 1U << DISPLAY_CORE_BUSY;
+ }
+
if (setup_sorting() < 0) {
if (sort_order)
parse_options_usage(report_usage, options, "s", 1);
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 25d6083..c2be455 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -17,7 +17,7 @@
static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
hpp_field_fn get_field, const char *fmt, int len,
- hpp_snprint_fn print_fn, bool fmt_percent)
+ hpp_snprint_fn print_fn, bool fmt_percent, bool single)
{
int ret;
struct hists *hists = he->hists;
@@ -36,7 +36,7 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
} else
ret = hpp__call_print_fn(hpp, print_fn, fmt, len, get_field(he));
- if (perf_evsel__is_group_event(evsel)) {
+ if (perf_evsel__is_group_event(evsel) && !single) {
int prev_idx, idx_delta;
struct hist_entry *pair;
int nr_members = evsel->nr_members;
@@ -109,10 +109,16 @@ int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent)
{
int len = fmt->user_len ?: fmt->len;
+ bool single = false;
+
+ if (((fmt == &perf_hpp__format[PERF_HPP__FREQ]) ||
+ (fmt == &perf_hpp__format[PERF_HPP__CPU_UTIL]) ||
+ (fmt == &perf_hpp__format[PERF_HPP__CORE_BUSY])))
+ single = true;
if (symbol_conf.field_sep) {
return __hpp__fmt(hpp, he, get_field, fmtstr, 1,
- print_fn, fmt_percent);
+ print_fn, fmt_percent, single);
}
if (fmt_percent)
@@ -120,7 +126,7 @@ int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
else
len -= 1;
- return __hpp__fmt(hpp, he, get_field, fmtstr, len, print_fn, fmt_percent);
+ return __hpp__fmt(hpp, he, get_field, fmtstr, len, print_fn, fmt_percent, single);
}
int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
@@ -234,6 +240,30 @@ static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name);
}
+static int hpp__single_width_fn(struct perf_hpp_fmt *fmt,
+ struct perf_hpp *hpp __maybe_unused,
+ struct perf_evsel *evsel)
+{
+ int len = fmt->user_len ?: fmt->len;
+
+ if (symbol_conf.event_group && !symbol_conf.show_freq_perf)
+ len = max(len, evsel->nr_members * fmt->len);
+
+ if (len < (int)strlen(fmt->name))
+ len = strlen(fmt->name);
+
+ return len;
+}
+
+static int hpp__single_header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+ struct perf_evsel *evsel)
+{
+ int len = hpp__single_width_fn(fmt, hpp, evsel);
+
+ return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name);
+}
+
+
static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)
{
va_list args;
@@ -363,6 +393,9 @@ HPP_PERCENT_ACC_FNS(overhead_acc, period)
HPP_RAW_FNS(samples, nr_events)
HPP_RAW_FNS(period, period)
+HPP_RAW_FNS(freq, freq)
+HPP_RAW_FNS(cpu_util, cpu_util)
+HPP_RAW_FNS(core_busy, core_busy)
static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
struct hist_entry *a __maybe_unused,
@@ -395,6 +428,17 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
.sort = hpp__sort_ ## _fn, \
}
+#define HPP__SINGLE_PRINT_FNS(_name, _fn) \
+ { \
+ .name = _name, \
+ .header = hpp__single_header_fn, \
+ .width = hpp__single_width_fn, \
+ .entry = hpp__entry_ ## _fn, \
+ .cmp = hpp__nop_cmp, \
+ .collapse = hpp__nop_cmp, \
+ .sort = hpp__sort_ ## _fn, \
+ }
+
#define HPP__PRINT_FNS(_name, _fn) \
{ \
.name = _name, \
@@ -414,7 +458,10 @@ struct perf_hpp_fmt perf_hpp__format[] = {
HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us),
HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc),
HPP__PRINT_FNS("Samples", samples),
- HPP__PRINT_FNS("Period", period)
+ HPP__PRINT_FNS("Period", period),
+ HPP__SINGLE_PRINT_FNS("FREQ MHz", freq),
+ HPP__SINGLE_PRINT_FNS("CPU%", cpu_util),
+ HPP__SINGLE_PRINT_FNS("CORE_BUSY%", core_busy)
};
LIST_HEAD(perf_hpp__list);
@@ -485,6 +532,15 @@ void perf_hpp__init(void)
if (symbol_conf.show_total_period)
perf_hpp__column_enable(PERF_HPP__PERIOD);
+ if (symbol_conf.show_freq_perf) {
+ if (symbol_conf.freq_perf_type & (1U << DISPLAY_FREQ))
+ perf_hpp__column_enable(PERF_HPP__FREQ);
+ if (symbol_conf.freq_perf_type & (1U << DISPLAY_CPU_UTIL))
+ perf_hpp__column_enable(PERF_HPP__CPU_UTIL);
+ if (symbol_conf.freq_perf_type & (1U << DISPLAY_CORE_BUSY))
+ perf_hpp__column_enable(PERF_HPP__CORE_BUSY);
+ }
+
/* prepend overhead field for backward compatiblity. */
list = &perf_hpp__format[PERF_HPP__OVERHEAD].sort_list;
if (list_empty(list))
@@ -652,6 +708,9 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
return;
switch (idx) {
+ case PERF_HPP__CPU_UTIL:
+ fmt->len = 5;
+ break;
case PERF_HPP__OVERHEAD:
case PERF_HPP__OVERHEAD_SYS:
case PERF_HPP__OVERHEAD_US:
@@ -661,6 +720,8 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
case PERF_HPP__OVERHEAD_GUEST_SYS:
case PERF_HPP__OVERHEAD_GUEST_US:
+ case PERF_HPP__FREQ:
+ case PERF_HPP__CORE_BUSY:
fmt->len = 9;
break;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index de6d58e..df07f28 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -237,6 +237,9 @@ enum {
PERF_HPP__OVERHEAD_ACC,
PERF_HPP__SAMPLES,
PERF_HPP__PERIOD,
+ PERF_HPP__FREQ,
+ PERF_HPP__CPU_UTIL,
+ PERF_HPP__CORE_BUSY,
PERF_HPP__MAX_INDEX
};
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index ba763f7..071fe65 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -908,26 +908,29 @@ static void sample_read__printf(struct perf_sample *sample,
printf("..... id %016" PRIx64
", value %016" PRIx64 "\n",
value->id, value->value);
-
- sid = perf_evlist__id2sid(evlist, value->id);
- evsel = sid->evsel;
- if (evsel != NULL)
- perf_freq__init(evlist->env->msr_pmu_type,
- evsel, data, value->value);
+ if (symbol_conf.show_freq_perf) {
+ sid = perf_evlist__id2sid(evlist, value->id);
+ evsel = sid->evsel;
+ if (evsel != NULL)
+ perf_freq__init(evlist->env->msr_pmu_type,
+ evsel, data, value->value);
+ }
}
} else
printf("..... id %016" PRIx64 ", value %016" PRIx64 "\n",
sample->read.one.id, sample->read.one.value);
- if (perf_freq__has_freq(data))
- printf("..... Freq %lu MHz\n",
- perf_freq__get_freq(data, cpu_max_freq/1000));
- if (perf_freq__has_cpu_util(data))
- printf("..... CPU%% %lu%%\n",
- perf_freq__get_cpu_util(data));
- if (perf_freq__has_core_busy(data))
- printf("..... CORE_BUSY%% %lu%%\n",
- perf_freq__get_core_busy(data));
+ if (symbol_conf.show_freq_perf) {
+ if (perf_freq__has_freq(data))
+ printf("..... Freq %lu MHz\n",
+ perf_freq__get_freq(data, cpu_max_freq/1000));
+ if (perf_freq__has_cpu_util(data))
+ printf("..... CPU%% %lu%%\n",
+ perf_freq__get_cpu_util(data));
+ if (perf_freq__has_core_busy(data))
+ printf("..... CORE_BUSY%% %lu%%\n",
+ perf_freq__get_core_busy(data));
+ }
}
static void dump_event(struct perf_evlist *evlist, union perf_event *event,
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index a97bcee..1d5c7d8 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1303,6 +1303,9 @@ static struct hpp_dimension hpp_sort_dimensions[] = {
DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
DIM(PERF_HPP__SAMPLES, "sample"),
DIM(PERF_HPP__PERIOD, "period"),
+ DIM(PERF_HPP__FREQ, "freq"),
+ DIM(PERF_HPP__CPU_UTIL, "cpu_u"),
+ DIM(PERF_HPP__CORE_BUSY, "core_busy"),
};
#undef DIM
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 440ba8a..8b21fb4 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -80,6 +80,14 @@ static inline size_t symbol__size(const struct symbol *sym)
struct strlist;
struct intlist;
+enum freq_perf_type_index {
+ DISPLAY_FREQ = 0,
+ DISPLAY_CPU_UTIL,
+ DISPLAY_CORE_BUSY,
+
+ DISPLAY_MAX
+};
+
struct symbol_conf {
unsigned short priv_size;
unsigned short nr_events;
@@ -107,7 +115,8 @@ struct symbol_conf {
show_hist_headers,
branch_callstack,
has_filter,
- show_ref_callgraph;
+ show_ref_callgraph,
+ show_freq_perf;
const char *vmlinux_name,
*kallsyms_name,
*source_prefix,
@@ -132,6 +141,7 @@ struct symbol_conf {
struct intlist *pid_list,
*tid_list;
const char *symfs;
+ u64 freq_perf_type;
};
extern struct symbol_conf symbol_conf;
--
1.8.3.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH V8 3/7] perf, record: introduce --freq-perf option
2015-09-03 12:30 ` [PATCH V8 3/7] perf, record: introduce --freq-perf option kan.liang
@ 2015-09-07 10:57 ` Jiri Olsa
2015-09-08 15:21 ` Liang, Kan
0 siblings, 1 reply; 13+ messages in thread
From: Jiri Olsa @ 2015-09-07 10:57 UTC (permalink / raw)
To: kan.liang
Cc: acme, jolsa, a.p.zijlstra, luto, mingo, eranian, ak,
mark.rutland, adrian.hunter, namhyung, linux-kernel
On Thu, Sep 03, 2015 at 08:30:59AM -0400, kan.liang@intel.com wrote:
> From: Kan Liang <kan.liang@intel.com>
>
> To generate the frequency and performance output, perf must sample read
> special events like cycles, ref-cycles, msr/tsc/, msr/aperf/ or
> msr/mperf/.
> With the --freq-perf option, perf record can automatically check and add
> those event into evlist for sampling read.
hum, not sure this is a big or small thing:
[jolsa@ibm-x3650m4-01 perf]$ ./perf record --freq-perf -e cache-misses ls
SNIP
[ perf record: Woken up 13 times to write data ]
[ perf record: Captured and wrote 0.014 MB perf.data (147 samples) ]
[jolsa@ibm-x3650m4-01 perf]$ ./perf report -D
non matching read_format[jolsa@ibm-x3650m4-01 perf]$
jirka
>
> Signed-off-by: Kan Liang <kan.liang@intel.com>
> ---
> tools/perf/Documentation/perf-record.txt | 4 ++++
> tools/perf/builtin-record.c | 39 +++++++++++++++++++++++++++++++-
> tools/perf/util/session.h | 10 ++++++++
> 3 files changed, 52 insertions(+), 1 deletion(-)
>
> diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
> index 2e9ce77..3f40712 100644
> --- a/tools/perf/Documentation/perf-record.txt
> +++ b/tools/perf/Documentation/perf-record.txt
> @@ -308,6 +308,10 @@ This option sets the time out limit. The default value is 500 ms.
> Record context switch events i.e. events of type PERF_RECORD_SWITCH or
> PERF_RECORD_SWITCH_CPU_WIDE.
>
> +--freq-perf::
> +Add frequency and performance related events to do sample read.
> +These events include cycles, ref-cycles, msr/tsc/, msr/aperf/ and msr/mperf/.
> +
> SEE ALSO
> --------
> linkperf:perf-stat[1], linkperf:perf-list[1]
> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
> index 142eeb3..e87dda3 100644
> --- a/tools/perf/builtin-record.c
> +++ b/tools/perf/builtin-record.c
> @@ -13,7 +13,7 @@
> #include "util/util.h"
> #include "util/parse-options.h"
> #include "util/parse-events.h"
> -
> +#include "util/pmu.h"
> #include "util/callchain.h"
> #include "util/cgroup.h"
> #include "util/header.h"
> @@ -50,6 +50,7 @@ struct record {
> bool no_buildid;
> bool no_buildid_cache;
> long samples;
> + bool freq_perf;
> };
>
> static int record__write(struct record *rec, void *bf, size_t size)
> @@ -948,6 +949,35 @@ out_free:
> return ret;
> }
>
> +const char *freq_perf_events[FREQ_PERF_MAX][3] = {
> + { "msr", "tsc", "msr/tsc/" },
> + { "msr", "aperf", "msr/aperf/" },
> + { "msr", "mperf", "msr/mperf/" },
> + { NULL, "cycles", "cycles" },
> + { NULL, "ref-cycles", "ref-cycles" },
> +};
> +
> +static int
> +record_add_freq_perf_events(struct perf_evlist *evlist)
> +{
> + int i;
> + char freq_perf_attrs[100];
> +
> + strcpy(freq_perf_attrs, "{cycles,ref-cycles");
> + for (i = 0; i < FREQ_PERF_MAX; i++) {
> + if ((i == FREQ_PERF_CYCLES) ||
> + (i == FREQ_PERF_REF_CYCLES))
> + continue;
> + if (pmu_have_event(freq_perf_events[i][0], freq_perf_events[i][1])) {
> + strcat(freq_perf_attrs, ",");
> + strcat(freq_perf_attrs, freq_perf_events[i][2]);
> + }
> + }
> + strcat(freq_perf_attrs, "}:S");
> +
> + return parse_events(evlist, freq_perf_attrs, NULL);
> +}
> +
> static const char * const __record_usage[] = {
> "perf record [<options>] [<command>]",
> "perf record [<options>] -- <command> [<options>]",
> @@ -1096,6 +1126,8 @@ struct option __record_options[] = {
> "per thread proc mmap processing timeout in ms"),
> OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
> "Record context switch events"),
> + OPT_BOOLEAN(0, "freq-perf", &record.freq_perf,
> + "Add frequency and performance related events to do sample read."),
> OPT_END()
> };
>
> @@ -1157,6 +1189,11 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
> if (rec->no_buildid_cache || rec->no_buildid)
> disable_buildid_cache();
>
> + if (rec->freq_perf && record_add_freq_perf_events(rec->evlist)) {
> + pr_err("Cannot set up freq and performance events\n");
> + goto out_symbol_exit;
> + }
> +
> if (rec->evlist->nr_entries == 0 &&
> perf_evlist__add_default(rec->evlist) < 0) {
> pr_err("Not enough memory for event selector list\n");
> diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
> index b44afc7..3915be7 100644
> --- a/tools/perf/util/session.h
> +++ b/tools/perf/util/session.h
> @@ -42,6 +42,16 @@ struct perf_session {
> #define PRINT_IP_OPT_ONELINE (1<<4)
> #define PRINT_IP_OPT_SRCLINE (1<<5)
>
> +enum perf_freq_perf_index {
> + FREQ_PERF_TSC = 0,
> + FREQ_PERF_APERF = 1,
> + FREQ_PERF_MPERF = 2,
> + FREQ_PERF_CYCLES = 3,
> + FREQ_PERF_REF_CYCLES = 4,
> +
> + FREQ_PERF_MAX
> +};
> +
> struct perf_tool;
>
> struct perf_session *perf_session__new(struct perf_data_file *file,
> --
> 1.8.3.1
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH V8 7/7] perf,tools: Show freq/CPU%/CORE_BUSY% in perf report --stdio
2015-09-03 12:31 ` [PATCH V8 7/7] perf,tools: Show freq/CPU%/CORE_BUSY% in perf report --stdio kan.liang
@ 2015-09-07 11:17 ` Jiri Olsa
0 siblings, 0 replies; 13+ messages in thread
From: Jiri Olsa @ 2015-09-07 11:17 UTC (permalink / raw)
To: kan.liang
Cc: acme, jolsa, a.p.zijlstra, luto, mingo, eranian, ak,
mark.rutland, adrian.hunter, namhyung, linux-kernel
On Thu, Sep 03, 2015 at 08:31:03AM -0400, kan.liang@intel.com wrote:
> From: Kan Liang <kan.liang@intel.com>
>
> Show frequency, CPU Utilization and percent performance for each symbol
> in perf report by --stdio --show-freq-perf
>
> In sampling group, only group leader do sampling. So only need to print
> group leader's freq in --group.
>
> Here is an example.
>
> $ perf report --stdio --group --show-freq-perf
Ithink the --show-freq-perf option should imply --group, so user would type:
perf record --freq-perf
perf report --show-freq-perf
I wonder we should use --freq-perf for report as well 'perf report --freq-perf'
jirka
>
> Overhead FREQ MHz CPU% CORE_BUSY%
> Command Shared Object Symbol
> ........................................ ......... ..... ..........
> ........... ................ ......................
>
> 99.54% 99.54% 99.53% 99.53% 99.53% 2301 96 99
> tchain_edit tchain_edit [.] f3
> 0.20% 0.20% 0.20% 0.20% 0.20% 2301 98 99
> tchain_edit tchain_edit [.] f2
> 0.05% 0.05% 0.05% 0.05% 0.05% 2300 98 99
> tchain_edit [kernel.vmlinux] [k] read_tsc
>
> Signed-off-by: Kan Liang <kan.liang@intel.com>
> ---
> tools/perf/Documentation/perf-report.txt | 12 ++++++
> tools/perf/builtin-report.c | 22 +++++++++-
> tools/perf/ui/hist.c | 71 +++++++++++++++++++++++++++++---
> tools/perf/util/hist.h | 3 ++
> tools/perf/util/session.c | 33 ++++++++-------
> tools/perf/util/sort.c | 3 ++
> tools/perf/util/symbol.h | 12 +++++-
> 7 files changed, 134 insertions(+), 22 deletions(-)
>
> diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
> index 9c7981b..6280e22 100644
> --- a/tools/perf/Documentation/perf-report.txt
> +++ b/tools/perf/Documentation/perf-report.txt
> @@ -306,6 +306,18 @@ OPTIONS
> special event -e cpu/mem-loads/ or -e cpu/mem-stores/. See
> 'perf mem' for simpler access.
>
> +--show-freq-perf::
> + Show CPU frequency and performance result from sample read.
> + To generate the frequency and performance output, the perf.data file
> + must have been obtained by group read and using special events cycles,
> + ref-cycles, msr/tsc/, msr/aperf/ or msr/mperf/
> + Freq MHz: The frequency during the sample interval. Needs cycles and
> + ref-cycles event.
> + CPU%: CPU utilization during the sample interval. Needs ref-cycles and
> + msr/tsc/ events.
> + CORE_BUSY%: actual percent performance (APERF/MPERF%) during the
> + sample interval. Needs msr/aperf/ and msr/mperf/ events.
> +
> --percent-limit::
> Do not show entries which have an overhead under that percent.
> (Default: 0).
> diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
> index 7673f1c..ebcbe4c 100644
> --- a/tools/perf/builtin-report.c
> +++ b/tools/perf/builtin-report.c
> @@ -133,7 +133,8 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter,
> struct branch_info *bi;
>
> if ((iter->ops == &hist_iter_normal) &&
> - perf_evsel__is_group_leader(evsel))
> + perf_evsel__is_group_leader(evsel) &&
> + symbol_conf.show_freq_perf)
> set_he_freq_perf(rep->session, iter);
>
> if (!ui__has_annotation())
> @@ -772,6 +773,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
> OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
> "Enable kernel symbol demangling"),
> OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
> + OPT_BOOLEAN(0, "show-freq-perf", &symbol_conf.show_freq_perf,
> + "show CPU freqency and performance info"),
> OPT_CALLBACK(0, "percent-limit", &report, "percent",
> "Don't show entries under that percent", parse_percent_limit),
> OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
> @@ -788,7 +791,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
> struct perf_data_file file = {
> .mode = PERF_DATA_MODE_READ,
> };
> + struct perf_evsel *pos;
> int ret = hists__init();
> + perf_freq_t freq_data_status = { 0 };
>
> if (ret < 0)
> return ret;
> @@ -873,6 +878,21 @@ repeat:
> symbol_conf.cumulate_callchain = false;
> }
>
> +
> + if (symbol_conf.show_freq_perf) {
> + symbol_conf.freq_perf_type = 0;
> + evlist__for_each(session->evlist, pos) {
> + perf_freq__init(session->header.env.msr_pmu_type,
> + pos, freq_data_status, 1);
> + }
> + if (perf_freq__has_freq(freq_data_status))
> + symbol_conf.freq_perf_type |= 1U << DISPLAY_FREQ;
> + if (perf_freq__has_cpu_util(freq_data_status))
> + symbol_conf.freq_perf_type |= 1U << DISPLAY_CPU_UTIL;
> + if (perf_freq__has_core_busy(freq_data_status))
> + symbol_conf.freq_perf_type |= 1U << DISPLAY_CORE_BUSY;
> + }
> +
> if (setup_sorting() < 0) {
> if (sort_order)
> parse_options_usage(report_usage, options, "s", 1);
> diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
> index 25d6083..c2be455 100644
> --- a/tools/perf/ui/hist.c
> +++ b/tools/perf/ui/hist.c
> @@ -17,7 +17,7 @@
>
> static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
> hpp_field_fn get_field, const char *fmt, int len,
> - hpp_snprint_fn print_fn, bool fmt_percent)
> + hpp_snprint_fn print_fn, bool fmt_percent, bool single)
> {
> int ret;
> struct hists *hists = he->hists;
> @@ -36,7 +36,7 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
> } else
> ret = hpp__call_print_fn(hpp, print_fn, fmt, len, get_field(he));
>
> - if (perf_evsel__is_group_event(evsel)) {
> + if (perf_evsel__is_group_event(evsel) && !single) {
> int prev_idx, idx_delta;
> struct hist_entry *pair;
> int nr_members = evsel->nr_members;
> @@ -109,10 +109,16 @@ int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
> const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent)
> {
> int len = fmt->user_len ?: fmt->len;
> + bool single = false;
> +
> + if (((fmt == &perf_hpp__format[PERF_HPP__FREQ]) ||
> + (fmt == &perf_hpp__format[PERF_HPP__CPU_UTIL]) ||
> + (fmt == &perf_hpp__format[PERF_HPP__CORE_BUSY])))
> + single = true;
>
> if (symbol_conf.field_sep) {
> return __hpp__fmt(hpp, he, get_field, fmtstr, 1,
> - print_fn, fmt_percent);
> + print_fn, fmt_percent, single);
> }
>
> if (fmt_percent)
> @@ -120,7 +126,7 @@ int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
> else
> len -= 1;
>
> - return __hpp__fmt(hpp, he, get_field, fmtstr, len, print_fn, fmt_percent);
> + return __hpp__fmt(hpp, he, get_field, fmtstr, len, print_fn, fmt_percent, single);
> }
>
> int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
> @@ -234,6 +240,30 @@ static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
> return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name);
> }
>
> +static int hpp__single_width_fn(struct perf_hpp_fmt *fmt,
> + struct perf_hpp *hpp __maybe_unused,
> + struct perf_evsel *evsel)
> +{
> + int len = fmt->user_len ?: fmt->len;
> +
> + if (symbol_conf.event_group && !symbol_conf.show_freq_perf)
> + len = max(len, evsel->nr_members * fmt->len);
> +
> + if (len < (int)strlen(fmt->name))
> + len = strlen(fmt->name);
> +
> + return len;
> +}
> +
> +static int hpp__single_header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
> + struct perf_evsel *evsel)
> +{
> + int len = hpp__single_width_fn(fmt, hpp, evsel);
> +
> + return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name);
> +}
> +
> +
> static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)
> {
> va_list args;
> @@ -363,6 +393,9 @@ HPP_PERCENT_ACC_FNS(overhead_acc, period)
>
> HPP_RAW_FNS(samples, nr_events)
> HPP_RAW_FNS(period, period)
> +HPP_RAW_FNS(freq, freq)
> +HPP_RAW_FNS(cpu_util, cpu_util)
> +HPP_RAW_FNS(core_busy, core_busy)
>
> static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
> struct hist_entry *a __maybe_unused,
> @@ -395,6 +428,17 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
> .sort = hpp__sort_ ## _fn, \
> }
>
> +#define HPP__SINGLE_PRINT_FNS(_name, _fn) \
> + { \
> + .name = _name, \
> + .header = hpp__single_header_fn, \
> + .width = hpp__single_width_fn, \
> + .entry = hpp__entry_ ## _fn, \
> + .cmp = hpp__nop_cmp, \
> + .collapse = hpp__nop_cmp, \
> + .sort = hpp__sort_ ## _fn, \
> + }
> +
> #define HPP__PRINT_FNS(_name, _fn) \
> { \
> .name = _name, \
> @@ -414,7 +458,10 @@ struct perf_hpp_fmt perf_hpp__format[] = {
> HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us),
> HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc),
> HPP__PRINT_FNS("Samples", samples),
> - HPP__PRINT_FNS("Period", period)
> + HPP__PRINT_FNS("Period", period),
> + HPP__SINGLE_PRINT_FNS("FREQ MHz", freq),
> + HPP__SINGLE_PRINT_FNS("CPU%", cpu_util),
> + HPP__SINGLE_PRINT_FNS("CORE_BUSY%", core_busy)
> };
>
> LIST_HEAD(perf_hpp__list);
> @@ -485,6 +532,15 @@ void perf_hpp__init(void)
> if (symbol_conf.show_total_period)
> perf_hpp__column_enable(PERF_HPP__PERIOD);
>
> + if (symbol_conf.show_freq_perf) {
> + if (symbol_conf.freq_perf_type & (1U << DISPLAY_FREQ))
> + perf_hpp__column_enable(PERF_HPP__FREQ);
> + if (symbol_conf.freq_perf_type & (1U << DISPLAY_CPU_UTIL))
> + perf_hpp__column_enable(PERF_HPP__CPU_UTIL);
> + if (symbol_conf.freq_perf_type & (1U << DISPLAY_CORE_BUSY))
> + perf_hpp__column_enable(PERF_HPP__CORE_BUSY);
> + }
> +
> /* prepend overhead field for backward compatiblity. */
> list = &perf_hpp__format[PERF_HPP__OVERHEAD].sort_list;
> if (list_empty(list))
> @@ -652,6 +708,9 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
> return;
>
> switch (idx) {
> + case PERF_HPP__CPU_UTIL:
> + fmt->len = 5;
> + break;
> case PERF_HPP__OVERHEAD:
> case PERF_HPP__OVERHEAD_SYS:
> case PERF_HPP__OVERHEAD_US:
> @@ -661,6 +720,8 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
>
> case PERF_HPP__OVERHEAD_GUEST_SYS:
> case PERF_HPP__OVERHEAD_GUEST_US:
> + case PERF_HPP__FREQ:
> + case PERF_HPP__CORE_BUSY:
> fmt->len = 9;
> break;
>
> diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
> index de6d58e..df07f28 100644
> --- a/tools/perf/util/hist.h
> +++ b/tools/perf/util/hist.h
> @@ -237,6 +237,9 @@ enum {
> PERF_HPP__OVERHEAD_ACC,
> PERF_HPP__SAMPLES,
> PERF_HPP__PERIOD,
> + PERF_HPP__FREQ,
> + PERF_HPP__CPU_UTIL,
> + PERF_HPP__CORE_BUSY,
>
> PERF_HPP__MAX_INDEX
> };
> diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
> index ba763f7..071fe65 100644
> --- a/tools/perf/util/session.c
> +++ b/tools/perf/util/session.c
> @@ -908,26 +908,29 @@ static void sample_read__printf(struct perf_sample *sample,
> printf("..... id %016" PRIx64
> ", value %016" PRIx64 "\n",
> value->id, value->value);
> -
> - sid = perf_evlist__id2sid(evlist, value->id);
> - evsel = sid->evsel;
> - if (evsel != NULL)
> - perf_freq__init(evlist->env->msr_pmu_type,
> - evsel, data, value->value);
> + if (symbol_conf.show_freq_perf) {
> + sid = perf_evlist__id2sid(evlist, value->id);
> + evsel = sid->evsel;
> + if (evsel != NULL)
> + perf_freq__init(evlist->env->msr_pmu_type,
> + evsel, data, value->value);
> + }
> }
> } else
> printf("..... id %016" PRIx64 ", value %016" PRIx64 "\n",
> sample->read.one.id, sample->read.one.value);
>
> - if (perf_freq__has_freq(data))
> - printf("..... Freq %lu MHz\n",
> - perf_freq__get_freq(data, cpu_max_freq/1000));
> - if (perf_freq__has_cpu_util(data))
> - printf("..... CPU%% %lu%%\n",
> - perf_freq__get_cpu_util(data));
> - if (perf_freq__has_core_busy(data))
> - printf("..... CORE_BUSY%% %lu%%\n",
> - perf_freq__get_core_busy(data));
> + if (symbol_conf.show_freq_perf) {
> + if (perf_freq__has_freq(data))
> + printf("..... Freq %lu MHz\n",
> + perf_freq__get_freq(data, cpu_max_freq/1000));
> + if (perf_freq__has_cpu_util(data))
> + printf("..... CPU%% %lu%%\n",
> + perf_freq__get_cpu_util(data));
> + if (perf_freq__has_core_busy(data))
> + printf("..... CORE_BUSY%% %lu%%\n",
> + perf_freq__get_core_busy(data));
> + }
> }
>
> static void dump_event(struct perf_evlist *evlist, union perf_event *event,
> diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
> index a97bcee..1d5c7d8 100644
> --- a/tools/perf/util/sort.c
> +++ b/tools/perf/util/sort.c
> @@ -1303,6 +1303,9 @@ static struct hpp_dimension hpp_sort_dimensions[] = {
> DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
> DIM(PERF_HPP__SAMPLES, "sample"),
> DIM(PERF_HPP__PERIOD, "period"),
> + DIM(PERF_HPP__FREQ, "freq"),
> + DIM(PERF_HPP__CPU_UTIL, "cpu_u"),
> + DIM(PERF_HPP__CORE_BUSY, "core_busy"),
> };
>
> #undef DIM
> diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
> index 440ba8a..8b21fb4 100644
> --- a/tools/perf/util/symbol.h
> +++ b/tools/perf/util/symbol.h
> @@ -80,6 +80,14 @@ static inline size_t symbol__size(const struct symbol *sym)
> struct strlist;
> struct intlist;
>
> +enum freq_perf_type_index {
> + DISPLAY_FREQ = 0,
> + DISPLAY_CPU_UTIL,
> + DISPLAY_CORE_BUSY,
> +
> + DISPLAY_MAX
> +};
> +
> struct symbol_conf {
> unsigned short priv_size;
> unsigned short nr_events;
> @@ -107,7 +115,8 @@ struct symbol_conf {
> show_hist_headers,
> branch_callstack,
> has_filter,
> - show_ref_callgraph;
> + show_ref_callgraph,
> + show_freq_perf;
> const char *vmlinux_name,
> *kallsyms_name,
> *source_prefix,
> @@ -132,6 +141,7 @@ struct symbol_conf {
> struct intlist *pid_list,
> *tid_list;
> const char *symfs;
> + u64 freq_perf_type;
> };
>
> extern struct symbol_conf symbol_conf;
> --
> 1.8.3.1
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH V8 0/7] Freq/CPU%/CORE_BUSY% support
2015-09-03 12:30 [PATCH V8 0/7] Freq/CPU%/CORE_BUSY% support kan.liang
` (6 preceding siblings ...)
2015-09-03 12:31 ` [PATCH V8 7/7] perf,tools: Show freq/CPU%/CORE_BUSY% in perf report --stdio kan.liang
@ 2015-09-07 11:36 ` Jiri Olsa
7 siblings, 0 replies; 13+ messages in thread
From: Jiri Olsa @ 2015-09-07 11:36 UTC (permalink / raw)
To: kan.liang
Cc: acme, jolsa, a.p.zijlstra, luto, mingo, eranian, ak,
mark.rutland, adrian.hunter, namhyung, linux-kernel
On Thu, Sep 03, 2015 at 08:30:56AM -0400, kan.liang@intel.com wrote:
> From: Kan Liang <kan.liang@intel.com>
>
> This patch set supports per-sample freq/CPU%/CORE_BUSY% print in perf
> report -D and --stdio.
> For printing these information, the perf.data file must have been obtained
> by group read and using special events cycles, ref-cycles, msr/tsc/,
> msr/aperf/ or msr/mperf/.
>
> - Freq (MHz): The frequency during the sample interval. Needs cycles
> ref-cycles event.
> - CPU%: CPU utilization during the sample interval. Needs ref-cycles and
> msr/tsc/ events.
> - CORE_BUSY%: actual percent performance (APERF/MPERF%) during the
> sample interval. Needs msr/aperf/ and msr/mperf/ events.
>
> Here is an example:
other than my latest 2 comments, I'm ok with the patchset
jirka
^ permalink raw reply [flat|nested] 13+ messages in thread
* [tip:perf/core] perf session: Don't call dump_sample() when evsel is NULL
2015-09-03 12:31 ` [PATCH V8 4/7] perf,tools: fix dump_sample crash when evsel is NULL kan.liang
@ 2015-09-08 14:38 ` tip-bot for Kan Liang
0 siblings, 0 replies; 13+ messages in thread
From: tip-bot for Kan Liang @ 2015-09-08 14:38 UTC (permalink / raw)
To: linux-tip-commits
Cc: acme, jolsa, luto, adrian.hunter, linux-kernel, mark.rutland,
mingo, a.p.zijlstra, eranian, ak, hpa, kan.liang, tglx, namhyung
Commit-ID: 1b29ac59b1d692c06ec543a5f35e0d9ebb98e003
Gitweb: http://git.kernel.org/tip/1b29ac59b1d692c06ec543a5f35e0d9ebb98e003
Author: Kan Liang <kan.liang@intel.com>
AuthorDate: Thu, 3 Sep 2015 08:31:00 -0400
Committer: Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Fri, 4 Sep 2015 12:01:04 -0300
perf session: Don't call dump_sample() when evsel is NULL
Need to check evsel before passing it to dump_sample().
Signed-off-by: Kan Liang <kan.liang@intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1441283463-51050-5-git-send-email-kan.liang@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/session.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 61669be..23fed17 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1080,11 +1080,11 @@ static int machines__deliver_event(struct machines *machines,
switch (event->header.type) {
case PERF_RECORD_SAMPLE:
- dump_sample(evsel, event, sample);
if (evsel == NULL) {
++evlist->stats.nr_unknown_id;
return 0;
}
+ dump_sample(evsel, event, sample);
if (machine == NULL) {
++evlist->stats.nr_unprocessable_samples;
return 0;
^ permalink raw reply [flat|nested] 13+ messages in thread
* RE: [PATCH V8 3/7] perf, record: introduce --freq-perf option
2015-09-07 10:57 ` Jiri Olsa
@ 2015-09-08 15:21 ` Liang, Kan
0 siblings, 0 replies; 13+ messages in thread
From: Liang, Kan @ 2015-09-08 15:21 UTC (permalink / raw)
To: Jiri Olsa
Cc: acme, jolsa, a.p.zijlstra, luto, mingo, eranian, ak,
mark.rutland, Hunter, Adrian, namhyung, linux-kernel
>
> On Thu, Sep 03, 2015 at 08:30:59AM -0400, kan.liang@intel.com wrote:
> > From: Kan Liang <kan.liang@intel.com>
> >
> > To generate the frequency and performance output, perf must sample
> > read special events like cycles, ref-cycles, msr/tsc/, msr/aperf/ or
> > msr/mperf/.
> > With the --freq-perf option, perf record can automatically check and
> > add those event into evlist for sampling read.
>
> hum, not sure this is a big or small thing:
>
> [jolsa@ibm-x3650m4-01 perf]$ ./perf record --freq-perf -e cache-misses ls
>
> SNIP
>
> [ perf record: Woken up 13 times to write data ] [ perf record: Captured
> and wrote 0.014 MB perf.data (147 samples) ]
> [jolsa@ibm-x3650m4-01 perf]$ ./perf report -D non matching
> read_format[jolsa@ibm-x3650m4-01 perf]$
>
>
The issue is not caused by this patch. It's also an issue in current codes.
In perf_session__open, it will check sample_type, sample_id and
read_format for each event by comparing it with the first event.
If the first events group are sample read and the next event is normal
event, it must error out.
I think it's not a bug. Because we should not allow to record events
with different format.
Thanks,
Kan
> jirka
>
> >
> > Signed-off-by: Kan Liang <kan.liang@intel.com>
> > ---
> > tools/perf/Documentation/perf-record.txt | 4 ++++
> > tools/perf/builtin-record.c | 39
> +++++++++++++++++++++++++++++++-
> > tools/perf/util/session.h | 10 ++++++++
> > 3 files changed, 52 insertions(+), 1 deletion(-)
> >
> > diff --git a/tools/perf/Documentation/perf-record.txt
> > b/tools/perf/Documentation/perf-record.txt
> > index 2e9ce77..3f40712 100644
> > --- a/tools/perf/Documentation/perf-record.txt
> > +++ b/tools/perf/Documentation/perf-record.txt
> > @@ -308,6 +308,10 @@ This option sets the time out limit. The default
> value is 500 ms.
> > Record context switch events i.e. events of type PERF_RECORD_SWITCH
> > or PERF_RECORD_SWITCH_CPU_WIDE.
> >
> > +--freq-perf::
> > +Add frequency and performance related events to do sample read.
> > +These events include cycles, ref-cycles, msr/tsc/, msr/aperf/ and
> msr/mperf/.
> > +
> > SEE ALSO
> > --------
> > linkperf:perf-stat[1], linkperf:perf-list[1] diff --git
> > a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index
> > 142eeb3..e87dda3 100644
> > --- a/tools/perf/builtin-record.c
> > +++ b/tools/perf/builtin-record.c
> > @@ -13,7 +13,7 @@
> > #include "util/util.h"
> > #include "util/parse-options.h"
> > #include "util/parse-events.h"
> > -
> > +#include "util/pmu.h"
> > #include "util/callchain.h"
> > #include "util/cgroup.h"
> > #include "util/header.h"
> > @@ -50,6 +50,7 @@ struct record {
> > bool no_buildid;
> > bool no_buildid_cache;
> > long samples;
> > + bool freq_perf;
> > };
> >
> > static int record__write(struct record *rec, void *bf, size_t size)
> > @@ -948,6 +949,35 @@ out_free:
> > return ret;
> > }
> >
> > +const char *freq_perf_events[FREQ_PERF_MAX][3] = {
> > + { "msr", "tsc", "msr/tsc/" },
> > + { "msr", "aperf", "msr/aperf/" },
> > + { "msr", "mperf", "msr/mperf/" },
> > + { NULL, "cycles", "cycles" },
> > + { NULL, "ref-cycles", "ref-cycles" }, };
> > +
> > +static int
> > +record_add_freq_perf_events(struct perf_evlist *evlist) {
> > + int i;
> > + char freq_perf_attrs[100];
> > +
> > + strcpy(freq_perf_attrs, "{cycles,ref-cycles");
> > + for (i = 0; i < FREQ_PERF_MAX; i++) {
> > + if ((i == FREQ_PERF_CYCLES) ||
> > + (i == FREQ_PERF_REF_CYCLES))
> > + continue;
> > + if (pmu_have_event(freq_perf_events[i][0],
> freq_perf_events[i][1])) {
> > + strcat(freq_perf_attrs, ",");
> > + strcat(freq_perf_attrs, freq_perf_events[i][2]);
> > + }
> > + }
> > + strcat(freq_perf_attrs, "}:S");
> > +
> > + return parse_events(evlist, freq_perf_attrs, NULL); }
> > +
> > static const char * const __record_usage[] = {
> > "perf record [<options>] [<command>]",
> > "perf record [<options>] -- <command> [<options>]", @@ -1096,6
> > +1126,8 @@ struct option __record_options[] = {
> > "per thread proc mmap processing timeout in ms"),
> > OPT_BOOLEAN(0, "switch-events",
> &record.opts.record_switch_events,
> > "Record context switch events"),
> > + OPT_BOOLEAN(0, "freq-perf", &record.freq_perf,
> > + "Add frequency and performance related events to do
> sample
> > +read."),
> > OPT_END()
> > };
> >
> > @@ -1157,6 +1189,11 @@ int cmd_record(int argc, const char **argv,
> const char *prefix __maybe_unused)
> > if (rec->no_buildid_cache || rec->no_buildid)
> > disable_buildid_cache();
> >
> > + if (rec->freq_perf && record_add_freq_perf_events(rec->evlist))
> {
> > + pr_err("Cannot set up freq and performance events\n");
> > + goto out_symbol_exit;
> > + }
> > +
> > if (rec->evlist->nr_entries == 0 &&
> > perf_evlist__add_default(rec->evlist) < 0) {
> > pr_err("Not enough memory for event selector list\n");
> diff --git
> > a/tools/perf/util/session.h b/tools/perf/util/session.h index
> > b44afc7..3915be7 100644
> > --- a/tools/perf/util/session.h
> > +++ b/tools/perf/util/session.h
> > @@ -42,6 +42,16 @@ struct perf_session {
> > #define PRINT_IP_OPT_ONELINE (1<<4)
> > #define PRINT_IP_OPT_SRCLINE (1<<5)
> >
> > +enum perf_freq_perf_index {
> > + FREQ_PERF_TSC = 0,
> > + FREQ_PERF_APERF = 1,
> > + FREQ_PERF_MPERF = 2,
> > + FREQ_PERF_CYCLES = 3,
> > + FREQ_PERF_REF_CYCLES = 4,
> > +
> > + FREQ_PERF_MAX
> > +};
> > +
> > struct perf_tool;
> >
> > struct perf_session *perf_session__new(struct perf_data_file *file,
> > --
> > 1.8.3.1
> >
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2015-09-08 15:21 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-09-03 12:30 [PATCH V8 0/7] Freq/CPU%/CORE_BUSY% support kan.liang
2015-09-03 12:30 ` [PATCH V8 1/7] perf,tools: introduce generic FEAT for CPU attributes kan.liang
2015-09-03 12:30 ` [PATCH V8 2/7] perf,tools: read msr pmu type from header kan.liang
2015-09-03 12:30 ` [PATCH V8 3/7] perf, record: introduce --freq-perf option kan.liang
2015-09-07 10:57 ` Jiri Olsa
2015-09-08 15:21 ` Liang, Kan
2015-09-03 12:31 ` [PATCH V8 4/7] perf,tools: fix dump_sample crash when evsel is NULL kan.liang
2015-09-08 14:38 ` [tip:perf/core] perf session: Don't call dump_sample() " tip-bot for Kan Liang
2015-09-03 12:31 ` [PATCH V8 5/7] perf,tools: Dump per-sample freq/CPU%/CORE_BUSY% in report -D kan.liang
2015-09-03 12:31 ` [PATCH V8 6/7] perf,tools: caculate and save freq/CPU%/CORE_BUSY% in he_stat kan.liang
2015-09-03 12:31 ` [PATCH V8 7/7] perf,tools: Show freq/CPU%/CORE_BUSY% in perf report --stdio kan.liang
2015-09-07 11:17 ` Jiri Olsa
2015-09-07 11:36 ` [PATCH V8 0/7] Freq/CPU%/CORE_BUSY% support Jiri Olsa
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome