Add perf context support for ARMv7
authorJulien Desfossez <jdesfossez@efficios.com>
Mon, 27 Jun 2016 21:40:01 +0000 (17:40 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Mon, 27 Jun 2016 23:10:39 +0000 (19:10 -0400)
Allow to add perf context to UST traces. ARMv7 does not have a reliable
way to read perf PMU counters entirely from user-space like we do on
x86, so this approach requires a system call every time a counter needs
to be read which has a significant performance impact.

ARMv7 does not have way to read PMU from userspace because it requires
write access to the debug coprocessor to select which PMU counter to
read which defeats user-space/kernel protection. For that reason, the
bits required to allow user-space access to those registers are not
enabled in the kernel and Perf does not expose any information in the
shared mmap page, so we do not know what is the counter index. Also, for
ARMv7 we cannot set the exclude_kernel flag, so the counter stays active
even when the process is executing in kernel context (system calls
mainly).

This generic approach might work on other architecture, but it has not
yet been tested so it is not enabled in the code.

Signed-off-by: Julien Desfossez <jdesfossez@efficios.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
configure.ac
liblttng-ust-ctl/ustctl.c
liblttng-ust/lttng-context-perf-counters.c

index 105b46ff97831a549aa8304bd78a260701fe223f..a9667329a42244d18fec9175c99dc9e9d65354e1 100644 (file)
@@ -222,6 +222,7 @@ AS_CASE([$host_cpu],
        [i[[3456]]86], [UST_SUPPORT_FOR_ARCH_PERF_EVENT_COUNTERS=yes],
        [x86_64], [UST_SUPPORT_FOR_ARCH_PERF_EVENT_COUNTERS=yes],
        [amd64], [UST_SUPPORT_FOR_ARCH_PERF_EVENT_COUNTERS=yes],
+       [armv7l], [UST_SUPPORT_FOR_ARCH_PERF_EVENT_COUNTERS=yes],
        [UST_SUPPORT_FOR_ARCH_PERF_EVENT_COUNTERS=no])
 AC_MSG_RESULT([$UST_SUPPORT_FOR_ARCH_PERF_EVENT_COUNTERS])
 
index 0165786c256b18203f49e9951132ead745ad638e..97445d5ecb90252e0cfaf43df2a018eeb789a34c 100644 (file)
@@ -1742,7 +1742,7 @@ int ustctl_get_instance_id(struct ustctl_consumer_stream *stream,
        return client_cb->instance_id(buf, handle, id);
 }
 
-#if defined(__x86_64__) || defined(__i386__)
+#if defined(__x86_64__) || defined(__i386__) || defined(__ARM_ARCH_7A__)
 
 int ustctl_has_perf_counters(void)
 {
index 383d020ce42e02be05c4c89dbd578294091aa6c9..c98e2ebdceeb2786862fcb95d8f331ae115aab0d 100644 (file)
@@ -96,17 +96,13 @@ static bool arch_perf_use_read(void)
        return false;
 }
 
-#else /* defined(__x86_64__) || defined(__i386__) */
-
-#error "Perf event counters are only supported on x86 so far."
-
-#endif /* #else defined(__x86_64__) || defined(__i386__) */
-
 static
-uint64_t read_perf_counter(struct perf_event_mmap_page *pc)
+uint64_t read_perf_counter(
+               struct lttng_perf_counter_thread_field *thread_field)
 {
        uint32_t seq, idx;
        uint64_t count;
+       struct perf_event_mmap_page *pc = thread_field->pc;
 
        if (caa_unlikely(!pc))
                return 0;
@@ -127,6 +123,35 @@ uint64_t read_perf_counter(struct perf_event_mmap_page *pc)
        return count;
 }
 
+#elif defined (__ARM_ARCH_7A__)
+
+static bool arch_perf_use_read(void)
+{
+       return true;
+}
+
+static
+uint64_t read_perf_counter(
+               struct lttng_perf_counter_thread_field *thread_field)
+{
+       uint64_t count;
+
+       if (caa_unlikely(thread_field->fd < 0))
+               return 0;
+
+       if (caa_unlikely(read(thread_field->fd, &count, sizeof(count))
+                               < sizeof(count)))
+               return 0;
+
+       return count;
+}
+
+#else /* defined(__x86_64__) || defined(__i386__) || defined(__ARM_ARCH_7A__) */
+
+#error "Perf event counters are only supported on x86 and ARMv7 so far."
+
+#endif /* #else defined(__x86_64__) || defined(__i386__) || defined(__ARM_ARCH_7A__) */
+
 static
 int sys_perf_event_open(struct perf_event_attr *attr,
                pid_t pid, int cpu, int group_fd,
@@ -148,6 +173,20 @@ int open_perf_fd(struct perf_event_attr *attr)
        return fd;
 }
 
+static
+void close_perf_fd(int fd)
+{
+       int ret;
+
+       if (fd < 0)
+               return;
+
+       ret = close(fd);
+       if (ret) {
+               perror("Error closing LTTng-UST perf memory mapping FD");
+       }
+}
+
 static
 struct perf_event_mmap_page *setup_perf(
                struct lttng_perf_counter_thread_field *thread_field)
@@ -164,23 +203,9 @@ struct perf_event_mmap_page *setup_perf(
                thread_field->fd = -1;
        }
 
-end:
        return perf_addr;
 }
 
-static
-void close_perf_fd(int fd)
-{
-       int ret;
-
-       if (fd < 0)
-               return;
-
-       ret = close(fd);
-       if (ret)
-               perror("Error closing LTTng-UST perf memory mapping FD");
-}
-
 static
 void unmap_perf_page(struct perf_event_mmap_page *pc)
 {
@@ -298,7 +323,7 @@ uint64_t wrapper_perf_counter_read(struct lttng_ctx_field *field)
 
        perf_field = field->u.perf_counter;
        perf_thread_field = get_thread_field(perf_field);
-       return read_perf_counter(perf_thread_field->pc);
+       return read_perf_counter(perf_thread_field);
 }
 
 static
@@ -369,6 +394,24 @@ void lttng_destroy_perf_counter_field(struct lttng_ctx_field *field)
        free(perf_field);
 }
 
+#ifdef __ARM_ARCH_7A__
+
+static
+int perf_get_exclude_kernel(void)
+{
+       return 0;
+}
+
+#else /* __ARM_ARCH_7A__ */
+
+static
+int perf_get_exclude_kernel(void)
+{
+       return 1;
+}
+
+#endif /* __ARM_ARCH_7A__ */
+
 /* Called with UST lock held */
 int lttng_add_perf_counter_to_ctx(uint32_t type,
                                uint64_t config,
@@ -419,7 +462,7 @@ int lttng_add_perf_counter_to_ctx(uint32_t type,
 
        perf_field->attr.type = type;
        perf_field->attr.config = config;
-       perf_field->attr.exclude_kernel = 1;
+       perf_field->attr.exclude_kernel = perf_get_exclude_kernel();
        CDS_INIT_LIST_HEAD(&perf_field->thread_field_list);
        field->u.perf_counter = perf_field;
 
This page took 0.028956 seconds and 4 git commands to generate.