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