Introduce perf_event__synthesize_cpu_map function to
synthesize struct cpu_map.

Added generic interface:
  cpu_map_data__alloc
  cpu_map_data__synthesize

to make the cpu_map synthesizing usable for other events.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
 tools/perf/tests/Build          |   1 +
 tools/perf/tests/builtin-test.c |   4 ++
 tools/perf/tests/cpumap.c       |  71 ++++++++++++++++++++++
 tools/perf/tests/tests.h        |   1 +
 tools/perf/util/event.c         | 131 ++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/event.h         |   8 +++
 6 files changed, 216 insertions(+)
 create mode 100644 tools/perf/tests/cpumap.c

diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 50de2253cff6..1c0296fc95ea 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -33,6 +33,7 @@ perf-y += kmod-path.o
 perf-y += thread-map.o
 perf-y += llvm.o
 perf-y += topology.o
+perf-y += cpumap.o
 
 ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64))
 perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index a59fd320da64..bdccd27868ba 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -170,6 +170,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
index 000000000000..cebb251402fa
--- /dev/null
+++ b/tools/perf/tests/cpumap.c
@@ -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_data_mask *mask;
+       struct cpu_map_data *data;
+
+       data = &map->data;
+
+       TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__MASK);
+
+       mask = (struct cpu_map_data_mask *) data->data;
+
+       TEST_ASSERT_VAL("wrong nr",   mask->nr == 1);
+       TEST_ASSERT_VAL("wrong cpu",  test_bit(1, mask->mask));
+       TEST_ASSERT_VAL("wrong cpu",  test_bit(2, mask->mask));
+       TEST_ASSERT_VAL("wrong cpu",  test_bit(3, mask->mask));
+       TEST_ASSERT_VAL("wrong cpu",  test_bit(4, mask->mask));
+       TEST_ASSERT_VAL("wrong cpu",  test_bit(5, mask->mask));
+       TEST_ASSERT_VAL("wrong cpu",  test_bit(6, 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_data_cpus *cpus;
+       struct cpu_map_data *data;
+
+       data = &map->data;
+
+       TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__CPUS);
+
+       cpus = (struct cpu_map_data_cpus *) 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(void)
+{
+       struct cpu_map *cpus;
+
+       /* This one is better stores in mask. */
+       cpus = cpu_map__new("1,2,3,4,5,6");
+
+       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;
+}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 2e280a5cd579..c7f3c3211bcf 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -68,6 +68,7 @@ int test__thread_map(void);
 int test__llvm(void);
 int test_session_topology(void);
 int test__thread_map_synthesize(void);
+int test__cpu_map_synthesize(void);
 
 #if defined(__arm__) || defined(__aarch64__)
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index c05f4b036069..76f34ca4af4e 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -737,6 +737,137 @@ int perf_event__synthesize_thread_map2(struct perf_tool 
*tool,
        return err;
 }
 
+static void synthesize_cpus(struct cpu_map_data_cpus *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_data_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_data_cpus) + map->nr * sizeof(u64);
+}
+
+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_data_mask) + BITS_TO_LONGS(*max) * 
sizeof(long);
+}
+
+void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u64 *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_data_cpus' +
+        *           number of cpus * sizeof(u64)
+        *
+        *   mask  = size of 'struct cpu_map_data_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,
+                             u64 type, int max)
+{
+       data->type = type;
+
+       switch (type) {
+       case PERF_CPU_MAP__CPUS:
+               synthesize_cpus((struct cpu_map_data_cpus *) data->data, map);
+               break;
+       case PERF_CPU_MAP__MASK:
+               synthesize_mask((struct cpu_map_data_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;
+       u64 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;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 7dcbd7f5b68c..2e4a4d32224d 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -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, u64 *type, int 
*max);
+void  cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map,
+                              u64 type, int max);
 #endif /* __PERF_RECORD_H */
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to