Skip to content
Snippets Groups Projects
parse-events.c 4.38 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"
    
    struct perf_counter_attr		attrs[MAX_COUNTERS];
    
    
    struct event_symbol {
    
    	__u8	type;
    	__u64	config;
    	char	*symbol;
    
    #define C(x, y) .type = PERF_TYPE_##x, .config = PERF_COUNT_##y
    
    
    static struct event_symbol event_symbols[] = {
    
      { C(HARDWARE, CPU_CYCLES),		"cpu-cycles",		},
      { C(HARDWARE, CPU_CYCLES),		"cycles",		},
      { C(HARDWARE, INSTRUCTIONS),		"instructions",		},
      { C(HARDWARE, CACHE_REFERENCES),	"cache-references",	},
      { C(HARDWARE, CACHE_MISSES),		"cache-misses",		},
      { C(HARDWARE, BRANCH_INSTRUCTIONS),	"branch-instructions",	},
      { C(HARDWARE, BRANCH_INSTRUCTIONS),	"branches",		},
      { C(HARDWARE, BRANCH_MISSES),		"branch-misses",	},
      { C(HARDWARE, BUS_CYCLES),		"bus-cycles",		},
    
      { C(SOFTWARE, CPU_CLOCK),		"cpu-clock",		},
      { C(SOFTWARE, TASK_CLOCK),		"task-clock",		},
      { C(SOFTWARE, PAGE_FAULTS),		"page-faults",		},
      { C(SOFTWARE, PAGE_FAULTS),		"faults",		},
      { C(SOFTWARE, PAGE_FAULTS_MIN),	"minor-faults",		},
      { C(SOFTWARE, PAGE_FAULTS_MAJ),	"major-faults",		},
      { C(SOFTWARE, CONTEXT_SWITCHES),	"context-switches",	},
      { C(SOFTWARE, CONTEXT_SWITCHES),	"cs",			},
      { C(SOFTWARE, CPU_MIGRATIONS),	"cpu-migrations",	},
      { C(SOFTWARE, 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 counter)
    
    	__u64 config = attrs[counter].config;
    	int type = attrs[counter].type;
    
    	static char buf[32];
    
    
    	if (attrs[counter].type == PERF_TYPE_RAW) {
    		sprintf(buf, "raw 0x%llx", config);
    
    		return buf;
    	}
    
    	switch (type) {
    	case PERF_TYPE_HARDWARE:
    
    		if (config < PERF_HW_EVENTS_MAX)
    			return hw_event_names[config];
    
    		return "unknown-hardware";
    
    	case PERF_TYPE_SOFTWARE:
    
    		if (config < PERF_SW_EVENTS_MAX)
    			return sw_event_names[config];
    
    		return "unknown-software";
    
    	default:
    		break;
    	}
    
    	return "unknown";
    }
    
    
    /*
     * Each event can have multiple symbolic names.
     * Symbolic names are (almost) exactly matched.
     */
    
    static int match_event_symbols(const char *str, struct perf_counter_attr *attr)
    
    {
    	__u64 config, id;
    	int type;
    	unsigned int i;
    
    	if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) {
    		attr->type = PERF_TYPE_RAW;
    		attr->config = config;
    
    		return 0;
    	}
    
    	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'))
    
    				attr->exclude_user = 1;
    
    				attr->exclude_kernel = 1;
    
    		attr->type = type;
    		attr->config = id;
    
    		return 0;
    
    
    	for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
    		if (!strncmp(str, event_symbols[i].symbol,
    
    			     strlen(event_symbols[i].symbol))) {
    
    			attr->type = event_symbols[i].type;
    			attr->config = event_symbols[i].config;
    
    			return 0;
    		}
    
    }
    
    int parse_events(const struct option *opt, const char *str, int unset)
    {
    
    	struct perf_counter_attr attr;
    	int ret;
    
    	memset(&attr, 0, sizeof(attr));
    
    again:
    	if (nr_counters == MAX_COUNTERS)
    		return -1;
    
    
    	ret = match_event_symbols(str, &attr);
    	if (ret < 0)
    		return ret;
    
    	attrs[nr_counters] = attr;
    
    	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;
    
    	str = events_help_msg;
    
    	str += sprintf(str,
    	"event name: [");
    
    	for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
    		int type, id;
    
    
    		type = event_symbols[i].type;
    		id = event_symbols[i].config;
    
    
    		if (i)
    			str += sprintf(str, "|");
    
    		str += sprintf(str, "%s",
    				event_symbols[i].symbol);
    	}
    
    	str += sprintf(str, "|rNNN]");
    }