xref: /titanic_44/usr/src/cmd/powertop/common/events.c (revision b47b5b34b42fa8056577c43496cdb99a4c99f8d7)
1*b47b5b34SRafael Vanoni /*
2*b47b5b34SRafael Vanoni  * Copyright 2009, Intel Corporation
3*b47b5b34SRafael Vanoni  * Copyright 2009, Sun Microsystems, Inc
4*b47b5b34SRafael Vanoni  *
5*b47b5b34SRafael Vanoni  * This file is part of PowerTOP
6*b47b5b34SRafael Vanoni  *
7*b47b5b34SRafael Vanoni  * This program file is free software; you can redistribute it and/or modify it
8*b47b5b34SRafael Vanoni  * under the terms of the GNU General Public License as published by the
9*b47b5b34SRafael Vanoni  * Free Software Foundation; version 2 of the License.
10*b47b5b34SRafael Vanoni  *
11*b47b5b34SRafael Vanoni  * This program is distributed in the hope that it will be useful, but WITHOUT
12*b47b5b34SRafael Vanoni  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13*b47b5b34SRafael Vanoni  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14*b47b5b34SRafael Vanoni  * for more details.
15*b47b5b34SRafael Vanoni  *
16*b47b5b34SRafael Vanoni  * You should have received a copy of the GNU General Public License
17*b47b5b34SRafael Vanoni  * along with this program in a file named COPYING; if not, write to the
18*b47b5b34SRafael Vanoni  * Free Software Foundation, Inc.,
19*b47b5b34SRafael Vanoni  * 51 Franklin Street, Fifth Floor,
20*b47b5b34SRafael Vanoni  * Boston, MA 02110-1301 USA
21*b47b5b34SRafael Vanoni  *
22*b47b5b34SRafael Vanoni  * Authors:
23*b47b5b34SRafael Vanoni  *	Arjan van de Ven <arjan@linux.intel.com>
24*b47b5b34SRafael Vanoni  *	Eric C Saxe <eric.saxe@sun.com>
25*b47b5b34SRafael Vanoni  *	Aubrey Li <aubrey.li@intel.com>
26*b47b5b34SRafael Vanoni  */
27*b47b5b34SRafael Vanoni 
28*b47b5b34SRafael Vanoni /*
29*b47b5b34SRafael Vanoni  * GPL Disclaimer
30*b47b5b34SRafael Vanoni  *
31*b47b5b34SRafael Vanoni  * For the avoidance of doubt, except that if any license choice other
32*b47b5b34SRafael Vanoni  * than GPL or LGPL is available it will apply instead, Sun elects to
33*b47b5b34SRafael Vanoni  * use only the General Public License version 2 (GPLv2) at this time
34*b47b5b34SRafael Vanoni  * for any software where a choice of GPL license versions is made
35*b47b5b34SRafael Vanoni  * available with the language indicating that GPLv2 or any later
36*b47b5b34SRafael Vanoni  * version may be used, or where a choice of which version of the GPL
37*b47b5b34SRafael Vanoni  * is applied is otherwise unspecified.
38*b47b5b34SRafael Vanoni  */
39*b47b5b34SRafael Vanoni 
40*b47b5b34SRafael Vanoni #include <string.h>
41*b47b5b34SRafael Vanoni #include <stdlib.h>
42*b47b5b34SRafael Vanoni #include <dtrace.h>
43*b47b5b34SRafael Vanoni #include "powertop.h"
44*b47b5b34SRafael Vanoni 
45*b47b5b34SRafael Vanoni static dtrace_hdl_t *dtp;
46*b47b5b34SRafael Vanoni 
47*b47b5b34SRafael Vanoni /*ARGSUSED*/
48*b47b5b34SRafael Vanoni static int
49*b47b5b34SRafael Vanoni walk(const dtrace_aggdata_t *data, void *arg)
50*b47b5b34SRafael Vanoni {
51*b47b5b34SRafael Vanoni 	dtrace_aggdesc_t 	*aggdesc = data->dtada_desc;
52*b47b5b34SRafael Vanoni 	dtrace_recdesc_t 	*rec1, *rec2, *rec3;
53*b47b5b34SRafael Vanoni 	dtrace_syminfo_t 	dts;
54*b47b5b34SRafael Vanoni 	char 			*offense_name;
55*b47b5b34SRafael Vanoni 	uint64_t		offender_addr;
56*b47b5b34SRafael Vanoni 	int32_t 		*instance, *offender_cpu;
57*b47b5b34SRafael Vanoni 	int 			i;
58*b47b5b34SRafael Vanoni 	uint64_t 		n = 0;
59*b47b5b34SRafael Vanoni 	GElf_Sym 		sym;
60*b47b5b34SRafael Vanoni 
61*b47b5b34SRafael Vanoni 	if (g_tog_p_events >= EVENT_NUM_MAX)
62*b47b5b34SRafael Vanoni 		return (0);
63*b47b5b34SRafael Vanoni 
64*b47b5b34SRafael Vanoni 	rec1 = &aggdesc->dtagd_rec[1];
65*b47b5b34SRafael Vanoni 	rec2 = &aggdesc->dtagd_rec[2];
66*b47b5b34SRafael Vanoni 
67*b47b5b34SRafael Vanoni 	/*
68*b47b5b34SRafael Vanoni 	 * Report interrupts
69*b47b5b34SRafael Vanoni 	 */
70*b47b5b34SRafael Vanoni 	if (strcmp(aggdesc->dtagd_name, "interrupts") == 0) {
71*b47b5b34SRafael Vanoni 		offense_name = data->dtada_data + rec1->dtrd_offset;
72*b47b5b34SRafael Vanoni 
73*b47b5b34SRafael Vanoni 		/* LINTED - alignment */
74*b47b5b34SRafael Vanoni 		instance = (int32_t *)(data->dtada_data + rec2->dtrd_offset);
75*b47b5b34SRafael Vanoni 		(void) snprintf((char *)(g_p_event->offender_name),
76*b47b5b34SRafael Vanoni 		    EVENT_NAME_MAX, "%s", "<interrupt>");
77*b47b5b34SRafael Vanoni 		(void) snprintf((char *)(g_p_event->offense_name),
78*b47b5b34SRafael Vanoni 		    EVENT_NAME_MAX, "%s#%d", offense_name, *instance);
79*b47b5b34SRafael Vanoni 	/*
80*b47b5b34SRafael Vanoni 	 * Report kernel events
81*b47b5b34SRafael Vanoni 	 */
82*b47b5b34SRafael Vanoni 	} else if (strcmp(aggdesc->dtagd_name, "events_k") == 0) {
83*b47b5b34SRafael Vanoni 
84*b47b5b34SRafael Vanoni 		(void) snprintf((char *)(g_p_event->offender_name),
85*b47b5b34SRafael Vanoni 		    EVENT_NAME_MAX, "%s", "<kernel>");
86*b47b5b34SRafael Vanoni 
87*b47b5b34SRafael Vanoni 		/*
88*b47b5b34SRafael Vanoni 		 * Casting offender_addr to the wrong type will cause
89*b47b5b34SRafael Vanoni 		 * dtrace_lookup_by_addr to return 0 and the report
90*b47b5b34SRafael Vanoni 		 * to show an address instead of a name.
91*b47b5b34SRafael Vanoni 		 */
92*b47b5b34SRafael Vanoni 		switch (g_bit_depth) {
93*b47b5b34SRafael Vanoni 		case 32:
94*b47b5b34SRafael Vanoni 			/* LINTED - alignment */
95*b47b5b34SRafael Vanoni 			offender_addr = *(uint32_t *)(data->dtada_data +
96*b47b5b34SRafael Vanoni 			    rec1->dtrd_offset);
97*b47b5b34SRafael Vanoni 			break;
98*b47b5b34SRafael Vanoni 		case 64:
99*b47b5b34SRafael Vanoni 			/* LINTED - alignment */
100*b47b5b34SRafael Vanoni 			offender_addr = *(uint64_t *)(data->dtada_data +
101*b47b5b34SRafael Vanoni 			    rec1->dtrd_offset);
102*b47b5b34SRafael Vanoni 			break;
103*b47b5b34SRafael Vanoni 		}
104*b47b5b34SRafael Vanoni 
105*b47b5b34SRafael Vanoni 		/*
106*b47b5b34SRafael Vanoni 		 * We have the address of the kernel callout.
107*b47b5b34SRafael Vanoni 		 * Try to resolve it into a meaningful symbol
108*b47b5b34SRafael Vanoni 		 */
109*b47b5b34SRafael Vanoni 		if (offender_addr != NULL && dtrace_lookup_by_addr(dtp,
110*b47b5b34SRafael Vanoni 		    offender_addr, &sym, &dts) == 0) {
111*b47b5b34SRafael Vanoni 			(void) snprintf((char *)(g_p_event->offense_name),
112*b47b5b34SRafael Vanoni 			    EVENT_NAME_MAX, "%s`%s", dts.dts_object,
113*b47b5b34SRafael Vanoni 			    dts.dts_name);
114*b47b5b34SRafael Vanoni 		} else {
115*b47b5b34SRafael Vanoni 			(void) snprintf((char *)(g_p_event->offense_name),
116*b47b5b34SRafael Vanoni 			    EVENT_NAME_MAX, "0x%llx", offender_addr);
117*b47b5b34SRafael Vanoni 		}
118*b47b5b34SRafael Vanoni 	/*
119*b47b5b34SRafael Vanoni 	 * Report user events
120*b47b5b34SRafael Vanoni 	 */
121*b47b5b34SRafael Vanoni 	} else if (strcmp(aggdesc->dtagd_name, "events_u") == 0) {
122*b47b5b34SRafael Vanoni 		offense_name = data->dtada_data + rec1->dtrd_offset;
123*b47b5b34SRafael Vanoni 
124*b47b5b34SRafael Vanoni 		(void) snprintf((char *)(g_p_event->offender_name),
125*b47b5b34SRafael Vanoni 		    EVENT_NAME_MAX, "%s", offense_name);
126*b47b5b34SRafael Vanoni 		(void) snprintf((char *)(g_p_event->offense_name),
127*b47b5b34SRafael Vanoni 		    EVENT_NAME_MAX, "<scheduled timeout expiration>");
128*b47b5b34SRafael Vanoni 	/*
129*b47b5b34SRafael Vanoni 	 * Report cross calls
130*b47b5b34SRafael Vanoni 	 */
131*b47b5b34SRafael Vanoni 	} else if (strcmp(aggdesc->dtagd_name, "events_x") == 0) {
132*b47b5b34SRafael Vanoni 		offense_name = data->dtada_data + rec1->dtrd_offset;
133*b47b5b34SRafael Vanoni 
134*b47b5b34SRafael Vanoni 		(void) snprintf((char *)(g_p_event->offender_name),
135*b47b5b34SRafael Vanoni 		    EVENT_NAME_MAX, "%s", offense_name);
136*b47b5b34SRafael Vanoni 
137*b47b5b34SRafael Vanoni 		switch (g_bit_depth) {
138*b47b5b34SRafael Vanoni 		case 32:
139*b47b5b34SRafael Vanoni 			/* LINTED - alignment */
140*b47b5b34SRafael Vanoni 			offender_addr = *(uint32_t *)(data->dtada_data +
141*b47b5b34SRafael Vanoni 			    rec2->dtrd_offset);
142*b47b5b34SRafael Vanoni 			break;
143*b47b5b34SRafael Vanoni 		case 64:
144*b47b5b34SRafael Vanoni 			/* LINTED - alignment */
145*b47b5b34SRafael Vanoni 			offender_addr = *(uint64_t *)(data->dtada_data +
146*b47b5b34SRafael Vanoni 			    rec2->dtrd_offset);
147*b47b5b34SRafael Vanoni 			break;
148*b47b5b34SRafael Vanoni 		}
149*b47b5b34SRafael Vanoni 
150*b47b5b34SRafael Vanoni 		/*
151*b47b5b34SRafael Vanoni 		 * Try to resolve the address of the cross call function.
152*b47b5b34SRafael Vanoni 		 */
153*b47b5b34SRafael Vanoni 		if (offender_addr != NULL && dtrace_lookup_by_addr(dtp,
154*b47b5b34SRafael Vanoni 		    offender_addr, &sym, &dts) == 0) {
155*b47b5b34SRafael Vanoni 			(void) snprintf((char *)(g_p_event->offense_name),
156*b47b5b34SRafael Vanoni 			    EVENT_NAME_MAX, "<xcalls> %s`%s",
157*b47b5b34SRafael Vanoni 			    dts.dts_object, dts.dts_name);
158*b47b5b34SRafael Vanoni 		} else {
159*b47b5b34SRafael Vanoni 			(void) snprintf((char *)(g_p_event->offense_name),
160*b47b5b34SRafael Vanoni 			    EVENT_NAME_MAX, "<xcalls>");
161*b47b5b34SRafael Vanoni 		}
162*b47b5b34SRafael Vanoni 	/*
163*b47b5b34SRafael Vanoni 	 * Report cross calls from other CPUs than the one we're observing
164*b47b5b34SRafael Vanoni 	 * with the -C option
165*b47b5b34SRafael Vanoni 	 */
166*b47b5b34SRafael Vanoni 	} else if (strcmp(aggdesc->dtagd_name, "events_xc") == 0) {
167*b47b5b34SRafael Vanoni 		rec3 = &aggdesc->dtagd_rec[3];
168*b47b5b34SRafael Vanoni 		offense_name = data->dtada_data + rec1->dtrd_offset;
169*b47b5b34SRafael Vanoni 
170*b47b5b34SRafael Vanoni 		(void) snprintf((char *)(g_p_event->offender_name),
171*b47b5b34SRafael Vanoni 		    EVENT_NAME_MAX, "%s", offense_name);
172*b47b5b34SRafael Vanoni 
173*b47b5b34SRafael Vanoni 		switch (g_bit_depth) {
174*b47b5b34SRafael Vanoni 		case 32:
175*b47b5b34SRafael Vanoni 			/* LINTED - alignment */
176*b47b5b34SRafael Vanoni 			offender_addr = *(uint32_t *)(data->dtada_data +
177*b47b5b34SRafael Vanoni 			    rec2->dtrd_offset);
178*b47b5b34SRafael Vanoni 			break;
179*b47b5b34SRafael Vanoni 		case 64:
180*b47b5b34SRafael Vanoni 			/* LINTED - alignment */
181*b47b5b34SRafael Vanoni 			offender_addr = *(uint64_t *)(data->dtada_data +
182*b47b5b34SRafael Vanoni 			    rec2->dtrd_offset);
183*b47b5b34SRafael Vanoni 			break;
184*b47b5b34SRafael Vanoni 		}
185*b47b5b34SRafael Vanoni 		/* LINTED - alignment */
186*b47b5b34SRafael Vanoni 		offender_cpu = (int32_t *)(data->dtada_data +
187*b47b5b34SRafael Vanoni 		    rec3->dtrd_offset);
188*b47b5b34SRafael Vanoni 
189*b47b5b34SRafael Vanoni 		/*
190*b47b5b34SRafael Vanoni 		 * Try to resolve the address of the cross call function.
191*b47b5b34SRafael Vanoni 		 */
192*b47b5b34SRafael Vanoni 		if (offender_addr != NULL && dtrace_lookup_by_addr(dtp,
193*b47b5b34SRafael Vanoni 		    offender_addr, &sym, &dts) == 0) {
194*b47b5b34SRafael Vanoni 			(void) snprintf((char *)(g_p_event->offense_name),
195*b47b5b34SRafael Vanoni 			    EVENT_NAME_MAX, "<xcalls> %s`%s (CPU %d)",
196*b47b5b34SRafael Vanoni 			    dts.dts_object, dts.dts_name, *offender_cpu);
197*b47b5b34SRafael Vanoni 		} else {
198*b47b5b34SRafael Vanoni 			(void) snprintf((char *)(g_p_event->offense_name),
199*b47b5b34SRafael Vanoni 			    EVENT_NAME_MAX, "<xcalls> (CPU %d)",
200*b47b5b34SRafael Vanoni 			    *offender_cpu);
201*b47b5b34SRafael Vanoni 		}
202*b47b5b34SRafael Vanoni 	/*
203*b47b5b34SRafael Vanoni 	 * Report unknown events
204*b47b5b34SRafael Vanoni 	 */
205*b47b5b34SRafael Vanoni 	} else {
206*b47b5b34SRafael Vanoni 		(void) snprintf((char *)(g_p_event->offender_name),
207*b47b5b34SRafael Vanoni 		    EVENT_NAME_MAX, "%s", "<unknown>");
208*b47b5b34SRafael Vanoni 		(void) snprintf((char *)(g_p_event->offense_name),
209*b47b5b34SRafael Vanoni 		    EVENT_NAME_MAX, "%s", "<unknown>");
210*b47b5b34SRafael Vanoni 	}
211*b47b5b34SRafael Vanoni 
212*b47b5b34SRafael Vanoni 	for (i = 0; i < g_ncpus; i++)
213*b47b5b34SRafael Vanoni 		/* LINTED - alignment */
214*b47b5b34SRafael Vanoni 		n += *((uint64_t *)(data->dtada_percpu[i]));
215*b47b5b34SRafael Vanoni 
216*b47b5b34SRafael Vanoni 	g_p_event->total_count = n;
217*b47b5b34SRafael Vanoni 
218*b47b5b34SRafael Vanoni 	g_p_event++;
219*b47b5b34SRafael Vanoni 	g_tog_p_events++;
220*b47b5b34SRafael Vanoni 
221*b47b5b34SRafael Vanoni 	return (DTRACE_AGGWALK_NEXT);
222*b47b5b34SRafael Vanoni }
223*b47b5b34SRafael Vanoni 
224*b47b5b34SRafael Vanoni int
225*b47b5b34SRafael Vanoni pt_events_stat_prepare(void)
226*b47b5b34SRafael Vanoni {
227*b47b5b34SRafael Vanoni 	dtrace_prog_t 		*prog;
228*b47b5b34SRafael Vanoni 	dtrace_proginfo_t 	info;
229*b47b5b34SRafael Vanoni 	int 			err;
230*b47b5b34SRafael Vanoni 	dtrace_optval_t 	statustime;
231*b47b5b34SRafael Vanoni 	char			*prog_ptr;
232*b47b5b34SRafael Vanoni 
233*b47b5b34SRafael Vanoni 	g_p_event = g_event_info;
234*b47b5b34SRafael Vanoni 
235*b47b5b34SRafael Vanoni 	if ((dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) {
236*b47b5b34SRafael Vanoni 		pt_error("%s : cannot open dtrace library: %s\n", __FILE__,
237*b47b5b34SRafael Vanoni 		    dtrace_errmsg(NULL, err));
238*b47b5b34SRafael Vanoni 		return (-1);
239*b47b5b34SRafael Vanoni 	}
240*b47b5b34SRafael Vanoni 
241*b47b5b34SRafael Vanoni 	/*
242*b47b5b34SRafael Vanoni 	 * Execute different scripts (defined in the platform specific file)
243*b47b5b34SRafael Vanoni 	 * depending on user specified options.
244*b47b5b34SRafael Vanoni 	 */
245*b47b5b34SRafael Vanoni 	if (PTOP_ON_VERBOSE) {
246*b47b5b34SRafael Vanoni 		prog_ptr = (char *)g_dtp_events_v;
247*b47b5b34SRafael Vanoni 	} else {
248*b47b5b34SRafael Vanoni 		if (PTOP_ON_CPU)
249*b47b5b34SRafael Vanoni 			prog_ptr = (char *)g_dtp_events_c;
250*b47b5b34SRafael Vanoni 		else
251*b47b5b34SRafael Vanoni 			prog_ptr = (char *)g_dtp_events;
252*b47b5b34SRafael Vanoni 	}
253*b47b5b34SRafael Vanoni 
254*b47b5b34SRafael Vanoni 	if ((prog = dtrace_program_strcompile(dtp, prog_ptr,
255*b47b5b34SRafael Vanoni 	    DTRACE_PROBESPEC_NAME, 0, g_argc, g_argv)) == NULL) {
256*b47b5b34SRafael Vanoni 		pt_error("%s : failed to compile DTrace program\n", __FILE__);
257*b47b5b34SRafael Vanoni 		return (dtrace_errno(dtp));
258*b47b5b34SRafael Vanoni 	}
259*b47b5b34SRafael Vanoni 
260*b47b5b34SRafael Vanoni 	if (dtrace_program_exec(dtp, prog, &info) == -1) {
261*b47b5b34SRafael Vanoni 		pt_error("%s : failed to enable probes\n", __FILE__);
262*b47b5b34SRafael Vanoni 		return (dtrace_errno(dtp));
263*b47b5b34SRafael Vanoni 	}
264*b47b5b34SRafael Vanoni 
265*b47b5b34SRafael Vanoni 	if (dtrace_setopt(dtp, "aggsize", "128k") == -1) {
266*b47b5b34SRafael Vanoni 		pt_error("%s : failed to set 'aggsize'\n", __FILE__);
267*b47b5b34SRafael Vanoni 		return (dtrace_errno(dtp));
268*b47b5b34SRafael Vanoni 	}
269*b47b5b34SRafael Vanoni 
270*b47b5b34SRafael Vanoni 	if (dtrace_setopt(dtp, "aggrate", "0") == -1) {
271*b47b5b34SRafael Vanoni 		pt_error("%s : failed to set 'aggrate'\n", __FILE__);
272*b47b5b34SRafael Vanoni 		return (dtrace_errno(dtp));
273*b47b5b34SRafael Vanoni 	}
274*b47b5b34SRafael Vanoni 
275*b47b5b34SRafael Vanoni 	if (dtrace_setopt(dtp, "aggpercpu", 0) == -1) {
276*b47b5b34SRafael Vanoni 		pt_error("%s : failed to set 'aggpercpu'\n", __FILE__);
277*b47b5b34SRafael Vanoni 		return (dtrace_errno(dtp));
278*b47b5b34SRafael Vanoni 	}
279*b47b5b34SRafael Vanoni 
280*b47b5b34SRafael Vanoni 	if (dtrace_go(dtp) != 0) {
281*b47b5b34SRafael Vanoni 		pt_error("%s : dtrace_go() failed\n", __FILE__);
282*b47b5b34SRafael Vanoni 		return (dtrace_errno(dtp));
283*b47b5b34SRafael Vanoni 	}
284*b47b5b34SRafael Vanoni 
285*b47b5b34SRafael Vanoni 	if (dtrace_getopt(dtp, "statusrate", &statustime) == -1) {
286*b47b5b34SRafael Vanoni 		pt_error("%s : failed to get 'statusrate'\n", __FILE__);
287*b47b5b34SRafael Vanoni 		return (dtrace_errno(dtp));
288*b47b5b34SRafael Vanoni 	}
289*b47b5b34SRafael Vanoni 
290*b47b5b34SRafael Vanoni 	return (0);
291*b47b5b34SRafael Vanoni }
292*b47b5b34SRafael Vanoni 
293*b47b5b34SRafael Vanoni int
294*b47b5b34SRafael Vanoni pt_events_stat_collect(void)
295*b47b5b34SRafael Vanoni {
296*b47b5b34SRafael Vanoni 	g_p_event 	= g_event_info;
297*b47b5b34SRafael Vanoni 	g_tog_p_events 	= 0;
298*b47b5b34SRafael Vanoni 
299*b47b5b34SRafael Vanoni 	if (dtrace_status(dtp) == -1)
300*b47b5b34SRafael Vanoni 		return (-1);
301*b47b5b34SRafael Vanoni 
302*b47b5b34SRafael Vanoni 	if (dtrace_aggregate_snap(dtp) != 0)
303*b47b5b34SRafael Vanoni 		pt_error("%s : failed to add to aggregate", __FILE__);
304*b47b5b34SRafael Vanoni 
305*b47b5b34SRafael Vanoni 	if (dtrace_aggregate_walk_keyvarsorted(dtp, walk, NULL) != 0)
306*b47b5b34SRafael Vanoni 		pt_error("%s : failed to sort aggregate", __FILE__);
307*b47b5b34SRafael Vanoni 
308*b47b5b34SRafael Vanoni 	dtrace_aggregate_clear(dtp);
309*b47b5b34SRafael Vanoni 
310*b47b5b34SRafael Vanoni 	return (0);
311*b47b5b34SRafael Vanoni }
312