Perf: Add L1 counters to tracepoints
Create a new tracepoint to get L1 PMU counter
information at every context switch. Counters
are captured only when the tracepoint is enabled
via perf or ftrace.
Change-Id: If05527b29e04c700170cfdf9f88d300b2f558ffa
Signed-off-by: Ashwin Chaugule <ashwinc@codeaurora.org>
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index d07b094..dc8b675 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -24,6 +24,7 @@
endif
obj-y += acpuclock.o
+obj-$(CONFIG_HW_PERF_EVENTS) += perf_trace_counters.o
obj-$(CONFIG_ARCH_MSM_KRAIT) += acpuclock-krait.o
ifdef CONFIG_ARCH_MSM_KRAIT
obj-$(CONFIG_DEBUG_FS) += acpuclock-krait-debug.o
diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
index 96122de..5bf88a2 100644
--- a/arch/arm/mach-msm/perf_debug.c
+++ b/arch/arm/mach-msm/perf_debug.c
@@ -29,6 +29,7 @@
"4 Perf: Check perf activity on correct CPU\n"
"5 Perf: Add DT support for L1 and L2 PMU\n"
"6 Perf: Add cortex A5 device tree support\n"
+ "7 Perf: Add L1 counters to tracepoints\n"
;
static ssize_t desc_read(struct file *fp, char __user *buf,
diff --git a/arch/arm/mach-msm/perf_trace_counters.c b/arch/arm/mach-msm/perf_trace_counters.c
new file mode 100644
index 0000000..d961994
--- /dev/null
+++ b/arch/arm/mach-msm/perf_trace_counters.c
@@ -0,0 +1,42 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <asm/thread_notify.h>
+#define CREATE_TRACE_POINTS
+#include "perf_trace_counters.h"
+
+static int tracectr_notifier(struct notifier_block *self, unsigned long cmd,
+ void *v)
+{
+ static int old_pid = -1;
+ struct thread_info *thread = v;
+ int current_pid;
+
+ if (cmd != THREAD_NOTIFY_SWITCH)
+ return old_pid;
+
+ current_pid = thread->task->pid;
+ if (old_pid != -1)
+ trace_sched_switch_with_ctrs(old_pid, current_pid);
+ old_pid = current_pid;
+ return old_pid;
+}
+
+static struct notifier_block tracectr_notifier_block = {
+ .notifier_call = tracectr_notifier,
+};
+
+int __init init_tracecounters(void)
+{
+ thread_register_notifier(&tracectr_notifier_block);
+ return 0;
+}
+late_initcall(init_tracecounters);
diff --git a/arch/arm/mach-msm/perf_trace_counters.h b/arch/arm/mach-msm/perf_trace_counters.h
new file mode 100644
index 0000000..ce7e336
--- /dev/null
+++ b/arch/arm/mach-msm/perf_trace_counters.h
@@ -0,0 +1,127 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM perf_trace_counters
+
+#if !defined(_PERF_TRACE_COUNTERS_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _PERF_TRACE_COUNTERS_H_
+
+/* Ctr index for PMCNTENSET/CLR */
+#define CC 0x80000000
+#define C0 0x1
+#define C1 0x10
+#define C2 0x100
+#define C3 0x1000
+
+
+#include <linux/sched.h>
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(sched_switch_with_ctrs,
+
+ TP_PROTO(pid_t prev, pid_t next),
+
+ TP_ARGS(prev, next),
+
+ TP_STRUCT__entry(
+ __field(pid_t, old_pid)
+ __field(pid_t, new_pid)
+ __field(u32, cctr)
+ __field(u32, ctr0)
+ __field(u32, ctr1)
+ __field(u32, ctr2)
+ __field(u32, ctr3)
+ ),
+
+ TP_fast_assign(
+ __entry->old_pid = prev;
+ __entry->new_pid = next;
+
+ /* cycle counter */
+ /* Disable */
+ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r"(CC));
+ /* Read value */
+ asm volatile("mrc p15, 0, %0, c9, c13, 0"
+ : "=r"(__entry->cctr));
+ /* Reset */
+ asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r"(0));
+ /* Enable */
+ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r"(CC));
+
+ /* ctr 0 */
+ /* Disable */
+ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r"(C0));
+ /* Select */
+ asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r"(0));
+ /* Read value */
+ asm volatile("mrc p15, 0, %0, c9, c13, 2"
+ : "=r"(__entry->ctr0));
+ /* Reset */
+ asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r"(0));
+ /* Enable */
+ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r"(C0));
+
+ /* ctr 1 */
+ /* Disable */
+ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r"(C1));
+ /* Select */
+ asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r"(1));
+ /* Read value */
+ asm volatile("mrc p15, 0, %0, c9, c13, 2"
+ : "=r"(__entry->ctr1));
+ /* Reset */
+ asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r"(0));
+ /* Enable */
+ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r"(C1));
+
+ /* ctr 2 */
+ /* Disable */
+ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r"(C2));
+ /* Select */
+ asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r"(2));
+ /* Read value */
+ asm volatile("mrc p15, 0, %0, c9, c13, 2"
+ : "=r"(__entry->ctr2));
+ /* Reset */
+ asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r"(0));
+ /* Enable */
+ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r"(C2));
+
+ /* ctr 3 */
+ /* Disable */
+ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r"(C3));
+ /* Select */
+ asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r"(3));
+ /* Read value */
+ asm volatile("mrc p15, 0, %0, c9, c13, 2"
+ : "=r"(__entry->ctr3));
+ /* Reset */
+ asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r"(0));
+ /* Enable */
+ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r"(C3));
+
+ ),
+
+ TP_printk("prev_pid=%d, next_pid=%d, CCNTR: %u, CTR0: %u," \
+ " CTR1: %u, CTR2: %u, CTR3: %u",
+ __entry->old_pid, __entry->new_pid,
+ __entry->cctr, __entry->ctr0, __entry->ctr1,
+ __entry->ctr2, __entry->ctr3)
+);
+
+#endif
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE perf_trace_counters
+#include <trace/define_trace.h>
+