Commit dc29bb47 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo-20160630' of...

Merge tag 'perf-core-for-mingo-20160630' 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:

New features:

 - Allow running 'perf test' entries in the same process, not forking to
   test each testcase, useful for debugging (Jiri Olsa)

 - Show number of samples in the stdio annotate header (Peter Zijlstra)

Documentation changes:

 - Add documentation for perf.data on disk format (Andi Kleen)

Build fixes:

 - Fix 'perf trace' build on old systems wrt missing SCHED_RESET_ON_FORK and
   eventfd.h (Arnaldo Carvalho de Melo)

Infrastructure changes:

 - Utility function to fetch arch from evsel/evlist (Ravi Bangoria)

Trivial changes:

 - Fix spelling mistake: "missmatch" -> "mismatch" in libbpf (Colin Ian King)
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents d905768c a24020e6
...@@ -71,7 +71,7 @@ static const char *libbpf_strerror_table[NR_ERRNO] = { ...@@ -71,7 +71,7 @@ static const char *libbpf_strerror_table[NR_ERRNO] = {
[ERRCODE_OFFSET(LIBELF)] = "Something wrong in libelf", [ERRCODE_OFFSET(LIBELF)] = "Something wrong in libelf",
[ERRCODE_OFFSET(FORMAT)] = "BPF object format invalid", [ERRCODE_OFFSET(FORMAT)] = "BPF object format invalid",
[ERRCODE_OFFSET(KVERSION)] = "'version' section incorrect or lost", [ERRCODE_OFFSET(KVERSION)] = "'version' section incorrect or lost",
[ERRCODE_OFFSET(ENDIAN)] = "Endian missmatch", [ERRCODE_OFFSET(ENDIAN)] = "Endian mismatch",
[ERRCODE_OFFSET(INTERNAL)] = "Internal error in libbpf", [ERRCODE_OFFSET(INTERNAL)] = "Internal error in libbpf",
[ERRCODE_OFFSET(RELOC)] = "Relocation failed", [ERRCODE_OFFSET(RELOC)] = "Relocation failed",
[ERRCODE_OFFSET(VERIFY)] = "Kernel verifier blocks program loading", [ERRCODE_OFFSET(VERIFY)] = "Kernel verifier blocks program loading",
......
...@@ -19,7 +19,7 @@ enum libbpf_errno { ...@@ -19,7 +19,7 @@ enum libbpf_errno {
LIBBPF_ERRNO__LIBELF = __LIBBPF_ERRNO__START, LIBBPF_ERRNO__LIBELF = __LIBBPF_ERRNO__START,
LIBBPF_ERRNO__FORMAT, /* BPF object format invalid */ LIBBPF_ERRNO__FORMAT, /* BPF object format invalid */
LIBBPF_ERRNO__KVERSION, /* Incorrect or no 'version' section */ LIBBPF_ERRNO__KVERSION, /* Incorrect or no 'version' section */
LIBBPF_ERRNO__ENDIAN, /* Endian missmatch */ LIBBPF_ERRNO__ENDIAN, /* Endian mismatch */
LIBBPF_ERRNO__INTERNAL, /* Internal error in libbpf */ LIBBPF_ERRNO__INTERNAL, /* Internal error in libbpf */
LIBBPF_ERRNO__RELOC, /* Relocation failed */ LIBBPF_ERRNO__RELOC, /* Relocation failed */
LIBBPF_ERRNO__LOAD, /* Load program failure for unknown reason */ LIBBPF_ERRNO__LOAD, /* Load program failure for unknown reason */
......
...@@ -30,3 +30,7 @@ OPTIONS ...@@ -30,3 +30,7 @@ OPTIONS
-v:: -v::
--verbose:: --verbose::
Be more verbose. Be more verbose.
-F::
--dont-fork::
Do not fork child for each test, run all tests within single process.
This diff is collapsed.
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include <subcmd/parse-options.h> #include <subcmd/parse-options.h>
#include "symbol.h" #include "symbol.h"
static bool dont_fork;
struct test __weak arch_tests[] = { struct test __weak arch_tests[] = {
{ {
.func = NULL, .func = NULL,
...@@ -211,6 +213,10 @@ static struct test generic_tests[] = { ...@@ -211,6 +213,10 @@ static struct test generic_tests[] = {
.desc = "Test backward reading from ring buffer", .desc = "Test backward reading from ring buffer",
.func = test__backward_ring_buffer, .func = test__backward_ring_buffer,
}, },
{
.desc = "Test cpu map print",
.func = test__cpu_map_print,
},
{ {
.func = NULL, .func = NULL,
}, },
...@@ -247,7 +253,7 @@ static bool perf_test__matches(struct test *test, int curr, int argc, const char ...@@ -247,7 +253,7 @@ static bool perf_test__matches(struct test *test, int curr, int argc, const char
static int run_test(struct test *test, int subtest) static int run_test(struct test *test, int subtest)
{ {
int status, err = -1, child = fork(); int status, err = -1, child = dont_fork ? 0 : fork();
char sbuf[STRERR_BUFSIZE]; char sbuf[STRERR_BUFSIZE];
if (child < 0) { if (child < 0) {
...@@ -257,9 +263,12 @@ static int run_test(struct test *test, int subtest) ...@@ -257,9 +263,12 @@ static int run_test(struct test *test, int subtest)
} }
if (!child) { if (!child) {
if (!dont_fork) {
pr_debug("test child forked, pid %d\n", getpid()); pr_debug("test child forked, pid %d\n", getpid());
if (!verbose) { if (!verbose) {
int nullfd = open("/dev/null", O_WRONLY); int nullfd = open("/dev/null", O_WRONLY);
if (nullfd >= 0) { if (nullfd >= 0) {
close(STDERR_FILENO); close(STDERR_FILENO);
close(STDOUT_FILENO); close(STDOUT_FILENO);
...@@ -272,11 +281,14 @@ static int run_test(struct test *test, int subtest) ...@@ -272,11 +281,14 @@ static int run_test(struct test *test, int subtest)
signal(SIGSEGV, sighandler_dump_stack); signal(SIGSEGV, sighandler_dump_stack);
signal(SIGFPE, sighandler_dump_stack); signal(SIGFPE, sighandler_dump_stack);
} }
}
err = test->func(subtest); err = test->func(subtest);
if (!dont_fork)
exit(err); exit(err);
} }
if (!dont_fork) {
wait(&status); wait(&status);
if (WIFEXITED(status)) { if (WIFEXITED(status)) {
...@@ -286,6 +298,7 @@ static int run_test(struct test *test, int subtest) ...@@ -286,6 +298,7 @@ static int run_test(struct test *test, int subtest)
err = -1; err = -1;
pr_debug("test child interrupted\n"); pr_debug("test child interrupted\n");
} }
}
return err; return err;
} }
...@@ -425,6 +438,8 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -425,6 +438,8 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_STRING('s', "skip", &skip, "tests", "tests to skip"), OPT_STRING('s', "skip", &skip, "tests", "tests to skip"),
OPT_INCR('v', "verbose", &verbose, OPT_INCR('v', "verbose", &verbose,
"be more verbose (show symbol address, etc)"), "be more verbose (show symbol address, etc)"),
OPT_BOOLEAN('F', "dont-fork", &dont_fork,
"Do not fork for testcase"),
OPT_END() OPT_END()
}; };
const char * const test_subcommands[] = { "list", NULL }; const char * const test_subcommands[] = { "list", NULL };
......
...@@ -86,3 +86,27 @@ int test__cpu_map_synthesize(int subtest __maybe_unused) ...@@ -86,3 +86,27 @@ int test__cpu_map_synthesize(int subtest __maybe_unused)
cpu_map__put(cpus); cpu_map__put(cpus);
return 0; return 0;
} }
static int cpu_map_print(const char *str)
{
struct cpu_map *map = cpu_map__new(str);
char buf[100];
if (!map)
return -1;
cpu_map__snprint(map, buf, sizeof(buf));
return !strcmp(buf, str);
}
int test__cpu_map_print(int subtest __maybe_unused)
{
TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1"));
TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1,5"));
TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1,3,5,7,9,11,13,15,17,19,21-40"));
TEST_ASSERT_VAL("failed to convert map", cpu_map_print("2-5"));
TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1,3-6,8-10,24,35-37"));
TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1,3-6,8-10,24,35-37"));
TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1-10,12-20,22-30,32-40"));
return 0;
}
...@@ -251,6 +251,9 @@ int test__dso_data_cache(int subtest __maybe_unused) ...@@ -251,6 +251,9 @@ int test__dso_data_cache(int subtest __maybe_unused)
long nr_end, nr = open_files_cnt(); long nr_end, nr = open_files_cnt();
int dso_cnt, limit, i, fd; int dso_cnt, limit, i, fd;
/* Rest the internal dso open counter limit. */
reset_fd_limit();
memset(&machine, 0, sizeof(machine)); memset(&machine, 0, sizeof(machine));
/* set as system limit */ /* set as system limit */
...@@ -312,6 +315,9 @@ int test__dso_data_reopen(int subtest __maybe_unused) ...@@ -312,6 +315,9 @@ int test__dso_data_reopen(int subtest __maybe_unused)
#define dso_1 (dsos[1]) #define dso_1 (dsos[1])
#define dso_2 (dsos[2]) #define dso_2 (dsos[2])
/* Rest the internal dso open counter limit. */
reset_fd_limit();
memset(&machine, 0, sizeof(machine)); memset(&machine, 0, sizeof(machine));
/* /*
......
...@@ -87,6 +87,7 @@ int test__synthesize_stat_round(int subtest); ...@@ -87,6 +87,7 @@ int test__synthesize_stat_round(int subtest);
int test__event_update(int subtest); int test__event_update(int subtest);
int test__event_times(int subtest); int test__event_times(int subtest);
int test__backward_ring_buffer(int subtest); int test__backward_ring_buffer(int subtest);
int test__cpu_map_print(int subtest);
#if defined(__arm__) || defined(__aarch64__) #if defined(__arm__) || defined(__aarch64__)
#ifdef HAVE_DWARF_UNWIND_SUPPORT #ifdef HAVE_DWARF_UNWIND_SUPPORT
......
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <sys/prctl.h>
#include "tests.h" #include "tests.h"
#include "thread_map.h" #include "thread_map.h"
#include "debug.h" #include "debug.h"
#define NAME (const char *) "perf"
#define NAMEUL (unsigned long) NAME
int test__thread_map(int subtest __maybe_unused) int test__thread_map(int subtest __maybe_unused)
{ {
struct thread_map *map; struct thread_map *map;
TEST_ASSERT_VAL("failed to set process name",
!prctl(PR_SET_NAME, NAMEUL, 0, 0, 0));
/* test map on current pid */ /* test map on current pid */
map = thread_map__new_by_pid(getpid()); map = thread_map__new_by_pid(getpid());
TEST_ASSERT_VAL("failed to alloc map", map); TEST_ASSERT_VAL("failed to alloc map", map);
...@@ -19,7 +26,7 @@ int test__thread_map(int subtest __maybe_unused) ...@@ -19,7 +26,7 @@ int test__thread_map(int subtest __maybe_unused)
thread_map__pid(map, 0) == getpid()); thread_map__pid(map, 0) == getpid());
TEST_ASSERT_VAL("wrong comm", TEST_ASSERT_VAL("wrong comm",
thread_map__comm(map, 0) && thread_map__comm(map, 0) &&
!strcmp(thread_map__comm(map, 0), "perf")); !strcmp(thread_map__comm(map, 0), NAME));
TEST_ASSERT_VAL("wrong refcnt", TEST_ASSERT_VAL("wrong refcnt",
atomic_read(&map->refcnt) == 1); atomic_read(&map->refcnt) == 1);
thread_map__put(map); thread_map__put(map);
...@@ -51,7 +58,7 @@ static int process_event(struct perf_tool *tool __maybe_unused, ...@@ -51,7 +58,7 @@ static int process_event(struct perf_tool *tool __maybe_unused,
TEST_ASSERT_VAL("wrong nr", map->nr == 1); TEST_ASSERT_VAL("wrong nr", map->nr == 1);
TEST_ASSERT_VAL("wrong pid", map->entries[0].pid == (u64) getpid()); TEST_ASSERT_VAL("wrong pid", map->entries[0].pid == (u64) getpid());
TEST_ASSERT_VAL("wrong comm", !strcmp(map->entries[0].comm, "perf")); TEST_ASSERT_VAL("wrong comm", !strcmp(map->entries[0].comm, NAME));
threads = thread_map__new_event(&event->thread_map); threads = thread_map__new_event(&event->thread_map);
TEST_ASSERT_VAL("failed to alloc map", threads); TEST_ASSERT_VAL("failed to alloc map", threads);
...@@ -61,7 +68,7 @@ static int process_event(struct perf_tool *tool __maybe_unused, ...@@ -61,7 +68,7 @@ static int process_event(struct perf_tool *tool __maybe_unused,
thread_map__pid(threads, 0) == getpid()); thread_map__pid(threads, 0) == getpid());
TEST_ASSERT_VAL("wrong comm", TEST_ASSERT_VAL("wrong comm",
thread_map__comm(threads, 0) && thread_map__comm(threads, 0) &&
!strcmp(thread_map__comm(threads, 0), "perf")); !strcmp(thread_map__comm(threads, 0), NAME));
TEST_ASSERT_VAL("wrong refcnt", TEST_ASSERT_VAL("wrong refcnt",
atomic_read(&threads->refcnt) == 1); atomic_read(&threads->refcnt) == 1);
thread_map__put(threads); thread_map__put(threads);
...@@ -72,6 +79,9 @@ int test__thread_map_synthesize(int subtest __maybe_unused) ...@@ -72,6 +79,9 @@ int test__thread_map_synthesize(int subtest __maybe_unused)
{ {
struct thread_map *threads; struct thread_map *threads;
TEST_ASSERT_VAL("failed to set process name",
!prctl(PR_SET_NAME, NAMEUL, 0, 0, 0));
/* test map on current pid */ /* test map on current pid */
threads = thread_map__new_by_pid(getpid()); threads = thread_map__new_by_pid(getpid());
TEST_ASSERT_VAL("failed to alloc map", threads); TEST_ASSERT_VAL("failed to alloc map", threads);
......
#include <sys/eventfd.h>
#ifndef EFD_SEMAPHORE #ifndef EFD_SEMAPHORE
#define EFD_SEMAPHORE 1 #define EFD_SEMAPHORE 1
#endif #endif
......
...@@ -9,6 +9,9 @@ ...@@ -9,6 +9,9 @@
#ifndef SCHED_DEADLINE #ifndef SCHED_DEADLINE
#define SCHED_DEADLINE 6 #define SCHED_DEADLINE 6
#endif #endif
#ifndef SCHED_RESET_ON_FORK
#define SCHED_RESET_ON_FORK 0x40000000
#endif
static size_t syscall_arg__scnprintf_sched_policy(char *bf, size_t size, static size_t syscall_arg__scnprintf_sched_policy(char *bf, size_t size,
struct syscall_arg *arg) struct syscall_arg *arg)
......
...@@ -1522,13 +1522,14 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, ...@@ -1522,13 +1522,14 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
const char *d_filename; const char *d_filename;
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 disasm_line *pos, *queue = NULL; struct disasm_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;
int more = 0; int more = 0;
u64 len; u64 len;
int width = 8; int width = 8;
int namelen, evsel_name_len, graph_dotted_len; int graph_dotted_len;
filename = strdup(dso->long_name); filename = strdup(dso->long_name);
if (!filename) if (!filename)
...@@ -1540,17 +1541,14 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, ...@@ -1540,17 +1541,14 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
d_filename = basename(filename); d_filename = basename(filename);
len = symbol__size(sym); len = symbol__size(sym);
namelen = strlen(d_filename);
evsel_name_len = strlen(evsel_name);
if (perf_evsel__is_group_event(evsel)) if (perf_evsel__is_group_event(evsel))
width *= evsel->nr_members; width *= evsel->nr_members;
printf(" %-*.*s| Source code & Disassembly of %s for %s\n", graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n",
width, width, "Percent", d_filename, evsel_name); width, width, "Percent", d_filename, evsel_name, h->sum);
graph_dotted_len = width + namelen + evsel_name_len; printf("%-*.*s----\n",
printf("-%-*.*s-----------------------------------------\n",
graph_dotted_len, graph_dotted_len, graph_dotted_line); graph_dotted_len, graph_dotted_len, graph_dotted_line);
if (verbose) if (verbose)
......
...@@ -236,13 +236,12 @@ struct cpu_map *cpu_map__new_data(struct cpu_map_data *data) ...@@ -236,13 +236,12 @@ struct cpu_map *cpu_map__new_data(struct cpu_map_data *data)
size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp) size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
{ {
int i; #define BUFSIZE 1024
size_t printed = fprintf(fp, "%d cpu%s: ", char buf[BUFSIZE];
map->nr, map->nr > 1 ? "s" : "");
for (i = 0; i < map->nr; ++i)
printed += fprintf(fp, "%s%d", i ? ", " : "", map->map[i]);
return printed + fprintf(fp, "\n"); cpu_map__snprint(map, buf, sizeof(buf));
return fprintf(fp, "%s\n", buf);
#undef BUFSIZE
} }
struct cpu_map *cpu_map__dummy_new(void) struct cpu_map *cpu_map__dummy_new(void)
...@@ -599,3 +598,46 @@ bool cpu_map__has(struct cpu_map *cpus, int cpu) ...@@ -599,3 +598,46 @@ bool cpu_map__has(struct cpu_map *cpus, int cpu)
return false; return false;
} }
size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size)
{
int i, cpu, start = -1;
bool first = true;
size_t ret = 0;
#define COMMA first ? "" : ","
for (i = 0; i < map->nr + 1; i++) {
bool last = i == map->nr;
cpu = last ? INT_MAX : map->map[i];
if (start == -1) {
start = i;
if (last) {
ret += snprintf(buf + ret, size - ret,
"%s%d", COMMA,
map->map[i]);
}
} else if (((i - start) != (cpu - map->map[start])) || last) {
int end = i - 1;
if (start == end) {
ret += snprintf(buf + ret, size - ret,
"%s%d", COMMA,
map->map[start]);
} else {
ret += snprintf(buf + ret, size - ret,
"%s%d-%d", COMMA,
map->map[start], map->map[end]);
}
first = false;
start = i;
}
}
#undef COMMA
pr_debug("cpumask list: %s\n", buf);
return ret;
}
...@@ -19,6 +19,7 @@ struct cpu_map *cpu_map__empty_new(int nr); ...@@ -19,6 +19,7 @@ struct cpu_map *cpu_map__empty_new(int nr);
struct cpu_map *cpu_map__dummy_new(void); struct cpu_map *cpu_map__dummy_new(void);
struct cpu_map *cpu_map__new_data(struct cpu_map_data *data); struct cpu_map *cpu_map__new_data(struct cpu_map_data *data);
struct cpu_map *cpu_map__read(FILE *file); struct cpu_map *cpu_map__read(FILE *file);
size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size);
size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
int cpu_map__get_socket_id(int cpu); int cpu_map__get_socket_id(int cpu);
int cpu_map__get_socket(struct cpu_map *map, int idx, void *data); int cpu_map__get_socket(struct cpu_map *map, int idx, void *data);
......
...@@ -442,17 +442,27 @@ static rlim_t get_fd_limit(void) ...@@ -442,17 +442,27 @@ static rlim_t get_fd_limit(void)
return limit; return limit;
} }
static bool may_cache_fd(void) static rlim_t fd_limit;
/*
* Used only by tests/dso-data.c to reset the environment
* for tests. I dont expect we should change this during
* standard runtime.
*/
void reset_fd_limit(void)
{ {
static rlim_t limit; fd_limit = 0;
}
if (!limit) static bool may_cache_fd(void)
limit = get_fd_limit(); {
if (!fd_limit)
fd_limit = get_fd_limit();
if (limit == RLIM_INFINITY) if (fd_limit == RLIM_INFINITY)
return true; return true;
return limit > (rlim_t) dso__data_open_cnt; return fd_limit > (rlim_t) dso__data_open_cnt;
} }
/* /*
......
...@@ -360,4 +360,6 @@ enum dso_type dso__type(struct dso *dso, struct machine *machine); ...@@ -360,4 +360,6 @@ enum dso_type dso__type(struct dso *dso, struct machine *machine);
int dso__strerror_load(struct dso *dso, char *buf, size_t buflen); int dso__strerror_load(struct dso *dso, char *buf, size_t buflen);
void reset_fd_limit(void);
#endif /* __PERF_DSO */ #endif /* __PERF_DSO */
...@@ -1092,7 +1092,7 @@ size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp) ...@@ -1092,7 +1092,7 @@ size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp)
struct cpu_map *cpus = cpu_map__new_data(&event->cpu_map.data); struct cpu_map *cpus = cpu_map__new_data(&event->cpu_map.data);
size_t ret; size_t ret;
ret = fprintf(fp, " nr: "); ret = fprintf(fp, ": ");
if (cpus) if (cpus)
ret += cpu_map__fprintf(cpus, fp); ret += cpu_map__fprintf(cpus, fp);
......
...@@ -2422,3 +2422,10 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, ...@@ -2422,3 +2422,10 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
err, strerror_r(err, sbuf, sizeof(sbuf)), err, strerror_r(err, sbuf, sizeof(sbuf)),
perf_evsel__name(evsel)); perf_evsel__name(evsel));
} }
char *perf_evsel__env_arch(struct perf_evsel *evsel)
{
if (evsel && evsel->evlist && evsel->evlist->env)
return evsel->evlist->env->arch;
return NULL;
}
...@@ -435,4 +435,6 @@ typedef int (*attr__fprintf_f)(FILE *, const char *, const char *, void *); ...@@ -435,4 +435,6 @@ typedef int (*attr__fprintf_f)(FILE *, const char *, const char *, void *);
int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr,
attr__fprintf_f attr__fprintf, void *priv); attr__fprintf_f attr__fprintf, void *priv);
char *perf_evsel__env_arch(struct perf_evsel *evsel);
#endif /* __PERF_EVSEL_H */ #endif /* __PERF_EVSEL_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment