perf cpu_map: Add cpu_map event synthesize function
Introduce the perf_event__synthesize_cpu_map function to synthesize a struct cpu_map. Added generic interface: cpu_map_data__alloc cpu_map_data__synthesize to make the cpu_map synthesizing usable for other events. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-9-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
		
							parent
							
								
									6640b6c227
								
							
						
					
					
						commit
						6c872901af
					
				| @ -34,6 +34,7 @@ perf-y += thread-map.o | ||||
| perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o llvm-src-prologue.o | ||||
| perf-y += bpf.o | ||||
| perf-y += topology.o | ||||
| perf-y += cpumap.o | ||||
| 
 | ||||
| $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build | ||||
| 	$(call rule_mkdir) | ||||
|  | ||||
| @ -183,6 +183,10 @@ static struct test generic_tests[] = { | ||||
| 		.desc = "Test thread map synthesize", | ||||
| 		.func = test__thread_map_synthesize, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.desc = "Test cpu map synthesize", | ||||
| 		.func = test__cpu_map_synthesize, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.func = NULL, | ||||
| 	}, | ||||
|  | ||||
							
								
								
									
										71
									
								
								tools/perf/tests/cpumap.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								tools/perf/tests/cpumap.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,71 @@ | ||||
| #include "tests.h" | ||||
| #include "cpumap.h" | ||||
| 
 | ||||
| static int process_event_mask(struct perf_tool *tool __maybe_unused, | ||||
| 			 union perf_event *event, | ||||
| 			 struct perf_sample *sample __maybe_unused, | ||||
| 			 struct machine *machine __maybe_unused) | ||||
| { | ||||
| 	struct cpu_map_event *map = &event->cpu_map; | ||||
| 	struct cpu_map_mask *mask; | ||||
| 	struct cpu_map_data *data; | ||||
| 	int i; | ||||
| 
 | ||||
| 	data = &map->data; | ||||
| 
 | ||||
| 	TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__MASK); | ||||
| 
 | ||||
| 	mask = (struct cpu_map_mask *)data->data; | ||||
| 
 | ||||
| 	TEST_ASSERT_VAL("wrong nr",   mask->nr == 1); | ||||
| 
 | ||||
| 	for (i = 0; i < 20; i++) { | ||||
| 		TEST_ASSERT_VAL("wrong cpu", test_bit(i, mask->mask)); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int process_event_cpus(struct perf_tool *tool __maybe_unused, | ||||
| 			 union perf_event *event, | ||||
| 			 struct perf_sample *sample __maybe_unused, | ||||
| 			 struct machine *machine __maybe_unused) | ||||
| { | ||||
| 	struct cpu_map_event *map = &event->cpu_map; | ||||
| 	struct cpu_map_entries *cpus; | ||||
| 	struct cpu_map_data *data; | ||||
| 
 | ||||
| 	data = &map->data; | ||||
| 
 | ||||
| 	TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__CPUS); | ||||
| 
 | ||||
| 	cpus = (struct cpu_map_entries *)data->data; | ||||
| 
 | ||||
| 	TEST_ASSERT_VAL("wrong nr",   cpus->nr == 2); | ||||
| 	TEST_ASSERT_VAL("wrong cpu",  cpus->cpu[0] == 1); | ||||
| 	TEST_ASSERT_VAL("wrong cpu",  cpus->cpu[1] == 256); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int test__cpu_map_synthesize(int subtest __maybe_unused) | ||||
| { | ||||
| 	struct cpu_map *cpus; | ||||
| 
 | ||||
| 	/* This one is better stores in mask. */ | ||||
| 	cpus = cpu_map__new("0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19"); | ||||
| 
 | ||||
| 	TEST_ASSERT_VAL("failed to synthesize map", | ||||
| 		!perf_event__synthesize_cpu_map(NULL, cpus, process_event_mask, NULL)); | ||||
| 
 | ||||
| 	cpu_map__put(cpus); | ||||
| 
 | ||||
| 	/* This one is better stores in cpu values. */ | ||||
| 	cpus = cpu_map__new("1,256"); | ||||
| 
 | ||||
| 	TEST_ASSERT_VAL("failed to synthesize map", | ||||
| 		!perf_event__synthesize_cpu_map(NULL, cpus, process_event_cpus, NULL)); | ||||
| 
 | ||||
| 	cpu_map__put(cpus); | ||||
| 	return 0; | ||||
| } | ||||
| @ -80,6 +80,7 @@ const char *test__bpf_subtest_get_desc(int subtest); | ||||
| int test__bpf_subtest_get_nr(void); | ||||
| int test_session_topology(int subtest); | ||||
| int test__thread_map_synthesize(int subtest); | ||||
| int test__cpu_map_synthesize(int subtest); | ||||
| 
 | ||||
| #if defined(__arm__) || defined(__aarch64__) | ||||
| #ifdef HAVE_DWARF_UNWIND_SUPPORT | ||||
|  | ||||
| @ -737,6 +737,137 @@ int perf_event__synthesize_thread_map2(struct perf_tool *tool, | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static void synthesize_cpus(struct cpu_map_entries *cpus, | ||||
| 			    struct cpu_map *map) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	cpus->nr = map->nr; | ||||
| 
 | ||||
| 	for (i = 0; i < map->nr; i++) | ||||
| 		cpus->cpu[i] = map->map[i]; | ||||
| } | ||||
| 
 | ||||
| static void synthesize_mask(struct cpu_map_mask *mask, | ||||
| 			    struct cpu_map *map, int max) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	mask->nr = BITS_TO_LONGS(max); | ||||
| 	mask->long_size = sizeof(long); | ||||
| 
 | ||||
| 	for (i = 0; i < map->nr; i++) | ||||
| 		set_bit(map->map[i], mask->mask); | ||||
| } | ||||
| 
 | ||||
| static size_t cpus_size(struct cpu_map *map) | ||||
| { | ||||
| 	return sizeof(struct cpu_map_entries) + map->nr * sizeof(u16); | ||||
| } | ||||
| 
 | ||||
| static size_t mask_size(struct cpu_map *map, int *max) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	*max = 0; | ||||
| 
 | ||||
| 	for (i = 0; i < map->nr; i++) { | ||||
| 		/* bit possition of the cpu is + 1 */ | ||||
| 		int bit = map->map[i] + 1; | ||||
| 
 | ||||
| 		if (bit > *max) | ||||
| 			*max = bit; | ||||
| 	} | ||||
| 
 | ||||
| 	return sizeof(struct cpu_map_mask) + BITS_TO_LONGS(*max) * sizeof(long); | ||||
| } | ||||
| 
 | ||||
| void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max) | ||||
| { | ||||
| 	size_t size_cpus, size_mask; | ||||
| 	bool is_dummy = cpu_map__empty(map); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Both array and mask data have variable size based | ||||
| 	 * on the number of cpus and their actual values. | ||||
| 	 * The size of the 'struct cpu_map_data' is: | ||||
| 	 * | ||||
| 	 *   array = size of 'struct cpu_map_entries' + | ||||
| 	 *           number of cpus * sizeof(u64) | ||||
| 	 * | ||||
| 	 *   mask  = size of 'struct cpu_map_mask' + | ||||
| 	 *           maximum cpu bit converted to size of longs | ||||
| 	 * | ||||
| 	 * and finaly + the size of 'struct cpu_map_data'. | ||||
| 	 */ | ||||
| 	size_cpus = cpus_size(map); | ||||
| 	size_mask = mask_size(map, max); | ||||
| 
 | ||||
| 	if (is_dummy || (size_cpus < size_mask)) { | ||||
| 		*size += size_cpus; | ||||
| 		*type  = PERF_CPU_MAP__CPUS; | ||||
| 	} else { | ||||
| 		*size += size_mask; | ||||
| 		*type  = PERF_CPU_MAP__MASK; | ||||
| 	} | ||||
| 
 | ||||
| 	*size += sizeof(struct cpu_map_data); | ||||
| 	return zalloc(*size); | ||||
| } | ||||
| 
 | ||||
| void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map, | ||||
| 			      u16 type, int max) | ||||
| { | ||||
| 	data->type = type; | ||||
| 
 | ||||
| 	switch (type) { | ||||
| 	case PERF_CPU_MAP__CPUS: | ||||
| 		synthesize_cpus((struct cpu_map_entries *) data->data, map); | ||||
| 		break; | ||||
| 	case PERF_CPU_MAP__MASK: | ||||
| 		synthesize_mask((struct cpu_map_mask *) data->data, map, max); | ||||
| 	default: | ||||
| 		break; | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| static struct cpu_map_event* cpu_map_event__new(struct cpu_map *map) | ||||
| { | ||||
| 	size_t size = sizeof(struct cpu_map_event); | ||||
| 	struct cpu_map_event *event; | ||||
| 	int max; | ||||
| 	u16 type; | ||||
| 
 | ||||
| 	event = cpu_map_data__alloc(map, &size, &type, &max); | ||||
| 	if (!event) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	event->header.type = PERF_RECORD_CPU_MAP; | ||||
| 	event->header.size = size; | ||||
| 	event->data.type   = type; | ||||
| 
 | ||||
| 	cpu_map_data__synthesize(&event->data, map, type, max); | ||||
| 	return event; | ||||
| } | ||||
| 
 | ||||
| int perf_event__synthesize_cpu_map(struct perf_tool *tool, | ||||
| 				   struct cpu_map *map, | ||||
| 				   perf_event__handler_t process, | ||||
| 				   struct machine *machine) | ||||
| { | ||||
| 	struct cpu_map_event *event; | ||||
| 	int err; | ||||
| 
 | ||||
| 	event = cpu_map_event__new(map); | ||||
| 	if (!event) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	err = process(tool, (union perf_event *) event, NULL, machine); | ||||
| 
 | ||||
| 	free(event); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) | ||||
| { | ||||
| 	const char *s; | ||||
|  | ||||
| @ -425,6 +425,7 @@ void perf_event__print_totals(void); | ||||
| 
 | ||||
| struct perf_tool; | ||||
| struct thread_map; | ||||
| struct cpu_map; | ||||
| 
 | ||||
| typedef int (*perf_event__handler_t)(struct perf_tool *tool, | ||||
| 				     union perf_event *event, | ||||
| @ -440,6 +441,10 @@ int perf_event__synthesize_thread_map2(struct perf_tool *tool, | ||||
| 				      struct thread_map *threads, | ||||
| 				      perf_event__handler_t process, | ||||
| 				      struct machine *machine); | ||||
| int perf_event__synthesize_cpu_map(struct perf_tool *tool, | ||||
| 				   struct cpu_map *cpus, | ||||
| 				   perf_event__handler_t process, | ||||
| 				   struct machine *machine); | ||||
| int perf_event__synthesize_threads(struct perf_tool *tool, | ||||
| 				   perf_event__handler_t process, | ||||
| 				   struct machine *machine, bool mmap_data, | ||||
| @ -550,4 +555,7 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp); | ||||
| u64 kallsyms__get_function_start(const char *kallsyms_filename, | ||||
| 				 const char *symbol_name); | ||||
| 
 | ||||
| void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max); | ||||
| void  cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map, | ||||
| 			       u16 type, int max); | ||||
| #endif /* __PERF_RECORD_H */ | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user