Re: [PATCH v3 25/30] perf clang jit: Allow jitted perf hook access BPF maps

2016-11-26 Thread Alexei Starovoitov
On Sat, Nov 26, 2016 at 07:03:49AM +, Wang Nan wrote:
> Newly introduced jit-helpers.[ch] defines a series of helpers which helps
> jitted perf hook functions accessing BPF maps defined in their BPF scripts.
> The helpers fetches fd of 'struct bpf_map' from 'struct bpf_object' and the
> address of 'struct bpf_map_def' in jitted file. 'struct bpf_object' is the
> context passed to hooks.
> 
> Jit helpers added in this commits are all leading with 'perf_'. We don't use
> 'bpf_' prefix because in following commits 'bpf_' prefix is going to be 
> assigned
> to kernel side BPF map operations. Same operation has different protocol for
> kernel and user.
> 
>  Example:
> 
>   $ cat ./test.c
>   /***/
>   #define SEC(name) __attribute__((section(name), used))
>   #define BPF_MAP_TYPE_ARRAY 2
>   #define BPF_MAP_TYPE_PERF_EVENT_ARRAY 4
>   #define BPF_FUNC_map_lookup_elem 1
>   static void *(*bpf_map_lookup_elem)(void *map, void *key) =
>   (void *) BPF_FUNC_map_lookup_elem;
>   struct bpf_map_def {
>   unsigned int type;
>   unsigned int key_size;
>   unsigned int value_size;
>   unsigned int max_entries;
>   };
>   struct bpf_map_def SEC("maps") counter = {
>   .type = BPF_MAP_TYPE_ARRAY,
>   .key_size = sizeof(int),
>   .value_size = sizeof(int),
>   .max_entries = 1,
>   };
>   extern int perf_map_update_elem(void *ctx, struct bpf_map_def *map,
>  void *key, void *value, unsigned long flags);
>   extern int perf_map_lookup_elem(void *ctx, struct bpf_map_def *map,
>  void *key, void *value);
>   SEC("sys_close=SyS_close")
>   int sys_close(void *ctx)
>   {
>   int key = 0;
>   int *value;
>   value = bpf_map_lookup_elem(&counter, &key);
>   if (!value)
>   return 0;
>   __sync_fetch_and_add(value, 1);
>   return 0;
>   }
>   extern int printf(const char *fmt, ...);
>   SEC("perfhook:record_start")
>   void record_start(void *ctx)
>   {
>   int key = 0;
>   int value = 1;
>   printf("Welcom to perf record\n");
>   perf_map_update_elem(ctx, &counter, &key, &value, 0);
>   }
> 
>   SEC("perfhook:record_end")
>   void record_end(void *ctx)
>   {
>   int key = 0;
>   int value;
>   perf_map_lookup_elem(ctx, &counter, &key, &value);
>   printf("Goodbye, perf record, value=%d\n", value);
>   }
>   char _license[] SEC("license") = "GPL";
>   int _version SEC("version") = LINUX_VERSION_CODE;
>   /***/
>   $ sudo perf record  -e ./test.c echo Hehe
>   Welcom to perf record
>   Hehe
>   [ perf record: Woken up 1 times to write data ]
>   Goodbye, perf record, value=10644
>   [ perf record: Captured and wrote 0.014 MB perf.data ]
> 
> Signed-off-by: Wang Nan 
...
> +#define __stringify_1(x) #x
> +#define __stringify(x)   __stringify_1(x)
>  static std::map exported_funcs =
>  {
> -#define EXPORT(f) {#f, (const void *)&f}
> +#define EXPORT(f) {__stringify(f), (const void *)&f}
>   EXPORT(test__clang_callback),
>   EXPORT(printf),
>   EXPORT(puts),
> + EXPORT(JIT_HELPER_FUNC_NAME(map_update_elem)),
> + EXPORT(JIT_HELPER_FUNC_NAME(map_lookup_elem)),
> + EXPORT(JIT_HELPER_FUNC_NAME(map_get_next_key)),
> + EXPORT(JIT_HELPER_FUNC_NAME(map_pin)),
>  #undef EXPORT
...
> +#define PARAMS(args...) args
> +#define DEFINE_JIT_BPF_MAP_HELPER(name, proto, args) \
> + JIT_BPF_MAP_HELPER(name, proto) {   \
> + int map_fd = get_bpf_map_fd(ctx, map);  \
> + \
> + if (map_fd < 0) \
> + return map_fd;  \
> + return bpf_map_##name(map_fd, args);\
> + }
> +
> +DEFINE_JIT_BPF_MAP_HELPER(update_elem,
> +   PARAMS(void *key, void *value, u64 flags),
> +   PARAMS(key, value, flags))

the naming and approach to exports look good to me.
Acked-by: Alexei Starovoitov 



[PATCH v3 25/30] perf clang jit: Allow jitted perf hook access BPF maps

2016-11-25 Thread Wang Nan
Newly introduced jit-helpers.[ch] defines a series of helpers which helps
jitted perf hook functions accessing BPF maps defined in their BPF scripts.
The helpers fetches fd of 'struct bpf_map' from 'struct bpf_object' and the
address of 'struct bpf_map_def' in jitted file. 'struct bpf_object' is the
context passed to hooks.

Jit helpers added in this commits are all leading with 'perf_'. We don't use
'bpf_' prefix because in following commits 'bpf_' prefix is going to be assigned
to kernel side BPF map operations. Same operation has different protocol for
kernel and user.

 Example:

  $ cat ./test.c
  /***/
  #define SEC(name) __attribute__((section(name), used))
  #define BPF_MAP_TYPE_ARRAY 2
  #define BPF_MAP_TYPE_PERF_EVENT_ARRAY 4
  #define BPF_FUNC_map_lookup_elem 1
  static void *(*bpf_map_lookup_elem)(void *map, void *key) =
  (void *) BPF_FUNC_map_lookup_elem;
  struct bpf_map_def {
  unsigned int type;
  unsigned int key_size;
  unsigned int value_size;
  unsigned int max_entries;
  };
  struct bpf_map_def SEC("maps") counter = {
  .type = BPF_MAP_TYPE_ARRAY,
  .key_size = sizeof(int),
  .value_size = sizeof(int),
  .max_entries = 1,
  };
  extern int perf_map_update_elem(void *ctx, struct bpf_map_def *map,
 void *key, void *value, unsigned long flags);
  extern int perf_map_lookup_elem(void *ctx, struct bpf_map_def *map,
 void *key, void *value);
  SEC("sys_close=SyS_close")
  int sys_close(void *ctx)
  {
  int key = 0;
  int *value;
  value = bpf_map_lookup_elem(&counter, &key);
  if (!value)
  return 0;
  __sync_fetch_and_add(value, 1);
  return 0;
  }
  extern int printf(const char *fmt, ...);
  SEC("perfhook:record_start")
  void record_start(void *ctx)
  {
  int key = 0;
  int value = 1;
  printf("Welcom to perf record\n");
  perf_map_update_elem(ctx, &counter, &key, &value, 0);
  }

  SEC("perfhook:record_end")
  void record_end(void *ctx)
  {
  int key = 0;
  int value;
  perf_map_lookup_elem(ctx, &counter, &key, &value);
  printf("Goodbye, perf record, value=%d\n", value);
  }
  char _license[] SEC("license") = "GPL";
  int _version SEC("version") = LINUX_VERSION_CODE;
  /***/
  $ sudo perf record  -e ./test.c echo Hehe
  Welcom to perf record
  Hehe
  [ perf record: Woken up 1 times to write data ]
  Goodbye, perf record, value=10644
  [ perf record: Captured and wrote 0.014 MB perf.data ]

Signed-off-by: Wang Nan 
Cc: Arnaldo Carvalho de Melo 
Cc: Alexei Starovoitov 
Cc: He Kuang 
Cc: Jiri Olsa 
Cc: Zefan Li 
Cc: pi3or...@163.com
---
 tools/perf/util/Build |  1 +
 tools/perf/util/c++/clang.cpp |  9 ++-
 tools/perf/util/jit-helpers.c | 57 +++
 tools/perf/util/jit-helpers.h | 28 +
 4 files changed, 94 insertions(+), 1 deletion(-)
 create mode 100644 tools/perf/util/jit-helpers.c
 create mode 100644 tools/perf/util/jit-helpers.h

diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 743a889..33773cb 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -124,6 +124,7 @@ libperf-$(CONFIG_DWARF) += genelf_debug.o
 endif
 
 libperf-y += perf-hooks.o
+libperf-y += jit-helpers.o
 
 libperf-$(CONFIG_CXX) += c++/
 
diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp
index f8ea9bd..48bd3ee 100644
--- a/tools/perf/util/c++/clang.cpp
+++ b/tools/perf/util/c++/clang.cpp
@@ -38,6 +38,7 @@
 #include "llvm-utils.h"
 #include "util-cxx.h"
 #include "perf-hooks.h"
+#include "jit-helpers.h"
 
 namespace perf {
 
@@ -196,12 +197,18 @@ PerfModule::toBPFObject(void)
return std::move(Buffer);
 }
 
+#define __stringify_1(x)   #x
+#define __stringify(x) __stringify_1(x)
 static std::map exported_funcs =
 {
-#define EXPORT(f) {#f, (const void *)&f}
+#define EXPORT(f) {__stringify(f), (const void *)&f}
EXPORT(test__clang_callback),
EXPORT(printf),
EXPORT(puts),
+   EXPORT(JIT_HELPER_FUNC_NAME(map_update_elem)),
+   EXPORT(JIT_HELPER_FUNC_NAME(map_lookup_elem)),
+   EXPORT(JIT_HELPER_FUNC_NAME(map_get_next_key)),
+   EXPORT(JIT_HELPER_FUNC_NAME(map_pin)),
 #undef EXPORT
 };
 
diff --git a/tools/perf/util/jit-helpers.c b/tools/perf/util/jit-helpers.c
new file mode 100644
index 000..1a37a20
--- /dev/null
+++ b/tools/perf/util/jit-helpers.c
@@ -0,0 +1,57 @@
+/*
+ * jit-helper.c
+ *
+ * Copyright (C) 2016 Wang Nan 
+ * Copyright (C) 2016 Huawei Inc.
+ *
+ * Provide helpers which can be invoked by jit scripts attached to
+ * perf hooks.
+ */
+
+#include 
+#include 
+#include 
+#include 
+
+#include "asm/bug.h"
+
+static int get_bpf_map_fd(struct bpf_object *obj, void *map)
+{
+   int fd;
+   char errbuf[BUFSIZ];
+
+   fd = bpf__map_fd(obj, map);
+   if (fd < 0) {
+