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