perf evlist: Maintain evlist->all_cpus
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>
This commit is contained in:
		
							parent
							
								
									7074674e73
								
							
						
					
					
						commit
						a2408a7036
					
				| @ -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; | ||||
| } | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user