Files
s390-tools/cpacfstats/perf_crypto.c
Michael Holzheu b627b8d8e1 Initial s390-tools-2.0.0 import
This commit is based on the s390-tools-1.39.0 version.

Changes on top of s390-tools-1.39.0:

 - Add MIT license to all source files
 - Add LICENSE file
 - Transform REAMDE to README.md (markdown)
 - Add AUTHORS.md file
 - Add CONTRIBUTING.md file
 - Move changelog from README to CHANGELOG.md file

Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com>
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
2017-08-21 10:55:40 +02:00

259 lines
5.7 KiB
C

/*
* cpacfstats - display and maintain CPACF perf counters
*
* low level perf functions
*
* Copyright IBM Corp. 2015, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <errno.h>
#include <getopt.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <perfmon/perf_event.h>
#include <perfmon/pfmlib.h>
#include <perfmon/pfmlib_perf_event.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "cpacfstats.h"
/* correlation between counter and perf counter string */
static const struct {
char pfm_name[80];
enum ctr_e ctr;
} pmf_counter_name[ALL_COUNTER] = {
{"cpum_cf::DEA_FUNCTIONS", DES_FUNCTIONS},
{"cpum_cf::AES_FUNCTIONS", AES_FUNCTIONS},
{"cpum_cf::SHA_FUNCTIONS", SHA_FUNCTIONS},
{"cpum_cf::PRNG_FUNCTIONS", PRNG_FUNCTIONS}
};
/*
* We need one filedescriptor per CPU per counter.
* So perf_init builds this:
*
* ctr_fds - is an array of pointers to file descriptor arrays.
* Each file descriptor array has space for number of logical CPUs + 1
* filedescriptors (int values). The last element of each file descriptor
* array is always 0, assuming there will never appear a filedescriptor
* with value 0:
*
* ctr_fds:
* ctr_fds[0] -> [file descriptor 0] [fd1] ... [fd cpus-1][0]
* ctr_fds[1] -> [file descriptor 0] [fd1] ... [fd cpus-1][0]
* ...
* ctr_fds[ALL_COUNTER-1] -> [file descriptor 0] [fd1] ... [fd cpus-1][0]
*/
static int *ctr_fds[ALL_COUNTER];
int perf_init(void)
{
int i, cpus, ctr, cpu, ec, *fds;
memset(ctr_fds, 0, sizeof(ctr_fds));
/* initialize performance monitoring library */
ec = pfm_initialize();
if (ec != PFM_SUCCESS) {
eprint("Pfm_initialize() returned with failure (%d:%s)\n",
ec, pfm_strerror(ec));
return -1;
}
/* get number of logical processors */
cpus = sysconf(_SC_NPROCESSORS_ONLN);
/* for each counter */
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
/*
* allocate an array of ints to store for each CPU
* one filedescriptor + a terminating 0
*/
fds = (int *) calloc(sizeof(int), cpus+1);
if (!fds) {
eprint("Malloc() of %d byte failed, errno=%d [%s]\n",
(int)(sizeof(int) * (cpus+1)),
errno, strerror(errno));
return -1;
}
ctr_fds[ctr] = fds;
for (cpu = 0; cpu < cpus; cpu++) {
pfm_perf_encode_arg_t pfm_arg;
struct perf_event_attr pfm_event;
int fd;
memset(&pfm_arg, 0, sizeof(pfm_arg));
memset(&pfm_event, 0, sizeof(pfm_event));
pfm_arg.attr = &pfm_event;
pfm_arg.size = sizeof(pfm_arg);
/* search for the counter's corresponding pfm name */
for (i = ALL_COUNTER-1; i >= 0; i--)
if ((int) pmf_counter_name[i].ctr == ctr)
break;
if (i < 0) {
eprint("Pfm ctr name not found for counter %d, please adjust pmf_counter_name[] in %s\n",
ctr, __FILE__);
return -1;
}
/* encode the counters perf event into pfm_arg.attr */
ec = pfm_get_os_event_encoding(
pmf_counter_name[i].pfm_name,
PFM_PLM0,
PFM_OS_PERF_EVENT,
&pfm_arg);
if (ec != PFM_SUCCESS) {
eprint("Pfm_initialize() for %s failed (%d:%s)\n",
pmf_counter_name[i].pfm_name,
ec, pfm_strerror(ec));
return -1;
}
/* fetch file descriptor for this perf event
* the counter event should start disabled
*/
pfm_event.disabled = 1;
fd = perf_event_open(
&pfm_event,
-1, /* pid -1 means all processes */
cpu,
-1, /* group filedescriptor */
0); /* flags */
if (fd < 0) {
eprint("Perf_event_open() failed with errno=%d [%s]\n",
errno, strerror(errno));
return -1;
}
fds[cpu] = fd;
}
}
return 0;
}
void perf_close(void)
{
int ctr, *fds;
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
close(*fds);
*fds = 0;
}
free(ctr_fds[ctr]);
ctr_fds[ctr] = NULL;
}
}
int perf_enable_ctr(enum ctr_e ctr)
{
int *fds, ec, rc = 0;
if (ctr == ALL_COUNTER) {
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
rc = perf_enable_ctr(ctr);
if (rc != 0)
return rc;
}
} else {
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
ec = ioctl(*fds, PERF_EVENT_IOC_ENABLE, 0);
if (ec < 0) {
eprint("Ioctl(PERF_EVENT_IOC_ENABLE) failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
}
}
}
return rc;
}
int perf_disable_ctr(enum ctr_e ctr)
{
int *fds, ec, rc = 0;
if (ctr == ALL_COUNTER) {
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
rc = perf_disable_ctr(ctr);
if (rc != 0)
return rc;
}
} else {
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
ec = ioctl(*fds, PERF_EVENT_IOC_DISABLE, 0);
if (ec < 0) {
eprint("Ioctl(PERF_EVENT_IOC_DISABLE) failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
}
}
}
return rc;
}
int perf_reset_ctr(enum ctr_e ctr)
{
int *fds, ec, rc = 0;
if (ctr == ALL_COUNTER) {
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
rc = perf_reset_ctr(ctr);
if (rc != 0)
return rc;
}
} else {
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
ec = ioctl(*fds, PERF_EVENT_IOC_RESET, 0);
if (ec < 0) {
eprint("Ioctl(PERF_EVENT_IOC_RESET) failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
}
}
}
return rc;
}
int perf_read_ctr(enum ctr_e ctr, uint64_t *value)
{
int *fds, ec, rc = -1;
uint64_t val;
if (!value)
return -1;
*value = 0;
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
ec = read(*fds, &val, sizeof(val));
if (ec != sizeof(val)) {
eprint("Read() on perf file descriptor failed with errno=%d [%s]\n",
errno, strerror(errno));
} else {
*value += val;
rc = 0;
}
}
return rc;
}