| /* | 
 |  * check_events.c - show event encoding | 
 |  * | 
 |  * Copyright (c) 2009 Google, Inc | 
 |  * Contributed by Stephane Eranian <eranian@gmail.com> | 
 |  * | 
 |  * Permission is hereby granted, free of charge, to any person obtaining a copy | 
 |  * of this software and associated documentation files (the "Software"), to deal | 
 |  * in the Software without restriction, including without limitation the rights | 
 |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | 
 |  * of the Software, and to permit persons to whom the Software is furnished to do so, | 
 |  * subject to the following conditions: | 
 |  * | 
 |  * The above copyright notice and this permission notice shall be included in all | 
 |  * copies or substantial portions of the Software. | 
 |  * | 
 |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | 
 |  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | 
 |  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | 
 |  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | 
 |  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE | 
 |  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | 
 |  * | 
 |  * This file is part of libpfm, a performance monitoring support library for | 
 |  * applications on Linux. | 
 |  */ | 
 | #include <sys/types.h> | 
 | #include <inttypes.h> | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <stdarg.h> | 
 | #include <string.h> | 
 | #include <perfmon/err.h> | 
 |  | 
 | #include <perfmon/pfmlib.h> | 
 |  | 
 | int | 
 | pmu_is_present(pfm_pmu_t p) | 
 | { | 
 | 	pfm_pmu_info_t pinfo; | 
 | 	int ret; | 
 |  | 
 | 	memset(&pinfo, 0, sizeof(pinfo)); | 
 | 	ret = pfm_get_pmu_info(p, &pinfo); | 
 | 	return ret == PFM_SUCCESS ? pinfo.is_present : 0; | 
 | } | 
 |  | 
 | int | 
 | main(int argc, const char **argv) | 
 | { | 
 | 	pfm_pmu_info_t pinfo; | 
 | 	pfm_pmu_encode_arg_t e; | 
 | 	const char *arg[3]; | 
 | 	const char **p; | 
 | 	char *fqstr; | 
 | 	pfm_event_info_t info; | 
 | 	int i, j, ret; | 
 | 	int total_supported_events = 0; | 
 | 	int total_available_events = 0; | 
 |  | 
 | 	/* | 
 | 	 * Initialize pfm library (required before we can use it) | 
 | 	 */ | 
 | 	ret = pfm_initialize(); | 
 | 	if (ret != PFM_SUCCESS) | 
 | 		errx(1, "cannot initialize library: %s\n", pfm_strerror(ret)); | 
 |  | 
 | 	memset(&pinfo, 0, sizeof(pinfo)); | 
 | 	memset(&info, 0, sizeof(info)); | 
 |  | 
 | 	printf("Supported PMU models:\n"); | 
 | 	for(i=0; i < PFM_PMU_MAX; i++) { | 
 | 		ret = pfm_get_pmu_info(i, &pinfo); | 
 | 		if (ret != PFM_SUCCESS) | 
 | 			continue; | 
 | 		 | 
 | 		printf("\t[%d, %s, \"%s\"]\n", i, pinfo.name, pinfo.desc); | 
 | 	} | 
 |  | 
 | 	printf("Detected PMU models:\n"); | 
 | 	for(i=0; i < PFM_PMU_MAX; i++) { | 
 | 		ret = pfm_get_pmu_info(i, &pinfo); | 
 | 		if (ret != PFM_SUCCESS) | 
 | 			continue; | 
 | 		if (pinfo.is_present) { | 
 | 			printf("\t[%d, %s, \"%s\"]\n", i, pinfo.name, pinfo.desc); | 
 | 			total_supported_events += pinfo.nevents; | 
 | 		} | 
 | 		total_available_events += pinfo.nevents; | 
 | 	} | 
 |  | 
 | 	printf("Total events: %d available, %d supported\n", total_available_events, total_supported_events); | 
 |  | 
 | 	/* | 
 | 	 * be nice to user! | 
 | 	 */ | 
 | 	if (argc < 2  && pmu_is_present(PFM_PMU_PERF_EVENT)) { | 
 | 		arg[0] = "PERF_COUNT_HW_CPU_CYCLES"; | 
 | 		arg[1] = "PERF_COUNT_HW_INSTRUCTIONS"; | 
 | 		arg[2] = NULL; | 
 | 		p = arg; | 
 | 	} else { | 
 | 		p = argv+1; | 
 | 	} | 
 |  | 
 | 	if (!*p) | 
 | 		errx(1, "you must pass at least one event"); | 
 |  | 
 | 	memset(&e, 0, sizeof(e)); | 
 | 	while(*p) { | 
 | 		/* | 
 | 		 * extract raw event encoding | 
 | 		 * | 
 | 		 * For perf_event encoding, use | 
 | 		 * #include <perfmon/pfmlib_perf_event.h> | 
 | 		 * and the function: | 
 | 		 * pfm_get_perf_event_encoding() | 
 | 		 */ | 
 | 		fqstr = NULL; | 
 | 		e.fstr = &fqstr; | 
 | 		ret = pfm_get_os_event_encoding(*p, PFM_PLM0|PFM_PLM3, PFM_OS_NONE, &e); | 
 | 		if (ret != PFM_SUCCESS) { | 
 | 			/* | 
 | 			 * codes is too small for this event | 
 | 			 * free and let the library resize | 
 | 			 */ | 
 | 			if (ret == PFM_ERR_TOOSMALL) { | 
 | 				free(e.codes); | 
 | 				e.codes = NULL; | 
 | 				e.count = 0; | 
 | 				free(fqstr); | 
 | 				continue; | 
 | 			} | 
 | 			if (ret == PFM_ERR_NOTFOUND && strstr(*p, "::")) | 
 | 				errx(1, "%s: try setting LIBPFM_ENCODE_INACTIVE=1", pfm_strerror(ret)); | 
 | 			errx(1, "cannot encode event %s: %s", *p, pfm_strerror(ret)); | 
 | 		} | 
 | 		ret = pfm_get_event_info(e.idx, PFM_OS_NONE, &info); | 
 | 		if (ret != PFM_SUCCESS) | 
 | 			errx(1, "cannot get event info: %s", pfm_strerror(ret)); | 
 |  | 
 | 		ret = pfm_get_pmu_info(info.pmu, &pinfo); | 
 | 		if (ret != PFM_SUCCESS) | 
 | 			errx(1, "cannot get PMU info: %s", pfm_strerror(ret)); | 
 |  | 
 | 		printf("Requested Event: %s\n", *p); | 
 | 		printf("Actual    Event: %s\n", fqstr); | 
 | 		printf("PMU            : %s\n", pinfo.desc); | 
 | 		printf("IDX            : %d\n", e.idx); | 
 | 		printf("Codes          :"); | 
 | 		for(j=0; j < e.count; j++) | 
 | 			printf(" 0x%"PRIx64, e.codes[j]); | 
 | 		putchar('\n'); | 
 |  | 
 | 		free(fqstr); | 
 | 		p++; | 
 | 	} | 
 | 	if (e.codes) | 
 | 		free(e.codes); | 
 | 	return 0; | 
 | } |