Skip to content

Commit

Permalink
perf evlist: Maintain evlist->all_cpus
Browse files Browse the repository at this point in the history
Maintain a cpumap in the evlist that is the union of all the cpus of the
events.

This needs a cpumap merge operation, which is added together with tests.

v2:
Add tests for cpu map merge
Fix handling of duplicates
Rename _update to _merge
Factor out sorting.
Fix handling of NULL maps in merge

v3:
Add comments and empty lines to _merge

Committer testing:

  # perf test "Merge cpu map"
  52: Merge cpu map                                         : Ok
  #

Signed-off-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lore.kernel.org/lkml/20191121001522.180827-5-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Andi Kleen authored and Arnaldo Carvalho de Melo committed Nov 29, 2019
1 parent 7074674 commit a2408a7
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 0 deletions.
57 changes: 57 additions & 0 deletions tools/perf/lib/cpumap.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,3 +286,60 @@ int perf_cpu_map__max(struct perf_cpu_map *map)

return max;
}

/*
* Merge two cpumaps
*
* orig either gets freed and replaced with a new map, or reused
* with no reference count change (similar to "realloc")
* other has its reference count increased.
*/

struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig,
struct perf_cpu_map *other)
{
int *tmp_cpus;
int tmp_len;
int i, j, k;
struct perf_cpu_map *merged;

if (!orig && !other)
return NULL;
if (!orig) {
perf_cpu_map__get(other);
return other;
}
if (!other)
return orig;
if (orig->nr == other->nr &&
!memcmp(orig->map, other->map, orig->nr * sizeof(int)))
return orig;

tmp_len = orig->nr + other->nr;
tmp_cpus = malloc(tmp_len * sizeof(int));
if (!tmp_cpus)
return NULL;

/* Standard merge algorithm from wikipedia */
i = j = k = 0;
while (i < orig->nr && j < other->nr) {
if (orig->map[i] <= other->map[j]) {
if (orig->map[i] == other->map[j])
j++;
tmp_cpus[k++] = orig->map[i++];
} else
tmp_cpus[k++] = other->map[j++];
}

while (i < orig->nr)
tmp_cpus[k++] = orig->map[i++];

while (j < other->nr)
tmp_cpus[k++] = other->map[j++];
assert(k <= tmp_len);

merged = cpu_map__trim_new(k, tmp_cpus);
free(tmp_cpus);
perf_cpu_map__put(orig);
return merged;
}
1 change: 1 addition & 0 deletions tools/perf/lib/evlist.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,

perf_thread_map__put(evsel->threads);
evsel->threads = perf_thread_map__get(evlist->threads);
evlist->all_cpus = perf_cpu_map__merge(evlist->all_cpus, evsel->cpus);
}

static void perf_evlist__propagate_maps(struct perf_evlist *evlist)
Expand Down
1 change: 1 addition & 0 deletions tools/perf/lib/include/internal/evlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ struct perf_evlist {
int nr_entries;
bool has_user_cpus;
struct perf_cpu_map *cpus;
struct perf_cpu_map *all_cpus;
struct perf_thread_map *threads;
int nr_mmaps;
size_t mmap_len;
Expand Down
2 changes: 2 additions & 0 deletions tools/perf/lib/include/perf/cpumap.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ LIBPERF_API struct perf_cpu_map *perf_cpu_map__dummy_new(void);
LIBPERF_API struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list);
LIBPERF_API struct perf_cpu_map *perf_cpu_map__read(FILE *file);
LIBPERF_API struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map);
LIBPERF_API struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig,
struct perf_cpu_map *other);
LIBPERF_API void perf_cpu_map__put(struct perf_cpu_map *map);
LIBPERF_API int perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx);
LIBPERF_API int perf_cpu_map__nr(const struct perf_cpu_map *cpus);
Expand Down
5 changes: 5 additions & 0 deletions tools/perf/tests/builtin-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,11 @@ static struct test generic_tests[] = {
.desc = "Print cpu map",
.func = test__cpu_map_print,
},
{
.desc = "Merge cpu map",
.func = test__cpu_map_merge,
},

{
.desc = "Probe SDT events",
.func = test__sdt_event,
Expand Down
16 changes: 16 additions & 0 deletions tools/perf/tests/cpumap.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,19 @@ int test__cpu_map_print(struct test *test __maybe_unused, int subtest __maybe_un
TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1-10,12-20,22-30,32-40"));
return 0;
}

int test__cpu_map_merge(struct test *test __maybe_unused, int subtest __maybe_unused)
{
struct perf_cpu_map *a = perf_cpu_map__new("4,2,1");
struct perf_cpu_map *b = perf_cpu_map__new("4,5,7");
struct perf_cpu_map *c = perf_cpu_map__merge(a, b);
char buf[100];

TEST_ASSERT_VAL("failed to merge map: bad nr", c->nr == 5);
cpu_map__snprint(c, buf, sizeof(buf));
TEST_ASSERT_VAL("failed to merge map: bad result", !strcmp(buf, "1-2,4-5,7"));
perf_cpu_map__put(a);
perf_cpu_map__put(b);
perf_cpu_map__put(c);
return 0;
}
1 change: 1 addition & 0 deletions tools/perf/tests/tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ int test__event_update(struct test *test, int subtest);
int test__event_times(struct test *test, int subtest);
int test__backward_ring_buffer(struct test *test, int subtest);
int test__cpu_map_print(struct test *test, int subtest);
int test__cpu_map_merge(struct test *test, int subtest);
int test__sdt_event(struct test *test, int subtest);
int test__is_printable_array(struct test *test, int subtest);
int test__bitmap_print(struct test *test, int subtest);
Expand Down

0 comments on commit a2408a7

Please sign in to comment.