Skip to content
Snippets Groups Projects
parse-events.c 4.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • 
    #include "../perf.h"
    #include "util.h"
    #include "parse-options.h"
    #include "parse-events.h"
    #include "exec_cmd.h"
    
    
    int nr_counters;
    
    __u64			event_id[MAX_COUNTERS]		= { };
    
    int			event_mask[MAX_COUNTERS];
    
    
    struct event_symbol {
    	__u64 event;
    	char *symbol;
    };
    
    static struct event_symbol event_symbols[] = {
    	{EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES),		"cpu-cycles",		},
    	{EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES),		"cycles",		},
    	{EID(PERF_TYPE_HARDWARE, PERF_COUNT_INSTRUCTIONS),		"instructions",		},
    	{EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES),		"cache-references",	},
    	{EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES),		"cache-misses",		},
    	{EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS),	"branch-instructions",	},
    	{EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS),	"branches",		},
    	{EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_MISSES),		"branch-misses",	},
    	{EID(PERF_TYPE_HARDWARE, PERF_COUNT_BUS_CYCLES),		"bus-cycles",		},
    
    	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_CLOCK),			"cpu-clock",		},
    	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK),		"task-clock",		},
    	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS),		"page-faults",		},
    	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS),		"faults",		},
    	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MIN),		"minor-faults",		},
    	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MAJ),		"major-faults",		},
    	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES),		"context-switches",	},
    	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES),		"cs",			},
    	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS),		"cpu-migrations",	},
    	{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS),		"migrations",		},
    };
    
    
    #define __PERF_COUNTER_FIELD(config, name) \
    	((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
    
    #define PERF_COUNTER_RAW(config)	__PERF_COUNTER_FIELD(config, RAW)
    #define PERF_COUNTER_CONFIG(config)	__PERF_COUNTER_FIELD(config, CONFIG)
    #define PERF_COUNTER_TYPE(config)	__PERF_COUNTER_FIELD(config, TYPE)
    #define PERF_COUNTER_ID(config)		__PERF_COUNTER_FIELD(config, EVENT)
    
    static char *hw_event_names[] = {
    	"CPU cycles",
    	"instructions",
    	"cache references",
    	"cache misses",
    	"branches",
    	"branch misses",
    	"bus cycles",
    };
    
    static char *sw_event_names[] = {
    	"cpu clock ticks",
    	"task clock ticks",
    	"pagefaults",
    	"context switches",
    	"CPU migrations",
    	"minor faults",
    	"major faults",
    };
    
    char *event_name(int ctr)
    {
    	__u64 config = event_id[ctr];
    	int type = PERF_COUNTER_TYPE(config);
    	int id = PERF_COUNTER_ID(config);
    	static char buf[32];
    
    	if (PERF_COUNTER_RAW(config)) {
    		sprintf(buf, "raw 0x%llx", PERF_COUNTER_CONFIG(config));
    		return buf;
    	}
    
    	switch (type) {
    	case PERF_TYPE_HARDWARE:
    		if (id < PERF_HW_EVENTS_MAX)
    			return hw_event_names[id];
    		return "unknown-hardware";
    
    	case PERF_TYPE_SOFTWARE:
    		if (id < PERF_SW_EVENTS_MAX)
    			return sw_event_names[id];
    		return "unknown-software";
    
    	default:
    		break;
    	}
    
    	return "unknown";
    }
    
    
    /*
     * Each event can have multiple symbolic names.
     * Symbolic names are (almost) exactly matched.
     */
    static __u64 match_event_symbols(const char *str)
    {
    	__u64 config, id;
    	int type;
    	unsigned int i;
    
    	if (str[0] == 'r' && hex2u64(str + 1, &config) > 0)
    
    		return config | PERF_COUNTER_RAW_MASK;
    
    
    	pstr = str;
    	sep = strchr(pstr, ':');
    	if (sep) {
    		type = atoi(pstr);
    		pstr = sep + 1;
    		id = atoi(pstr);
    		sep = strchr(pstr, ':');
    		if (sep) {
    			pstr = sep + 1;
    			if (strchr(pstr, 'k'))
    
    				event_mask[nr_counters] |= EVENT_MASK_USER;
    
    				event_mask[nr_counters] |= EVENT_MASK_KERNEL;
    
    
    	for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
    		if (!strncmp(str, event_symbols[i].symbol,
    			     strlen(event_symbols[i].symbol)))
    			return event_symbols[i].event;
    	}
    
    	return ~0ULL;
    }
    
    int parse_events(const struct option *opt, const char *str, int unset)
    {
    	__u64 config;
    
    again:
    	if (nr_counters == MAX_COUNTERS)
    		return -1;
    
    	config = match_event_symbols(str);
    	if (config == ~0ULL)
    		return -1;
    
    	event_id[nr_counters] = config;
    	nr_counters++;
    
    	str = strstr(str, ",");
    	if (str) {
    		str++;
    		goto again;
    	}
    
    	return 0;
    }
    
    /*
     * Create the help text for the event symbols:
     */
    void create_events_help(char *events_help_msg)
    {
    	unsigned int i;
    	char *str;
    	__u64 e;
    
    	str = events_help_msg;
    
    	str += sprintf(str,
    	"event name: [");
    
    	for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
    		int type, id;
    
    		e = event_symbols[i].event;
    		type = PERF_COUNTER_TYPE(e);
    		id = PERF_COUNTER_ID(e);
    
    		if (i)
    			str += sprintf(str, "|");
    
    		str += sprintf(str, "%s",
    				event_symbols[i].symbol);
    	}
    
    	str += sprintf(str, "|rNNN]");
    }