xref: /openbmc/linux/kernel/events/callchain.c (revision e6dab5ffab59e910ec0e3355f4a6f29f7a7be474)
19251f904SBorislav Petkov /*
29251f904SBorislav Petkov  * Performance events callchain code, extracted from core.c:
39251f904SBorislav Petkov  *
49251f904SBorislav Petkov  *  Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
59251f904SBorislav Petkov  *  Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar
69251f904SBorislav Petkov  *  Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
79251f904SBorislav Petkov  *  Copyright  �  2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
89251f904SBorislav Petkov  *
99251f904SBorislav Petkov  * For licensing details see kernel-base/COPYING
109251f904SBorislav Petkov  */
119251f904SBorislav Petkov 
129251f904SBorislav Petkov #include <linux/perf_event.h>
139251f904SBorislav Petkov #include <linux/slab.h>
149251f904SBorislav Petkov #include "internal.h"
159251f904SBorislav Petkov 
169251f904SBorislav Petkov struct callchain_cpus_entries {
179251f904SBorislav Petkov 	struct rcu_head			rcu_head;
189251f904SBorislav Petkov 	struct perf_callchain_entry	*cpu_entries[0];
199251f904SBorislav Petkov };
209251f904SBorislav Petkov 
219251f904SBorislav Petkov static DEFINE_PER_CPU(int, callchain_recursion[PERF_NR_CONTEXTS]);
229251f904SBorislav Petkov static atomic_t nr_callchain_events;
239251f904SBorislav Petkov static DEFINE_MUTEX(callchain_mutex);
249251f904SBorislav Petkov static struct callchain_cpus_entries *callchain_cpus_entries;
259251f904SBorislav Petkov 
269251f904SBorislav Petkov 
279251f904SBorislav Petkov __weak void perf_callchain_kernel(struct perf_callchain_entry *entry,
289251f904SBorislav Petkov 				  struct pt_regs *regs)
299251f904SBorislav Petkov {
309251f904SBorislav Petkov }
319251f904SBorislav Petkov 
329251f904SBorislav Petkov __weak void perf_callchain_user(struct perf_callchain_entry *entry,
339251f904SBorislav Petkov 				struct pt_regs *regs)
349251f904SBorislav Petkov {
359251f904SBorislav Petkov }
369251f904SBorislav Petkov 
379251f904SBorislav Petkov static void release_callchain_buffers_rcu(struct rcu_head *head)
389251f904SBorislav Petkov {
399251f904SBorislav Petkov 	struct callchain_cpus_entries *entries;
409251f904SBorislav Petkov 	int cpu;
419251f904SBorislav Petkov 
429251f904SBorislav Petkov 	entries = container_of(head, struct callchain_cpus_entries, rcu_head);
439251f904SBorislav Petkov 
449251f904SBorislav Petkov 	for_each_possible_cpu(cpu)
459251f904SBorislav Petkov 		kfree(entries->cpu_entries[cpu]);
469251f904SBorislav Petkov 
479251f904SBorislav Petkov 	kfree(entries);
489251f904SBorislav Petkov }
499251f904SBorislav Petkov 
509251f904SBorislav Petkov static void release_callchain_buffers(void)
519251f904SBorislav Petkov {
529251f904SBorislav Petkov 	struct callchain_cpus_entries *entries;
539251f904SBorislav Petkov 
549251f904SBorislav Petkov 	entries = callchain_cpus_entries;
559251f904SBorislav Petkov 	rcu_assign_pointer(callchain_cpus_entries, NULL);
569251f904SBorislav Petkov 	call_rcu(&entries->rcu_head, release_callchain_buffers_rcu);
579251f904SBorislav Petkov }
589251f904SBorislav Petkov 
599251f904SBorislav Petkov static int alloc_callchain_buffers(void)
609251f904SBorislav Petkov {
619251f904SBorislav Petkov 	int cpu;
629251f904SBorislav Petkov 	int size;
639251f904SBorislav Petkov 	struct callchain_cpus_entries *entries;
649251f904SBorislav Petkov 
659251f904SBorislav Petkov 	/*
669251f904SBorislav Petkov 	 * We can't use the percpu allocation API for data that can be
679251f904SBorislav Petkov 	 * accessed from NMI. Use a temporary manual per cpu allocation
689251f904SBorislav Petkov 	 * until that gets sorted out.
699251f904SBorislav Petkov 	 */
709251f904SBorislav Petkov 	size = offsetof(struct callchain_cpus_entries, cpu_entries[nr_cpu_ids]);
719251f904SBorislav Petkov 
729251f904SBorislav Petkov 	entries = kzalloc(size, GFP_KERNEL);
739251f904SBorislav Petkov 	if (!entries)
749251f904SBorislav Petkov 		return -ENOMEM;
759251f904SBorislav Petkov 
769251f904SBorislav Petkov 	size = sizeof(struct perf_callchain_entry) * PERF_NR_CONTEXTS;
779251f904SBorislav Petkov 
789251f904SBorislav Petkov 	for_each_possible_cpu(cpu) {
799251f904SBorislav Petkov 		entries->cpu_entries[cpu] = kmalloc_node(size, GFP_KERNEL,
809251f904SBorislav Petkov 							 cpu_to_node(cpu));
819251f904SBorislav Petkov 		if (!entries->cpu_entries[cpu])
829251f904SBorislav Petkov 			goto fail;
839251f904SBorislav Petkov 	}
849251f904SBorislav Petkov 
859251f904SBorislav Petkov 	rcu_assign_pointer(callchain_cpus_entries, entries);
869251f904SBorislav Petkov 
879251f904SBorislav Petkov 	return 0;
889251f904SBorislav Petkov 
899251f904SBorislav Petkov fail:
909251f904SBorislav Petkov 	for_each_possible_cpu(cpu)
919251f904SBorislav Petkov 		kfree(entries->cpu_entries[cpu]);
929251f904SBorislav Petkov 	kfree(entries);
939251f904SBorislav Petkov 
949251f904SBorislav Petkov 	return -ENOMEM;
959251f904SBorislav Petkov }
969251f904SBorislav Petkov 
979251f904SBorislav Petkov int get_callchain_buffers(void)
989251f904SBorislav Petkov {
999251f904SBorislav Petkov 	int err = 0;
1009251f904SBorislav Petkov 	int count;
1019251f904SBorislav Petkov 
1029251f904SBorislav Petkov 	mutex_lock(&callchain_mutex);
1039251f904SBorislav Petkov 
1049251f904SBorislav Petkov 	count = atomic_inc_return(&nr_callchain_events);
1059251f904SBorislav Petkov 	if (WARN_ON_ONCE(count < 1)) {
1069251f904SBorislav Petkov 		err = -EINVAL;
1079251f904SBorislav Petkov 		goto exit;
1089251f904SBorislav Petkov 	}
1099251f904SBorislav Petkov 
1109251f904SBorislav Petkov 	if (count > 1) {
1119251f904SBorislav Petkov 		/* If the allocation failed, give up */
1129251f904SBorislav Petkov 		if (!callchain_cpus_entries)
1139251f904SBorislav Petkov 			err = -ENOMEM;
1149251f904SBorislav Petkov 		goto exit;
1159251f904SBorislav Petkov 	}
1169251f904SBorislav Petkov 
1179251f904SBorislav Petkov 	err = alloc_callchain_buffers();
1189251f904SBorislav Petkov exit:
1199251f904SBorislav Petkov 	mutex_unlock(&callchain_mutex);
1209251f904SBorislav Petkov 
1219251f904SBorislav Petkov 	return err;
1229251f904SBorislav Petkov }
1239251f904SBorislav Petkov 
1249251f904SBorislav Petkov void put_callchain_buffers(void)
1259251f904SBorislav Petkov {
1269251f904SBorislav Petkov 	if (atomic_dec_and_mutex_lock(&nr_callchain_events, &callchain_mutex)) {
1279251f904SBorislav Petkov 		release_callchain_buffers();
1289251f904SBorislav Petkov 		mutex_unlock(&callchain_mutex);
1299251f904SBorislav Petkov 	}
1309251f904SBorislav Petkov }
1319251f904SBorislav Petkov 
1329251f904SBorislav Petkov static struct perf_callchain_entry *get_callchain_entry(int *rctx)
1339251f904SBorislav Petkov {
1349251f904SBorislav Petkov 	int cpu;
1359251f904SBorislav Petkov 	struct callchain_cpus_entries *entries;
1369251f904SBorislav Petkov 
1379251f904SBorislav Petkov 	*rctx = get_recursion_context(__get_cpu_var(callchain_recursion));
1389251f904SBorislav Petkov 	if (*rctx == -1)
1399251f904SBorislav Petkov 		return NULL;
1409251f904SBorislav Petkov 
1419251f904SBorislav Petkov 	entries = rcu_dereference(callchain_cpus_entries);
1429251f904SBorislav Petkov 	if (!entries)
1439251f904SBorislav Petkov 		return NULL;
1449251f904SBorislav Petkov 
1459251f904SBorislav Petkov 	cpu = smp_processor_id();
1469251f904SBorislav Petkov 
1479251f904SBorislav Petkov 	return &entries->cpu_entries[cpu][*rctx];
1489251f904SBorislav Petkov }
1499251f904SBorislav Petkov 
1509251f904SBorislav Petkov static void
1519251f904SBorislav Petkov put_callchain_entry(int rctx)
1529251f904SBorislav Petkov {
1539251f904SBorislav Petkov 	put_recursion_context(__get_cpu_var(callchain_recursion), rctx);
1549251f904SBorislav Petkov }
1559251f904SBorislav Petkov 
156*e6dab5ffSAndrew Vagin struct perf_callchain_entry *
157*e6dab5ffSAndrew Vagin perf_callchain(struct perf_event *event, struct pt_regs *regs)
1589251f904SBorislav Petkov {
1599251f904SBorislav Petkov 	int rctx;
1609251f904SBorislav Petkov 	struct perf_callchain_entry *entry;
1619251f904SBorislav Petkov 
1629251f904SBorislav Petkov 
1639251f904SBorislav Petkov 	entry = get_callchain_entry(&rctx);
1649251f904SBorislav Petkov 	if (rctx == -1)
1659251f904SBorislav Petkov 		return NULL;
1669251f904SBorislav Petkov 
1679251f904SBorislav Petkov 	if (!entry)
1689251f904SBorislav Petkov 		goto exit_put;
1699251f904SBorislav Petkov 
1709251f904SBorislav Petkov 	entry->nr = 0;
1719251f904SBorislav Petkov 
1729251f904SBorislav Petkov 	if (!user_mode(regs)) {
1739251f904SBorislav Petkov 		perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
1749251f904SBorislav Petkov 		perf_callchain_kernel(entry, regs);
1759251f904SBorislav Petkov 		if (current->mm)
1769251f904SBorislav Petkov 			regs = task_pt_regs(current);
1779251f904SBorislav Petkov 		else
1789251f904SBorislav Petkov 			regs = NULL;
1799251f904SBorislav Petkov 	}
1809251f904SBorislav Petkov 
1819251f904SBorislav Petkov 	if (regs) {
182*e6dab5ffSAndrew Vagin 		/*
183*e6dab5ffSAndrew Vagin 		 * Disallow cross-task user callchains.
184*e6dab5ffSAndrew Vagin 		 */
185*e6dab5ffSAndrew Vagin 		if (event->ctx->task && event->ctx->task != current)
186*e6dab5ffSAndrew Vagin 			goto exit_put;
187*e6dab5ffSAndrew Vagin 
1889251f904SBorislav Petkov 		perf_callchain_store(entry, PERF_CONTEXT_USER);
1899251f904SBorislav Petkov 		perf_callchain_user(entry, regs);
1909251f904SBorislav Petkov 	}
1919251f904SBorislav Petkov 
1929251f904SBorislav Petkov exit_put:
1939251f904SBorislav Petkov 	put_callchain_entry(rctx);
1949251f904SBorislav Petkov 
1959251f904SBorislav Petkov 	return entry;
1969251f904SBorislav Petkov }
197