perf cpu_map: Add cpu_map event synthesize function
authorJiri Olsa <jolsa@kernel.org>
Sun, 25 Oct 2015 14:51:24 +0000 (15:51 +0100)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 17 Dec 2015 17:38:18 +0000 (14:38 -0300)
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>
tools/perf/tests/Build
tools/perf/tests/builtin-test.c
tools/perf/tests/cpumap.c [new file with mode: 0644]
tools/perf/tests/tests.h
tools/perf/util/event.c
tools/perf/util/event.h

index f23fb7e..7abad28 100644 (file)
@@ -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)
index 745bdb0..0c3fe28 100644 (file)
@@ -184,6 +184,10 @@ static struct test generic_tests[] = {
                .func = test__thread_map_synthesize,
        },
        {
+               .desc = "Test cpu map synthesize",
+               .func = test__cpu_map_synthesize,
+       },
+       {
                .func = NULL,
        },
 };
diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c
new file mode 100644 (file)
index 0000000..7154805
--- /dev/null
@@ -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;
+}
index 3fe52cc..f85160f 100644 (file)
@@ -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
index 719c078..15d6466 100644 (file)
@@ -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;
index 1c82a0e..de18ee0 100644 (file)
@@ -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 */