Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3e284bf3 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "Perf: arm64: add perf trace user"

parents 05160a08 295e31f6
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -25,7 +25,8 @@ arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
arm64-obj-$(CONFIG_SMP)			+= smp.o smp_spin_table.o topology.o
arm64-obj-$(CONFIG_SMP)			+= smp.o smp_spin_table.o topology.o
arm64-obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o
arm64-obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS)	+= perf_event.o perf_debug.o 		\
arm64-obj-$(CONFIG_HW_PERF_EVENTS)	+= perf_event.o perf_debug.o 		\
					   perf_trace_counters.o
					   perf_trace_counters.o 		\
					   perf_trace_user.o
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= hw_breakpoint.o
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= hw_breakpoint.o
arm64-obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
arm64-obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND)	+= sleep.o suspend.o
arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND)	+= sleep.o suspend.o
+1 −0
Original line number Original line Diff line number Diff line
@@ -38,6 +38,7 @@ static char *descriptions =
	"13 Perf: arm64: restore registers after reset\n"
	"13 Perf: arm64: restore registers after reset\n"
	"14 Perf: arm64: stop counters when going into hotplug\n"
	"14 Perf: arm64: stop counters when going into hotplug\n"
	"15 Perf: arm64: make debug dir handle exportable\n"
	"15 Perf: arm64: make debug dir handle exportable\n"
	"16 Perf: arm64: add perf trace user\n"
;
;


static ssize_t desc_read(struct file *fp, char __user *buf,
static ssize_t desc_read(struct file *fp, char __user *buf,
+96 −0
Original line number Original line Diff line number Diff line
/* Copyright (c) 2014, 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 <linux/perf_event.h>
#include <linux/types.h>
#include <linux/tracepoint.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/preempt.h>
#include <linux/stat.h>
#include <asm/uaccess.h>

#define CREATE_TRACE_POINTS
#include "perf_trace_user.h"

#undef TRACE_SYSTEM
#define TRACE_SYSTEM perf_trace_counters

#define TRACE_USER_MAX_BUF_SIZE 100

static ssize_t perf_trace_write(struct file *file,
				const char __user *user_string_in,
				size_t len, loff_t *ppos)
{
	u32 cnten_val;
	int rc;
	char buf[TRACE_USER_MAX_BUF_SIZE + 1];
	ssize_t length;

	if (len == 0)
		return 0;

	length = len > TRACE_USER_MAX_BUF_SIZE ? TRACE_USER_MAX_BUF_SIZE : len;

	rc = copy_from_user(buf, user_string_in, length);
	if (rc) {
		pr_err("%s copy_from_user failed, rc=%d\n", __func__, rc);
		return length;
	}

	/* Remove any trailing newline and make sure string is terminated */
	if (buf[length - 1] == '\n')
		buf[length - 1] = '\0';
	else
		buf[length] = '\0';

	/*
	 * Disable preemption to ensure that all the performance counter
	 * accesses happen on the same cpu
	 */
	preempt_disable();
	/* stop counters, call the trace function, restart them */

	asm volatile("mrs %0, pmcntenset_el0" : "=r" (cnten_val));
	/* Disable all the counters that were enabled */
	asm volatile("msr pmcntenclr_el0, %0" : : "r" (cnten_val));

	trace_perf_trace_user(buf, cnten_val);

	/* Enable all the counters that were disabled */
	asm volatile("msr pmcntenset_el0, %0" : : "r" (cnten_val));
	preempt_enable();

	return length;
}

static const struct file_operations perf_trace_fops = {
	.write = perf_trace_write
};

static int __init init_perf_trace(void)
{
	struct dentry *dir;
	struct dentry *file;
	unsigned int value = 1;

	dir = perf_create_debug_dir();
	if (!dir)
		return -ENOMEM;
	file = debugfs_create_file("trace_marker", S_IWUSR | S_IWGRP, dir,
		&value, &perf_trace_fops);
	if (!file)
		return -ENOMEM;

	return 0;
}

late_initcall(init_perf_trace);
+85 −0
Original line number Original line Diff line number Diff line
/* Copyright (c) 2014, 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.
 */
#if !defined(_PERF_TRACE_USER_H_) || defined(TRACE_HEADER_MULTI_READ)
#define _PERF_TRACE_USER_H_

#undef TRACE_SYSTEM
#define TRACE_SYSTEM perf_trace_counters

#include <linux/tracepoint.h>

#define CNTENSET_CC    0x80000000
#define NUM_L1_CTRS             4

TRACE_EVENT(perf_trace_user,
	TP_PROTO(char *string, u32 cnten_val),
	TP_ARGS(string, cnten_val),

	TP_STRUCT__entry(
		__field(u32, cctr)
		__field(u32, ctr0)
		__field(u32, ctr1)
		__field(u32, ctr2)
		__field(u32, ctr3)
		__field(u32, lctr0)
		__field(u32, lctr1)
		__string(user_string, string)
		),

	TP_fast_assign(
		u32 cnt;
		u32 l1_cnts[NUM_L1_CTRS];
		int i;

		if (cnten_val & CNTENSET_CC) {
			/* Read value */
			asm volatile("mrs %0, pmccntr_el0" : "=r" (cnt));
			__entry->cctr = cnt;
		} else
			__entry->cctr = 0;
		for (i = 0; i < NUM_L1_CTRS; i++) {
			if (cnten_val & (1 << i)) {
				/* Select */
				asm volatile("msr pmselr_el0, %0"
					     : : "r" (i));
				isb();
				/* Read value */
				asm volatile("mrs %0, pmxevcntr_el0"
					     : "=r" (cnt));
				l1_cnts[i] = cnt;
			} else {
				l1_cnts[i] = 0;
			}
		}

		__entry->ctr0 = l1_cnts[0];
		__entry->ctr1 = l1_cnts[1];
		__entry->ctr2 = l1_cnts[2];
		__entry->ctr3 = l1_cnts[3];
		__entry->lctr0 = 0;
		__entry->lctr1 = 0;
		__assign_str(user_string, string);
		),

		TP_printk("CCNTR: %u, CTR0: %u, CTR1: %u, CTR2: %u, CTR3: %u, L2CTR0: %u, L2CTR1: %u, MSG=%s",
			  __entry->cctr, __entry->ctr0, __entry->ctr1,
			  __entry->ctr2, __entry->ctr3,
			  __entry->lctr0, __entry->lctr1,
			  __get_str(user_string)
			)
	);

#endif
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH ../../arch/arm64/kernel
#define TRACE_INCLUDE_FILE perf_trace_user
#include <trace/define_trace.h>