Blame src/libpfm-3.y/lib/pfmlib_common.c

Packit 577717
/*
Packit 577717
 * pfmlib_common.c: set of functions common to all PMU models
Packit 577717
 *
Packit 577717
 * Copyright (c) 2001-2006 Hewlett-Packard Development Company, L.P.
Packit 577717
 * Contributed by Stephane Eranian <eranian@hpl.hp.com>
Packit 577717
 *
Packit 577717
 * Permission is hereby granted, free of charge, to any person obtaining a copy
Packit 577717
 * of this software and associated documentation files (the "Software"), to deal
Packit 577717
 * in the Software without restriction, including without limitation the rights
Packit 577717
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
Packit 577717
 * of the Software, and to permit persons to whom the Software is furnished to do so,
Packit 577717
 * subject to the following conditions:
Packit 577717
 *
Packit 577717
 * The above copyright notice and this permission notice shall be included in all
Packit 577717
 * copies or substantial portions of the Software.
Packit 577717
 *
Packit 577717
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
Packit 577717
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
Packit 577717
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
Packit 577717
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
Packit 577717
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
Packit 577717
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Packit 577717
 */
Packit 577717
#ifndef _GNU_SOURCE
Packit 577717
#define _GNU_SOURCE /* for getline */
Packit 577717
#endif
Packit 577717
#include <sys/types.h>
Packit 577717
#include <ctype.h>
Packit 577717
#include <string.h>
Packit 577717
#include <stdio.h>
Packit 577717
#include <stdlib.h>
Packit 577717
#include <stdarg.h>
Packit 577717
#include <limits.h>
Packit 577717
Packit 577717
#include <perfmon/pfmlib.h>
Packit 577717
Packit 577717
#include "pfmlib_priv.h"
Packit 577717
Packit 577717
static pfm_pmu_support_t *supported_pmus[]=
Packit 577717
{
Packit 577717
Packit 577717
#ifdef CONFIG_PFMLIB_ARCH_IA64
Packit 577717
	&montecito_support,
Packit 577717
	&itanium2_support,
Packit 577717
	&itanium_support,
Packit 577717
	&generic_ia64_support,	/* must always be last for IA-64 */
Packit 577717
#endif
Packit 577717
Packit 577717
#ifdef CONFIG_PFMLIB_ARCH_X86_64
Packit 577717
	&amd64_support,
Packit 577717
	&pentium4_support,
Packit 577717
	&core_support,
Packit 577717
	&intel_atom_support,
Packit 577717
	&intel_nhm_support,
Packit 577717
	&intel_wsm_support,
Packit 577717
	&gen_ia32_support, /* must always be last for x86-64 */
Packit 577717
#endif
Packit 577717
Packit 577717
#ifdef CONFIG_PFMLIB_ARCH_I386
Packit 577717
	&i386_pii_support,
Packit 577717
	&i386_ppro_support,
Packit 577717
	&i386_p6_support,
Packit 577717
	&i386_pm_support,
Packit 577717
	&coreduo_support,
Packit 577717
	&amd64_support,
Packit 577717
	&pentium4_support,
Packit 577717
	&core_support,
Packit 577717
	&intel_atom_support,
Packit 577717
	&intel_nhm_support,
Packit 577717
	&intel_wsm_support,
Packit 577717
	&gen_ia32_support, /* must always be last for i386 */
Packit 577717
#endif
Packit 577717
Packit 577717
#ifdef CONFIG_PFMLIB_ARCH_MIPS64
Packit 577717
	&generic_mips64_support,
Packit 577717
#endif
Packit 577717
Packit 577717
#ifdef CONFIG_PFMLIB_ARCH_SICORTEX
Packit 577717
	&sicortex_support,
Packit 577717
#endif
Packit 577717
Packit 577717
#ifdef CONFIG_PFMLIB_ARCH_POWERPC
Packit 577717
	&gen_powerpc_support,
Packit 577717
#endif
Packit 577717
Packit 577717
#ifdef CONFIG_PFMLIB_ARCH_SPARC
Packit 577717
	&sparc_support,
Packit 577717
#endif
Packit 577717
Packit 577717
#ifdef CONFIG_PFMLIB_ARCH_CRAYX2
Packit 577717
	&crayx2_support,
Packit 577717
#endif
Packit 577717
Packit 577717
#ifdef CONFIG_PFMLIB_CELL
Packit 577717
	&cell_support,
Packit 577717
#endif
Packit 577717
	NULL
Packit 577717
};
Packit 577717
Packit 577717
/*
Packit 577717
 * contains runtime configuration options for the library.
Packit 577717
 * mostly for debug purposes.
Packit 577717
 */
Packit 577717
pfm_config_t pfm_config = {
Packit 577717
       .current = NULL
Packit 577717
};
Packit 577717
Packit 577717
int forced_pmu = PFMLIB_NO_PMU;
Packit 577717
Packit 577717
/*
Packit 577717
 * check environment variables for:
Packit 577717
 *  LIBPFM_VERBOSE : enable verbose output (must be 1)
Packit 577717
 *  LIBPFM_DEBUG   : enable debug output (must be 1)
Packit 577717
 */
Packit 577717
static void
Packit 577717
pfm_check_debug_env(void)
Packit 577717
{
Packit 577717
	char *str;
Packit 577717
Packit 577717
	libpfm_fp = stderr;
Packit 577717
Packit 577717
	str = getenv("LIBPFM_VERBOSE");
Packit 577717
	if (str && *str >= '0' && *str <= '9') {
Packit 577717
		pfm_config.options.pfm_verbose = *str - '0';
Packit 577717
		pfm_config.options_env_set = 1;
Packit 577717
	}
Packit 577717
Packit 577717
	str = getenv("LIBPFM_DEBUG");
Packit 577717
	if (str && *str >= '0' && *str <= '9') {
Packit 577717
		pfm_config.options.pfm_debug = *str - '0';
Packit 577717
		pfm_config.options_env_set = 1;
Packit 577717
	}
Packit 577717
Packit 577717
	str = getenv("LIBPFM_DEBUG_STDOUT");
Packit 577717
	if (str)
Packit 577717
		libpfm_fp = stdout;
Packit 577717
Packit 577717
	str = getenv("LIBPFM_FORCE_PMU");
Packit 577717
	if (str)
Packit 577717
		forced_pmu = atoi(str);
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_initialize(void)
Packit 577717
{
Packit 577717
	pfm_pmu_support_t **p = supported_pmus;
Packit 577717
	int ret;
Packit 577717
Packit 577717
	pfm_check_debug_env();
Packit 577717
	/*
Packit 577717
 	 * syscall mapping, no failure on error
Packit 577717
 	 */	
Packit 577717
	pfm_init_syscalls();
Packit 577717
Packit 577717
	while(*p) {
Packit 577717
		DPRINT("trying %s\n", (*p)->pmu_name);
Packit 577717
		/*
Packit 577717
		 * check for forced_pmu
Packit 577717
		 * pmu_type can never be zero
Packit 577717
		 */
Packit 577717
		if ((*p)->pmu_type == forced_pmu) {
Packit 577717
			__pfm_vbprintf("PMU forced to %s\n", (*p)->pmu_name);
Packit 577717
			goto found;
Packit 577717
		}
Packit 577717
Packit 577717
		if (forced_pmu == PFMLIB_NO_PMU && (*p)->pmu_detect() == PFMLIB_SUCCESS)
Packit 577717
			goto found;
Packit 577717
		p++;
Packit 577717
	}
Packit 577717
	return PFMLIB_ERR_NOTSUPP;
Packit 577717
found:
Packit 577717
	DPRINT("found %s\n", (*p)->pmu_name);
Packit 577717
	/*
Packit 577717
	 * run a few sanity checks
Packit 577717
	 */
Packit 577717
	if ((*p)->pmc_count >= PFMLIB_MAX_PMCS)
Packit 577717
		return PFMLIB_ERR_NOTSUPP;
Packit 577717
Packit 577717
	if ((*p)->pmd_count >= PFMLIB_MAX_PMDS)
Packit 577717
		return PFMLIB_ERR_NOTSUPP;
Packit 577717
Packit 577717
	if ((*p)->pmu_init) {
Packit 577717
		ret = (*p)->pmu_init();
Packit 577717
		if (ret != PFMLIB_SUCCESS)
Packit 577717
			return ret;
Packit 577717
	}
Packit 577717
Packit 577717
	pfm_current = *p;
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_set_options(pfmlib_options_t *opt)
Packit 577717
{
Packit 577717
	if (opt == NULL)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
	/*
Packit 577717
	 * environment variables override program presets
Packit 577717
	 */
Packit 577717
	if (pfm_config.options_env_set == 0)
Packit 577717
		pfm_config.options = *opt;
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * return the name corresponding to the pmu type. Only names
Packit 577717
 * of PMU actually compiled in the library will be returned.
Packit 577717
 */
Packit 577717
int
Packit 577717
pfm_get_pmu_name_bytype(int type, char *name, size_t maxlen)
Packit 577717
{
Packit 577717
	pfm_pmu_support_t **p = supported_pmus;
Packit 577717
Packit 577717
	if (name == NULL || maxlen < 1) return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	while (*p) {
Packit 577717
		if ((*p)->pmu_type == type) goto found;
Packit 577717
		p++;
Packit 577717
	}
Packit 577717
	return PFMLIB_ERR_INVAL;
Packit 577717
found:
Packit 577717
	strncpy(name, (*p)->pmu_name, maxlen-1);
Packit 577717
Packit 577717
	/* make sure the string is null terminated */
Packit 577717
	name[maxlen-1] = '\0';
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_list_supported_pmus(int (*pf)(const char *fmt,...))
Packit 577717
{
Packit 577717
	pfm_pmu_support_t **p;
Packit 577717
Packit 577717
	if (pf == NULL) return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	(*pf)("supported PMU models: ");
Packit 577717
Packit 577717
	for (p = supported_pmus; *p; p++) {
Packit 577717
		(*pf)("[%s] ", (*p)->pmu_name);;
Packit 577717
	}
Packit 577717
Packit 577717
	(*pf)("\ndetected host PMU: %s\n", pfm_current ? pfm_current->pmu_name : "not detected yet");
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_pmu_name(char *name, int maxlen)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0) return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (name == NULL || maxlen < 1) return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	strncpy(name, pfm_current->pmu_name, maxlen-1);
Packit 577717
Packit 577717
	name[maxlen-1] = '\0';
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_pmu_type(int *type)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0) return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (type == NULL) return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	*type = pfm_current->pmu_type;
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * boolean return value
Packit 577717
 */
Packit 577717
int
Packit 577717
pfm_is_pmu_supported(int type)
Packit 577717
{
Packit 577717
	pfm_pmu_support_t **p = supported_pmus;
Packit 577717
Packit 577717
	if (PFMLIB_INITIALIZED() == 0) return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	while (*p) {
Packit 577717
		if ((*p)->pmu_type == type) return PFMLIB_SUCCESS;
Packit 577717
		p++;
Packit 577717
	}
Packit 577717
	return PFMLIB_ERR_NOTSUPP;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_force_pmu(int type)
Packit 577717
{
Packit 577717
	pfm_pmu_support_t **p = supported_pmus;
Packit 577717
Packit 577717
	while (*p) {
Packit 577717
		if ((*p)->pmu_type == type) goto found;
Packit 577717
		p++;
Packit 577717
	}
Packit 577717
	return PFMLIB_ERR_NOTSUPP;
Packit 577717
found:
Packit 577717
	pfm_current = *p;
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_find_event_byname(const char *n, unsigned int *idx)
Packit 577717
{
Packit 577717
	char *p, *e;
Packit 577717
	unsigned int i;
Packit 577717
	size_t len;
Packit 577717
Packit 577717
	if (PFMLIB_INITIALIZED() == 0)
Packit 577717
		return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (n == NULL || idx == NULL)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * this function ignores any ':' separator
Packit 577717
	 */
Packit 577717
	p = strchr(n, ':');
Packit 577717
	if (!p)
Packit 577717
		len = strlen(n);
Packit 577717
	else
Packit 577717
		len = p - n;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * we do case insensitive comparisons
Packit 577717
	 *
Packit 577717
	 * event names must match completely
Packit 577717
	 */
Packit 577717
	for(i=0; i < pfm_current->pme_count; i++) {
Packit 577717
		e = pfm_current->get_event_name(i);
Packit 577717
		if (!e)
Packit 577717
			continue;
Packit 577717
		if (!strncasecmp(e, n, len)
Packit 577717
		    && len == strlen(e))
Packit 577717
			goto found;
Packit 577717
	}
Packit 577717
	return PFMLIB_ERR_NOTFOUND;
Packit 577717
found:
Packit 577717
	*idx = i;
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_find_event_bycode(int code, unsigned int *idx)
Packit 577717
{
Packit 577717
	pfmlib_regmask_t impl_cnt;
Packit 577717
	unsigned int i, j, num_cnt;
Packit 577717
	int code2;
Packit 577717
Packit 577717
	if (PFMLIB_INITIALIZED() == 0) return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (idx == NULL) return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	if (pfm_current->flags & PFMLIB_MULT_CODE_EVENT) {
Packit 577717
		pfm_current->get_impl_counters(&impl_cnt);
Packit 577717
		num_cnt = pfm_current->num_cnt;
Packit 577717
Packit 577717
		for(i=0; i < pfm_current->pme_count; i++) {
Packit 577717
			for(j=0; num_cnt; j++) {
Packit 577717
				if (pfm_regmask_isset(&impl_cnt, j)) {
Packit 577717
					pfm_current->get_event_code(i, j, &code2);
Packit 577717
					if (code2 == code)
Packit 577717
						goto found;
Packit 577717
					num_cnt--;
Packit 577717
				}
Packit 577717
			}
Packit 577717
		}
Packit 577717
	} else {
Packit 577717
		for(i=0; i < pfm_current->pme_count; i++) {
Packit 577717
			pfm_current->get_event_code(i, PFMLIB_CNT_FIRST, &code2);
Packit 577717
			if (code2 == code) goto found;
Packit 577717
		}
Packit 577717
	}
Packit 577717
	return PFMLIB_ERR_NOTFOUND;
Packit 577717
found:
Packit 577717
	*idx = i;
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_find_event(const char *v, unsigned int *ev)
Packit 577717
{
Packit 577717
	unsigned long number;
Packit 577717
	char *endptr = NULL;
Packit 577717
	int ret = PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	if (PFMLIB_INITIALIZED() == 0)
Packit 577717
		return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (v == NULL || ev == NULL)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	if (isdigit((int)*v)) {
Packit 577717
		number = strtoul(v,&endptr, 0);
Packit 577717
		/* check for errors */
Packit 577717
		if (*endptr!='\0')
Packit 577717
			return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
		if (number <= INT_MAX) {
Packit 577717
			int the_int_number = (int)number;
Packit 577717
			ret = pfm_find_event_bycode(the_int_number, ev);
Packit 577717
		}
Packit 577717
	} else 
Packit 577717
		ret = pfm_find_event_byname(v, ev);
Packit 577717
	return ret;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_find_event_bycode_next(int code, unsigned int i, unsigned int *next)
Packit 577717
{
Packit 577717
	int code2;
Packit 577717
Packit 577717
	if (PFMLIB_INITIALIZED() == 0)
Packit 577717
		return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (!next)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	for(++i; i < pfm_current->pme_count; i++) {
Packit 577717
		pfm_current->get_event_code(i, PFMLIB_CNT_FIRST, &code2);
Packit 577717
		if (code2 == code) goto found;
Packit 577717
	}
Packit 577717
	return PFMLIB_ERR_NOTFOUND;
Packit 577717
found:
Packit 577717
	*next = i;
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_do_find_event_mask(unsigned int ev, const char *str, unsigned int *mask_idx)
Packit 577717
{
Packit 577717
	unsigned int i, c, num_masks = 0;
Packit 577717
	unsigned long mask_val = -1;
Packit 577717
	char *endptr = NULL;
Packit 577717
	char *mask_name;
Packit 577717
Packit 577717
	/* empty mask name */
Packit 577717
	if (*str == '\0')
Packit 577717
		return PFMLIB_ERR_UMASK;
Packit 577717
Packit 577717
	num_masks = pfm_num_masks(ev);
Packit 577717
	for (i = 0; i < num_masks; i++) {
Packit 577717
		mask_name = pfm_current->get_event_mask_name(ev, i);
Packit 577717
		if (!mask_name)
Packit 577717
			continue;
Packit 577717
		if (strcasecmp(mask_name, str))
Packit 577717
			continue;
Packit 577717
		*mask_idx = i;
Packit 577717
		return PFMLIB_SUCCESS;
Packit 577717
	}
Packit 577717
	/* don't give up yet; check for a exact numerical value */
Packit 577717
	mask_val = strtoul(str, &endptr, 0);
Packit 577717
	if (mask_val != ULONG_MAX && endptr && *endptr == '\0') {
Packit 577717
		for (i = 0; i < num_masks; i++) {
Packit 577717
			pfm_current->get_event_mask_code(ev, i, &c);
Packit 577717
			if (mask_val == c) {
Packit 577717
				*mask_idx = i;
Packit 577717
				return PFMLIB_SUCCESS;
Packit 577717
			}
Packit 577717
		}
Packit 577717
	}
Packit 577717
	return PFMLIB_ERR_UMASK;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_find_event_mask(unsigned int ev, const char *str, unsigned int *mask_idx)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0)
Packit 577717
		return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (str == NULL || mask_idx == NULL || ev >= pfm_current->pme_count)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	return pfm_do_find_event_mask(ev, str, mask_idx);
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * check if unit mask is not already present
Packit 577717
 */
Packit 577717
static inline int
Packit 577717
pfm_check_duplicates(pfmlib_event_t *e, unsigned int u)
Packit 577717
{
Packit 577717
	unsigned int j;
Packit 577717
Packit 577717
	for(j=0; j < e->num_masks; j++) {
Packit 577717
		if (e->unit_masks[j] == u)
Packit 577717
			return PFMLIB_ERR_UMASK;
Packit 577717
	}
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_add_numeric_masks(pfmlib_event_t *e, const char *str)
Packit 577717
{
Packit 577717
	unsigned int i, j, c;
Packit 577717
	unsigned int num_masks = 0;
Packit 577717
	unsigned long mask_val = -1, m = 0;
Packit 577717
	char *endptr = NULL;
Packit 577717
	int ret = PFMLIB_ERR_UMASK;
Packit 577717
Packit 577717
	/* empty mask name */
Packit 577717
	if (*str == '\0')
Packit 577717
		return PFMLIB_ERR_UMASK;
Packit 577717
Packit 577717
	num_masks = pfm_num_masks(e->event);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * add to the existing list of unit masks
Packit 577717
	 */
Packit 577717
	j = e->num_masks;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * use unsigned long to benefit from radix wildcard
Packit 577717
	 * and error checking of strtoul()
Packit 577717
	 */
Packit 577717
	mask_val = strtoul(str, &endptr, 0);
Packit 577717
	if (endptr && *endptr != '\0')
Packit 577717
		return PFMLIB_ERR_UMASK;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * look for a numerical match
Packit 577717
	 */
Packit 577717
	for (i = 0; i < num_masks; i++) {
Packit 577717
		pfm_current->get_event_mask_code(e->event, i, &c);
Packit 577717
		if ((mask_val & c) == (unsigned long)c) {
Packit 577717
			/* ignore duplicates */
Packit 577717
			if (pfm_check_duplicates(e, i) == PFMLIB_SUCCESS) {
Packit 577717
				if (j == PFMLIB_MAX_MASKS_PER_EVENT) {
Packit 577717
					ret = PFMLIB_ERR_TOOMANY;
Packit 577717
					break;
Packit 577717
				}
Packit 577717
				e->unit_masks[j++] = i;
Packit 577717
			}
Packit 577717
			m |= c;
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	/*
Packit 577717
	 * all bits accounted for
Packit 577717
	 */
Packit 577717
	if (mask_val == m) {
Packit 577717
		e->num_masks = j;
Packit 577717
		return PFMLIB_SUCCESS;
Packit 577717
	}
Packit 577717
Packit 577717
	/*
Packit 577717
	 * extra bits left over;
Packit 577717
	 * reset and flag error
Packit 577717
	 */
Packit 577717
	for (i = e->num_masks; i < j; i++)
Packit 577717
		e->unit_masks[i] = 0;
Packit 577717
Packit 577717
	return ret;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_event_name(unsigned int i, char *name, size_t maxlen)
Packit 577717
{
Packit 577717
	size_t l, j;
Packit 577717
	char *str;
Packit 577717
Packit 577717
	if (PFMLIB_INITIALIZED() == 0)
Packit 577717
		return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (i >= pfm_current->pme_count || name == NULL || maxlen < 1)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	str = pfm_current->get_event_name(i);
Packit 577717
	if (!str)
Packit 577717
		return PFMLIB_ERR_BADHOST;
Packit 577717
	l = strlen(str);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * we fail if buffer is too small, simply because otherwise we
Packit 577717
	 * get partial names which are useless for subsequent calls
Packit 577717
	 * users mus invoke pfm_get_event_name_max_len() to correctly size
Packit 577717
	 * the buffer for this call
Packit 577717
	 */
Packit 577717
	if ((maxlen-1) < l)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	for(j=0; j < l; j++)
Packit 577717
		name[j] = (char)toupper(str[j]);
Packit 577717
Packit 577717
	name[l] = '\0';
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_event_code(unsigned int i, int *code)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0) return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (i >= pfm_current->pme_count || code == NULL) return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	return pfm_current->get_event_code(i, PFMLIB_CNT_FIRST, code);
Packit 577717
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_event_code_counter(unsigned int i, unsigned int cnt, int *code)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0) return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (i >= pfm_current->pme_count || code == NULL) return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	return pfm_current->get_event_code(i, cnt, code);
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_event_counters(unsigned int i, pfmlib_regmask_t *counters)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0) return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (i >= pfm_current->pme_count) return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	pfm_current->get_event_counters(i, counters);
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_event_mask_name(unsigned int ev, unsigned int mask, char *name, size_t maxlen)
Packit 577717
{
Packit 577717
	char *str;
Packit 577717
	unsigned int num;
Packit 577717
	size_t l, j;
Packit 577717
Packit 577717
	if (PFMLIB_INITIALIZED() == 0)
Packit 577717
		return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (ev >= pfm_current->pme_count || name == NULL || maxlen < 1)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	num = pfm_num_masks(ev);
Packit 577717
	if (num == 0)
Packit 577717
		return PFMLIB_ERR_NOTSUPP;
Packit 577717
Packit 577717
	if (mask >= num)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	str = pfm_current->get_event_mask_name(ev, mask);
Packit 577717
	if (!str)
Packit 577717
		return PFMLIB_ERR_BADHOST;
Packit 577717
	l = strlen(str);
Packit 577717
	if (l >= (maxlen-1))
Packit 577717
		return PFMLIB_ERR_FULL;
Packit 577717
Packit 577717
	strcpy(name, str);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * present nice uniform names
Packit 577717
	 */
Packit 577717
	l = strlen(name);
Packit 577717
	for(j=0; j < l; j++)
Packit 577717
		if (islower(name[j]))
Packit 577717
				name[j] = (char)toupper(name[j]);
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_num_events(unsigned int *count)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0) return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (count == NULL) return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	*count = pfm_current->pme_count;
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_num_event_masks(unsigned int ev, unsigned int *count)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0)
Packit 577717
		return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (ev >= pfm_current->pme_count || count == NULL)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	*count = pfm_num_masks(ev);
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
#if 0
Packit 577717
/*
Packit 577717
 * check that the unavailable PMCs registers correspond
Packit 577717
 * to implemented PMC registers
Packit 577717
 */
Packit 577717
static int
Packit 577717
pfm_check_unavail_pmcs(pfmlib_regmask_t *pmcs)
Packit 577717
{
Packit 577717
	pfmlib_regmask_t impl_pmcs;
Packit 577717
	pfm_current->get_impl_pmcs(&impl_pmcs);
Packit 577717
	unsigned int i;
Packit 577717
Packit 577717
	for (i=0; i < PFMLIB_REG_BV; i++) {
Packit 577717
		if ((pmcs->bits[i] & impl_pmcs.bits[i]) != pmcs->bits[i])
Packit 577717
			return PFMLIB_ERR_INVAL;
Packit 577717
	}
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
#endif
Packit 577717
Packit 577717
Packit 577717
/*
Packit 577717
 * we do not check if pfp_unavail_pmcs contains only implemented PMC
Packit 577717
 * registers. In other words, invalid registers are ignored
Packit 577717
 */
Packit 577717
int
Packit 577717
pfm_dispatch_events(
Packit 577717
	pfmlib_input_param_t *inp, void *model_in,
Packit 577717
	pfmlib_output_param_t *outp, void *model_out)
Packit 577717
{
Packit 577717
	unsigned count;
Packit 577717
	unsigned int i;
Packit 577717
	int ret;
Packit 577717
Packit 577717
	if (PFMLIB_INITIALIZED() == 0)
Packit 577717
		return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	/* at least one input and one output set must exist */
Packit 577717
	if (!inp && !model_in)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
	if (!outp && !model_out)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	if (!inp)
Packit 577717
		count = 0;
Packit 577717
	else if (inp->pfp_dfl_plm == 0)
Packit 577717
		/* the default priv level must be set to something */
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
	else if (inp->pfp_event_count >= PFMLIB_MAX_PMCS)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
	else if (inp->pfp_event_count > pfm_current->num_cnt)
Packit 577717
		return PFMLIB_ERR_NOASSIGN;
Packit 577717
	else
Packit 577717
		count = inp->pfp_event_count;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * check that event and unit masks descriptors are correct
Packit 577717
	 */
Packit 577717
	for (i=0; i < count; i++) {
Packit 577717
		ret = __pfm_check_event(inp->pfp_events+i);
Packit 577717
		if (ret != PFMLIB_SUCCESS)
Packit 577717
			return ret;
Packit 577717
	}
Packit 577717
Packit 577717
	/* reset output data structure */
Packit 577717
	if (outp)
Packit 577717
		memset(outp, 0, sizeof(*outp));
Packit 577717
Packit 577717
	return pfm_current->dispatch_events(inp, model_in, outp, model_out);
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * more or less obosleted by pfm_get_impl_counters()
Packit 577717
 */
Packit 577717
int
Packit 577717
pfm_get_num_counters(unsigned int *num)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0) return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (num == NULL) return PFMLIB_ERR_INVAL;
Packit 577717
	
Packit 577717
	*num = pfm_current->num_cnt;
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_num_pmcs(unsigned int *num)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0) return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (num == NULL) return PFMLIB_ERR_INVAL;
Packit 577717
	
Packit 577717
	*num = pfm_current->pmc_count;
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_num_pmds(unsigned int *num)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0) return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (num == NULL) return PFMLIB_ERR_INVAL;
Packit 577717
	
Packit 577717
	*num = pfm_current->pmd_count;
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_impl_pmcs(pfmlib_regmask_t *impl_pmcs)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0) return PFMLIB_ERR_NOINIT;
Packit 577717
	if (impl_pmcs == NULL) return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	memset(impl_pmcs , 0, sizeof(*impl_pmcs));
Packit 577717
Packit 577717
	pfm_current->get_impl_pmcs(impl_pmcs);
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_impl_pmds(pfmlib_regmask_t *impl_pmds)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0) return PFMLIB_ERR_NOINIT;
Packit 577717
	if (impl_pmds == NULL) return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	memset(impl_pmds, 0, sizeof(*impl_pmds));
Packit 577717
Packit 577717
	pfm_current->get_impl_pmds(impl_pmds);
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_impl_counters(pfmlib_regmask_t *impl_counters)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0) return PFMLIB_ERR_NOINIT;
Packit 577717
	if (impl_counters == NULL) return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	memset(impl_counters, 0, sizeof(*impl_counters));
Packit 577717
Packit 577717
	pfm_current->get_impl_counters(impl_counters);
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_hw_counter_width(unsigned int *width)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0) return PFMLIB_ERR_NOINIT;
Packit 577717
	if (width == NULL) return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	pfm_current->get_hw_counter_width(width);
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
Packit 577717
/* sorry, only English supported at this point! */
Packit 577717
static char *pfmlib_err_list[]=
Packit 577717
{
Packit 577717
	"success",
Packit 577717
	"not supported",
Packit 577717
	"invalid parameters",
Packit 577717
	"pfmlib not initialized",
Packit 577717
	"event not found",
Packit 577717
	"cannot assign events to counters",
Packit 577717
	"buffer is full or too small",
Packit 577717
	"event used more than once",
Packit 577717
	"invalid model specific magic number",
Packit 577717
	"invalid combination of model specific features",
Packit 577717
	"incompatible event sets",
Packit 577717
	"incompatible events combination",
Packit 577717
	"too many events or unit masks",
Packit 577717
	"code range too big",
Packit 577717
	"empty code range",
Packit 577717
	"invalid code range",
Packit 577717
	"too many code ranges",
Packit 577717
	"invalid data range",
Packit 577717
	"too many data ranges",
Packit 577717
	"not supported by host cpu",
Packit 577717
	"code range is not bundle-aligned",
Packit 577717
	"code range requires some flags in rr_flags",
Packit 577717
	"invalid or missing unit mask",
Packit 577717
	"out of memory"
Packit 577717
};
Packit 577717
static size_t pfmlib_err_count = sizeof(pfmlib_err_list)/sizeof(char *);
Packit 577717
Packit 577717
char *
Packit 577717
pfm_strerror(int code)
Packit 577717
{
Packit 577717
	code = -code;
Packit 577717
	if (code <0 || code >= pfmlib_err_count) return "unknown error code";
Packit 577717
	return pfmlib_err_list[code];
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_version(unsigned int *version)
Packit 577717
{
Packit 577717
	if (version == NULL) return PFMLIB_ERR_INVAL;
Packit 577717
	*version = PFMLIB_VERSION;
Packit 577717
	return 0;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_max_event_name_len(size_t *len)
Packit 577717
{
Packit 577717
	unsigned int i, j, num_masks;
Packit 577717
	size_t max = 0, l;
Packit 577717
	char *str;
Packit 577717
Packit 577717
	if (PFMLIB_INITIALIZED() == 0)
Packit 577717
		return PFMLIB_ERR_NOINIT;
Packit 577717
	if (len == NULL)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	for(i=0; i < pfm_current->pme_count; i++) {
Packit 577717
		str = pfm_current->get_event_name(i);
Packit 577717
		if (!str)
Packit 577717
			continue;
Packit 577717
		l = strlen(str);
Packit 577717
		if (l > max) max = l;
Packit 577717
Packit 577717
		num_masks = pfm_num_masks(i);
Packit 577717
		/*
Packit 577717
		 * we need to add up all length because unit masks can
Packit 577717
		 * be combined typically. We add 1 to account for ':'
Packit 577717
		 * which is inserted as the unit mask separator
Packit 577717
		 */
Packit 577717
		for (j = 0; j < num_masks; j++) {
Packit 577717
			str = pfm_current->get_event_mask_name(i, j);
Packit 577717
			if (!str)
Packit 577717
				continue;
Packit 577717
			l += 1 + strlen(str);
Packit 577717
		}
Packit 577717
		if (l > max) max = l;
Packit 577717
	}
Packit 577717
	*len = max;
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * return the index of the event that counts elapsed cycles
Packit 577717
 */
Packit 577717
int
Packit 577717
pfm_get_cycle_event(pfmlib_event_t *e)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0)
Packit 577717
		return PFMLIB_ERR_NOINIT;
Packit 577717
	if (e == NULL)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	if (!pfm_current->get_cycle_event)
Packit 577717
		return PFMLIB_ERR_NOTSUPP;
Packit 577717
Packit 577717
	memset(e, 0, sizeof(*e));
Packit 577717
Packit 577717
	return pfm_current->get_cycle_event(e);
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * return the index of the event that retired instructions
Packit 577717
 */
Packit 577717
int
Packit 577717
pfm_get_inst_retired_event(pfmlib_event_t *e)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0)
Packit 577717
		return PFMLIB_ERR_NOINIT;
Packit 577717
	if (e == NULL)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	if (!pfm_current->get_inst_retired_event)
Packit 577717
		return PFMLIB_ERR_NOTSUPP;
Packit 577717
Packit 577717
	memset(e, 0, sizeof(*e));
Packit 577717
Packit 577717
	return pfm_current->get_inst_retired_event(e);
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_event_description(unsigned int i, char **str)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0) return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (i >= pfm_current->pme_count || str == NULL) return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	if (pfm_current->get_event_desc == NULL) {
Packit 577717
		*str = strdup("no description available");
Packit 577717
		return PFMLIB_SUCCESS;
Packit 577717
	}
Packit 577717
	return pfm_current->get_event_desc(i, str);
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_event_mask_description(unsigned int event_idx, unsigned int mask_idx, char **desc)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0) return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (event_idx >= pfm_current->pme_count || desc == NULL) return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	if (pfm_current->get_event_mask_desc == NULL) {
Packit 577717
		*desc = strdup("no description available");
Packit 577717
		return PFMLIB_SUCCESS;
Packit 577717
	}
Packit 577717
	if (mask_idx >= pfm_current->get_num_event_masks(event_idx))
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	return pfm_current->get_event_mask_desc(event_idx, mask_idx, desc);
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfm_get_event_mask_code(unsigned int event_idx, unsigned int mask_idx, unsigned int *code)
Packit 577717
{
Packit 577717
	if (PFMLIB_INITIALIZED() == 0) return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (event_idx >= pfm_current->pme_count || code == NULL) return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	if (pfm_current->get_event_mask_code == NULL) {
Packit 577717
		*code = 0;
Packit 577717
		return PFMLIB_SUCCESS;
Packit 577717
	}
Packit 577717
	if (mask_idx >= pfm_current->get_num_event_masks(event_idx))
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	return pfm_current->get_event_mask_code(event_idx, mask_idx, code);
Packit 577717
}
Packit 577717
	
Packit 577717
int
Packit 577717
pfm_get_full_event_name(pfmlib_event_t *e, char *name, size_t maxlen)
Packit 577717
{
Packit 577717
	char *str;
Packit 577717
	size_t l, j;
Packit 577717
	int ret;
Packit 577717
Packit 577717
	if (PFMLIB_INITIALIZED() == 0)
Packit 577717
		return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (e == NULL || name == NULL || maxlen < 1)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	ret = __pfm_check_event(e);
Packit 577717
	if (ret != PFMLIB_SUCCESS)
Packit 577717
		return ret;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * make sure the string is at least empty
Packit 577717
	 * important for programs that do not check return value
Packit 577717
	 * from this function!
Packit 577717
	 */
Packit 577717
	*name = '\0';
Packit 577717
Packit 577717
	str = pfm_current->get_event_name(e->event);
Packit 577717
	if (!str)
Packit 577717
		return PFMLIB_ERR_BADHOST;
Packit 577717
	l = strlen(str);
Packit 577717
	if (l > (maxlen-1))
Packit 577717
		return PFMLIB_ERR_FULL;
Packit 577717
Packit 577717
	strcpy(name, str);
Packit 577717
	maxlen -= l + 1;
Packit 577717
	for(j=0; j < e->num_masks; j++) {
Packit 577717
		str = pfm_current->get_event_mask_name(e->event, e->unit_masks[j]);
Packit 577717
		if (!str)
Packit 577717
			continue;
Packit 577717
		l = strlen(str);
Packit 577717
		if (l > (maxlen-1))
Packit 577717
			return PFMLIB_ERR_FULL;
Packit 577717
Packit 577717
		strcat(name, ":");
Packit 577717
		strcat(name, str);
Packit 577717
		maxlen -= l + 1;
Packit 577717
	}
Packit 577717
	/*
Packit 577717
	 * present nice uniform names
Packit 577717
	 */
Packit 577717
	l = strlen(name);
Packit 577717
	for(j=0; j < l; j++)
Packit 577717
		if (islower(name[j]))
Packit 577717
			name[j] = (char)toupper(name[j]);
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
	
Packit 577717
int
Packit 577717
pfm_find_full_event(const char *v, pfmlib_event_t *e)
Packit 577717
{
Packit 577717
	char *str, *p, *q;
Packit 577717
	unsigned int j, mask;
Packit 577717
	int ret = PFMLIB_SUCCESS;
Packit 577717
Packit 577717
	if (PFMLIB_INITIALIZED() == 0)
Packit 577717
		return PFMLIB_ERR_NOINIT;
Packit 577717
Packit 577717
	if (v == NULL || e == NULL)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	memset(e, 0, sizeof(*e));
Packit 577717
Packit 577717
	/*
Packit 577717
	 * must copy string because we modify it when parsing
Packit 577717
	 */
Packit 577717
	str = strdup(v);
Packit 577717
	if (!str)
Packit 577717
		return PFMLIB_ERR_NOMEM;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * find event. this function ignores ':' separator
Packit 577717
	 */
Packit 577717
	ret = pfm_find_event_byname(str, &e->event);
Packit 577717
	if (ret)
Packit 577717
		goto error;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * get number of unit masks for event
Packit 577717
	 */
Packit 577717
	j = pfm_num_masks(e->event);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * look for colon (unit mask separator)
Packit 577717
	 */
Packit 577717
	p = strchr(str, ':');
Packit 577717
Packit 577717
	/* If no unit masks available and none specified, we're done */
Packit 577717
Packit 577717
	if ((j == 0) && (p == NULL)) {
Packit 577717
		  free(str);
Packit 577717
		  return PFMLIB_SUCCESS;
Packit 577717
	}
Packit 577717
	
Packit 577717
	ret = PFMLIB_ERR_UMASK;
Packit 577717
	/*
Packit 577717
	 * error if:
Packit 577717
	 * 	- event has no unit mask and at least one is passed
Packit 577717
	 */
Packit 577717
 	if (p && !j)
Packit 577717
		goto error;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * error if:
Packit 577717
	 * 	- event has unit masks, no default unit mask, and none is passed
Packit 577717
	 */
Packit 577717
	if (j && !p) {
Packit 577717
		if (pfm_current->has_umask_default
Packit 577717
		    && pfm_current->has_umask_default(e->event)) {
Packit 577717
			free(str);
Packit 577717
			return PFMLIB_SUCCESS;
Packit 577717
		}
Packit 577717
		goto error;
Packit 577717
	}
Packit 577717
Packit 577717
	/* skip : */
Packit 577717
	p++;
Packit 577717
	/*
Packit 577717
 	 * separator is passed but there is nothing behind it
Packit 577717
 	 */
Packit 577717
	if (!*p)
Packit 577717
		goto error;
Packit 577717
Packit 577717
	/* parse unit masks */
Packit 577717
	for( q = p; q ; p = q) {
Packit 577717
Packit 577717
		q = strchr(p,':');
Packit 577717
		if (q)
Packit 577717
			*q++ = '\0';
Packit 577717
Packit 577717
		/*
Packit 577717
		 * text or exact unit mask value match
Packit 577717
		 */
Packit 577717
		ret = pfm_do_find_event_mask(e->event, p, &mask);
Packit 577717
		if (ret == PFMLIB_ERR_UMASK) {
Packit 577717
			ret = pfm_add_numeric_masks(e, p);
Packit 577717
			if (ret != PFMLIB_SUCCESS)
Packit 577717
				break;
Packit 577717
		} else if (ret == PFMLIB_SUCCESS) {
Packit 577717
			/*
Packit 577717
			 * ignore duplicates
Packit 577717
			 */
Packit 577717
			ret = pfm_check_duplicates(e, mask);
Packit 577717
			if (ret != PFMLIB_SUCCESS) {
Packit 577717
				ret = PFMLIB_SUCCESS;
Packit 577717
				continue;
Packit 577717
			}
Packit 577717
Packit 577717
			if (e->num_masks == PFMLIB_MAX_MASKS_PER_EVENT) {
Packit 577717
				ret = PFMLIB_ERR_TOOMANY;
Packit 577717
				break;
Packit 577717
			}
Packit 577717
			e->unit_masks[e->num_masks] = mask;
Packit 577717
			e->num_masks++;
Packit 577717
		}
Packit 577717
	}
Packit 577717
error:
Packit 577717
	free(str);
Packit 577717
	return ret;
Packit 577717
}