view usr/src/cmd/cpc/common/setgrp.c @ 0:c9caec207d52 b86

Initial porting based on b86
author Koji Uno <koji.uno@sun.com>
date Tue, 02 Jun 2009 18:56:50 +0900
parents
children 1a15d5aaf794
line wrap: on
line source

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"@(#)setgrp.c	1.4	05/06/08 SMI"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <libintl.h>
#include <sys/types.h>


#include <libcpc.h>
#include "cpucmds.h"

#define	CHARS_PER_REQ 11	/* space required for printing column headers */

/*
 * These routines are solely used to manage a list of request sets.
 */

struct __cpc_setgrp {
	struct setgrp_elem {
		cpc_set_t	*set;
		uint8_t		sysonly;	/* All reqs sys-mode only ? */
		int		nreqs;
		int		*picnums;	/* picnum used per req */
		cpc_buf_t	*data1;
		cpc_buf_t	*data2;
		cpc_buf_t	*scratch;
		char *name;
		char *hdr;
	} *sets;		/* array of events and names */
	int nelem;		/* size of array */
	int current;		/* currently bound event in eventset */
	int smt;		/* Measures physical events on SMT CPU */
	int has_sysonly_set;	/* Does this group have a system-only set? */
	cpc_t *cpc;		/* library handle */
};

static void *emalloc(size_t n);

cpc_setgrp_t *
cpc_setgrp_new(cpc_t *cpc, int smt)
{
	cpc_setgrp_t *sgrp;

	sgrp = emalloc(sizeof (*sgrp));
	sgrp->current = -1;
	sgrp->cpc = cpc;
	sgrp->smt = smt;
	sgrp->has_sysonly_set = 0;
	return (sgrp);
}

/*
 * Walker to count the number of requests in a set, and check if any requests
 * count user-mode events.
 */
/*ARGSUSED*/
static void
cpc_setgrp_walker(void *arg, int index, const char *event, uint64_t preset,
    uint_t flags, int nattrs, const cpc_attr_t *attrs)
{
	struct setgrp_elem *se = arg;

	se->nreqs++;
	if (flags & CPC_COUNT_USER)
		se->sysonly = 0;
}

/*
 * Walker to discover the picnums used by the requests in a set.
 */
/*ARGSUSED*/
static void
cpc_setgrp_picwalker(void *arg, int index, const char *event, uint64_t preset,
    uint_t flags, int nattrs, const cpc_attr_t *attrs)
{
	int *picnums = arg;
	int i;

	for (i = 0; i < nattrs; i++) {
		if (strncmp(attrs[i].ca_name, "picnum", 7) == 0)
			break;
	}
	if (i == nattrs)
		picnums[index] = -1;

	picnums[index] = (int)attrs[i].ca_val;
}

cpc_setgrp_t *
cpc_setgrp_newset(cpc_setgrp_t *sgrp, const char *spec, int *errcnt)
{
	cpc_set_t		*set;
	struct setgrp_elem	*new;
	char			hdr[CHARS_PER_REQ+1];
	int			i;

	if ((set = cpc_strtoset(sgrp->cpc, spec, sgrp->smt)) == NULL) {
		*errcnt += 1;
		return (NULL);
	}

	if ((new = realloc(sgrp->sets, (1 + sgrp->nelem) * sizeof (*new)))
	    == NULL) {
		(void) fprintf(stderr,
		    gettext("cpc_setgrp: no re memory available\n"));
		exit(0);
	}

	sgrp->sets = new;
	sgrp->sets[sgrp->nelem].set = set;
	/*
	 * Count the number of requests in the set we just made. If any requests
	 * in the set have CPC_COUNT_USER in the flags, the sysonly flag will
	 * be cleared.
	 */
	sgrp->sets[sgrp->nelem].nreqs = 0;
	sgrp->sets[sgrp->nelem].sysonly = 1;
	cpc_walk_requests(sgrp->cpc, set, &(sgrp->sets[sgrp->nelem]),
	    cpc_setgrp_walker);

	if (sgrp->sets[sgrp->nelem].sysonly == 1)
		sgrp->has_sysonly_set = 1;

	sgrp->sets[sgrp->nelem].picnums = emalloc(sgrp->sets[sgrp->nelem].nreqs
	    * sizeof (int));

	sgrp->sets[sgrp->nelem].hdr = emalloc((sgrp->sets[sgrp->nelem].nreqs *
	    CHARS_PER_REQ) + 1);

	/*
	 * Find out which picnums the requests are using.
	 */
	cpc_walk_requests(sgrp->cpc, set, sgrp->sets[sgrp->nelem].picnums,
	    cpc_setgrp_picwalker);
	/*
	 * Use the picnums we discovered to build a printable header for this
	 * set.
	 */
	sgrp->sets[sgrp->nelem].hdr[0] = '\0';
	for (i = 0; i < sgrp->sets[sgrp->nelem].nreqs; i++) {
		(void) snprintf(hdr, CHARS_PER_REQ, "%8s%-2d ", "pic",
		    sgrp->sets[sgrp->nelem].picnums[i]);
		(void) strncat(sgrp->sets[sgrp->nelem].hdr, hdr,
		    sgrp->sets[sgrp->nelem].nreqs * CHARS_PER_REQ);
	}
	sgrp->sets[sgrp->nelem].hdr[strlen(sgrp->sets[sgrp->nelem].hdr)] = '\0';

	if ((sgrp->sets[sgrp->nelem].name = strdup(spec)) == NULL) {
		(void) fprintf(stderr,
		    gettext("cpc_setgrp: no memory available\n"));
		exit(0);
	}

	if ((sgrp->sets[sgrp->nelem].data1 = cpc_buf_create(sgrp->cpc, set))
	    == NULL ||
	    (sgrp->sets[sgrp->nelem].data2 = cpc_buf_create(sgrp->cpc, set))
	    == NULL ||
	    (sgrp->sets[sgrp->nelem].scratch = cpc_buf_create(sgrp->cpc, set))
	    == NULL) {
		(void) fprintf(stderr,
		    gettext("cpc_setgrp: no memory available\n"));
		exit(0);
	}

	if (sgrp->current < 0)
		sgrp->current = 0;
	sgrp->nelem++;
	return (sgrp);
}

int
cpc_setgrp_getbufs(cpc_setgrp_t *sgrp, cpc_buf_t ***data1, cpc_buf_t ***data2,
    cpc_buf_t ***scratch)
{
	if ((uint_t)sgrp->current >= sgrp->nelem)
		return (-1);

	*data1   = &(sgrp->sets[sgrp->current].data1);
	*data2   = &(sgrp->sets[sgrp->current].data2);
	*scratch = &(sgrp->sets[sgrp->current].scratch);

	return (sgrp->sets[sgrp->current].nreqs);
}

cpc_setgrp_t *
cpc_setgrp_clone(cpc_setgrp_t *old)
{
	int			i;
	cpc_setgrp_t		*new;
	struct setgrp_elem	*newa;

	new = emalloc(sizeof (*new));
	newa = emalloc(old->nelem * sizeof (*newa));

	new->nelem = old->nelem;
	new->current = old->current;
	new->cpc = old->cpc;
	new->sets = newa;
	new->smt = old->smt;
	new->has_sysonly_set = old->has_sysonly_set;
	for (i = 0; i < old->nelem; i++) {
		if ((newa[i].set = cpc_strtoset(old->cpc, old->sets[i].name,
		    old->smt)) == NULL) {
			(void) fprintf(stderr,
			    gettext("cpc_setgrp: cpc_strtoset() failed\n"));
			exit(0);
		}
		if ((newa[i].name = strdup(old->sets[i].name)) == NULL) {
			(void) fprintf(stderr,
			    gettext("cpc_setgrp: no memory available\n"));
			exit(0);
		}
		newa[i].sysonly = old->sets[i].sysonly;
		newa[i].nreqs = old->sets[i].nreqs;
		newa[i].data1 = cpc_buf_create(old->cpc, newa[i].set);
		newa[i].data2 = cpc_buf_create(old->cpc, newa[i].set);
		newa[i].scratch = cpc_buf_create(old->cpc, newa[i].set);
		if (newa[i].data1 == NULL || newa[i].data2 == NULL ||
		    newa[i].scratch == NULL) {
			(void) fprintf(stderr,
			    gettext("cpc_setgrp: no memory available\n"));
			exit(0);
		}
		cpc_buf_copy(old->cpc, newa[i].data1, old->sets[i].data1);
		cpc_buf_copy(old->cpc, newa[i].data2, old->sets[i].data2);
		cpc_buf_copy(old->cpc, newa[i].scratch, old->sets[i].scratch);
	}
	return (new);
}

static void
cpc_setgrp_delset(cpc_setgrp_t *sgrp)
{
	int l;

	if ((uint_t)sgrp->current >= sgrp->nelem)
		sgrp->current = sgrp->nelem - 1;
	if (sgrp->current < 0)
		return;
	free(sgrp->sets[sgrp->current].name);
	free(sgrp->sets[sgrp->current].hdr);
	free(sgrp->sets[sgrp->current].picnums);
	(void) cpc_buf_destroy(sgrp->cpc, sgrp->sets[sgrp->current].data1);
	(void) cpc_buf_destroy(sgrp->cpc, sgrp->sets[sgrp->current].data2);
	(void) cpc_buf_destroy(sgrp->cpc, sgrp->sets[sgrp->current].scratch);
	for (l = sgrp->current; l < sgrp->nelem - 1; l++)
		sgrp->sets[l] = sgrp->sets[l + 1];
	sgrp->nelem--;
}

void
cpc_setgrp_free(cpc_setgrp_t *sgrp)
{
	if (sgrp->sets) {
		while (sgrp->nelem)
			cpc_setgrp_delset(sgrp);
		free(sgrp->sets);
	}
	free(sgrp);
}

cpc_set_t *
cpc_setgrp_getset(cpc_setgrp_t *sgrp)
{
	if ((uint_t)sgrp->current >= sgrp->nelem)
		return (NULL);
	return (sgrp->sets[sgrp->current].set);
}

const char *
cpc_setgrp_getname(cpc_setgrp_t *sgrp)
{
	if ((uint_t)sgrp->current >= sgrp->nelem)
		return (NULL);
	return (sgrp->sets[sgrp->current].name);
}

const char *
cpc_setgrp_gethdr(cpc_setgrp_t *sgrp)
{
	if ((uint_t)sgrp->current >= sgrp->nelem)
		return (NULL);
	return (sgrp->sets[sgrp->current].hdr);
}

int
cpc_setgrp_numsets(cpc_setgrp_t *sgrp)
{
	return (sgrp->nelem);
}

cpc_set_t *
cpc_setgrp_nextset(cpc_setgrp_t *sgrp)
{
	if (sgrp->current < 0)
		return (NULL);

	if (++sgrp->current >= sgrp->nelem)
		sgrp->current = 0;

	return (cpc_setgrp_getset(sgrp));
}

/*
 * Put the setgrp pointer back to the beginning of the set
 */
void
cpc_setgrp_reset(cpc_setgrp_t *sgrp)
{
	if (sgrp->current > 0)
		sgrp->current = 0;
}

/*
 * Adds the data from the 'data1' buf into the accum setgrp.
 */
void
cpc_setgrp_accum(cpc_setgrp_t *accum, cpc_setgrp_t *sgrp)
{
	int i;

	cpc_setgrp_reset(accum);
	cpc_setgrp_reset(sgrp);
	if (accum->nelem != sgrp->nelem)
		return;

	for (i = 0; i < sgrp->nelem; i++) {
		if (accum->sets[i].nreqs != sgrp->sets[i].nreqs)
			return;
		cpc_buf_add(sgrp->cpc, accum->sets[i].data1,
		    accum->sets[i].data1, sgrp->sets[i].data1);
	}
}

/*
 * Returns 1 if all requests in the current set count only system-mode events.
 */
int
cpc_setgrp_sysonly(cpc_setgrp_t *sgrp)
{
	return ((int)sgrp->sets[sgrp->current].sysonly);
}

/*
 * Returns 1 if any set in the group is a system-mode-only set.
 */
int
cpc_setgrp_has_sysonly(cpc_setgrp_t *sgrp)
{
	return (sgrp->has_sysonly_set);
}

/*
 * If we ever fail to get memory, we print an error message and exit.
 */
static void *
emalloc(size_t n)
{
	/*
	 * Several callers of this routine need zero-filled buffers.
	 */
	void *p = calloc(1, n);

	if (p == NULL) {
		(void) fprintf(stderr,
		    gettext("cpc_setgrp: no memory available\n"));
		exit(0);
	}

	return (p);
}