xref: /openbmc/linux/kernel/events/callchain.c (revision 9251f904f95175b4a1d8cbc0449e748f9edd7629)
1*9251f904SBorislav Petkov /*
2*9251f904SBorislav Petkov  * Performance events callchain code, extracted from core.c:
3*9251f904SBorislav Petkov  *
4*9251f904SBorislav Petkov  *  Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
5*9251f904SBorislav Petkov  *  Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar
6*9251f904SBorislav Petkov  *  Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
7*9251f904SBorislav Petkov  *  Copyright  �  2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
8*9251f904SBorislav Petkov  *
9*9251f904SBorislav Petkov  * For licensing details see kernel-base/COPYING
10*9251f904SBorislav Petkov  */
11*9251f904SBorislav Petkov 
12*9251f904SBorislav Petkov #include <linux/perf_event.h>
13*9251f904SBorislav Petkov #include <linux/slab.h>
14*9251f904SBorislav Petkov #include "internal.h"
15*9251f904SBorislav Petkov 
16*9251f904SBorislav Petkov struct callchain_cpus_entries {
17*9251f904SBorislav Petkov 	struct rcu_head			rcu_head;
18*9251f904SBorislav Petkov 	struct perf_callchain_entry	*cpu_entries[0];
19*9251f904SBorislav Petkov };
20*9251f904SBorislav Petkov 
21*9251f904SBorislav Petkov static DEFINE_PER_CPU(int, callchain_recursion[PERF_NR_CONTEXTS]);
22*9251f904SBorislav Petkov static atomic_t nr_callchain_events;
23*9251f904SBorislav Petkov static DEFINE_MUTEX(callchain_mutex);
24*9251f904SBorislav Petkov static struct callchain_cpus_entries *callchain_cpus_entries;
25*9251f904SBorislav Petkov 
26*9251f904SBorislav Petkov 
27*9251f904SBorislav Petkov __weak void perf_callchain_kernel(struct perf_callchain_entry *entry,
28*9251f904SBorislav Petkov 				  struct pt_regs *regs)
29*9251f904SBorislav Petkov {
30*9251f904SBorislav Petkov }
31*9251f904SBorislav Petkov 
32*9251f904SBorislav Petkov __weak void perf_callchain_user(struct perf_callchain_entry *entry,
33*9251f904SBorislav Petkov 				struct pt_regs *regs)
34*9251f904SBorislav Petkov {
35*9251f904SBorislav Petkov }
36*9251f904SBorislav Petkov 
37*9251f904SBorislav Petkov static void release_callchain_buffers_rcu(struct rcu_head *head)
38*9251f904SBorislav Petkov {
39*9251f904SBorislav Petkov 	struct callchain_cpus_entries *entries;
40*9251f904SBorislav Petkov 	int cpu;
41*9251f904SBorislav Petkov 
42*9251f904SBorislav Petkov 	entries = container_of(head, struct callchain_cpus_entries, rcu_head);
43*9251f904SBorislav Petkov 
44*9251f904SBorislav Petkov 	for_each_possible_cpu(cpu)
45*9251f904SBorislav Petkov 		kfree(entries->cpu_entries[cpu]);
46*9251f904SBorislav Petkov 
47*9251f904SBorislav Petkov 	kfree(entries);
48*9251f904SBorislav Petkov }
49*9251f904SBorislav Petkov 
50*9251f904SBorislav Petkov static void release_callchain_buffers(void)
51*9251f904SBorislav Petkov {
52*9251f904SBorislav Petkov 	struct callchain_cpus_entries *entries;
53*9251f904SBorislav Petkov 
54*9251f904SBorislav Petkov 	entries = callchain_cpus_entries;
55*9251f904SBorislav Petkov 	rcu_assign_pointer(callchain_cpus_entries, NULL);
56*9251f904SBorislav Petkov 	call_rcu(&entries->rcu_head, release_callchain_buffers_rcu);
57*9251f904SBorislav Petkov }
58*9251f904SBorislav Petkov 
59*9251f904SBorislav Petkov static int alloc_callchain_buffers(void)
60*9251f904SBorislav Petkov {
61*9251f904SBorislav Petkov 	int cpu;
62*9251f904SBorislav Petkov 	int size;
63*9251f904SBorislav Petkov 	struct callchain_cpus_entries *entries;
64*9251f904SBorislav Petkov 
65*9251f904SBorislav Petkov 	/*
66*9251f904SBorislav Petkov 	 * We can't use the percpu allocation API for data that can be
67*9251f904SBorislav Petkov 	 * accessed from NMI. Use a temporary manual per cpu allocation
68*9251f904SBorislav Petkov 	 * until that gets sorted out.
69*9251f904SBorislav Petkov 	 */
70*9251f904SBorislav Petkov 	size = offsetof(struct callchain_cpus_entries, cpu_entries[nr_cpu_ids]);
71*9251f904SBorislav Petkov 
72*9251f904SBorislav Petkov 	entries = kzalloc(size, GFP_KERNEL);
73*9251f904SBorislav Petkov 	if (!entries)
74*9251f904SBorislav Petkov 		return -ENOMEM;
75*9251f904SBorislav Petkov 
76*9251f904SBorislav Petkov 	size = sizeof(struct perf_callchain_entry) * PERF_NR_CONTEXTS;
77*9251f904SBorislav Petkov 
78*9251f904SBorislav Petkov 	for_each_possible_cpu(cpu) {
79*9251f904SBorislav Petkov 		entries->cpu_entries[cpu] = kmalloc_node(size, GFP_KERNEL,
80*9251f904SBorislav Petkov 							 cpu_to_node(cpu));
81*9251f904SBorislav Petkov 		if (!entries->cpu_entries[cpu])
82*9251f904SBorislav Petkov 			goto fail;
83*9251f904SBorislav Petkov 	}
84*9251f904SBorislav Petkov 
85*9251f904SBorislav Petkov 	rcu_assign_pointer(callchain_cpus_entries, entries);
86*9251f904SBorislav Petkov 
87*9251f904SBorislav Petkov 	return 0;
88*9251f904SBorislav Petkov 
89*9251f904SBorislav Petkov fail:
90*9251f904SBorislav Petkov 	for_each_possible_cpu(cpu)
91*9251f904SBorislav Petkov 		kfree(entries->cpu_entries[cpu]);
92*9251f904SBorislav Petkov 	kfree(entries);
93*9251f904SBorislav Petkov 
94*9251f904SBorislav Petkov 	return -ENOMEM;
95*9251f904SBorislav Petkov }
96*9251f904SBorislav Petkov 
97*9251f904SBorislav Petkov int get_callchain_buffers(void)
98*9251f904SBorislav Petkov {
99*9251f904SBorislav Petkov 	int err = 0;
100*9251f904SBorislav Petkov 	int count;
101*9251f904SBorislav Petkov 
102*9251f904SBorislav Petkov 	mutex_lock(&callchain_mutex);
103*9251f904SBorislav Petkov 
104*9251f904SBorislav Petkov 	count = atomic_inc_return(&nr_callchain_events);
105*9251f904SBorislav Petkov 	if (WARN_ON_ONCE(count < 1)) {
106*9251f904SBorislav Petkov 		err = -EINVAL;
107*9251f904SBorislav Petkov 		goto exit;
108*9251f904SBorislav Petkov 	}
109*9251f904SBorislav Petkov 
110*9251f904SBorislav Petkov 	if (count > 1) {
111*9251f904SBorislav Petkov 		/* If the allocation failed, give up */
112*9251f904SBorislav Petkov 		if (!callchain_cpus_entries)
113*9251f904SBorislav Petkov 			err = -ENOMEM;
114*9251f904SBorislav Petkov 		goto exit;
115*9251f904SBorislav Petkov 	}
116*9251f904SBorislav Petkov 
117*9251f904SBorislav Petkov 	err = alloc_callchain_buffers();
118*9251f904SBorislav Petkov 	if (err)
119*9251f904SBorislav Petkov 		release_callchain_buffers();
120*9251f904SBorislav Petkov exit:
121*9251f904SBorislav Petkov 	mutex_unlock(&callchain_mutex);
122*9251f904SBorislav Petkov 
123*9251f904SBorislav Petkov 	return err;
124*9251f904SBorislav Petkov }
125*9251f904SBorislav Petkov 
126*9251f904SBorislav Petkov void put_callchain_buffers(void)
127*9251f904SBorislav Petkov {
128*9251f904SBorislav Petkov 	if (atomic_dec_and_mutex_lock(&nr_callchain_events, &callchain_mutex)) {
129*9251f904SBorislav Petkov 		release_callchain_buffers();
130*9251f904SBorislav Petkov 		mutex_unlock(&callchain_mutex);
131*9251f904SBorislav Petkov 	}
132*9251f904SBorislav Petkov }
133*9251f904SBorislav Petkov 
134*9251f904SBorislav Petkov static struct perf_callchain_entry *get_callchain_entry(int *rctx)
135*9251f904SBorislav Petkov {
136*9251f904SBorislav Petkov 	int cpu;
137*9251f904SBorislav Petkov 	struct callchain_cpus_entries *entries;
138*9251f904SBorislav Petkov 
139*9251f904SBorislav Petkov 	*rctx = get_recursion_context(__get_cpu_var(callchain_recursion));
140*9251f904SBorislav Petkov 	if (*rctx == -1)
141*9251f904SBorislav Petkov 		return NULL;
142*9251f904SBorislav Petkov 
143*9251f904SBorislav Petkov 	entries = rcu_dereference(callchain_cpus_entries);
144*9251f904SBorislav Petkov 	if (!entries)
145*9251f904SBorislav Petkov 		return NULL;
146*9251f904SBorislav Petkov 
147*9251f904SBorislav Petkov 	cpu = smp_processor_id();
148*9251f904SBorislav Petkov 
149*9251f904SBorislav Petkov 	return &entries->cpu_entries[cpu][*rctx];
150*9251f904SBorislav Petkov }
151*9251f904SBorislav Petkov 
152*9251f904SBorislav Petkov static void
153*9251f904SBorislav Petkov put_callchain_entry(int rctx)
154*9251f904SBorislav Petkov {
155*9251f904SBorislav Petkov 	put_recursion_context(__get_cpu_var(callchain_recursion), rctx);
156*9251f904SBorislav Petkov }
157*9251f904SBorislav Petkov 
158*9251f904SBorislav Petkov struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
159*9251f904SBorislav Petkov {
160*9251f904SBorislav Petkov 	int rctx;
161*9251f904SBorislav Petkov 	struct perf_callchain_entry *entry;
162*9251f904SBorislav Petkov 
163*9251f904SBorislav Petkov 
164*9251f904SBorislav Petkov 	entry = get_callchain_entry(&rctx);
165*9251f904SBorislav Petkov 	if (rctx == -1)
166*9251f904SBorislav Petkov 		return NULL;
167*9251f904SBorislav Petkov 
168*9251f904SBorislav Petkov 	if (!entry)
169*9251f904SBorislav Petkov 		goto exit_put;
170*9251f904SBorislav Petkov 
171*9251f904SBorislav Petkov 	entry->nr = 0;
172*9251f904SBorislav Petkov 
173*9251f904SBorislav Petkov 	if (!user_mode(regs)) {
174*9251f904SBorislav Petkov 		perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
175*9251f904SBorislav Petkov 		perf_callchain_kernel(entry, regs);
176*9251f904SBorislav Petkov 		if (current->mm)
177*9251f904SBorislav Petkov 			regs = task_pt_regs(current);
178*9251f904SBorislav Petkov 		else
179*9251f904SBorislav Petkov 			regs = NULL;
180*9251f904SBorislav Petkov 	}
181*9251f904SBorislav Petkov 
182*9251f904SBorislav Petkov 	if (regs) {
183*9251f904SBorislav Petkov 		perf_callchain_store(entry, PERF_CONTEXT_USER);
184*9251f904SBorislav Petkov 		perf_callchain_user(entry, regs);
185*9251f904SBorislav Petkov 	}
186*9251f904SBorislav Petkov 
187*9251f904SBorislav Petkov exit_put:
188*9251f904SBorislav Petkov 	put_callchain_entry(rctx);
189*9251f904SBorislav Petkov 
190*9251f904SBorislav Petkov 	return entry;
191*9251f904SBorislav Petkov }
192