Skip to contentSkip to conversation

Add perf context support for ARMv7

PATCH New Julien Desfossez 2 participants 2 messages Jun 27, 2016 1 message not in the archive

lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

#1 lore raw

PATCH v4 2/2 Add perf context support for ARMv7

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.

---
 configure.ac                               |  1 +
 liblttng-ust-ctl/ustctl.c                  |  2 +-
 liblttng-ust/lttng-context-perf-counters.c | 89 ++++++++++++++++++++++--------
 3 files changed, 68 insertions(+), 24 deletions(-)
configure.ac +1 -0
index 105b46f..a966732 100644
@@ -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])
 
liblttng-ust-ctl/ustctl.c +1 -1
index 0165786..97445d5 100644
@@ -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)
 {
liblttng-ust/lttng-context-perf-counters.c +66 -23

139 lines not on this page · raw message

Signature · 6 lines
1.9.1

_______________________________________________
lttng-dev mailing list
[email protected]
https://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
#2 lore raw

Re: [PATCH lttng-ust v4 1/2] Keep perf context FD open for other architectures

In reply to a message not in the archive

Both patches merged, thanks!

Mathieu

Quoted 151 lines · ----- On Jun 27, 2016, at 5:40 PM, Julien Desfossez [email protected]…

Instead of closing the perf context after the page has been mapped, keep it open so it can be used with the read() system call if the architecture does not support direct access from user-space.

---
liblttng-ust/lttng-context-perf-counters.c | 65 +++++++++++++++++++++++-------

1 file changed, 50 insertions(+), 15 deletions(-)
liblttng-ust/lttng-context-perf-counters.c +1 -0
index 97ddf97..db756d6 100644
@@ -55,6 +55,7 @@ struct lttng_perf_counter_thread_field {
 	struct perf_event_mmap_page *pc;
 	struct cds_list_head thread_field_node;	/* Per-field list of thread fields
 	(node) */
 	struct cds_list_head rcu_field_node;	/* RCU per-thread list of fields (node) */
+	int fd;					/* Perf FD */
 };
 

struct lttng_perf_counter_thread {

liblttng-ust/lttng-context-perf-counters.c +5 -0
@@ -90,6 +91,11 @@ uint64_t rdpmc(unsigned int counter)
 	return low | ((uint64_t) high) << 32;
 }
 
+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."
@@ -131,27 +137,51 @@ int sys_perf_event_open(struct perf_event_attr *attr,
 }
 

static

liblttng-ust/lttng-context-perf-counters.c +1 -1
-struct perf_event_mmap_page *setup_perf(struct perf_event_attr *attr)
+int open_perf_fd(struct perf_event_attr *attr)

{

liblttng-ust/lttng-context-perf-counters.c +1 -2
-	void *perf_addr;
-	int fd, ret;
+	int fd;
	fd = sys_perf_event_open(attr, 0, -1, -1, 0);
	if (fd < 0)
liblttng-ust/lttng-context-perf-counters.c +10 -1
-		return NULL;
+		return -1;
+
+	return fd;
+}
+
+static
+struct perf_event_mmap_page *setup_perf(
+		struct lttng_perf_counter_thread_field *thread_field)
+{
+	void *perf_addr;

perf_addr = mmap(NULL, sizeof(struct perf_event_mmap_page),

liblttng-ust/lttng-context-perf-counters.c +1 -1
-			PROT_READ, MAP_SHARED, fd, 0);
+			PROT_READ, MAP_SHARED, thread_field->fd, 0);
	if (perf_addr == MAP_FAILED)
liblttng-ust/lttng-context-perf-counters.c +5 -4
-		return NULL;
-	ret = close(fd);
-	if (ret) {
-		perror("Error closing LTTng-UST perf memory mapping FD");
+		perf_addr = NULL;
+
+	if (!arch_perf_use_read()) {
+		close_perf_fd(thread_field->fd);
+		thread_field->fd = -1;
	}
liblttng-ust/lttng-context-perf-counters.c +2 -0
+
+end:
	return perf_addr;
}

static

liblttng-ust/lttng-context-perf-counters.c +13 -0
+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)

{
	int ret;
liblttng-ust/lttng-context-perf-counters.c +7 -2
@@ -221,8 +251,13 @@ struct lttng_perf_counter_thread_field *
 	if (!thread_field)
 		abort();
 	thread_field->field = perf_field;
-	thread_field->pc = setup_perf(&perf_field->attr);
-	/* Note: thread_field->pc can be NULL if setup_perf() fails. */
+	thread_field->fd = open_perf_fd(&perf_field->attr);
+	if (thread_field->fd >= 0)
+		thread_field->pc = setup_perf(thread_field);
+	/*
+	 * Note: thread_field->pc can be NULL if setup_perf() fails.
+	 * Also, thread_field->fd can be -1 if open_perf_fd fails.
+	 */
 	ust_lock_nocheck();
 	cds_list_add_rcu(&thread_field->rcu_field_node,
 			&perf_thread->rcu_field_list);
@@ -293,6 +328,7 @@ static

void lttng_destroy_perf_thread_field(
struct lttng_perf_counter_thread_field *thread_field)
{

liblttng-ust/lttng-context-perf-counters.c +1 -0
+	close_perf_fd(thread_field->fd);
	unmap_perf_page(thread_field->pc);
	cds_list_del_rcu(&thread_field->rcu_field_node);
	cds_list_del(&thread_field->thread_field_node);
liblttng-ust/lttng-context-perf-counters.c +3 -5
@@ -341,7 +377,6 @@ int lttng_add_perf_counter_to_ctx(uint32_t type,
 {
 	struct lttng_ctx_field *field;
 	struct lttng_perf_counter_field *perf_field;
-	struct perf_event_mmap_page *tmp_pc;
 	char *name_alloc;
 	int ret;
 
@@ -389,12 +424,12 @@ int lttng_add_perf_counter_to_ctx(uint32_t type,
 	field->u.perf_counter = perf_field;
 
 	/* Ensure that this perf counter can be used in this process. */
-	tmp_pc = setup_perf(&perf_field->attr);
-	if (!tmp_pc) {
+	ret = open_perf_fd(&perf_field->attr);
+	if (ret < 0) {
 		ret = -ENODEV;
 		goto setup_error;
 	}
-	unmap_perf_page(tmp_pc);
+	close_perf_fd(ret);
 
 	/*
 	 * Contexts can only be added before tracing is started, so we
--

1.9.1

_______________________________________________
lttng-dev mailing list
[email protected]
https://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev

Signature · 7 lines
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com
_______________________________________________
lttng-dev mailing list
[email protected]
https://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev