linux-stable/tools/perf/tests/pfm.c
Stephane Eranian 7094349078 perf tools: Add optional support for libpfm4
This patch links perf with the libpfm4 library if it is available and
LIBPFM4 is passed to the build. The libpfm4 library contains hardware
event tables for all processors supported by perf_events. It is a helper
library that helps convert from a symbolic event name to the event
encoding required by the underlying kernel interface. This library is
open-source and available from: http://perfmon2.sf.net.

With this patch, it is possible to specify full hardware events by name.
Hardware filters are also supported. Events must be specified via the
--pfm-events and not -e option. Both options are active at the same time
and it is possible to mix and match:

  $ perf stat --pfm-events inst_retired:any_p:c=1:i -e cycles ....

One needs to explicitely ask for its inclusion by using the LIBPFM4 make
command line option, ie its opt-in rather than opt-out of feature
detection and build support.

Signed-off-by: Stephane Eranian <eranian@google.com>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Alexey Budankov <alexey.budankov@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Andrii Nakryiko <andriin@fb.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Florian Fainelli <f.fainelli@gmail.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Igor Lubashev <ilubashe@akamai.com>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Jiwei Sun <jiwei.sun@windriver.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: netdev@vger.kernel.org
Cc: yuzhoujian <yuzhoujian@didichuxing.com>
Link: http://lore.kernel.org/lkml/20200505182943.218248-2-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-05-29 16:51:38 -03:00

203 lines
3.5 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Test support for libpfm4 event encodings.
*
* Copyright 2020 Google LLC.
*/
#include "tests.h"
#include "util/debug.h"
#include "util/evlist.h"
#include "util/pfm.h"
#include <linux/kernel.h>
#ifdef HAVE_LIBPFM
static int test__pfm_events(void);
static int test__pfm_group(void);
#endif
static const struct {
int (*func)(void);
const char *desc;
} pfm_testcase_table[] = {
#ifdef HAVE_LIBPFM
{
.func = test__pfm_events,
.desc = "test of individual --pfm-events",
},
{
.func = test__pfm_group,
.desc = "test groups of --pfm-events",
},
#endif
};
#ifdef HAVE_LIBPFM
static int count_pfm_events(struct perf_evlist *evlist)
{
struct perf_evsel *evsel;
int count = 0;
perf_evlist__for_each_entry(evlist, evsel) {
count++;
}
return count;
}
static int test__pfm_events(void)
{
struct evlist *evlist;
struct option opt;
size_t i;
const struct {
const char *events;
int nr_events;
} table[] = {
{
.events = "",
.nr_events = 0,
},
{
.events = "instructions",
.nr_events = 1,
},
{
.events = "instructions,cycles",
.nr_events = 2,
},
{
.events = "stereolab",
.nr_events = 0,
},
{
.events = "instructions,instructions",
.nr_events = 2,
},
{
.events = "stereolab,instructions",
.nr_events = 0,
},
{
.events = "instructions,stereolab",
.nr_events = 1,
},
};
for (i = 0; i < ARRAY_SIZE(table); i++) {
evlist = evlist__new();
if (evlist == NULL)
return -ENOMEM;
opt.value = evlist;
parse_libpfm_events_option(&opt,
table[i].events,
0);
TEST_ASSERT_EQUAL(table[i].events,
count_pfm_events(&evlist->core),
table[i].nr_events);
TEST_ASSERT_EQUAL(table[i].events,
evlist->nr_groups,
0);
evlist__delete(evlist);
}
return 0;
}
static int test__pfm_group(void)
{
struct evlist *evlist;
struct option opt;
size_t i;
const struct {
const char *events;
int nr_events;
int nr_groups;
} table[] = {
{
.events = "{},",
.nr_events = 0,
.nr_groups = 0,
},
{
.events = "{instructions}",
.nr_events = 1,
.nr_groups = 1,
},
{
.events = "{instructions},{}",
.nr_events = 1,
.nr_groups = 1,
},
{
.events = "{},{instructions}",
.nr_events = 0,
.nr_groups = 0,
},
{
.events = "{instructions},{instructions}",
.nr_events = 2,
.nr_groups = 2,
},
{
.events = "{instructions,cycles},{instructions,cycles}",
.nr_events = 4,
.nr_groups = 2,
},
{
.events = "{stereolab}",
.nr_events = 0,
.nr_groups = 0,
},
{
.events =
"{instructions,cycles},{instructions,stereolab}",
.nr_events = 3,
.nr_groups = 1,
},
};
for (i = 0; i < ARRAY_SIZE(table); i++) {
evlist = evlist__new();
if (evlist == NULL)
return -ENOMEM;
opt.value = evlist;
parse_libpfm_events_option(&opt,
table[i].events,
0);
TEST_ASSERT_EQUAL(table[i].events,
count_pfm_events(&evlist->core),
table[i].nr_events);
TEST_ASSERT_EQUAL(table[i].events,
evlist->nr_groups,
table[i].nr_groups);
evlist__delete(evlist);
}
return 0;
}
#endif
const char *test__pfm_subtest_get_desc(int i)
{
if (i < 0 || i >= (int)ARRAY_SIZE(pfm_testcase_table))
return NULL;
return pfm_testcase_table[i].desc;
}
int test__pfm_subtest_get_nr(void)
{
return (int)ARRAY_SIZE(pfm_testcase_table);
}
int test__pfm(struct test *test __maybe_unused, int i __maybe_unused)
{
#ifdef HAVE_LIBPFM
if (i < 0 || i >= (int)ARRAY_SIZE(pfm_testcase_table))
return TEST_FAIL;
return pfm_testcase_table[i].func();
#else
return TEST_SKIP;
#endif
}