mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
cpacfstats: Handle CPU hotplug
cpacfstatsd now correctly handles offline cpus and dynamically attaches to cpus once they get online. If events are enabled when a hotplug event occurs, cpacfstatsd uses a pseudo-counter to notify user applications about the occurence of this event and a potential data inaccuracy. cpacfstats shows if a hotplug event has been detected since at least one counter was activated. As soon as all counters are deactivated, the hotplug detection state is reset. Signed-off-by: Juergen Christ <jchrist@linux.ibm.com> Reviewed-By: Harald Freudenberger <freude@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
225964875c
commit
72b5e8b313
17
README.md
17
README.md
@@ -306,7 +306,6 @@ build options:
|
|||||||
| | | hsavmcore |
|
| | | hsavmcore |
|
||||||
| zlib | `HAVE_ZLIB` | zgetdump, dump2tar |
|
| zlib | `HAVE_ZLIB` | zgetdump, dump2tar |
|
||||||
| ncurses | `HAVE_NCURSES` | hyptop |
|
| ncurses | `HAVE_NCURSES` | hyptop |
|
||||||
| pfm | `HAVE_PFM` | cpacfstats |
|
|
||||||
| net-snmp | `HAVE_SNMP` | osasnmpd |
|
| net-snmp | `HAVE_SNMP` | osasnmpd |
|
||||||
| glibc-static | `HAVE_LIBC_STATIC` | zfcpdump |
|
| glibc-static | `HAVE_LIBC_STATIC` | zfcpdump |
|
||||||
| openssl | `HAVE_OPENSSL` | genprotimg, zkey, libekmfweb, |
|
| openssl | `HAVE_OPENSSL` | genprotimg, zkey, libekmfweb, |
|
||||||
@@ -320,6 +319,7 @@ build options:
|
|||||||
| libxml2 | `HAVE_LIBXML2` | libkmipclient |
|
| libxml2 | `HAVE_LIBXML2` | libkmipclient |
|
||||||
| systemd | `HAVE_SYSTEMD` | hsavmcore |
|
| systemd | `HAVE_SYSTEMD` | hsavmcore |
|
||||||
| liblockfile | `HAVE_LOCKFILE` | ap-check |
|
| liblockfile | `HAVE_LOCKFILE` | ap-check |
|
||||||
|
| libudev | `HAVE_LIBUDEV` | cpacfstatsd |
|
||||||
|
|
||||||
This table lists additional build or install options:
|
This table lists additional build or install options:
|
||||||
|
|
||||||
@@ -403,14 +403,13 @@ the different tools are provided:
|
|||||||
As of s390-tools-1.13.0, the minimum required kernel level is 2.6.38.
|
As of s390-tools-1.13.0, the minimum required kernel level is 2.6.38.
|
||||||
|
|
||||||
* cpacfstats:
|
* cpacfstats:
|
||||||
For building the cpacfstats tools you need libpfm version 4 or
|
For building the cpacfstats tools you need libudev installed
|
||||||
newer installed (libpfm-devel.rpm). Tip: you may skip the cpacfstats
|
(systemd-devel.rpm). Tip: you may skip the cpacfstats build by
|
||||||
build by adding `HAVE_PFN=0` to the make invocation. To run the
|
adding `HAVE_LIBUDEV=0` to the make invocation. To run the
|
||||||
cpacfstats daemon the kernel needs to have performance
|
cpacfstats daemon the kernel needs to have performance events
|
||||||
events enabled (check for `CONFIG_PERF_EVENTS=y`) and you need libpfm
|
enabled (check for `CONFIG_PERF_EVENTS=y`). A new group 'cpacfstats'
|
||||||
version 4 or newer installed. A new group 'cpacfstats' needs to be
|
needs to be created and all users intending to use the tool should
|
||||||
created and all users intending to use the tool should be added to
|
be added to this group.
|
||||||
this group.
|
|
||||||
|
|
||||||
* zdev:
|
* zdev:
|
||||||
Depending on the boot loader and initial RAM-disk mechanism used by a
|
Depending on the boot loader and initial RAM-disk mechanism used by a
|
||||||
|
|||||||
@@ -1,11 +1,28 @@
|
|||||||
include ../common.mak
|
include ../common.mak
|
||||||
|
|
||||||
|
ifeq (${HAVE_LIBUDEV},0)
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(SKIP) HAVE_LIBUDEV=0
|
||||||
|
|
||||||
|
install:
|
||||||
|
$(SKIP) HAVE_LIBUDEV=0
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
check_dep:
|
||||||
|
$(call check_dep, \
|
||||||
|
"cpacfstatsd", \
|
||||||
|
"libudev.h", \
|
||||||
|
"systemd-devel", \
|
||||||
|
"HAVE_LIBUDEV=0")
|
||||||
|
|
||||||
ALL_CPPFLAGS += -DVERSION=$(VERSION)
|
ALL_CPPFLAGS += -DVERSION=$(VERSION)
|
||||||
|
|
||||||
all: cpacfstats cpacfstatsd
|
all: check_dep cpacfstats cpacfstatsd
|
||||||
|
|
||||||
cpacfstatsd: cpacfstatsd.o stats_sock.o perf_crypto.o
|
cpacfstatsd: cpacfstatsd.o stats_sock.o perf_crypto.o
|
||||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -ludev -lpthread -o $@
|
||||||
|
|
||||||
cpacfstats: cpacfstats.o stats_sock.o
|
cpacfstats: cpacfstats.o stats_sock.o
|
||||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||||
@@ -16,6 +33,8 @@ install: all
|
|||||||
$(INSTALL) -m 644 cpacfstatsd.8 $(DESTDIR)$(MANDIR)/man8
|
$(INSTALL) -m 644 cpacfstatsd.8 $(DESTDIR)$(MANDIR)/man8
|
||||||
$(INSTALL) -m 644 cpacfstats.1 $(DESTDIR)$(MANDIR)/man1
|
$(INSTALL) -m 644 cpacfstats.1 $(DESTDIR)$(MANDIR)/man1
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o *~ cpacfstatsd cpacfstats
|
rm -f *.o *~ cpacfstatsd cpacfstats
|
||||||
|
|
||||||
|
|||||||
@@ -91,9 +91,20 @@ static int recv_answer(int s, int *ctr, int *state, uint64_t *value)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_virtual_counter_answer(int ctr, int state, uint64_t value)
|
||||||
|
{
|
||||||
|
if (ctr == HOTPLUG_DETECTED) {
|
||||||
|
if (state >= 0 && value > 0)
|
||||||
|
printf(" hotplug detected\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void print_answer(int ctr, int state, uint64_t value)
|
static void print_answer(int ctr, int state, uint64_t value)
|
||||||
{
|
{
|
||||||
|
if (ctr > ALL_COUNTER) {
|
||||||
|
print_virtual_counter_answer(ctr, state, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (state < 0)
|
if (state < 0)
|
||||||
printf(" %s counter: error state %d\n",
|
printf(" %s counter: error state %d\n",
|
||||||
counter_str[ctr], state);
|
counter_str[ctr], state);
|
||||||
@@ -232,6 +243,18 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
print_answer(j, state, value);
|
print_answer(j, state, value);
|
||||||
}
|
}
|
||||||
|
/* receive hotplug state */
|
||||||
|
if (recv_answer(s, &j, &state, &value) != 0) {
|
||||||
|
eprint("Error on receiving hotplug state from daemon\n");
|
||||||
|
close(s);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (state < 0) {
|
||||||
|
eprint("Received bad status code %d from daemon\n", state);
|
||||||
|
close(s);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
print_answer(j, state, value);
|
||||||
|
|
||||||
/* close connection */
|
/* close connection */
|
||||||
close(s);
|
close(s);
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ int eprint(const char *format, ...);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Counter names
|
* Counter names
|
||||||
* ALL_COUNTER must always be the last member of the enum
|
* ALL_COUNTER specifies the number of physical counters. Virtual
|
||||||
|
* counters might be added afterwards.
|
||||||
*/
|
*/
|
||||||
enum ctr_e {
|
enum ctr_e {
|
||||||
DES_FUNCTIONS = 0,
|
DES_FUNCTIONS = 0,
|
||||||
@@ -31,7 +32,8 @@ enum ctr_e {
|
|||||||
SHA_FUNCTIONS,
|
SHA_FUNCTIONS,
|
||||||
PRNG_FUNCTIONS,
|
PRNG_FUNCTIONS,
|
||||||
ECC_FUNCTIONS,
|
ECC_FUNCTIONS,
|
||||||
ALL_COUNTER
|
ALL_COUNTER,
|
||||||
|
HOTPLUG_DETECTED
|
||||||
};
|
};
|
||||||
|
|
||||||
enum type_e {
|
enum type_e {
|
||||||
@@ -53,7 +55,7 @@ enum state_e {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* query send from clent to daemon
|
* query send from client to daemon
|
||||||
* Consist of:
|
* Consist of:
|
||||||
* enum counter
|
* enum counter
|
||||||
* enum command
|
* enum command
|
||||||
@@ -102,17 +104,19 @@ struct msg {
|
|||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
int open_socket(int mode);
|
int open_socket(int mode);
|
||||||
int send_msg(int sfd, struct msg *m);
|
int send_msg(int sfd, struct msg *m, int timeout);
|
||||||
int recv_msg(int sfd, struct msg *m);
|
int recv_msg(int sfd, struct msg *m, int timeout);
|
||||||
|
|
||||||
/* perf_crypto.c */
|
/* perf_crypto.c */
|
||||||
|
|
||||||
int perf_init(void);
|
int perf_init(void);
|
||||||
|
void perf_stop(void);
|
||||||
void perf_close(void);
|
void perf_close(void);
|
||||||
int perf_enable_ctr(enum ctr_e ctr);
|
int perf_enable_ctr(enum ctr_e ctr);
|
||||||
int perf_disable_ctr(enum ctr_e ctr);
|
int perf_disable_ctr(enum ctr_e ctr);
|
||||||
int perf_reset_ctr(enum ctr_e ctr);
|
int perf_reset_ctr(enum ctr_e ctr);
|
||||||
int perf_read_ctr(enum ctr_e ctr, uint64_t *value);
|
int perf_read_ctr(enum ctr_e ctr, uint64_t *value);
|
||||||
int perf_ecc_supported(void);
|
int perf_ecc_supported(void);
|
||||||
|
int perf_ctr_state(enum ctr_e ctr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include "lib/zt_common.h"
|
#include "lib/zt_common.h"
|
||||||
#include "cpacfstats.h"
|
#include "cpacfstats.h"
|
||||||
|
|
||||||
|
static volatile int stopsig;
|
||||||
|
|
||||||
static const char *const name = "cpacfstatsd";
|
static const char *const name = "cpacfstatsd";
|
||||||
|
|
||||||
@@ -43,9 +44,6 @@ static const char *const usage =
|
|||||||
|
|
||||||
static int daemonized;
|
static int daemonized;
|
||||||
|
|
||||||
static int ctr_state[ALL_COUNTER];
|
|
||||||
|
|
||||||
|
|
||||||
static int recv_query(int s, enum ctr_e *ctr, enum cmd_e *cmd)
|
static int recv_query(int s, enum ctr_e *ctr, enum cmd_e *cmd)
|
||||||
{
|
{
|
||||||
struct msg m;
|
struct msg m;
|
||||||
@@ -89,32 +87,35 @@ static int send_answer(int s, int ctr, int state, uint64_t value)
|
|||||||
|
|
||||||
static int do_enable(int s, enum ctr_e ctr)
|
static int do_enable(int s, enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
uint64_t value;
|
uint64_t value = 0;
|
||||||
int i, rc = 0;
|
int i, rc = 0;
|
||||||
|
int state;
|
||||||
|
|
||||||
for (i = 0; i < ALL_COUNTER; i++) {
|
for (i = 0; i < ALL_COUNTER; i++) {
|
||||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||||
if (ctr_state[i] == DISABLED) {
|
state = perf_ctr_state(i);
|
||||||
|
if (state == DISABLED) {
|
||||||
rc = perf_enable_ctr(i);
|
rc = perf_enable_ctr(i);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
send_answer(s, i, rc, 0);
|
send_answer(s, i, rc, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ctr_state[i] = ENABLED;
|
state = ENABLED;
|
||||||
}
|
}
|
||||||
if (ctr_state[i] == UNSUPPORTED) {
|
if (state != UNSUPPORTED) {
|
||||||
send_answer(s, i, UNSUPPORTED, 0);
|
|
||||||
} else {
|
|
||||||
rc = perf_read_ctr(i, &value);
|
rc = perf_read_ctr(i, &value);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
send_answer(s, i, rc, 0);
|
send_answer(s, i, rc, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
send_answer(s, i, ENABLED, value);
|
|
||||||
}
|
}
|
||||||
|
send_answer(s, i, state, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (rc == 0) {
|
||||||
|
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
|
||||||
|
send_answer(s, HOTPLUG_DETECTED, rc, value);
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,67 +123,75 @@ static int do_enable(int s, enum ctr_e ctr)
|
|||||||
static int do_disable(int s, enum ctr_e ctr)
|
static int do_disable(int s, enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
int i, rc = 0;
|
int i, rc = 0;
|
||||||
|
uint64_t value;
|
||||||
|
|
||||||
for (i = 0; i < ALL_COUNTER; i++) {
|
for (i = 0; i < ALL_COUNTER; i++) {
|
||||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||||
if (ctr_state[i] == ENABLED) {
|
if (perf_ctr_state(i) == ENABLED) {
|
||||||
rc = perf_disable_ctr(i);
|
rc = perf_disable_ctr(i);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
send_answer(s, i, rc, 0);
|
send_answer(s, i, rc, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ctr_state[i] = 0;
|
|
||||||
}
|
}
|
||||||
send_answer(s, i, ctr_state[i], 0);
|
send_answer(s, i, perf_ctr_state(i), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (rc == 0) {
|
||||||
|
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
|
||||||
|
send_answer(s, HOTPLUG_DETECTED, rc, value);
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int do_reset(int s, enum ctr_e ctr)
|
static int do_reset(int s, enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
int i, rc = 0;
|
int i, rc = 0, state;
|
||||||
|
uint64_t value;
|
||||||
|
|
||||||
for (i = 0; i < ALL_COUNTER; i++) {
|
for (i = 0; i < ALL_COUNTER; i++) {
|
||||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||||
if (ctr_state[i] == ENABLED) {
|
state = perf_ctr_state(i);
|
||||||
|
if (state == ENABLED) {
|
||||||
rc = perf_reset_ctr(i);
|
rc = perf_reset_ctr(i);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
send_answer(s, i, rc, 0);
|
send_answer(s, i, rc, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
send_answer(s, i, ENABLED, 0);
|
|
||||||
} else {
|
|
||||||
send_answer(s, i, ctr_state[i], 0);
|
|
||||||
}
|
}
|
||||||
|
send_answer(s, i, state, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (rc == 0) {
|
||||||
|
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
|
||||||
|
send_answer(s, HOTPLUG_DETECTED, rc, value);
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_print(int s, enum ctr_e ctr)
|
static int do_print(int s, enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
int i, rc = 0;
|
int i, rc = 0, state;
|
||||||
uint64_t value;
|
uint64_t value = 0;
|
||||||
|
|
||||||
for (i = 0; i < ALL_COUNTER; i++) {
|
for (i = 0; i < ALL_COUNTER; i++) {
|
||||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||||
if (ctr_state[i] == ENABLED) {
|
state = perf_ctr_state(i);
|
||||||
|
if (state == ENABLED) {
|
||||||
rc = perf_read_ctr(i, &value);
|
rc = perf_read_ctr(i, &value);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
send_answer(s, i, rc, 0);
|
send_answer(s, i, rc, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
send_answer(s, i, ENABLED, value);
|
|
||||||
} else {
|
|
||||||
send_answer(s, i, ctr_state[i], 0);
|
|
||||||
}
|
}
|
||||||
|
send_answer(s, i, state, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (rc == 0) {
|
||||||
|
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
|
||||||
|
send_answer(s, HOTPLUG_DETECTED, rc, value);
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,18 +333,8 @@ static void remove_pidfile(void)
|
|||||||
|
|
||||||
void signalhandler(int sig)
|
void signalhandler(int sig)
|
||||||
{
|
{
|
||||||
if (sig == SIGTERM)
|
perf_stop();
|
||||||
eprint("Caught signal SIGTERM, terminating...\n");
|
stopsig = sig;
|
||||||
else if (sig == SIGINT)
|
|
||||||
eprint("Caught signal SIGINT, terminating...\n");
|
|
||||||
else
|
|
||||||
eprint("Caught signal %d, terminating...\n", sig);
|
|
||||||
|
|
||||||
remove_sock();
|
|
||||||
perf_close();
|
|
||||||
remove_pidfile();
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -416,9 +415,6 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
atexit(perf_close);
|
atexit(perf_close);
|
||||||
|
|
||||||
if (!perf_ecc_supported())
|
|
||||||
ctr_state[ECC_FUNCTIONS] = UNSUPPORTED;
|
|
||||||
|
|
||||||
sfd = open_socket(SERVER);
|
sfd = open_socket(SERVER);
|
||||||
if (sfd < 0) {
|
if (sfd < 0) {
|
||||||
eprint("Couldn't initialize server socket\n");
|
eprint("Couldn't initialize server socket\n");
|
||||||
@@ -442,7 +438,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
eprint("Running\n");
|
eprint("Running\n");
|
||||||
|
|
||||||
while (1) {
|
while (!stopsig) {
|
||||||
enum ctr_e ctr;
|
enum ctr_e ctr;
|
||||||
enum cmd_e cmd;
|
enum cmd_e cmd;
|
||||||
int s;
|
int s;
|
||||||
@@ -480,5 +476,13 @@ cleanup:
|
|||||||
close(s);
|
close(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stopsig == SIGTERM)
|
||||||
|
eprint("Caught signal SIGTERM, terminating...\n");
|
||||||
|
else if (stopsig == SIGINT)
|
||||||
|
eprint("Caught signal SIGINT, terminating...\n");
|
||||||
|
else
|
||||||
|
eprint("Caught signal %d, terminating...\n", stopsig);
|
||||||
|
remove_pidfile();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,9 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <linux/perf_event.h>
|
#include <linux/perf_event.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -23,14 +26,19 @@
|
|||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <libudev.h>
|
||||||
|
|
||||||
#include "cpacfstats.h"
|
#include "cpacfstats.h"
|
||||||
|
#include "../include/lib/zt_common.h"
|
||||||
|
|
||||||
|
#define NUM_COUNTER ALL_COUNTER
|
||||||
|
|
||||||
/* correlation between counter and perf counter string */
|
/* correlation between counter and perf counter string */
|
||||||
static const struct {
|
static const struct {
|
||||||
char pmu[20];
|
char pmu[20];
|
||||||
char pfm_name[60];
|
char pfm_name[60];
|
||||||
enum ctr_e ctr;
|
enum ctr_e ctr;
|
||||||
} pmf_counter_name[ALL_COUNTER] = {
|
} pmf_counter_name[NUM_COUNTER] = {
|
||||||
{"cpum_cf", "DEA_FUNCTIONS", DES_FUNCTIONS},
|
{"cpum_cf", "DEA_FUNCTIONS", DES_FUNCTIONS},
|
||||||
{"cpum_cf", "AES_FUNCTIONS", AES_FUNCTIONS},
|
{"cpum_cf", "AES_FUNCTIONS", AES_FUNCTIONS},
|
||||||
{"cpum_cf", "SHA_FUNCTIONS", SHA_FUNCTIONS},
|
{"cpum_cf", "SHA_FUNCTIONS", SHA_FUNCTIONS},
|
||||||
@@ -38,25 +46,71 @@ static const struct {
|
|||||||
{"cpum_cf", "ECC_FUNCTION_COUNT", ECC_FUNCTIONS}
|
{"cpum_cf", "ECC_FUNCTION_COUNT", ECC_FUNCTIONS}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
static struct pmf_data {
|
||||||
* We need one filedescriptor per CPU per counter.
|
int pmutype;
|
||||||
* So perf_init builds this:
|
int eventid;
|
||||||
*
|
} pmf_counter_data[NUM_COUNTER];
|
||||||
* 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];
|
|
||||||
|
|
||||||
static int ecc_supported;
|
struct percpucounter {
|
||||||
|
int ctr_fds[NUM_COUNTER];
|
||||||
|
unsigned int cpunum;
|
||||||
|
struct percpucounter *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct percpucounter *root;
|
||||||
|
pthread_mutex_t rootmux = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
static volatile int hotplugdetected;
|
||||||
|
static unsigned int enabledcounter;
|
||||||
|
pthread_t hotplugthread;
|
||||||
|
|
||||||
|
#define foreachcpu(PCPU) if (pthread_mutex_lock(&rootmux)) return -1; \
|
||||||
|
for ((PCPU) = root; (PCPU) != NULL; (PCPU) = (PCPU)->next)
|
||||||
|
#define endforeachcpu() pthread_mutex_unlock(&rootmux)
|
||||||
|
|
||||||
|
static int ctr_state[NUM_COUNTER];
|
||||||
|
|
||||||
|
static volatile int stoprequested;
|
||||||
|
|
||||||
|
static struct percpucounter *allocpercpucounter(unsigned int cpunum)
|
||||||
|
{
|
||||||
|
struct percpucounter *ppc;
|
||||||
|
|
||||||
|
ppc = malloc(sizeof(struct percpucounter));
|
||||||
|
if (ppc) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_COUNTER; ++i)
|
||||||
|
ppc->ctr_fds[i] = -1;
|
||||||
|
ppc->cpunum = cpunum;
|
||||||
|
ppc->next = NULL;
|
||||||
|
}
|
||||||
|
return ppc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void freepercpucounter(struct percpucounter *pcpu)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_COUNTER; ++i)
|
||||||
|
(void)close(pcpu->ctr_fds[i]);
|
||||||
|
free(pcpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct percpucounter *findcpu(unsigned int cpunum, int unlinkflag)
|
||||||
|
{
|
||||||
|
struct percpucounter **prev = &root, *walk = root;
|
||||||
|
|
||||||
|
while (walk) {
|
||||||
|
if (walk->cpunum == cpunum) {
|
||||||
|
if (unlinkflag)
|
||||||
|
*prev = walk->next;
|
||||||
|
return walk;
|
||||||
|
}
|
||||||
|
prev = &(walk->next);
|
||||||
|
walk = walk->next;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
|
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
|
||||||
int cpu, int group_fd, unsigned long flags)
|
int cpu, int group_fd, unsigned long flags)
|
||||||
@@ -85,12 +139,10 @@ static int perf_counter_supported(const char *pmu, const char *counter)
|
|||||||
return !access(buf, R_OK);
|
return !access(buf, R_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int perf_event_encode(struct perf_event_attr *attr,
|
static int perf_event_encode(int *pmutype, int *eventid,
|
||||||
const char *pmu, const char *event)
|
const char *pmu, const char *event)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
int eventid;
|
|
||||||
int pmutype;
|
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
|
|
||||||
if (snprintf(buf, PATH_MAX, "/sys/bus/event_source/devices/%s/events/%s",
|
if (snprintf(buf, PATH_MAX, "/sys/bus/event_source/devices/%s/events/%s",
|
||||||
@@ -104,7 +156,7 @@ static int perf_event_encode(struct perf_event_attr *attr,
|
|||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (fscanf(f, "event=0x%x\n", &eventid) != 1) {
|
if (fscanf(f, "event=0x%x\n", eventid) != 1) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
eprint("Event file %s has invalid format\n", buf);
|
eprint("Event file %s has invalid format\n", buf);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -121,21 +173,185 @@ static int perf_event_encode(struct perf_event_attr *attr,
|
|||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (fscanf(f, "%d\n", &pmutype) != 1) {
|
if (fscanf(f, "%d\n", pmutype) != 1) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
eprint("Type file %s has invalid format\n", buf);
|
eprint("Type file %s has invalid format\n", buf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
attr->type = pmutype;
|
|
||||||
attr->config = eventid;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int activatecpu(unsigned int cpu)
|
||||||
|
{
|
||||||
|
struct perf_event_attr pfm_event;
|
||||||
|
struct percpucounter *ppc;
|
||||||
|
int fd, i, rc = 0;
|
||||||
|
|
||||||
|
ppc = allocpercpucounter(cpu);
|
||||||
|
if (ppc == NULL) {
|
||||||
|
eprint("Failed to allocate per cpu counter data");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (pthread_mutex_lock(&rootmux)) {
|
||||||
|
freepercpucounter(ppc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (i = 0; i < NUM_COUNTER; ++i) {
|
||||||
|
if (ctr_state[i] == UNSUPPORTED)
|
||||||
|
continue;
|
||||||
|
memset(&pfm_event, 0, sizeof(pfm_event));
|
||||||
|
pfm_event.size = sizeof(pfm_event);
|
||||||
|
pfm_event.type = pmf_counter_data[i].pmutype;
|
||||||
|
pfm_event.config = pmf_counter_data[i].eventid;
|
||||||
|
|
||||||
|
/* fetch file descriptor for this perf event
|
||||||
|
* the counter event should start disabled
|
||||||
|
*/
|
||||||
|
pfm_event.disabled = ctr_state[i] == DISABLED;
|
||||||
|
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));
|
||||||
|
rc = -1;
|
||||||
|
ctr_state[i] = UNSUPPORTED;
|
||||||
|
} else {
|
||||||
|
ppc->ctr_fds[i] = fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ppc->next = root;
|
||||||
|
root = ppc;
|
||||||
|
if (enabledcounter)
|
||||||
|
hotplugdetected = 1;
|
||||||
|
pthread_mutex_unlock(&rootmux);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deactivatecpu(unsigned int cpunum)
|
||||||
|
{
|
||||||
|
struct percpucounter *pcpu;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (pthread_mutex_lock(&rootmux))
|
||||||
|
return;
|
||||||
|
pcpu = findcpu(cpunum, 1);
|
||||||
|
if (pcpu != NULL) {
|
||||||
|
for (i = 0; i < NUM_COUNTER; ++i)
|
||||||
|
(void)close(pcpu->ctr_fds[i]);
|
||||||
|
free(pcpu);
|
||||||
|
if (enabledcounter)
|
||||||
|
hotplugdetected = 1;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&rootmux);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int addallcpus(void)
|
||||||
|
{
|
||||||
|
unsigned int start, end;
|
||||||
|
int scanned, rc = 0;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
/* comma separated list of intervals */
|
||||||
|
if ((fp = fopen("/sys/devices/system/cpu/online", "r")) == NULL) {
|
||||||
|
eprint("Failed to get online cpus (%d:%s)\n",
|
||||||
|
errno, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!feof(fp)) {
|
||||||
|
/* scan all intervals of online cpus */
|
||||||
|
scanned = fscanf(fp, "%u-%u", &start, &end);
|
||||||
|
/* take care of singleton intervals */
|
||||||
|
if (scanned == 1)
|
||||||
|
end = start;
|
||||||
|
for (; start <= end; ++start) {
|
||||||
|
if (activatecpu(start)) {
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Skip comma separator */
|
||||||
|
(void)fgetc(fp);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
fclose(fp);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int perf_load_counter_data(void)
|
||||||
|
{
|
||||||
|
int i, res = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_COUNTER; ++i) {
|
||||||
|
if (ctr_state[i] != UNSUPPORTED)
|
||||||
|
res |= perf_event_encode(&pmf_counter_data[i].pmutype,
|
||||||
|
&pmf_counter_data[i].eventid,
|
||||||
|
pmf_counter_name[i].pmu,
|
||||||
|
pmf_counter_name[i].pfm_name);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *hotplughandler(void *UNUSED(unused))
|
||||||
|
{
|
||||||
|
struct udev *hotplug;
|
||||||
|
struct udev_monitor *monitor;
|
||||||
|
struct pollfd item;
|
||||||
|
|
||||||
|
hotplug = udev_new();
|
||||||
|
if (!hotplug) {
|
||||||
|
eprint("Failed to create hotplug device\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
monitor = udev_monitor_new_from_netlink(hotplug, "udev");
|
||||||
|
udev_monitor_filter_add_match_subsystem_devtype(monitor, "cpu", NULL);
|
||||||
|
udev_monitor_enable_receiving(monitor);
|
||||||
|
item.fd = udev_monitor_get_fd(monitor);
|
||||||
|
item.events = POLLIN;
|
||||||
|
item.revents = 0;
|
||||||
|
while (!stoprequested) {
|
||||||
|
struct udev_device *dev;
|
||||||
|
const char *path, *action;
|
||||||
|
unsigned int cpunum;
|
||||||
|
int rc, on, off;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
rc = poll(&item, 1, -1);
|
||||||
|
if (rc == -1) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dev = udev_monitor_receive_device(monitor);
|
||||||
|
if (dev == NULL)
|
||||||
|
continue;
|
||||||
|
action = udev_device_get_action(dev);
|
||||||
|
if (action == NULL)
|
||||||
|
continue;
|
||||||
|
off = strcmp(action, "offline") == 0;
|
||||||
|
on = strcmp(action, "online") == 0;
|
||||||
|
if (!on && !off)
|
||||||
|
continue;
|
||||||
|
path = udev_device_get_devpath(dev);
|
||||||
|
if (sscanf(path, "/devices/system/cpu/cpu%u", &cpunum) != 1)
|
||||||
|
continue;
|
||||||
|
if (on && activatecpu(cpunum))
|
||||||
|
eprint("Failed to attach to hotplugged CPU %u\n", cpunum);
|
||||||
|
if (off)
|
||||||
|
deactivatecpu(cpunum);
|
||||||
|
}
|
||||||
|
udev_monitor_unref(monitor);
|
||||||
|
udev_unref(hotplug);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int perf_init(void)
|
int perf_init(void)
|
||||||
{
|
{
|
||||||
int i, cpus, ctr, cpu, *fds;
|
int ecc_supported;
|
||||||
|
|
||||||
memset(ctr_fds, 0, sizeof(ctr_fds));
|
|
||||||
|
|
||||||
/* initialize performance monitoring library */
|
/* initialize performance monitoring library */
|
||||||
if (!perf_supported()) {
|
if (!perf_supported()) {
|
||||||
@@ -145,97 +361,44 @@ int perf_init(void)
|
|||||||
|
|
||||||
/* Check if ECC is supported on current hardware */
|
/* Check if ECC is supported on current hardware */
|
||||||
ecc_supported = perf_counter_supported("cpum_cf", "ECC_FUNCTION_COUNT");
|
ecc_supported = perf_counter_supported("cpum_cf", "ECC_FUNCTION_COUNT");
|
||||||
|
if (!ecc_supported)
|
||||||
|
ctr_state[ECC_FUNCTIONS] = UNSUPPORTED;
|
||||||
|
|
||||||
/* get number of logical processors */
|
if (perf_load_counter_data())
|
||||||
cpus = sysconf(_SC_NPROCESSORS_ONLN);
|
return -1;
|
||||||
|
if (pthread_create(&hotplugthread, NULL, hotplughandler, NULL)) {
|
||||||
/* for each counter */
|
eprint("Failed to start hotplug handler thread\n");
|
||||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
return -1;
|
||||||
|
|
||||||
/* Skip ECC counters completely if unsupported */
|
|
||||||
if (ctr == ECC_FUNCTIONS && !ecc_supported)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (cpu = 0; cpu < cpus; cpu++) {
|
|
||||||
struct perf_event_attr pfm_event;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
memset(&pfm_event, 0, sizeof(pfm_event));
|
|
||||||
pfm_event.size = sizeof(pfm_event);
|
|
||||||
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,
|
|
||||||
pmf_counter_name[i].pmu);
|
|
||||||
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 addallcpus();
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
void perf_stop(void)
|
||||||
|
{
|
||||||
|
stoprequested = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void perf_close(void)
|
void perf_close(void)
|
||||||
{
|
{
|
||||||
int ctr, *fds;
|
struct percpucounter *walk, *next;
|
||||||
|
|
||||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
pthread_kill(hotplugthread, SIGINT);
|
||||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
pthread_join(hotplugthread, NULL);
|
||||||
close(*fds);
|
walk = root;
|
||||||
*fds = 0;
|
while (walk) {
|
||||||
}
|
next = walk->next;
|
||||||
free(ctr_fds[ctr]);
|
freepercpucounter(walk);
|
||||||
ctr_fds[ctr] = NULL;
|
walk = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int perf_enable_ctr(enum ctr_e ctr)
|
int perf_enable_ctr(enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
int *fds, ec, rc = 0;
|
struct percpucounter *pcpu;
|
||||||
|
int ec, rc = 0;
|
||||||
|
|
||||||
if (ctr == ALL_COUNTER) {
|
if (ctr == ALL_COUNTER) {
|
||||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
||||||
@@ -243,15 +406,20 @@ int perf_enable_ctr(enum ctr_e ctr)
|
|||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (ctr < ALL_COUNTER) {
|
||||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
foreachcpu(pcpu) {
|
||||||
ec = ioctl(*fds, PERF_EVENT_IOC_ENABLE, 0);
|
ec = ioctl(pcpu->ctr_fds[ctr], PERF_EVENT_IOC_ENABLE, 0);
|
||||||
if (ec < 0) {
|
if (ec < 0) {
|
||||||
eprint("Ioctl(PERF_EVENT_IOC_ENABLE) failed with errno=%d [%s]\n",
|
eprint("Ioctl(PERF_EVENT_IOC_ENABLE) failed with errno=%d [%s]\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
rc = -1;
|
rc = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ctr_state[ctr] = ENABLED;
|
||||||
|
++enabledcounter;
|
||||||
|
endforeachcpu();
|
||||||
|
} else {
|
||||||
|
rc = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@@ -260,7 +428,8 @@ int perf_enable_ctr(enum ctr_e ctr)
|
|||||||
|
|
||||||
int perf_disable_ctr(enum ctr_e ctr)
|
int perf_disable_ctr(enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
int *fds, ec, rc = 0;
|
struct percpucounter *pcpu;
|
||||||
|
int ec, rc = 0;
|
||||||
|
|
||||||
if (ctr == ALL_COUNTER) {
|
if (ctr == ALL_COUNTER) {
|
||||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
||||||
@@ -268,15 +437,22 @@ int perf_disable_ctr(enum ctr_e ctr)
|
|||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (ctr < ALL_COUNTER) {
|
||||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
foreachcpu(pcpu) {
|
||||||
ec = ioctl(*fds, PERF_EVENT_IOC_DISABLE, 0);
|
ec = ioctl(pcpu->ctr_fds[ctr], PERF_EVENT_IOC_DISABLE, 0);
|
||||||
if (ec < 0) {
|
if (ec < 0) {
|
||||||
eprint("Ioctl(PERF_EVENT_IOC_DISABLE) failed with errno=%d [%s]\n",
|
eprint("Ioctl(PERF_EVENT_IOC_DISABLE) failed with errno=%d [%s]\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
rc = -1;
|
rc = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ctr_state[ctr] = DISABLED;
|
||||||
|
--enabledcounter;
|
||||||
|
if (enabledcounter == 0)
|
||||||
|
hotplugdetected = 0;
|
||||||
|
endforeachcpu();
|
||||||
|
} else {
|
||||||
|
rc = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@@ -285,7 +461,8 @@ int perf_disable_ctr(enum ctr_e ctr)
|
|||||||
|
|
||||||
int perf_reset_ctr(enum ctr_e ctr)
|
int perf_reset_ctr(enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
int *fds, ec, rc = 0;
|
struct percpucounter *pcpu;
|
||||||
|
int ec, rc = 0;
|
||||||
|
|
||||||
if (ctr == ALL_COUNTER) {
|
if (ctr == ALL_COUNTER) {
|
||||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
||||||
@@ -293,15 +470,18 @@ int perf_reset_ctr(enum ctr_e ctr)
|
|||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (ctr < ALL_COUNTER) {
|
||||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
foreachcpu(pcpu) {
|
||||||
ec = ioctl(*fds, PERF_EVENT_IOC_RESET, 0);
|
ec = ioctl(pcpu->ctr_fds[ctr], PERF_EVENT_IOC_RESET, 0);
|
||||||
if (ec < 0) {
|
if (ec < 0) {
|
||||||
eprint("Ioctl(PERF_EVENT_IOC_RESET) failed with errno=%d [%s]\n",
|
eprint("Ioctl(PERF_EVENT_IOC_RESET) failed with errno=%d [%s]\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
rc = -1;
|
rc = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
endforeachcpu();
|
||||||
|
} else {
|
||||||
|
rc = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@@ -310,15 +490,22 @@ int perf_reset_ctr(enum ctr_e ctr)
|
|||||||
|
|
||||||
int perf_read_ctr(enum ctr_e ctr, uint64_t *value)
|
int perf_read_ctr(enum ctr_e ctr, uint64_t *value)
|
||||||
{
|
{
|
||||||
int *fds, ec, rc = -1;
|
struct percpucounter *pcpu;
|
||||||
|
int ec, rc = -1;
|
||||||
uint64_t val;
|
uint64_t val;
|
||||||
|
|
||||||
if (!value)
|
if (!value)
|
||||||
return -1;
|
return -1;
|
||||||
|
if (ctr == HOTPLUG_DETECTED) {
|
||||||
|
*value = hotplugdetected;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (ctr >= ALL_COUNTER)
|
||||||
|
return -1;
|
||||||
*value = 0;
|
*value = 0;
|
||||||
|
|
||||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
foreachcpu(pcpu) {
|
||||||
ec = read(*fds, &val, sizeof(val));
|
ec = read(pcpu->ctr_fds[ctr], &val, sizeof(val));
|
||||||
if (ec != sizeof(val)) {
|
if (ec != sizeof(val)) {
|
||||||
eprint("Read() on perf file descriptor failed with errno=%d [%s]\n",
|
eprint("Read() on perf file descriptor failed with errno=%d [%s]\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
@@ -327,11 +514,18 @@ int perf_read_ctr(enum ctr_e ctr, uint64_t *value)
|
|||||||
rc = 0;
|
rc = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
endforeachcpu();
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int perf_ecc_supported(void)
|
int perf_ecc_supported(void)
|
||||||
{
|
{
|
||||||
return ecc_supported;
|
return ctr_state[ECC_FUNCTIONS] != UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int perf_ctr_state(enum ctr_e ctr) {
|
||||||
|
if (ctr < ALL_COUNTER)
|
||||||
|
return ctr_state[ctr];
|
||||||
|
return UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <endian.h>
|
#include <endian.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
|
#include <poll.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@@ -244,7 +245,7 @@ int recv_msg(int sfd, struct msg *m, int timeout)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = timeout ? __timedread(sfd, ((char *)m) + sizeof(m->head), len) :
|
n = timeout ? __timedread(sfd, ((char *)m) + sizeof(m->head), len, timeout) :
|
||||||
__read(sfd, ((char *)m) + sizeof(m->head), len);
|
__read(sfd, ((char *)m) + sizeof(m->head), len);
|
||||||
if (n != len) {
|
if (n != len) {
|
||||||
eprint("Recv() error: recv()=%d expected %d, errno=%d [%s]\n",
|
eprint("Recv() error: recv()=%d expected %d, errno=%d [%s]\n",
|
||||||
|
|||||||
Reference in New Issue
Block a user