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

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

Merge "msm: perf: add perf trace user"

parents 8b7519ff b49a34b2
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@ endif
obj-$(CONFIG_USE_OF) += board-dt.o

obj-y += acpuclock.o
obj-$(CONFIG_HW_PERF_EVENTS) += perf_trace_counters.o
obj-$(CONFIG_HW_PERF_EVENTS) += perf_trace_counters.o perf_trace_user.o
obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o perf_event_msm_krait_l2.o
obj-$(CONFIG_ARCH_MSM_KRAIT) += krait-scm.o
obj-$(CONFIG_DEBUG_FS) += perf_debug.o
+1 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ static char *descriptions =
	"29 msm: perf: Refine disable/enable in tracecounters\n"
	"30 Perf: reset pmu enables when starting perf\n"
	"31 Perf: make debug dir handle exportable\n"
	"32 msm: perf: add perf trace user\n"
;

static ssize_t desc_read(struct file *fp, char __user *buf,
+127 −0
Original line number 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
u32 perf_num_l2ctrs;

static int perf_trace_write(struct file *file,
			    const char __user *user_string_in,
			    size_t len, loff_t *ppos)
{
	u32 cnten_val;
	u32 bit;
	u32 cpu;
	u32 num_cores = nr_cpu_ids;
	u32 l2_enmask;
	u32 l2_cnten_val;
	unsigned long idx;
	int i;
	int rc;
	char buf[TRACE_USER_MAX_BUF_SIZE + 1];
	int 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);

	/* 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();
	cpu = smp_processor_id();

	/* stop counters, call the trace function, restart them */

	/* Read PMCNTENSET */
	asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(cnten_val));
	/* Disable all the counters that were enabled */
	asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r"(cnten_val));

	l2_cnten_val = get_l2_indirect_reg(L2PMCNTENSET);
	l2_enmask = 0;
	for (i = 0; i < NUM_L2_PERCPU; i++) {
		/*
		 * Assign L2 counters to cores sequentially
		 * starting from zero. A core could have
		 * multiple L2 counters allocated if # L2
		 * counters is more than the # cores
		 */
		idx = cpu + (num_cores * i);
		bit = BIT(idx);
		if (idx < perf_num_l2ctrs && (l2_cnten_val & bit)) {
			/* Disable */
			set_l2_indirect_reg(L2PMCNTENCLR, bit);
			l2_enmask |= bit;
		}
	}
	trace_perf_trace_user(buf, cnten_val, l2_enmask);

	/* Enable L2*/
	set_l2_indirect_reg(L2PMCNTENSET, l2_enmask);

	/* Enable all the counters that were disabled */
	asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "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)
{
	u32 val;
	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;

	val = get_l2_indirect_reg(L2PMCR);
	perf_num_l2ctrs = ((val >> 11) & 0x1f) + 1;

	return 0;
}

late_initcall(init_perf_trace);
+104 −0
Original line number 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.
 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM perf_trace_counters

#if !defined(_PERF_TRACE_USER_H_) || defined(TRACE_HEADER_MULTI_READ)
#define _PERF_TRACE_USER_H_

#include <linux/cpumask.h>
#include <linux/tracepoint.h>
#include <mach/msm-krait-l2-accessors.h>

#define CNTENSET_CC    0x80000000
#define NUM_L1_CTRS             4
#define NUM_L2_PERCPU           2

extern u32 perf_num_l2ctrs;

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

	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];
		u32 l2_cnts[NUM_L2_PERCPU];
		unsigned long idx;
		int i;

		if (cnten_val & CNTENSET_CC) {
			/* Read value */
			asm volatile("mrc p15, 0, %0, c9, c13, 0"
				     : "=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("mcr p15, 0, %0, c9, c12, 5"
					     : : "r"(i));
				/* Read value */
				asm volatile("mrc p15, 0, %0, c9, c13, 2"
					     : "=r"(cnt));
				l1_cnts[i] = cnt;
			} else {
				l1_cnts[i] = 0;
			}
		}

		/* L2 counters */
		i = 0;
		l2_cnts[0] = 0;
		l2_cnts[1] = 0;
		for_each_set_bit(idx, &l2_enmask, perf_num_l2ctrs) {
			/*
			 * L2PMXEVCNTR address offsets increment by 16,
			 * so multiply idx by 16 to get the next reg
			 */
			l2_cnts[i++] = get_l2_indirect_reg(
				(idx * 16) + IA_L2PMXEVCNTR_BASE);
		}
		__entry->ctr0 = l1_cnts[0];
		__entry->ctr1 = l1_cnts[1];
		__entry->ctr2 = l1_cnts[2];
		__entry->ctr3 = l1_cnts[3];
		__entry->lctr0 = l2_cnts[0];
		__entry->lctr1 = l2_cnts[1];
		__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/arm/mach-msm
#define TRACE_INCLUDE_FILE perf_trace_user
#include <trace/define_trace.h>