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

Packit 577717
#include <sys/types.h>
Packit 577717
#include <stdio.h>
Packit 577717
#include <stdlib.h>
Packit 577717
#include <unistd.h>
Packit 577717
#include <string.h>
Packit 577717
#include <pthread.h>
Packit 577717
#include <semaphore.h>
Packit 577717
#include <inttypes.h>
Packit 577717
#include <syscall.h>
Packit 577717
#include <errno.h>
Packit 577717
#include <stdarg.h>
Packit 577717
Packit 577717
#include <perfmon/perfmon.h>
Packit 577717
Packit 577717
#include "libpfms.h"
Packit 577717
Packit 577717
//#define dprint(format, arg...) fprintf(stderr, "%s.%d: " format , __FUNCTION__ , __LINE__, ## arg)
Packit 577717
#define dprint(format, arg...)
Packit 577717
Packit 577717
typedef enum {	CMD_NONE,
Packit 577717
		CMD_CTX,
Packit 577717
		CMD_LOAD,
Packit 577717
		CMD_UNLOAD,
Packit 577717
		CMD_WPMCS,
Packit 577717
		CMD_WPMDS,
Packit 577717
		CMD_RPMDS,
Packit 577717
		CMD_STOP,
Packit 577717
		CMD_START,
Packit 577717
		CMD_CLOSE
Packit 577717
} pfms_cmd_t;
Packit 577717
Packit 577717
typedef struct _barrier {
Packit 577717
	pthread_mutex_t mutex;
Packit 577717
	pthread_cond_t	cond;
Packit 577717
	uint32_t	counter;
Packit 577717
	uint32_t	max;
Packit 577717
	uint64_t	generation; /* avoid race condition on wake-up */
Packit 577717
} barrier_t;
Packit 577717
Packit 577717
typedef struct {
Packit 577717
	uint32_t	cpu;
Packit 577717
	uint32_t	fd;
Packit 577717
	void		*smpl_vaddr;
Packit 577717
	size_t		smpl_buf_size;
Packit 577717
} pfms_cpu_t;
Packit 577717
Packit 577717
typedef struct _pfms_thread {
Packit 577717
	uint32_t	cpu;
Packit 577717
	pfms_cmd_t	cmd;
Packit 577717
	void		*data;
Packit 577717
	uint32_t	ndata;
Packit 577717
	sem_t		cmd_sem;
Packit 577717
	int		ret;
Packit 577717
	pthread_t	tid;
Packit 577717
	barrier_t	*barrier; 
Packit 577717
} pfms_thread_t;
Packit 577717
Packit 577717
typedef struct  {
Packit 577717
	barrier_t	barrier;
Packit 577717
	uint32_t	ncpus;
Packit 577717
} pfms_session_t;
Packit 577717
Packit 577717
static uint32_t	ncpus;
Packit 577717
static pfms_thread_t	*tds;
Packit 577717
static pthread_mutex_t  tds_lock = PTHREAD_MUTEX_INITIALIZER;
Packit 577717
Packit 577717
static int
Packit 577717
barrier_init(barrier_t *b, uint32_t count)
Packit 577717
{
Packit 577717
	int r;
Packit 577717
Packit 577717
	r = pthread_mutex_init(&b->mutex, NULL);
Packit 577717
	if (r == -1) return -1;
Packit 577717
Packit 577717
	r = pthread_cond_init(&b->cond, NULL);
Packit 577717
	if (r == -1) return -1;
Packit 577717
Packit 577717
	b->max = b->counter = count;
Packit 577717
	b->generation = 0;
Packit 577717
Packit 577717
	return 0;
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
cleanup_barrier(void *arg)
Packit 577717
{
Packit 577717
	barrier_t *b = (barrier_t *)arg;
Packit 577717
	int r;
Packit 577717
	r = pthread_mutex_unlock(&b->mutex);
Packit 577717
	dprint("free barrier mutex r=%d\n", r);
Packit 577717
	(void) r;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
barrier_wait(barrier_t *b)
Packit 577717
{
Packit 577717
	uint64_t generation;
Packit 577717
	int oldstate;
Packit 577717
Packit 577717
	pthread_cleanup_push(cleanup_barrier, b);
Packit 577717
Packit 577717
	pthread_mutex_lock(&b->mutex);
Packit 577717
Packit 577717
	pthread_testcancel();
Packit 577717
Packit 577717
	if (--b->counter == 0) {
Packit 577717
Packit 577717
		/* reset barrier */
Packit 577717
		b->counter = b->max;
Packit 577717
		/*
Packit 577717
		 * bump generation number, this avoids thread getting stuck in the
Packit 577717
		 * wake up loop below in case a thread just out of the barrier goes
Packit 577717
		 * back in right away before all the thread from the previous "round"
Packit 577717
		 * have "escaped".
Packit 577717
		 */
Packit 577717
		b->generation++;
Packit 577717
Packit 577717
		pthread_cond_broadcast(&b->cond);
Packit 577717
	} else {
Packit 577717
Packit 577717
		generation = b->generation;
Packit 577717
Packit 577717
		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
Packit 577717
Packit 577717
		while (b->counter != b->max && generation == b->generation) {
Packit 577717
			pthread_cond_wait(&b->cond, &b->mutex);
Packit 577717
		}
Packit 577717
Packit 577717
		pthread_setcancelstate(oldstate, NULL);
Packit 577717
	}
Packit 577717
	pthread_mutex_unlock(&b->mutex);
Packit 577717
Packit 577717
	pthread_cleanup_pop(0);
Packit 577717
Packit 577717
	return 0;
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * placeholder for pthread_setaffinity_np(). This stuff is ugly
Packit 577717
 * and I could not figure out a way to get it compiled while also preserving
Packit 577717
 * the pthread_*cancel(). There are issues with LinuxThreads and NPTL. I
Packit 577717
 * decided to quit on this and implement my own affinity call until this 
Packit 577717
 * settles.
Packit 577717
 */
Packit 577717
static int
Packit 577717
pin_cpu(uint32_t cpu)
Packit 577717
{
Packit 577717
	uint64_t *mask;
Packit 577717
	size_t size;
Packit 577717
	pid_t pid;
Packit 577717
	int ret;
Packit 577717
Packit 577717
	pid = syscall(__NR_gettid);
Packit 577717
Packit 577717
	size = ncpus * sizeof(uint64_t);
Packit 577717
Packit 577717
	mask = calloc(1, size);
Packit 577717
	if (mask == NULL) {
Packit 577717
		dprint("CPU%u: cannot allocate bitvector\n", cpu);
Packit 577717
		return -1;
Packit 577717
	}
Packit 577717
	mask[cpu>>6] = 1ULL << (cpu & 63);
Packit 577717
Packit 577717
	ret = syscall(__NR_sched_setaffinity, pid, size, mask);
Packit 577717
Packit 577717
	free(mask);
Packit 577717
Packit 577717
	return ret;
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
pfms_thread_mainloop(void *arg)
Packit 577717
{
Packit 577717
	long k = (long )arg;
Packit 577717
	uint32_t mycpu = (uint32_t)k;
Packit 577717
	pfarg_ctx_t myctx, *ctx;
Packit 577717
	pfarg_load_t load_args;
Packit 577717
	int fd = -1;
Packit 577717
	pfms_thread_t *td;
Packit 577717
	sem_t *cmd_sem;
Packit 577717
	int ret = 0;
Packit 577717
Packit 577717
	memset(&load_args, 0, sizeof(load_args));
Packit 577717
	load_args.load_pid = mycpu;
Packit 577717
	td = tds+mycpu;
Packit 577717
Packit 577717
	ret = pin_cpu(mycpu);
Packit 577717
	dprint("CPU%u wthread created and pinned ret=%d\n", mycpu, ret);
Packit 577717
Packit 577717
	cmd_sem = &tds[mycpu].cmd_sem;
Packit 577717
Packit 577717
	for(;;) {
Packit 577717
		dprint("CPU%u waiting for cmd\n", mycpu);
Packit 577717
Packit 577717
		sem_wait(cmd_sem);
Packit 577717
Packit 577717
		switch(td->cmd) {
Packit 577717
			case CMD_NONE:
Packit 577717
				ret = 0;
Packit 577717
				break;
Packit 577717
Packit 577717
			case CMD_CTX:
Packit 577717
Packit 577717
				/*
Packit 577717
				 * copy context to get private fd
Packit 577717
				 */
Packit 577717
				ctx = td->data;
Packit 577717
				myctx = *ctx;
Packit 577717
Packit 577717
				fd = pfm_create_context(&myctx, NULL, NULL, 0);
Packit 577717
				ret = fd < 0 ? -1 : 0;
Packit 577717
				dprint("CPU%u CMD_CTX ret=%d errno=%d fd=%d\n", mycpu, ret, errno, fd);
Packit 577717
				break;
Packit 577717
Packit 577717
			case CMD_LOAD:
Packit 577717
				ret = pfm_load_context(fd, &load_args);
Packit 577717
				dprint("CPU%u CMD_LOAD ret=%d errno=%d fd=%d\n", mycpu, ret, errno, fd);
Packit 577717
				break;
Packit 577717
			case CMD_UNLOAD:
Packit 577717
				ret = pfm_unload_context(fd);
Packit 577717
				dprint("CPU%u CMD_UNLOAD ret=%d errno=%d fd=%d\n", mycpu, ret, errno, fd);
Packit 577717
				break;
Packit 577717
			case CMD_START:
Packit 577717
				ret = pfm_start(fd, NULL);
Packit 577717
				dprint("CPU%u CMD_START ret=%d errno=%d fd=%d\n", mycpu, ret, errno, fd);
Packit 577717
				break;
Packit 577717
			case CMD_STOP:
Packit 577717
				ret = pfm_stop(fd);
Packit 577717
				dprint("CPU%u CMD_STOP ret=%d errno=%d fd=%d\n", mycpu, ret, errno, fd);
Packit 577717
				break;
Packit 577717
			case CMD_WPMCS:
Packit 577717
				ret = pfm_write_pmcs(fd,(pfarg_pmc_t *)td->data, td->ndata);
Packit 577717
				dprint("CPU%u CMD_WPMCS ret=%d errno=%d fd=%d\n", mycpu, ret, errno, fd);
Packit 577717
				break;
Packit 577717
			case CMD_WPMDS:
Packit 577717
				ret = pfm_write_pmds(fd,(pfarg_pmd_t *)td->data, td->ndata);
Packit 577717
				dprint("CPU%u CMD_WPMDS ret=%d errno=%d fd=%d\n", mycpu, ret, errno, fd);
Packit 577717
				break;
Packit 577717
			case CMD_RPMDS:
Packit 577717
				ret = pfm_read_pmds(fd,(pfarg_pmd_t *)td->data, td->ndata);
Packit 577717
				dprint("CPU%u CMD_RPMDS ret=%d errno=%d fd=%d\n", mycpu, ret, errno, fd);
Packit 577717
				break;
Packit 577717
			case CMD_CLOSE:
Packit 577717
				dprint("CPU%u CMD_CLOSE fd=%d\n", mycpu, fd);
Packit 577717
				ret = close(fd);
Packit 577717
				fd = -1;
Packit 577717
				break;
Packit 577717
			default:
Packit 577717
				break;
Packit 577717
		}
Packit 577717
		td->ret = ret;
Packit 577717
Packit 577717
		dprint("CPU%u td->ret=%d\n", mycpu, ret);
Packit 577717
Packit 577717
		barrier_wait(td->barrier);
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
create_one_wthread(int cpu)
Packit 577717
{
Packit 577717
	int ret;
Packit 577717
Packit 577717
	sem_init(&tds[cpu].cmd_sem, 0, 0);
Packit 577717
Packit 577717
	ret = pthread_create(&tds[cpu].tid, 
Packit 577717
			     NULL, 
Packit 577717
			     (void *(*)(void *))pfms_thread_mainloop,
Packit 577717
			     (void *)(long)cpu);
Packit 577717
	return ret;
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * must be called with tds_lock held
Packit 577717
 */
Packit 577717
static int
Packit 577717
create_wthreads(uint64_t *cpu_list, uint32_t n)
Packit 577717
{
Packit 577717
	uint64_t v;
Packit 577717
	uint32_t i,k, cpu;
Packit 577717
	int ret = 0;
Packit 577717
Packit 577717
	for(k=0, cpu = 0; k < n; k++, cpu+= 64) {
Packit 577717
		v = cpu_list[k];
Packit 577717
		for(i=0; v && i < 63; i++, v>>=1, cpu++) {
Packit 577717
			if ((v & 0x1) && tds[cpu].tid == 0) {
Packit 577717
				ret = create_one_wthread(cpu);
Packit 577717
				if (ret) break;
Packit 577717
			}
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	if (ret)
Packit 577717
		dprint("cannot create wthread on CPU%u\n", cpu);
Packit 577717
Packit 577717
	return ret;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfms_initialize(void)
Packit 577717
{
Packit 577717
	printf("cpu_t=%zu thread=%zu session_t=%zu\n",
Packit 577717
		sizeof(pfms_cpu_t),
Packit 577717
		sizeof(pfms_thread_t),
Packit 577717
		sizeof(pfms_session_t));
Packit 577717
Packit 577717
	ncpus = (uint32_t)sysconf(_SC_NPROCESSORS_ONLN);
Packit 577717
	if (ncpus == -1) {
Packit 577717
		dprint("cannot retrieve number of online processors\n");
Packit 577717
		return -1;
Packit 577717
	}
Packit 577717
Packit 577717
	dprint("configured for %u CPUs\n", ncpus);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * XXX: assuming CPU are contiguously indexed
Packit 577717
	 */
Packit 577717
	tds = calloc(ncpus, sizeof(*tds));
Packit 577717
	if (tds == NULL) {
Packit 577717
		dprint("cannot allocate thread descriptors\n");
Packit 577717
		return -1;
Packit 577717
	}
Packit 577717
	return 0;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfms_create(uint64_t *cpu_list, size_t n, pfarg_ctx_t *ctx, pfms_ovfl_t *ovfl, void **desc)
Packit 577717
{
Packit 577717
	uint64_t v;
Packit 577717
	size_t k, i;
Packit 577717
	uint32_t num, cpu;
Packit 577717
	pfms_session_t *s;
Packit 577717
	int ret;
Packit 577717
Packit 577717
	if (cpu_list == NULL || n == 0 || ctx == NULL || desc == NULL) {
Packit 577717
		dprint("invalid parameters\n");
Packit 577717
		return -1;
Packit 577717
	}
Packit 577717
Packit 577717
	if ((ctx->ctx_flags & PFM_FL_SYSTEM_WIDE) == 0) {
Packit 577717
		dprint("only works for system wide\n");
Packit 577717
		return -1;
Packit 577717
	}
Packit 577717
Packit 577717
	*desc = NULL;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * XXX: assuming CPU are contiguously indexed
Packit 577717
	 */
Packit 577717
	num = 0;
Packit 577717
	for(k=0, cpu = 0; k < n; k++, cpu+=64) {
Packit 577717
		v = cpu_list[k];
Packit 577717
		for(i=0; v && i < 63; i++, v>>=1, cpu++) {
Packit 577717
			if (v & 0x1) {
Packit 577717
				if (cpu >= ncpus) {
Packit 577717
					dprint("unavailable CPU%u\n", cpu);
Packit 577717
					return -1;
Packit 577717
				}
Packit 577717
				num++;
Packit 577717
			}
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	if (num == 0)
Packit 577717
		return 0;
Packit 577717
Packit 577717
	s = calloc(1, sizeof(*s));
Packit 577717
	if (s == NULL) {
Packit 577717
		dprint("cannot allocate %u contexts\n", num);
Packit 577717
		return -1;
Packit 577717
	}
Packit 577717
	s->ncpus = num;
Packit 577717
Packit 577717
	printf("%u-way  session\n", num);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * +1 to account for main thread waiting
Packit 577717
	 */
Packit 577717
	ret = barrier_init(&s->barrier, num + 1);
Packit 577717
	if (ret) {
Packit 577717
		dprint("cannot init barrier\n");
Packit 577717
		goto error_free;
Packit 577717
	}
Packit 577717
Packit 577717
	/*
Packit 577717
	 * lock thread descriptor table, no other create_session, close_session
Packit 577717
	 * can occur
Packit 577717
	 */
Packit 577717
	pthread_mutex_lock(&tds_lock);
Packit 577717
Packit 577717
	if (create_wthreads(cpu_list, n))
Packit 577717
		goto error_free_unlock;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * check all needed threads are available
Packit 577717
	 */
Packit 577717
	for(k=0, cpu = 0; k < n; k++, cpu += 64) {
Packit 577717
		v = cpu_list[k];
Packit 577717
		for(i=0; v && i < 63; i++, v>>=1, cpu++) {
Packit 577717
			if (v & 0x1) {
Packit 577717
				if (tds[cpu].barrier) {
Packit 577717
					dprint("CPU%u already managing a session\n", cpu);
Packit 577717
					goto error_free_unlock;
Packit 577717
				}
Packit 577717
Packit 577717
			}
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	/*
Packit 577717
	 * send create context order
Packit 577717
	 */
Packit 577717
	for(k=0, cpu = 0; k < n; k++, cpu += 64) {
Packit 577717
		v = cpu_list[k];
Packit 577717
		for(i=0; v && i < 63; i++, v>>=1, cpu++) {
Packit 577717
			if (v & 0x1) {
Packit 577717
				tds[cpu].cmd  = CMD_CTX;
Packit 577717
				tds[cpu].data = ctx;
Packit 577717
				tds[cpu].barrier = &s->barrier;
Packit 577717
				sem_post(&tds[cpu].cmd_sem);
Packit 577717
			}
Packit 577717
		}
Packit 577717
	}
Packit 577717
	barrier_wait(&s->barrier);
Packit 577717
Packit 577717
	ret = 0;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * check for errors
Packit 577717
	 */
Packit 577717
	for(k=0; k < ncpus; k++) {
Packit 577717
		if (tds[k].barrier == &s->barrier) {
Packit 577717
			ret = tds[k].ret;
Packit 577717
			if (ret)
Packit 577717
				break;
Packit 577717
		}
Packit 577717
	}
Packit 577717
	/*
Packit 577717
	 * undo if error found
Packit 577717
	 */
Packit 577717
	if (k < ncpus) {
Packit 577717
		for(k=0; k < ncpus; k++) {
Packit 577717
			if (tds[k].barrier == &s->barrier) {
Packit 577717
				if (tds[k].ret == 0) {
Packit 577717
					tds[k].cmd = CMD_CLOSE;
Packit 577717
					sem_post(&tds[k].cmd_sem);
Packit 577717
				}
Packit 577717
				/* mark as free */
Packit 577717
				tds[k].barrier = NULL;
Packit 577717
			}
Packit 577717
		}
Packit 577717
	}
Packit 577717
	pthread_mutex_unlock(&tds_lock);
Packit 577717
Packit 577717
	if (ret == 0) *desc = s;
Packit 577717
Packit 577717
	return ret ? -1 : 0;
Packit 577717
Packit 577717
error_free_unlock:
Packit 577717
	pthread_mutex_unlock(&tds_lock);
Packit 577717
Packit 577717
error_free:
Packit 577717
	free(s);
Packit 577717
	return -1;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfms_load(void *desc)
Packit 577717
{
Packit 577717
	uint32_t k;
Packit 577717
	pfms_session_t *s;
Packit 577717
	int ret;
Packit 577717
Packit 577717
	if (desc == NULL) {
Packit 577717
		dprint("invalid parameters\n");
Packit 577717
		return -1;
Packit 577717
	}
Packit 577717
	s = (pfms_session_t *)desc;
Packit 577717
Packit 577717
	if (s->ncpus == 0) {
Packit 577717
		dprint("invalid session content 0 CPUS\n");
Packit 577717
		return -1;
Packit 577717
	}
Packit 577717
	/*
Packit 577717
	 * send create context order
Packit 577717
	 */
Packit 577717
	for(k=0; k < ncpus; k++) {
Packit 577717
		if (tds[k].barrier == &s->barrier) {
Packit 577717
			tds[k].cmd  = CMD_LOAD;
Packit 577717
			sem_post(&tds[k].cmd_sem);
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	barrier_wait(&s->barrier);
Packit 577717
Packit 577717
	ret = 0;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * check for errors
Packit 577717
	 */
Packit 577717
	for(k=0; k < ncpus; k++) {
Packit 577717
		if (tds[k].barrier == &s->barrier) {
Packit 577717
			ret = tds[k].ret;
Packit 577717
			if (ret) {
Packit 577717
				dprint("failure on CPU%u\n", k);
Packit 577717
				break;
Packit 577717
			}
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	/*
Packit 577717
	 * if error, unload all others
Packit 577717
	 */
Packit 577717
	if (k < ncpus) {
Packit 577717
		for(k=0; k < ncpus; k++) {
Packit 577717
			if (tds[k].barrier == &s->barrier) {
Packit 577717
				if (tds[k].ret == 0) {
Packit 577717
					tds[k].cmd = CMD_UNLOAD;
Packit 577717
					sem_post(&tds[k].cmd_sem);
Packit 577717
				}
Packit 577717
			}
Packit 577717
		}
Packit 577717
	}
Packit 577717
	return ret ? -1 : 0;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
__pfms_do_simple_cmd(pfms_cmd_t cmd, void *desc, void *data, uint32_t n)
Packit 577717
{
Packit 577717
	size_t k;
Packit 577717
	pfms_session_t *s;
Packit 577717
	int ret;
Packit 577717
Packit 577717
	if (desc == NULL) {
Packit 577717
		dprint("invalid parameters\n");
Packit 577717
		return -1;
Packit 577717
	}
Packit 577717
	s = (pfms_session_t *)desc;
Packit 577717
Packit 577717
	if (s->ncpus == 0) {
Packit 577717
		dprint("invalid session content 0 CPUS\n");
Packit 577717
		return -1;
Packit 577717
	}
Packit 577717
	/*
Packit 577717
	 * send create context order
Packit 577717
	 */
Packit 577717
	for(k=0; k < ncpus; k++) {
Packit 577717
		if (tds[k].barrier == &s->barrier) {
Packit 577717
			tds[k].cmd  = cmd;
Packit 577717
			tds[k].data = data;
Packit 577717
			tds[k].ndata = n;
Packit 577717
			sem_post(&tds[k].cmd_sem);
Packit 577717
		}
Packit 577717
	}
Packit 577717
	barrier_wait(&s->barrier);
Packit 577717
Packit 577717
	ret = 0;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * check for errors
Packit 577717
	 */
Packit 577717
	for(k=0; k < ncpus; k++) {
Packit 577717
		if (tds[k].barrier == &s->barrier) {
Packit 577717
			ret = tds[k].ret;
Packit 577717
			if (ret) {
Packit 577717
				dprint("failure on CPU%zu\n", k);
Packit 577717
				break;
Packit 577717
			}
Packit 577717
		}
Packit 577717
	}
Packit 577717
	/*
Packit 577717
	 * simple commands cannot be undone
Packit 577717
	 */
Packit 577717
	return ret ? -1 : 0;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfms_unload(void *desc)
Packit 577717
{
Packit 577717
	return __pfms_do_simple_cmd(CMD_UNLOAD, desc, NULL, 0);
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfms_start(void *desc)
Packit 577717
{
Packit 577717
	return __pfms_do_simple_cmd(CMD_START, desc, NULL, 0);
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfms_stop(void *desc)
Packit 577717
{
Packit 577717
	return __pfms_do_simple_cmd(CMD_STOP, desc, NULL, 0);
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfms_write_pmcs(void *desc, pfarg_pmc_t *pmcs, uint32_t n)
Packit 577717
{
Packit 577717
	return __pfms_do_simple_cmd(CMD_WPMCS, desc, pmcs, n);
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfms_write_pmds(void *desc, pfarg_pmd_t *pmds, uint32_t n)
Packit 577717
{
Packit 577717
	return __pfms_do_simple_cmd(CMD_WPMDS, desc, pmds, n);
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfms_close(void *desc)
Packit 577717
{
Packit 577717
	size_t k;
Packit 577717
	pfms_session_t *s;
Packit 577717
	int ret;
Packit 577717
Packit 577717
	if (desc == NULL) {
Packit 577717
		dprint("invalid parameters\n");
Packit 577717
		return -1;
Packit 577717
	}
Packit 577717
	s = (pfms_session_t *)desc;
Packit 577717
Packit 577717
	if (s->ncpus == 0) {
Packit 577717
		dprint("invalid session content 0 CPUS\n");
Packit 577717
		return -1;
Packit 577717
	}
Packit 577717
Packit 577717
	for(k=0; k < ncpus; k++) {
Packit 577717
		if (tds[k].barrier == &s->barrier) {
Packit 577717
			tds[k].cmd  = CMD_CLOSE;
Packit 577717
			sem_post(&tds[k].cmd_sem);
Packit 577717
		}
Packit 577717
	}
Packit 577717
	barrier_wait(&s->barrier);
Packit 577717
Packit 577717
	ret = 0;
Packit 577717
Packit 577717
	pthread_mutex_lock(&tds_lock);
Packit 577717
	/*
Packit 577717
	 * check for errors
Packit 577717
	 */
Packit 577717
	for(k=0; k < ncpus; k++) {
Packit 577717
		if (tds[k].barrier == &s->barrier) {
Packit 577717
			if (tds[k].ret) {
Packit 577717
				dprint("failure on CPU%zu\n", k);
Packit 577717
			}
Packit 577717
			ret |= tds[k].ret;
Packit 577717
			tds[k].barrier = NULL;
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	pthread_mutex_unlock(&tds_lock);
Packit 577717
Packit 577717
	free(s);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * XXX: we cannot undo close
Packit 577717
	 */
Packit 577717
	return ret ? -1 : 0;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
pfms_read_pmds(void *desc, pfarg_pmd_t *pmds, uint32_t n)
Packit 577717
{
Packit 577717
	pfms_session_t *s;
Packit 577717
	uint32_t k, pmds_per_cpu;
Packit 577717
	int ret;
Packit 577717
Packit 577717
	if (desc == NULL) {
Packit 577717
		dprint("invalid parameters\n");
Packit 577717
		return -1;
Packit 577717
	}
Packit 577717
	s = (pfms_session_t *)desc;
Packit 577717
Packit 577717
	if (s->ncpus == 0) {
Packit 577717
		dprint("invalid session content 0 CPUS\n");
Packit 577717
		return -1;
Packit 577717
	}
Packit 577717
	if (n % s->ncpus) {
Packit 577717
		dprint("invalid number of pfarg_pmd_t provided, must be multiple of %u\n", s->ncpus);
Packit 577717
		return -1;
Packit 577717
	}
Packit 577717
	pmds_per_cpu = n / s->ncpus;
Packit 577717
Packit 577717
	dprint("n=%u ncpus=%u per_cpu=%u\n", n, s->ncpus, pmds_per_cpu);
Packit 577717
Packit 577717
	for(k=0; k < ncpus; k++) {
Packit 577717
		if (tds[k].barrier == &s->barrier) {
Packit 577717
			tds[k].cmd  = CMD_RPMDS;
Packit 577717
			tds[k].data = pmds;
Packit 577717
			tds[k].ndata= pmds_per_cpu;
Packit 577717
			sem_post(&tds[k].cmd_sem);
Packit 577717
			pmds += pmds_per_cpu;
Packit 577717
		}
Packit 577717
	}
Packit 577717
	barrier_wait(&s->barrier);
Packit 577717
Packit 577717
	ret = 0;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * check for errors
Packit 577717
	 */
Packit 577717
	for(k=0; k < ncpus; k++) {
Packit 577717
		if (tds[k].barrier == &s->barrier) {
Packit 577717
			ret = tds[k].ret;
Packit 577717
			if (ret) {
Packit 577717
				dprint("failure on CPU%u\n", k);
Packit 577717
				break;
Packit 577717
			}
Packit 577717
		}
Packit 577717
	}
Packit 577717
	/*
Packit 577717
	 * cannot undo pfm_read_pmds
Packit 577717
	 */
Packit 577717
	return ret ? -1 : 0;
Packit 577717
}
Packit 577717
#if 0
Packit 577717
Packit 577717
/*
Packit 577717
 * beginning of test program
Packit 577717
 */
Packit 577717
#include <perfmon/pfmlib.h>
Packit 577717
Packit 577717
#define NUM_PMCS PFMLIB_MAX_PMCS
Packit 577717
#define NUM_PMDS PFMLIB_MAX_PMDS
Packit 577717
Packit 577717
static void fatal_error(char *fmt,...) __attribute__((noreturn));
Packit 577717
Packit 577717
static void
Packit 577717
fatal_error(char *fmt, ...)
Packit 577717
{
Packit 577717
	va_list ap;
Packit 577717
Packit 577717
	va_start(ap, fmt);
Packit 577717
	vfprintf(stderr, fmt, ap);
Packit 577717
	va_end(ap);
Packit 577717
Packit 577717
	exit(1);
Packit 577717
}
Packit 577717
Packit 577717
static uint32_t
Packit 577717
popcount(uint64_t c)
Packit 577717
{
Packit 577717
	uint32_t count = 0;
Packit 577717
Packit 577717
	for(; c; c>>=1) {
Packit 577717
		if (c & 0x1)
Packit 577717
			count++;
Packit 577717
	}
Packit 577717
	return count;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
main(int argc, char **argv)
Packit 577717
{
Packit 577717
	pfarg_ctx_t ctx;
Packit 577717
	pfarg_pmc_t pc[NUM_PMCS];
Packit 577717
	pfarg_pmd_t *pd;
Packit 577717
	pfmlib_input_param_t inp;
Packit 577717
	pfmlib_output_param_t outp;
Packit 577717
	uint64_t cpu_list;
Packit 577717
	void *desc;
Packit 577717
	unsigned int num_counters;
Packit 577717
	uint32_t i, j, k, l, ncpus, npmds;
Packit 577717
	size_t len;
Packit 577717
	int ret;
Packit 577717
	char *name;
Packit 577717
Packit 577717
	if (pfm_initialize() != PFMLIB_SUCCESS)
Packit 577717
		fatal_error("cannot initialize libpfm\n");
Packit 577717
Packit 577717
	if (pfms_initialize())
Packit 577717
		fatal_error("cannot initialize libpfms\n");
Packit 577717
Packit 577717
	pfm_get_num_counters(&num_counters);
Packit 577717
	pfm_get_max_event_name_len(&len;;
Packit 577717
Packit 577717
	name = malloc(len+1);
Packit 577717
	if (name == NULL)
Packit 577717
		fatal_error("cannot allocate memory for event name\n");
Packit 577717
Packit 577717
	memset(&ctx, 0, sizeof(ctx));
Packit 577717
	memset(pc, 0, sizeof(pc));
Packit 577717
	memset(&inp,0, sizeof(inp));
Packit 577717
	memset(&outp,0, sizeof(outp));
Packit 577717
Packit 577717
	cpu_list = argc > 1 ? strtoul(argv[1], NULL, 0) : 0x3;
Packit 577717
Packit 577717
	ncpus = popcount(cpu_list);
Packit 577717
Packit 577717
		if (pfm_get_cycle_event(&inp.pfp_events[0].event) != PFMLIB_SUCCESS)
Packit 577717
		fatal_error("cannot find cycle event\n");
Packit 577717
Packit 577717
	if (pfm_get_inst_retired_event(&inp.pfp_events[1].event) != PFMLIB_SUCCESS)
Packit 577717
		fatal_error("cannot find inst retired event\n");
Packit 577717
Packit 577717
	i = 2;
Packit 577717
Packit 577717
	inp.pfp_dfl_plm = PFM_PLM3|PFM_PLM0;
Packit 577717
Packit 577717
	if (i > num_counters) {
Packit 577717
		i = num_counters;
Packit 577717
		printf("too many events provided (max=%d events), using first %d event(s)\n", num_counters, i);
Packit 577717
	}
Packit 577717
	/*
Packit 577717
	 * how many counters we use
Packit 577717
	 */
Packit 577717
	inp.pfp_event_count = i;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * indicate we are using the monitors for a system-wide session.
Packit 577717
	 * This may impact the way the library sets up the PMC values.
Packit 577717
	 */
Packit 577717
	inp.pfp_flags = PFMLIB_PFP_SYSTEMWIDE;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * let the library figure out the values for the PMCS
Packit 577717
	 */
Packit 577717
	if ((ret=pfm_dispatch_events(&inp, NULL, &outp, NULL)) != PFMLIB_SUCCESS)
Packit 577717
		fatal_error("cannot configure events: %s\n", pfm_strerror(ret));
Packit 577717
Packit 577717
	npmds = ncpus * inp.pfp_event_count;
Packit 577717
	dprint("ncpus=%u npmds=%u\n", ncpus, npmds);
Packit 577717
Packit 577717
	pd = calloc(npmds, sizeof(pfarg_pmd_t));
Packit 577717
	if (pd == NULL)
Packit 577717
		fatal_error("cannot allocate pd array\n");
Packit 577717
Packit 577717
	for (i=0; i < outp.pfp_pmc_count; i++) {
Packit 577717
		pc[i].reg_num   = outp.pfp_pmcs[i].reg_num;
Packit 577717
		pc[i].reg_value = outp.pfp_pmcs[i].reg_value;
Packit 577717
	}
Packit 577717
Packit 577717
	for(l=0, k = 0; l < ncpus; l++) {
Packit 577717
		for (i=0, j=0; i < inp.pfp_event_count; i++, k++) {
Packit 577717
			pd[k].reg_num   = outp.pfp_pmcs[j].reg_pmd_num;
Packit 577717
			for(; j < outp.pfp_pmc_count; j++)  if (outp.pfp_pmcs[j].reg_evt_idx != i) break;
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	/*
Packit 577717
	 * create a context on all CPUs we asked for
Packit 577717
	 *
Packit 577717
	 * libpfms only works for system-wide, so we set the flag in
Packit 577717
	 * the master context. the context argument is not modified by
Packit 577717
	 * call.
Packit 577717
	 *
Packit 577717
	 * desc is an opaque descriptor used to identify session.
Packit 577717
	 */
Packit 577717
	ctx.ctx_flags = PFM_FL_SYSTEM_WIDE;
Packit 577717
Packit 577717
	ret = pfms_create(&cpu_list, 1, &ctx, NULL, &desc);
Packit 577717
	if (ret == -1)
Packit 577717
		fatal_error("create error %d\n", ret);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * program the PMC registers on all CPUs of interest
Packit 577717
	 */
Packit 577717
	ret = pfms_write_pmcs(desc, pc, outp.pfp_pmc_count);
Packit 577717
	if (ret == -1)
Packit 577717
		fatal_error("write_pmcs error %d\n", ret);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * program the PMD registers on all CPUs of interest
Packit 577717
	 */
Packit 577717
	ret = pfms_write_pmds(desc, pd, inp.pfp_event_count);
Packit 577717
	if (ret == -1)
Packit 577717
		fatal_error("write_pmds error %d\n", ret);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * load context on all CPUs of interest
Packit 577717
	 */
Packit 577717
	ret = pfms_load(desc);
Packit 577717
	if (ret == -1)
Packit 577717
		fatal_error("load error %d\n", ret);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * start monitoring on all CPUs of interest
Packit 577717
	 */
Packit 577717
	ret = pfms_start(desc);
Packit 577717
	if (ret == -1)
Packit 577717
		fatal_error("start error %d\n", ret);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * simulate some work
Packit 577717
	 */
Packit 577717
	sleep(10);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * stop monitoring on all CPUs of interest
Packit 577717
	 */
Packit 577717
	ret = pfms_stop(desc);
Packit 577717
	if (ret == -1)
Packit 577717
		fatal_error("stop error %d\n", ret);
Packit 577717
	
Packit 577717
	/*
Packit 577717
	 * read the PMD registers on all CPUs of interest.
Packit 577717
	 * The pd[] array must be organized such that to
Packit 577717
	 * read 2 PMDs on each CPU you need:
Packit 577717
	 * 	- 2 * number of CPUs of interest
Packit 577717
	 * 	- the first 2 elements of pd[] read on 1st CPU
Packit 577717
	 * 	- the next  2 elements of pd[] read on the 2nd CPU
Packit 577717
	 * 	- and so on
Packit 577717
	 */
Packit 577717
	ret = pfms_read_pmds(desc, pd, npmds);
Packit 577717
	if (ret == -1)
Packit 577717
		fatal_error("read_pmds error %d\n", ret);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * pre per-CPU results
Packit 577717
	 */
Packit 577717
	for(j=0, k= 0; j < ncpus; j++) {
Packit 577717
		for (i=0; i < inp.pfp_event_count; i++, k++) {
Packit 577717
			pfm_get_full_event_name(&inp.pfp_events[i], name, len);
Packit 577717
			printf("CPU%-3d PMD%u %20"PRIu64" %s\n",
Packit 577717
			j,
Packit 577717
			pd[k].reg_num,
Packit 577717
			pd[k].reg_value,
Packit 577717
			name);
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	/*
Packit 577717
	 * destroy context  on all CPUs of interest.
Packit 577717
	 * After this call desc is invalid
Packit 577717
	 */
Packit 577717
	ret = pfms_close(desc);
Packit 577717
	if (ret == -1)
Packit 577717
		fatal_error("close error %d\n", ret);
Packit 577717
Packit 577717
	free(name);
Packit 577717
Packit 577717
	return 0;
Packit 577717
}
Packit 577717
#endif