linux/tools/perf/tests/expand-cgroup.c
Ian Rogers fd7b8e8fb2 perf parse-events: Print all errors
Prior to this patch the first and the last error encountered during
parsing are printed. To see other errors verbose needs
enabling. Unfortunately this can drop useful errors, in particular on
terms. This patch changes the errors so that instead of the first and
last all errors are recorded and printed, the underlying data
structure is changed to a list.

Before:
```
$ perf stat -e 'slots/edge=2/' true
event syntax error: 'slots/edge=2/'
                                \___ Bad event or PMU

Unable to find PMU or event on a PMU of 'slots'

Initial error:
event syntax error: 'slots/edge=2/'
                     \___ Cannot find PMU `slots'. Missing kernel support?
Run 'perf list' for a list of valid events

 Usage: perf stat [<options>] [<command>]

    -e, --event <event>   event selector. use 'perf list' to list available events
```

After:
```
$ perf stat -e 'slots/edge=2/' true
event syntax error: 'slots/edge=2/'
                     \___ Bad event or PMU

Unable to find PMU or event on a PMU of 'slots'

event syntax error: 'slots/edge=2/'
                                \___ value too big for format (edge), maximum is 1

event syntax error: 'slots/edge=2/'
                     \___ Cannot find PMU `slots'. Missing kernel support?
Run 'perf list' for a list of valid events

 Usage: perf stat [<options>] [<command>]

    -e, --event <event>   event selector. use 'perf list' to list available events
```

Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: James Clark <james.clark@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: tchen168@asu.edu
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Michael Petlan <mpetlan@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/r/20240131134940.593788-3-irogers@google.com
2024-02-02 13:08:05 -08:00

224 lines
5.4 KiB
C

// SPDX-License-Identifier: GPL-2.0
#include "tests.h"
#include "debug.h"
#include "evlist.h"
#include "cgroup.h"
#include "rblist.h"
#include "metricgroup.h"
#include "parse-events.h"
#include "pmu-events/pmu-events.h"
#include "pfm.h"
#include <subcmd/parse-options.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int test_expand_events(struct evlist *evlist,
struct rblist *metric_events)
{
int i, ret = TEST_FAIL;
int nr_events;
bool was_group_event;
int nr_members; /* for the first evsel only */
const char cgrp_str[] = "A,B,C";
const char *cgrp_name[] = { "A", "B", "C" };
int nr_cgrps = ARRAY_SIZE(cgrp_name);
char **ev_name;
struct evsel *evsel;
TEST_ASSERT_VAL("evlist is empty", !evlist__empty(evlist));
nr_events = evlist->core.nr_entries;
ev_name = calloc(nr_events, sizeof(*ev_name));
if (ev_name == NULL) {
pr_debug("memory allocation failure\n");
return TEST_FAIL;
}
i = 0;
evlist__for_each_entry(evlist, evsel) {
ev_name[i] = strdup(evsel->name);
if (ev_name[i] == NULL) {
pr_debug("memory allocation failure\n");
goto out;
}
i++;
}
/* remember grouping info */
was_group_event = evsel__is_group_event(evlist__first(evlist));
nr_members = evlist__first(evlist)->core.nr_members;
ret = evlist__expand_cgroup(evlist, cgrp_str, metric_events, false);
if (ret < 0) {
pr_debug("failed to expand events for cgroups\n");
goto out;
}
ret = TEST_FAIL;
if (evlist->core.nr_entries != nr_events * nr_cgrps) {
pr_debug("event count doesn't match\n");
goto out;
}
i = 0;
evlist__for_each_entry(evlist, evsel) {
if (!evsel__name_is(evsel, ev_name[i % nr_events])) {
pr_debug("event name doesn't match:\n");
pr_debug(" evsel[%d]: %s\n expected: %s\n",
i, evsel->name, ev_name[i % nr_events]);
goto out;
}
if (strcmp(evsel->cgrp->name, cgrp_name[i / nr_events])) {
pr_debug("cgroup name doesn't match:\n");
pr_debug(" evsel[%d]: %s\n expected: %s\n",
i, evsel->cgrp->name, cgrp_name[i / nr_events]);
goto out;
}
if ((i % nr_events) == 0) {
if (evsel__is_group_event(evsel) != was_group_event) {
pr_debug("event group doesn't match: got %s, expect %s\n",
evsel__is_group_event(evsel) ? "true" : "false",
was_group_event ? "true" : "false");
goto out;
}
if (evsel->core.nr_members != nr_members) {
pr_debug("event group member doesn't match: %d vs %d\n",
evsel->core.nr_members, nr_members);
goto out;
}
}
i++;
}
ret = TEST_OK;
out: for (i = 0; i < nr_events; i++)
free(ev_name[i]);
free(ev_name);
return ret;
}
static int expand_default_events(void)
{
int ret;
struct rblist metric_events;
struct evlist *evlist = evlist__new_default();
TEST_ASSERT_VAL("failed to get evlist", evlist);
rblist__init(&metric_events);
ret = test_expand_events(evlist, &metric_events);
evlist__delete(evlist);
return ret;
}
static int expand_group_events(void)
{
int ret;
struct evlist *evlist;
struct rblist metric_events;
struct parse_events_error err;
const char event_str[] = "{cycles,instructions}";
symbol_conf.event_group = true;
evlist = evlist__new();
TEST_ASSERT_VAL("failed to get evlist", evlist);
parse_events_error__init(&err);
ret = parse_events(evlist, event_str, &err);
if (ret < 0) {
pr_debug("failed to parse event '%s', err %d\n", event_str, ret);
parse_events_error__print(&err, event_str);
goto out;
}
rblist__init(&metric_events);
ret = test_expand_events(evlist, &metric_events);
out:
parse_events_error__exit(&err);
evlist__delete(evlist);
return ret;
}
static int expand_libpfm_events(void)
{
int ret;
struct evlist *evlist;
struct rblist metric_events;
const char event_str[] = "CYCLES";
struct option opt = {
.value = &evlist,
};
symbol_conf.event_group = true;
evlist = evlist__new();
TEST_ASSERT_VAL("failed to get evlist", evlist);
ret = parse_libpfm_events_option(&opt, event_str, 0);
if (ret < 0) {
pr_debug("failed to parse libpfm event '%s', err %d\n",
event_str, ret);
goto out;
}
if (evlist__empty(evlist)) {
pr_debug("libpfm was not enabled\n");
goto out;
}
rblist__init(&metric_events);
ret = test_expand_events(evlist, &metric_events);
out:
evlist__delete(evlist);
return ret;
}
static int expand_metric_events(void)
{
int ret;
struct evlist *evlist;
struct rblist metric_events;
const char metric_str[] = "CPI";
const struct pmu_metrics_table *pme_test;
evlist = evlist__new();
TEST_ASSERT_VAL("failed to get evlist", evlist);
rblist__init(&metric_events);
pme_test = find_core_metrics_table("testarch", "testcpu");
ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str, &metric_events);
if (ret < 0) {
pr_debug("failed to parse '%s' metric\n", metric_str);
goto out;
}
ret = test_expand_events(evlist, &metric_events);
out:
metricgroup__rblist_exit(&metric_events);
evlist__delete(evlist);
return ret;
}
static int test__expand_cgroup_events(struct test_suite *test __maybe_unused,
int subtest __maybe_unused)
{
int ret;
ret = expand_default_events();
TEST_ASSERT_EQUAL("failed to expand default events", ret, 0);
ret = expand_group_events();
TEST_ASSERT_EQUAL("failed to expand event group", ret, 0);
ret = expand_libpfm_events();
TEST_ASSERT_EQUAL("failed to expand event group", ret, 0);
ret = expand_metric_events();
TEST_ASSERT_EQUAL("failed to expand metric events", ret, 0);
return ret;
}
DEFINE_SUITE("Event expansion for cgroups", expand_cgroup_events);