cpacfstats: Bugfix to remove libpfm from cpacfstats

libpfm does not yet include counters introduced with z15 in a release.
cpacfstatsd now implements its own counter logic to become independent
of the slow release cycles of libpfm.

Reviewd-By: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewd-By: Harald Freudenberger <freude@de.ibm.com>
Signed-off-by: Juergen Christ <jchrist@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Juergen Christ
2020-07-24 17:57:45 +02:00
committed by Jan Höppner
parent 70f1dcd770
commit fd174cb952
2 changed files with 95 additions and 53 deletions

View File

@@ -2,28 +2,10 @@ include ../common.mak
ALL_CPPFLAGS += -DVERSION=$(VERSION)
ifeq (${HAVE_PFM},0)
all:
$(SKIP) HAVE_PFM=0
install:
$(SKIP) HAVE_PFM=0
else
check_dep:
$(call check_dep, \
"cpacfstats", \
"perfmon/pfmlib.h", \
"libpfm-devel or libpfm4-dev", \
"HAVE_PFM=0")
all: check_dep cpacfstats cpacfstatsd
all: cpacfstats cpacfstatsd
cpacfstatsd: cpacfstatsd.o stats_sock.o perf_crypto.o
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -lpfm -o $@
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
cpacfstats: cpacfstats.o stats_sock.o
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
@@ -34,7 +16,6 @@ install: all
$(INSTALL) -m 644 cpacfstatsd.8 $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 644 cpacfstats.1 $(DESTDIR)$(MANDIR)/man1
endif
clean:
rm -f *.o *~ cpacfstatsd cpacfstats

View File

@@ -9,33 +9,33 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <asm/unistd.h>
#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 <limits.h>
#include <linux/perf_event.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "cpacfstats.h"
#define PERF_ECC_COUNTER_NAME "cpum_cf::ECC_FUNCTION_COUNT"
/* correlation between counter and perf counter string */
static const struct {
char pfm_name[80];
char pmu[20];
char pfm_name[60];
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},
{PERF_ECC_COUNTER_NAME, ECC_FUNCTIONS}
{"cpum_cf", "DEA_FUNCTIONS", DES_FUNCTIONS},
{"cpum_cf", "AES_FUNCTIONS", AES_FUNCTIONS},
{"cpum_cf", "SHA_FUNCTIONS", SHA_FUNCTIONS},
{"cpum_cf", "PRNG_FUNCTIONS", PRNG_FUNCTIONS},
{"cpum_cf", "ECC_FUNCTION_COUNT", ECC_FUNCTIONS}
};
/*
@@ -58,23 +58,93 @@ static int *ctr_fds[ALL_COUNTER];
static int ecc_supported;
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
int cpu, int group_fd, unsigned long flags)
{
int ret;
ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
group_fd, flags);
return ret;
}
static int perf_supported(void)
{
return !access("/proc/sys/kernel/perf_event_paranoid", R_OK);
}
static int perf_counter_supported(const char *pmu, const char *counter)
{
char buf[PATH_MAX];
if (snprintf(buf, PATH_MAX, "/sys/bus/event_source/devices/%s/events/%s",
pmu, counter) >= PATH_MAX) {
eprint("overflow in path name");
return 0;
}
return !access(buf, R_OK);
}
static int perf_event_encode(struct perf_event_attr *attr,
const char *pmu, const char *event)
{
FILE *f;
int eventid;
int pmutype;
char buf[PATH_MAX];
if (snprintf(buf, PATH_MAX, "/sys/bus/event_source/devices/%s/events/%s",
pmu, event) >= PATH_MAX) {
eprint("overflow in path name");
return -1;
}
f = fopen(buf, "r");
if (!f) {
eprint("Event %s for pmu %s not found (%d:%s)\n", event, pmu,
errno, strerror(errno));
return -1;
}
if (fscanf(f, "event=0x%x\n", &eventid) != 1) {
fclose(f);
eprint("Event file %s has invalid format\n", buf);
return -1;
}
fclose(f);
if (snprintf(buf, PATH_MAX, "/sys/bus/event_source/devices/%s/type",
pmu) >= PATH_MAX) {
eprint("overflow in path name");
return -1;
}
f = fopen(buf, "r");
if (!f) {
eprint("Event %s for pmu %s not found (%d:%s)\n", event, pmu,
errno, strerror(errno));
return -1;
}
if (fscanf(f, "%d\n", &pmutype) != 1) {
fclose(f);
eprint("Type file %s has invalid format\n", buf);
return -1;
}
attr->type = pmutype;
attr->config = eventid;
return 0;
}
int perf_init(void)
{
int i, cpus, ctr, cpu, ec, *fds;
int i, cpus, ctr, cpu, *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));
if (!perf_supported()) {
eprint("Performance counter not supported");
return -1;
}
/* Check if ECC is supported on current hardware */
if (pfm_find_event(PERF_ECC_COUNTER_NAME) >= 0)
ecc_supported = 1;
ecc_supported = perf_counter_supported("cpum_cf", "ECC_FUNCTION_COUNT");
/* get number of logical processors */
cpus = sysconf(_SC_NPROCESSORS_ONLN);
@@ -111,26 +181,17 @@ int perf_init(void)
}
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);
pfm_event.size = sizeof(pfm_event);
/* 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",
if (perf_event_encode(&pfm_event,
pmf_counter_name[i].pmu,
pmf_counter_name[i].pfm_name)) {
eprint("Failed to initialize counter %s for pmu %s\n",
pmf_counter_name[i].pfm_name,
ec, pfm_strerror(ec));
pmf_counter_name[i].pmu);
return -1;
}