cpacfstats: Add PAI and hotplug support

Add virtual counters pai_user and pai_kernel to detail all Processor Activity
 Instrumentation (PAI) counters in user resp. kernel space.  Once activated,
they will show all counters for the corresponding set.  Add option -n to limit
the display to only non-zero counter values.

Add support for cpu hotplug events based on libudev.  CPU hotplug events are
used to either detach from a vanishing CPU or (re-)attach to a (re-)appearing
CPU.  In that case, a "hotplug detected" virtual counter is set to a non-zero
value to indicate possible loss of counters which happens when CPACF is used
on the CPU before cpacfstatsd could attach to it.  The hotplug indication is
cleared once all counters are deactivated.

Add support for JSON output.  The JSON document is an array of JSON objects
representing the counters and their values.  Every object has a name (property
"counter") and a value (property "value").  For PAI counters, the counters
also have a space (property "space") determining the counter set pai_user or
pai_kernel, and a numeric id (property "counterid") that can be used to filter
the JSON document.

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:
Juergen Christ
2022-05-23 11:41:47 +02:00
committed by Jan Höppner
parent 72b5e8b313
commit fcb1f7efd1
5 changed files with 1138 additions and 110 deletions

View File

@@ -1,6 +1,6 @@
.\" cpacfstats.1
.\"
.\" Copyright IBM Corp. 2015, 2020
.\" Copyright IBM Corp. 2015, 2022
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
@@ -32,7 +32,9 @@ cpacfstats \- enable, disable and display CPACF statistical data
.RB ]
.RB [ \-p | \-\-print
.I counter
.RB [ \-n | \-\-nonzero]
.RB ]
.RB [ \-j | \-\-json ]
.
.SH DESCRIPTION
The cpacfstats client application interacts with the cpacfstatsd daemon and
@@ -44,12 +46,344 @@ All counters are initially disabled and must be switched on to measure
CPACF activities of the system. There is a slight performance penalty with
CPACF counters enabled.
Note: All cryptographic counters are bound to physical CPUs. If you use
dedicated CPUs for your LPAR, you obtain only your CPACF activities. If
your CPUs are shared with other LPARs, their cryptographic activities might
distort the results. CPACF performance counters are available on LPARs
only. For security reasons only members of the group \fIcpacfstats\fR are
allowed to run the cpacfstats client application.
CPACF activity counters come in two flavors: CPU-MF and PAI. CPU-MF
counters are only available on LPARs and have to be authorized. If
they are available, the counters
.B des,
.B aes,
.B sha,
.B rng,
and
.B ecc
are made available. These counters can individually be activated,
reset, printed, or deactivated. PAI counters are a lot more detailed.
The user interface only offers the counters
.B pai_user
and
.B pai_kernel
to count CPACF usage in user-space or kernel-space. When printing
these counters, detailed counters are shown. The detailed names are:
.RS
.IP \(bu
KM DES,
.IP \(bu
KM 2key TDES,
.IP \(bu
KM TDES,
.IP \(bu
KM DES protected key,
.IP \(bu
KM 2key TDES protected key,
.IP \(bu
KM TDES protected key,
.IP \(bu
KM AES 128bit,
.IP \(bu
KM AES 192bit,
.IP \(bu
KM AES 256bit,
.IP \(bu
KM AES 128bit protected key,
.IP \(bu
KM AES 192bit protected key,
.IP \(bu
KM AES 256bit protected key,
.IP \(bu
KM AES-XTS 128bit,
.IP \(bu
KM AES-XTS 256bit,
.IP \(bu
KM AES-XTS 128bit protected key,
.IP \(bu
KM AES-XTS 256bit protected key,
.IP \(bu
KMC DES,
.IP \(bu
KMC 2key TDES,
.IP \(bu
KMC TDES,
.IP \(bu
KMC DES protected key,
.IP \(bu
KMC 2key TDES protected key,
.IP \(bu
KMC TDES protected key,
.IP \(bu
KMC AES 128bit,
.IP \(bu
KMC AES 192bit,
.IP \(bu
KMC AES 256bit,
.IP \(bu
KMC AES 128bit protected key,
.IP \(bu
KMC AES 192bit protected key,
.IP \(bu
KMC AES 256bit protected key,
.IP \(bu
KMC PRNG,
.IP \(bu
KMA AES 128bit,
.IP \(bu
KMA AES 192bit,
.IP \(bu
KMA AES 256bit,
.IP \(bu
KMA AES 128bit protected key,
.IP \(bu
KMA AES 192bit protected key,
.IP \(bu
KMA AES 256bit protected key,
.IP \(bu
KMF DES,
.IP \(bu
KMF 2key TDES,
.IP \(bu
KMF TDES,
.IP \(bu
KMF DES protected key,
.IP \(bu
KMF 2key TDES protected key,
.IP \(bu
KMF TDES protected key,
.IP \(bu
KMF AES 128bit,
.IP \(bu
KMF AES 192bit,
.IP \(bu
KMF AES 256bit,
.IP \(bu
KMF AES 128bit protected key,
.IP \(bu
KMF AES 192bit protected key,
.IP \(bu
KMF AES 256bit protected key,
.IP \(bu
KMCTR DES,
.IP \(bu
KMCTR 2key TDES,
.IP \(bu
KMCTR TDES,
.IP \(bu
KMCTR DES protected key,
.IP \(bu
KMCTR 2key TDES protected key,
.IP \(bu
KMCTR TDES protected key,
.IP \(bu
KMCTR AES 128bit,
.IP \(bu
KMCTR AES 192bit,
.IP \(bu
KMCTR AES 256bit,
.IP \(bu
KMCTR AES 128bit protected key,
.IP \(bu
KMCTR AES 192bit protected key,
.IP \(bu
KMCTR AES 256bit protected key,
.IP \(bu
KMO DES,
.IP \(bu
KMO 2key TDES,
.IP \(bu
KMO TDES,
.IP \(bu
KMO DES protected key,
.IP \(bu
KMO 2key TDES protected key,
.IP \(bu
KMO TDES protected key,
.IP \(bu
KMO AES 128bit,
.IP \(bu
KMO AES 192bit,
.IP \(bu
KMO AES 256bit,
.IP \(bu
KMO AES 128bit protected key,
.IP \(bu
KMO AES 192bit protected key,
.IP \(bu
KMO AES 256bit protected key,
.IP \(bu
KIMD SHA1,
.IP \(bu
KIMD SHA256,
.IP \(bu
KIMD SHA512,
.IP \(bu
KIMD SHA3-224,
.IP \(bu
KIMD SHA3-256,
.IP \(bu
KIMD SHA3-384,
.IP \(bu
KIMD SHA3-512,
.IP \(bu
KIMD SHAKE 128,
.IP \(bu
KIMD SHAE 256,
.IP \(bu
KIMD GHASH,
.IP \(bu
KLMD SHA1,
.IP \(bu
KLMD SHA256,
.IP \(bu
KLMD SHA512,
.IP \(bu
KLMD SHA3-224,
.IP \(bu
KLMD SHA3-256,
.IP \(bu
KLMD SHA3-384,
.IP \(bu
KLMD SHA3-512,
.IP \(bu
KLMD SHAKE 128,
.IP \(bu
KLMD SHAKE 256,
.IP \(bu
KMAC DES,
.IP \(bu
KMAC 2key TDES,
.IP \(bu
KMAC TDES,
.IP \(bu
KMAC DES protected key,
.IP \(bu
KMAC 2key TDES protected key,
.IP \(bu
KMAC TDES protected key,
.IP \(bu
KMAC AES 128bit,
.IP \(bu
KMAC AES 192bit,
.IP \(bu
KMAC AES 256bit,
.IP \(bu
KMAC AES 128bit protected key,
.IP \(bu
KMAC AES 192bit protected key,
.IP \(bu
KMAC AES 256bit protected key,
.IP \(bu
PCC Last Block CMAC DES,
.IP \(bu
PCC Last Block CMAC 2key TDES,
.IP \(bu
PCC Last Block CMAC TDES,
.IP \(bu
PCC Last Block CMAC DES protected key,
.IP \(bu
PCC Last Block CMAC 2key TDES protected key,
.IP \(bu
PCC Last Block CMAC TDES protected key,
.IP \(bu
PCC Last Block CMAC AES 128bit,
.IP \(bu
PCC Last Block CMAC AES 192bit,
.IP \(bu
PCC Last Block CMAC AES 256bit,
.IP \(bu
PCC Last Block CMAC AES 128bit protected key,
.IP \(bu
PCC Last Block CMAC AES 192bit protected key,
.IP \(bu
PCC Last Block CMAC AES 256bit protected key,
.IP \(bu
PCC XTS Parameter AES 128bit,
.IP \(bu
PCC XTS Parameter AES 256bit,
.IP \(bu
PCC XTS Parameter AES 128bit protected key,
.IP \(bu
PCC XTS Parameter AES 256bit protected key,
.IP \(bu
PCC Scalar Mult P256,
.IP \(bu
PCC Scalar Mult P384,
.IP \(bu
PCC Scalar Mult P521,
.IP \(bu
PCC Scalar Mult Ed25519,
.IP \(bu
PCC Scalar Mult Ed448,
.IP \(bu
PCC Scalar Mult X25519,
.IP \(bu
PCC Scalar Mult X448,
.IP \(bu
PRNO SHA512 DRNG,
.IP \(bu
PRNO TRNG Query Ratio,
.IP \(bu
PRNO TRNG,
.IP \(bu
KDSA ECDSA Verify P256,
.IP \(bu
KDSA ECDSA Verify P384,
.IP \(bu
KDSA ECDSA Verify P521,
.IP \(bu
KDSA ECDSA Sign P256,
.IP \(bu
KDSA ECDSA Sign P384,
.IP \(bu
KDSA ECDSA Sign P521,
.IP \(bu
KDSA ECDSA Sign P256 protected key,
.IP \(bu
KDSA ECDSA Sign P384 protected key,
.IP \(bu
KDSA ECDSA Sign P521 protected key,
.IP \(bu
KDSA EdDSA Verify Ed25519,
.IP \(bu
KDSA EdDSA Verify Ed448,
.IP \(bu
KDSA EdDSA Sign Ed25519,
.IP \(bu
KDSA EdDSA Sign Ed448,
.IP \(bu
KDSA EdDSA Sign Ed25519 protected key,
.IP \(bu
KDSA EdDSA Sign Ed448 protected key,
.IP \(bu
PCKMO DES,
.IP \(bu
PCKMO 2key TDES,
.IP \(bu
PCMKO TDES,
.IP \(bu
PCKMO AES 128bit,
.IP \(bu
PCKMO AES 192bit,
.IP \(bu
PCMKO AES 256bit,
.IP \(bu
PCKMO ECC P256,
.IP \(bu
PCKMO ECC P384,
.IP \(bu
PCKMO ECC P521,
.IP \(bu
PCKMO ECC Ed25519,
.IP \(bu
PCKMO ECC Ed448,
.IP \(bu
Reserved 1, and
.IP \(bu
Reserved 2.
.RE
Note that the counters starting with PCKMO and Reserved are only
available in the pai_kernel set.
Note: CPU-MF based CPACF performance counters are available on LPARs
only. PAI counters are available on all hypervisors. For security
reasons only members of the group \fIcpacfstats\fR are allowed to run
the cpacfstats client application.
Example usage scenario:
.P
@@ -101,12 +435,34 @@ argument can be one of: \fBdes\fR, \fBaes\fR, \fBsha\fR, \fBprng\fR,
\fBecc\fR, or \fBall\fR. If the counter argument is omitted, all
performance counters are reset to 0.
.TP
\fB\-p\fR or \fB\-\-print\fR [counter]
\fB\-p\fR or \fB\-\-print\fR [\fB\-n\fR or \fB\-\-nonzero\fR] [counter]
Display the value of one or all CPACF performance counters. The
optional counter argument can be one of: \fBdes\fR, \fBaes\fR,
\fBsha\fR, \fBprng\fR, \fBecc\fR, or \fBall\fR. If the counter
argument is omitted or if there is no argument, all performance
counters are displayed.
\fBsha\fR, \fBprng\fR, \fBecc\fR, \fBpai_user\fR, \fBpai_kernel\fR, or
\fBall\fR. If the counter argument is omitted or if there is no
argument, all performance counters are displayed. If the optional
\fB\-n\fR or \fB\-\-nonzero\fR argument is given, then only PAI
counters that have a non-zero value are printed.
.TP
\fB\-j\fR or \fB\-\-json\fR
Display all activated counters in JSON format. The JSON contains an
array of counter objects. Each object contains the property
.B counter
specifying either a CPU-MF counter of one of the detailed PAI counter.
Additional properties include
.B error
an error number if the counter could not be read,
.B value
the counter value if the counter could be read,
.B space
for PAI counters to specify
.B user
or
.B kernel
space counter set, and
.B counterid
for PAI counters to specify the PAI counter number as specified in the
Principles of Operation.
.TP
The default command is --print all.
.

View File

@@ -3,7 +3,7 @@
*
* cpacfstats client implementation
*
* Copyright IBM Corp. 2015, 2020
* Copyright IBM Corp. 2015, 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -39,17 +39,187 @@ static const char *const usage =
"\t-d, --disable [counter] Disable one or all counters\n"
"\t-r, --reset [counter] Reset one or all counter values\n"
"\t-p, --print [counter] Print one or all counter values\n"
"\tcounter can be: 'aes' 'des' 'rng' 'sha' 'ecc' or 'all'\n";
"\t-n, --nonzero Print all PAI counters\n"
"\t-j, --json Print all counter values in JSON format\n"
"\tcounter can be: 'aes' 'des' 'rng' 'sha' 'ecc'\n"
"\t 'pai_user' 'pai_kernel' or 'all'\n";
static const char *const counter_str[] = {
[DES_FUNCTIONS] = "des",
[AES_FUNCTIONS] = "aes",
[SHA_FUNCTIONS] = "sha",
[PRNG_FUNCTIONS] = "rng",
[ECC_FUNCTIONS] = "ecc",
[ALL_COUNTER] = "all"
[ECC_FUNCTIONS] = "ecc",
[ALL_COUNTER] = "all",
[PAI_USER] = "pai_user",
[PAI_KERNEL] = "pai_kernel"
};
/* Strings for the pai counter details. Note that this is 0-based
* while PoP is 1-based.
*/
static const char *const pai_str[] = {
[ 0] = "KM DES",
[ 1] = "KM 2key TDES",
[ 2] = "KM TDES",
[ 3] = "KM DES protected key",
[ 4] = "KM 2key TDES protected key",
[ 5] = "KM TDES protected key",
[ 6] = "KM AES 128bit",
[ 7] = "KM AES 192bit",
[ 8] = "KM AES 256bit",
[ 9] = "KM AES 128bit protected key",
[ 10] = "KM AES 192bit protected key",
[ 11] = "KM AES 256bit protected key",
[ 12] = "KM AES-XTS 128bit",
[ 13] = "KM AES-XTS 256bit",
[ 14] = "KM AES-XTS 128bit protected key",
[ 15] = "KM AES-XTS 256bit protected key",
[ 16] = "KMC DES",
[ 17] = "KMC 2key TDES",
[ 18] = "KMC TDES",
[ 19] = "KMC DES protected key",
[ 20] = "KMC 2key TDES protected key",
[ 21] = "KMC TDES protected key",
[ 22] = "KMC AES 128bit",
[ 23] = "KMC AES 192bit",
[ 24] = "KMC AES 256bit",
[ 25] = "KMC AES 128bit protected key",
[ 26] = "KMC AES 192bit protected key",
[ 27] = "KMC AES 256bit protected key",
[ 28] = "KMC PRNG",
[ 29] = "KMA AES 128bit",
[ 30] = "KMA AES 192bit",
[ 31] = "KMA AES 256bit",
[ 32] = "KMA AES 128bit protected key",
[ 33] = "KMA AES 192bit protected key",
[ 34] = "KMA AES 256bit protected key",
[ 35] = "KMF DES",
[ 36] = "KMF 2key TDES",
[ 37] = "KMF TDES",
[ 38] = "KMF DES protected key",
[ 39] = "KMF 2key TDES protected key",
[ 40] = "KMF TDES protected key",
[ 41] = "KMF AES 128bit",
[ 42] = "KMF AES 192bit",
[ 43] = "KMF AES 256bit",
[ 44] = "KMF AES 128bit protected key",
[ 45] = "KMF AES 192bit protected key",
[ 46] = "KMF AES 256bit protected key",
[ 47] = "KMCTR DES",
[ 48] = "KMCTR 2key TDES",
[ 49] = "KMCTR TDES",
[ 50] = "KMCTR DES protected key",
[ 51] = "KMCTR 2key TDES protected key",
[ 52] = "KMCTR TDES protected key",
[ 53] = "KMCTR AES 128bit",
[ 54] = "KMCTR AES 192bit",
[ 55] = "KMCTR AES 256bit",
[ 56] = "KMCTR AES 128bit protected key",
[ 57] = "KMCTR AES 192bit protected key",
[ 58] = "KMCTR AES 256bit protected key",
[ 59] = "KMO DES",
[ 60] = "KMO 2key TDES",
[ 61] = "KMO TDES",
[ 62] = "KMO DES protected key",
[ 63] = "KMO 2key TDES protected key",
[ 64] = "KMO TDES protected key",
[ 65] = "KMO AES 128bit",
[ 66] = "KMO AES 192bit",
[ 67] = "KMO AES 256bit",
[ 68] = "KMO AES 128bit protected key",
[ 69] = "KMO AES 192bit protected key",
[ 70] = "KMO AES 256bit protected key",
[ 71] = "KIMD SHA1",
[ 72] = "KIMD SHA256",
[ 73] = "KIMD SHA512",
[ 74] = "KIMD SHA3-224",
[ 75] = "KIMD SHA3-256",
[ 76] = "KIMD SHA3-384",
[ 77] = "KIMD SHA3-512",
[ 78] = "KIMD SHAKE 128",
[ 79] = "KIMD SHAE 256",
[ 80] = "KIMD GHASH",
[ 81] = "KLMD SHA1",
[ 82] = "KLMD SHA256",
[ 83] = "KLMD SHA512",
[ 84] = "KLMD SHA3-224",
[ 85] = "KLMD SHA3-256",
[ 86] = "KLMD SHA3-384",
[ 87] = "KLMD SHA3-512",
[ 88] = "KLMD SHAKE 128",
[ 89] = "KLMD SHAKE 256",
[ 90] = "KMAC DES",
[ 91] = "KMAC 2key TDES",
[ 92] = "KMAC TDES",
[ 93] = "KMAC DES protected key",
[ 94] = "KMAC 2key TDES protected key",
[ 95] = "KMAC TDES protected key",
[ 96] = "KMAC AES 128bit",
[ 97] = "KMAC AES 192bit",
[ 98] = "KMAC AES 256bit",
[ 99] = "KMAC AES 128bit protected key",
[100] = "KMAC AES 192bit protected key",
[101] = "KMAC AES 256bit protected key",
[102] = "PCC Last Block CMAC DES",
[103] = "PCC Last Block CMAC 2key TDES",
[104] = "PCC Last Block CMAC TDES",
[105] = "PCC Last Block CMAC DES protected key",
[106] = "PCC Last Block CMAC 2key TDES protected key",
[107] = "PCC Last Block CMAC TDES protected key",
[108] = "PCC Last Block CMAC AES 128bit",
[109] = "PCC Last Block CMAC AES 192bit",
[110] = "PCC Last Block CMAC AES 256bit",
[111] = "PCC Last Block CMAC AES 128bit protected key",
[112] = "PCC Last Block CMAC AES 192bit protected key",
[113] = "PCC Last Block CMAC AES 256bit protected key",
[114] = "PCC XTS Parameter AES 128bit",
[115] = "PCC XTS Parameter AES 256bit",
[116] = "PCC XTS Parameter AES 128bit protected key",
[117] = "PCC XTS Parameter AES 256bit protected key",
[118] = "PCC Scalar Mult P256",
[119] = "PCC Scalar Mult P384",
[120] = "PCC Scalar Mult P521",
[121] = "PCC Scalar Mult Ed25519",
[122] = "PCC Scalar Mult Ed448",
[123] = "PCC Scalar Mult X25519",
[124] = "PCC Scalar Mult X448",
[125] = "PRNO SHA512 DRNG",
[126] = "PRNO TRNG Query Ratio",
[127] = "PRNO TRNG",
[128] = "KDSA ECDSA Verify P256",
[129] = "KDSA ECDSA Verify P384",
[130] = "KDSA ECDSA Verify P521",
[131] = "KDSA ECDSA Sign P256",
[132] = "KDSA ECDSA Sign P384",
[133] = "KDSA ECDSA Sign P521",
[134] = "KDSA ECDSA Sign P256 protected key",
[135] = "KDSA ECDSA Sign P384 protected key",
[136] = "KDSA ECDSA Sign P521 protected key",
[137] = "KDSA EdDSA Verify Ed25519",
[138] = "KDSA EdDSA Verify Ed448",
[139] = "KDSA EdDSA Sign Ed25519",
[140] = "KDSA EdDSA Sign Ed448",
[141] = "KDSA EdDSA Sign Ed25519 protected key",
[142] = "KDSA EdDSA Sign Ed448 protected key",
[143] = "PCKMO DES",
[144] = "PCKMO 2key TDES",
[145] = "PCMKO TDES",
[146] = "PCKMO AES 128bit",
[147] = "PCKMO AES 192bit",
[148] = "PCMKO AES 256bit",
[149] = "PCKMO ECC P256",
[150] = "PCKMO ECC P384",
[151] = "PCKMO ECC P521",
[152] = "PCKMO ECC Ed25519",
[153] = "PCKMO ECC Ed448",
[154] = "Reserved 1",
[155] = "Reserved 2"
};
static int paiprintnonzero;
static int send_query(int s, enum cmd_e cmd, enum ctr_e ctr)
{
@@ -91,21 +261,140 @@ static int recv_answer(int s, int *ctr, int *state, uint64_t *value)
return rc;
}
static void print_virtual_counter_answer(int ctr, int state, uint64_t value)
static void printjsonsep(void)
{
if (ctr == HOTPLUG_DETECTED) {
if (state >= 0 && value > 0)
printf(" hotplug detected\n");
static const char *jsonsep = "";
fputs(jsonsep, stdout);
jsonsep = ",";
}
static void json_print_virtual_counter_answer(int s, int ctr,
int state, uint64_t value)
{
int paictr = 0, paistate = 0, ec;
uint64_t i, paivalue = 0, maxnum;
const char *space;
switch (ctr) {
case HOTPLUG_DETECTED:
printjsonsep();
printf("{\"counter\":\"hotplug detected\",");
if (state < 0)
printf("\"error\":%d}", state);
else
printf("\"value\":%d}", !!value);
return;
case PAI_USER:
maxnum = NUM_PAI_USER;
space = "user";
break;
case PAI_KERNEL:
maxnum = NUM_PAI_KERNEL;
space = "kernel";
break;
default:
return;
}
/* Here, we have validated the PAI counter retrieved, but not
* yet printed. */
if (state != ENABLED)
return;
if (value > maxnum) {
eprint("Incompatible versions detected!\n");
eprint("Expected %"PRIu64" counter space for %s, but got %"PRIu64"\n",
maxnum, space, value);
exit(EXIT_FAILURE);
}
for (i = 0; i < value; ++i) {
ec = recv_answer(s, &paictr, &paistate, &paivalue);
if (ec < 0 || paistate < 0) {
eprint("Error on receiving answer message from daemon\n");
/* No more data for this virtual event after error. */
return;
}
if (paictr > NUM_PAI_KERNEL) {
eprint("Pai counter number too big: %d\n", paictr);
} else {
printjsonsep();
printf("{\"counter\":\"%s\",\"space\":\"%s\",\"counterid\":%d,",
pai_str[paictr], space, paictr + 1);
if (paistate < 0) {
printf("\"error\":%d}", paistate);
/* Protocol does not send furter counters. */
return;
}
printf("\"value\":%"PRIu64"}", paivalue);
}
}
}
static void print_answer(int ctr, int state, uint64_t value)
static void print_virtual_counter_answer(int s,
int ctr, int state, uint64_t value)
{
if (ctr > ALL_COUNTER) {
print_virtual_counter_answer(ctr, state, value);
static const char *const states[] = {
[DISABLED] = "disabled",
[ENABLED] = "enabled",
[UNSUPPORTED] = "unsupported"
};
int paictr = 0, paistate = 0, ec;
uint64_t i, paivalue = 0, maxnum;
const char *ctrstr;
switch (ctr) {
case HOTPLUG_DETECTED:
if (state >= 0 && value > 0)
printf(" hotplug detected\n");
return;
case PAI_USER:
maxnum = NUM_PAI_USER;
ctrstr = "pai_user";
break;
case PAI_KERNEL:
maxnum = NUM_PAI_KERNEL;
ctrstr = "pai_kernel";
break;
default:
return;
}
if (state < 0)
/* Here, we have validated the PAI counter retrieved, but not
* yet printed. */
if (state < 0 || state > UNSUPPORTED) {
printf(" %11s: error state %d\n", ctrstr, state);
/* No details follow if counter in error state. */
return;
}
printf(" %-11s: %s\n", ctrstr, states[state]);
if (state != ENABLED)
return;
if (value > maxnum) {
eprint("Incompatible versions detected!\n");
eprint("Expected %"PRIu64" counters for %s, but got %"PRIu64"\n",
maxnum, ctrstr, value);
exit(EXIT_FAILURE);
}
for (i = 0; i < value; ++i) {
ec = recv_answer(s, &paictr, &paistate, &paivalue);
if (ec < 0 || paistate < 0) {
eprint("Error on receiving answer message from daemon\n");
/* No more data for this virtual event after error. */
return;
}
if (paictr > NUM_PAI_KERNEL)
eprint("Pai counter number too big: %d\n", paictr);
else if (!paiprintnonzero || paivalue > 0)
printf(" %-45s: %"PRIu64"\n", pai_str[paictr], paivalue);
}
}
static void print_answer(int s, int ctr, int state, uint64_t value)
{
if (ctr > ALL_COUNTER)
print_virtual_counter_answer(s, ctr, state, value);
else if (state < 0)
printf(" %s counter: error state %d\n",
counter_str[ctr], state);
else if (state == DISABLED)
@@ -117,6 +406,22 @@ static void print_answer(int ctr, int state, uint64_t value)
}
static void json_print_answer(int s, int ctr, int state, uint64_t value)
{
if (ctr > ALL_COUNTER) {
json_print_virtual_counter_answer(s, ctr, state, value);
} else if (state < 0) {
printjsonsep();
printf("{\"counter\":\"%s\",", counter_str[ctr]);
printf("\"error\":%d}\n", state);
} else if (state == ENABLED) {
printjsonsep();
printf("{\"counter\":\"%s\",", counter_str[ctr]);
printf("\"value\":%"PRIu64"}", value);
}
}
int eprint(const char *format, ...)
{
char buf[1024];
@@ -139,7 +444,7 @@ int main(int argc, char *argv[])
{
enum ctr_e ctr = ALL_COUNTER;
enum cmd_e cmd = PRINT;
int i, j, s, state;
int i, j, s, state, num, json = 0;
uint64_t value;
if (argc > 1) {
@@ -151,110 +456,108 @@ int main(int argc, char *argv[])
{ "disable", 0, NULL, 'd' },
{ "reset", 0, NULL, 'r' },
{ "print", 0, NULL, 'p' },
{ "nonzero", 0, NULL, 'n' },
{ "json", 0, NULL, 'j' },
{ NULL, 0, NULL, 0 } };
while (1) {
opt = getopt_long(argc, argv,
"hvedrp", long_opts, &idx);
"hvedrpnj", long_opts, &idx);
if (opt == -1)
break; /* no more arguments */
switch (opt) {
case 'h':
printf(usage, name);
exit(0);
break;
return 0;
case 'v':
printf("%s: Linux on System z CPACF Crypto Activity Counters Client\n"
"Version %s\n%s\n",
name, RELEASE_STRING, COPYRIGHT);
exit(0);
break;
return 0;
case 'e':
cmd = ENABLE;
json = 0;
break;
case 'd':
cmd = DISABLE;
json = 0;
break;
case 'r':
cmd = RESET;
break;
case 'p':
cmd = PRINT;
json = 0;
break;
case 'n':
paiprintnonzero = 1;
break;
case 'j':
cmd = PRINT;
json = 1;
break;
default:
eprint("Invalid argument, try -h or --help for more information\n");
exit(1);
break;
return EXIT_FAILURE;
}
}
/* there may be an optional counter argument */
if (optind > 0 && optind < argc) {
for (i = 0; i <= ALL_COUNTER; i++)
for (i = 0; i < NUM_COUNTER; i++)
if (strcmp(argv[optind], counter_str[i]) == 0)
break;
if (i > ALL_COUNTER) {
if (i >= NUM_COUNTER) {
eprint("Unknown counter '%s'\n", argv[optind]);
exit(1);
return EXIT_FAILURE;
}
ctr = (enum ctr_e) i;
}
}
if (json)
ctr = ALL_COUNTER;
/* try to open and connect socket to the cpacfstatsd daemon */
s = open_socket(CLIENT);
if (s < 0) {
eprint("Can't connect to daemon\n");
exit(1);
return EXIT_FAILURE;
}
/* send query */
if (send_query(s, cmd, ctr) != 0) {
eprint("Error on sending query message to daemon\n");
close(s);
exit(1);
return EXIT_FAILURE;
}
if (ctr == ALL_COUNTER) {
for (i = 0; i < ALL_COUNTER; i++) {
/* receive answer */
if (recv_answer(s, &j, &state, &value) != 0) {
eprint("Error on receiving answer message from daemon\n");
exit(1);
}
if (state < 0) {
eprint("Received bad status code %d from daemon\n",
state);
close(s);
exit(1);
}
print_answer(j, state, value);
}
/* The -1 is for ALL_COUNTER which is not sent, +1 for
* hotplug state. */
num = NUM_COUNTER - 1 + 1;
} else {
/* +1 for hotplug state */
num = 1 + 1;
}
if (json)
putchar('[');
for (i = 0; i < num; i++) {
/* receive answer */
if (recv_answer(s, &j, &state, &value) != 0) {
eprint("Error on receiving answer message from daemon\n");
close(s);
exit(1);
return EXIT_FAILURE;
}
if (state < 0) {
eprint("Received bad status code %d from daemon\n",
state);
state);
close(s);
exit(1);
return EXIT_FAILURE;
}
print_answer(j, state, value);
if (json)
json_print_answer(s, j, state, value);
else
print_answer(s, 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);
if (json)
putchar(']');
/* close connection */
close(s);

View File

@@ -3,7 +3,7 @@
*
* common function prototypes and definitions
*
* Copyright IBM Corp. 2015, 2020
* Copyright IBM Corp. 2015, 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -16,15 +16,25 @@
#define COPYRIGHT "Copyright IBM Corp. 2015, 2022"
#define DEFAULT_SEND_TIMEOUT (2 * 1000)
#define DEFAULT_RECV_TIMEOUT (2 * 1000)
#define DEFAULT_SEND_TIMEOUT (30 * 1000)
#define DEFAULT_RECV_TIMEOUT (30 * 1000)
/*
* Number of PAI counters for user space. This excludes PCKMO since
* this instruction is privileged.
*/
#define NUM_PAI_USER 143
/* Number of PAI counters for kernel space. Contains all counters. */
#define NUM_PAI_KERNEL 156
int eprint(const char *format, ...);
/*
* Counter names
* ALL_COUNTER specifies the number of physical counters. Virtual
* counters might be added afterwards.
* counters might be added afterwards. NUM_COUNTER is the last
* managed counter (i.e., a counter that can be activated, reset,
* deactivated).
*/
enum ctr_e {
DES_FUNCTIONS = 0,
@@ -33,7 +43,10 @@ enum ctr_e {
PRNG_FUNCTIONS,
ECC_FUNCTIONS,
ALL_COUNTER,
HOTPLUG_DETECTED
PAI_USER,
PAI_KERNEL,
NUM_COUNTER,
HOTPLUG_DETECTED = 0xffff
};
enum type_e {
@@ -68,7 +81,7 @@ struct msg_query {
/*
* answer send from daemon to client
* Consist of:
* enum counter
* enum counter or PAI counter number if following PAI_USER or PAI_KERNEL
* status code: < 0 error, 0 disabled, > 0 enabled
* counter value
*/
@@ -114,9 +127,10 @@ void perf_stop(void);
void perf_close(void);
int perf_enable_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, uint64_t *value);
int perf_read_ctr(enum ctr_e ctr, uint64_t *value);
int perf_ecc_supported(void);
int perf_ctr_state(enum ctr_e ctr);
int perf_read_pai_ctr(unsigned int ctrnum, int user, uint64_t *value);
#endif

View File

@@ -3,7 +3,7 @@
*
* cpacfstatsd daemon implementation
*
* Copyright IBM Corp. 2015, 2017
* Copyright IBM Corp. 2015, 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -85,13 +85,50 @@ static int send_answer(int s, int ctr, int state, uint64_t value)
}
/*
* Print according to protocol for PAI:
* - first the state and the number of PAI counters that follow
* - if state is ENABLED:
* - for each PAI counter the value with state ENABLED
* Note that the PAI counters are 0-based, not 1 based as in PoP!
* Sending ends with the first error.
*/
static int do_send_pai(int s, int user)
{
int ctr, state, i, maxctr, rc = 0;
uint64_t value;
if (user) {
ctr = PAI_USER;
maxctr = NUM_PAI_USER;
} else {
ctr = PAI_KERNEL;
maxctr = NUM_PAI_KERNEL;
}
state = perf_ctr_state(ctr);
if (state != ENABLED)
return rc;
for (i = 0; i < maxctr; ++i) {
rc = perf_read_pai_ctr(i, user, &value);
if (rc != 0) {
send_answer(s, i, rc, 0);
break;
}
send_answer(s, i, state, value);
}
return rc;
}
static int do_enable(int s, enum ctr_e ctr)
{
uint64_t value = 0;
int i, rc = 0;
int state;
for (i = 0; i < ALL_COUNTER; i++) {
for (i = 0; i < NUM_COUNTER; i++) {
if (i == ALL_COUNTER)
continue;
if (i == (int) ctr || ctr == ALL_COUNTER) {
state = perf_ctr_state(i);
if (state == DISABLED) {
@@ -110,6 +147,10 @@ static int do_enable(int s, enum ctr_e ctr)
}
}
send_answer(s, i, state, value);
if (i == PAI_USER)
rc = do_send_pai(s, 1);
if (i == PAI_KERNEL)
rc = do_send_pai(s, 0);
}
}
if (rc == 0) {
@@ -125,7 +166,9 @@ static int do_disable(int s, enum ctr_e ctr)
int i, rc = 0;
uint64_t value;
for (i = 0; i < ALL_COUNTER; i++) {
for (i = 0; i < NUM_COUNTER; i++) {
if (i == ALL_COUNTER)
continue;
if (i == (int) ctr || ctr == ALL_COUNTER) {
if (perf_ctr_state(i) == ENABLED) {
rc = perf_disable_ctr(i);
@@ -150,17 +193,23 @@ static int do_reset(int s, enum ctr_e ctr)
int i, rc = 0, state;
uint64_t value;
for (i = 0; i < ALL_COUNTER; i++) {
for (i = 0; i < NUM_COUNTER; i++) {
if (i == ALL_COUNTER)
continue;
if (i == (int) ctr || ctr == ALL_COUNTER) {
state = perf_ctr_state(i);
if (state == ENABLED) {
rc = perf_reset_ctr(i);
rc = perf_reset_ctr(i, &value);
if (rc != 0) {
send_answer(s, i, rc, 0);
break;
}
}
send_answer(s, i, state, 0);
send_answer(s, i, state, value);
if (i == PAI_USER)
rc = do_send_pai(s, 1);
if (i == PAI_KERNEL)
rc = do_send_pai(s, 0);
}
}
if (rc == 0) {
@@ -170,12 +219,15 @@ static int do_reset(int s, enum ctr_e ctr)
return rc;
}
static int do_print(int s, enum ctr_e ctr)
{
int i, rc = 0, state;
uint64_t value = 0;
for (i = 0; i < ALL_COUNTER; i++) {
for (i = 0; i < NUM_COUNTER; i++) {
if (i == ALL_COUNTER)
continue;
if (i == (int) ctr || ctr == ALL_COUNTER) {
state = perf_ctr_state(i);
if (state == ENABLED) {
@@ -186,6 +238,10 @@ static int do_print(int s, enum ctr_e ctr)
}
}
send_answer(s, i, state, value);
if (i == PAI_USER)
rc = do_send_pai(s, 1);
if (i == PAI_KERNEL)
rc = do_send_pai(s, 0);
}
}
if (rc == 0) {
@@ -380,7 +436,7 @@ int main(int argc, char *argv[])
switch (opt) {
case 'h':
printf(usage, name);
exit(0);
return 0;
case 'f':
foreground = 1;
break;
@@ -388,37 +444,37 @@ int main(int argc, char *argv[])
printf("%s: Linux on System z CPACF Crypto Activity Counters Daemon\n"
"Version %s\n%s\n",
name, RELEASE_STRING, COPYRIGHT);
exit(0);
return 0;
default:
printf("%s: Invalid argument, try -h or --help for more information\n",
name);
exit(1);
return EXIT_FAILURE;
}
}
}
if (check_pidfile() != 0) {
eprint("Stalled pid file or daemon allready running, terminating\n");
exit(1);
return EXIT_FAILURE;
}
if (!foreground) {
if (become_daemon() != 0) {
eprint("Couldn't daemonize\n");
exit(1);
return EXIT_FAILURE;
}
}
if (perf_init() != 0) {
eprint("Couldn't initialize perf lib\n");
exit(1);
return EXIT_FAILURE;
}
atexit(perf_close);
sfd = open_socket(SERVER);
if (sfd < 0) {
eprint("Couldn't initialize server socket\n");
exit(1);
return EXIT_FAILURE;
}
atexit(remove_sock);
@@ -428,13 +484,15 @@ int main(int argc, char *argv[])
if (sigaction(SIGINT, &act, 0) != 0) {
eprint("Couldn't establish signal handler for SIGINT, errno=%d [%s]\n",
errno, strerror(errno));
exit(1);
return EXIT_FAILURE;
}
if (sigaction(SIGTERM, &act, 0) != 0) {
eprint("Couldn't establish signal handler for SIGTERM, errno=%d [%s]\n",
errno, strerror(errno));
exit(1);
return EXIT_FAILURE;
}
/* Ignore SIGPIPE such that we see EPIPE as return from write. */
signal(SIGPIPE, SIG_IGN);
eprint("Running\n");
@@ -449,7 +507,7 @@ int main(int argc, char *argv[])
continue;
eprint("Accept() failure, errno=%d [%s]\n",
errno, strerror(errno));
exit(1);
return EXIT_FAILURE;
}
rc = recv_query(s, &ctr, &cmd);

View File

@@ -3,7 +3,7 @@
*
* low level perf functions
*
* Copyright IBM Corp. 2015, 2020
* Copyright IBM Corp. 2015, 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -24,6 +24,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <unistd.h>
#include <libudev.h>
@@ -31,14 +32,12 @@
#include "cpacfstats.h"
#include "../include/lib/zt_common.h"
#define NUM_COUNTER ALL_COUNTER
/* correlation between counter and perf counter string */
static const struct {
char pmu[20];
char pfm_name[60];
enum ctr_e ctr;
} pmf_counter_name[NUM_COUNTER] = {
} pmf_counter_name[ALL_COUNTER] = {
{"cpum_cf", "DEA_FUNCTIONS", DES_FUNCTIONS},
{"cpum_cf", "AES_FUNCTIONS", AES_FUNCTIONS},
{"cpum_cf", "SHA_FUNCTIONS", SHA_FUNCTIONS},
@@ -49,10 +48,12 @@ static const struct {
static struct pmf_data {
int pmutype;
int eventid;
} pmf_counter_data[NUM_COUNTER];
} pmf_counter_data[ALL_COUNTER];
struct percpucounter {
int ctr_fds[NUM_COUNTER];
int ctr_fds[ALL_COUNTER];
int pai_user[NUM_PAI_USER];
int pai_kernel[NUM_PAI_KERNEL];
unsigned int cpunum;
struct percpucounter *next;
};
@@ -71,6 +72,8 @@ static int ctr_state[NUM_COUNTER];
static volatile int stoprequested;
static int paipmutype, paipmueventstart;
static struct percpucounter *allocpercpucounter(unsigned int cpunum)
{
struct percpucounter *ppc;
@@ -79,8 +82,12 @@ static struct percpucounter *allocpercpucounter(unsigned int cpunum)
if (ppc) {
int i;
for (i = 0; i < NUM_COUNTER; ++i)
for (i = 0; i < ALL_COUNTER; ++i)
ppc->ctr_fds[i] = -1;
for (i = 0; i < NUM_PAI_USER; ++i)
ppc->pai_user[i] = -1;
for (i = 0; i < NUM_PAI_KERNEL; ++i)
ppc->pai_kernel[i] = -1;
ppc->cpunum = cpunum;
ppc->next = NULL;
}
@@ -91,8 +98,12 @@ static void freepercpucounter(struct percpucounter *pcpu)
{
int i;
for (i = 0; i < NUM_COUNTER; ++i)
for (i = 0; i < ALL_COUNTER; ++i)
(void)close(pcpu->ctr_fds[i]);
for (i = 0; i < NUM_PAI_USER; ++i)
(void)close(pcpu->pai_user[i]);
for (i = 0; i < NUM_PAI_KERNEL; ++i)
(void)close(pcpu->pai_kernel[i]);
free(pcpu);
}
@@ -139,6 +150,39 @@ static int perf_counter_supported(const char *pmu, const char *counter)
return !access(buf, R_OK);
}
static int cpumf_authorized(void)
{
unsigned vermin, vermax, auth;
int res = 0, found = 0;
size_t linesize = 0;
char *line = NULL;
FILE *f;
f = fopen("/proc/service_levels", "r");
if (f == NULL) {
eprint("Failed to open /proc/service_levels (%d:%s)\n",
errno, strerror(errno));
return 0;
}
while (getline(&line, &linesize, f) >= 0) {
if (sscanf(line,
"CPU-MF: Counter facility: version=%d.%d authorization=%x",
&vermin, &vermax, &auth) == 3) {
if (auth & 0x8)
res = 1;
else
eprint("CPU-MF counters not authorized.\n");
found = 1;
break;
}
}
if (!found)
eprint("CPU-MF counters not available.\n");
free(line);
fclose(f);
return res;
}
static int perf_event_encode(int *pmutype, int *eventid,
const char *pmu, const char *event)
{
@@ -196,7 +240,8 @@ static int activatecpu(unsigned int cpu)
freepercpucounter(ppc);
return -1;
}
for (i = 0; i < NUM_COUNTER; ++i) {
/* activate CPU-MF */
for (i = 0; i < ALL_COUNTER; ++i) {
if (ctr_state[i] == UNSUPPORTED)
continue;
memset(&pfm_event, 0, sizeof(pfm_event));
@@ -223,6 +268,67 @@ static int activatecpu(unsigned int cpu)
ppc->ctr_fds[i] = fd;
}
}
/* activate pai_user and pai_kernel */
/* invariant:
(ctr_state[PAI_USER] == UNSUPPORTED) ==
(ctr_state[PAI_KERNEL] == UNSUPPORTED) */
if (ctr_state[PAI_USER] != UNSUPPORTED) {
for (i = 1; i <= NUM_PAI_USER; ++i) {
memset(&pfm_event, 0, sizeof(pfm_event));
pfm_event.size = sizeof(pfm_event);
pfm_event.type = paipmutype;
pfm_event.config = paipmueventstart + i;
pfm_event.exclude_kernel = 1;
pfm_event.exclude_user = 0;
pfm_event.disabled = ctr_state[PAI_USER] == DISABLED;
fd = perf_event_open(&pfm_event, -1, cpu, -1, 0);
if (fd < 0) {
eprint("Perf_event_open() failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
ctr_state[PAI_USER] = UNSUPPORTED;
ctr_state[PAI_KERNEL] = UNSUPPORTED;
goto outevents;
} else {
ppc->pai_user[i - 1] = fd;
}
pfm_event.exclude_kernel = 0;
pfm_event.exclude_user = 1;
pfm_event.disabled = ctr_state[PAI_KERNEL] == DISABLED;
fd = perf_event_open(&pfm_event, -1, cpu, -1, 0);
if (fd < 0) {
eprint("Perf_event_open() failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
ctr_state[PAI_USER] = UNSUPPORTED;
ctr_state[PAI_KERNEL] = UNSUPPORTED;
goto outevents;
} else {
ppc->pai_kernel[i - 1] = fd;
}
}
for (; i <= NUM_PAI_KERNEL; ++i) {
memset(&pfm_event, 0, sizeof(pfm_event));
pfm_event.size = sizeof(pfm_event);
pfm_event.type = paipmutype;
pfm_event.config = paipmueventstart + i;
pfm_event.exclude_kernel = 0;
pfm_event.exclude_user = 1;
pfm_event.disabled = ctr_state[PAI_KERNEL] == DISABLED;
fd = perf_event_open(&pfm_event, -1, cpu, -1, 0);
if (fd < 0) {
eprint("Perf_event_open() failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
ctr_state[PAI_USER] = UNSUPPORTED;
ctr_state[PAI_KERNEL] = UNSUPPORTED;
goto outevents;
} else {
ppc->pai_kernel[i - 1] = fd;
}
}
}
outevents:
ppc->next = root;
root = ppc;
if (enabledcounter)
@@ -240,8 +346,12 @@ static void deactivatecpu(unsigned int cpunum)
return;
pcpu = findcpu(cpunum, 1);
if (pcpu != NULL) {
for (i = 0; i < NUM_COUNTER; ++i)
for (i = 0; i < ALL_COUNTER; ++i)
(void)close(pcpu->ctr_fds[i]);
for (i = 0; i < NUM_PAI_USER; ++i)
(void)close(pcpu->pai_user[i]);
for (i = 0; i < NUM_PAI_KERNEL; ++i)
(void)close(pcpu->pai_kernel[i]);
free(pcpu);
if (enabledcounter)
hotplugdetected = 1;
@@ -286,13 +396,16 @@ static int perf_load_counter_data(void)
{
int i, res = 0;
for (i = 0; i < NUM_COUNTER; ++i) {
for (i = 0; i < ALL_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);
}
if (ctr_state[PAI_USER] != UNSUPPORTED)
res |= perf_event_encode(&paipmutype, &paipmueventstart,
"pai_crypto", "CRYPTO_ALL");
return res;
}
@@ -351,7 +464,10 @@ static void *hotplughandler(void *UNUSED(unused))
int perf_init(void)
{
int ecc_supported;
int ecc_supported, i, num;
unsigned long maxfd;
struct rlimit rlim;
FILE *f;
/* initialize performance monitoring library */
if (!perf_supported()) {
@@ -359,13 +475,56 @@ int perf_init(void)
return -1;
}
/* We currently support all cpumf counters plus two virtual
* counters for PAI. */
num = ALL_COUNTER + 2;
/* Check if ECC is supported on current hardware */
ecc_supported = perf_counter_supported("cpum_cf", "ECC_FUNCTION_COUNT");
if (!ecc_supported)
if (!cpumf_authorized()) {
for (i = 0; i < ALL_COUNTER; ++i)
ctr_state[i] = UNSUPPORTED;
num -= ALL_COUNTER;
} else if (!ecc_supported) {
ctr_state[ECC_FUNCTIONS] = UNSUPPORTED;
--num;
}
if (!perf_counter_supported("pai_crypto", "CRYPTO_ALL")) {
ctr_state[PAI_USER] = UNSUPPORTED;
ctr_state[PAI_KERNEL] = UNSUPPORTED;
num -= 2;
}
if (num == 0) {
eprint("No crypto counters supported!\n");
return -1;
}
if (perf_load_counter_data())
return -1;
/* We have to adjust the number of FDs possible since we might
* need more than 1024 (the typical soft limit) */
f = fopen("/proc/sys/fs/nr_open", "r");
if (f == NULL) {
eprint("fopen failed for /proc/sys/fs/nr_open with errno=%d [%s]\n",
errno, strerror(errno));
return -1;
}
if (fscanf(f, "%lu", &maxfd) != 1) {
fclose(f);
eprint("Failed to parse /proc/sys/fs/nr_open\n");
return -1;
}
fclose(f);
rlim.rlim_cur = maxfd;
rlim.rlim_max = maxfd;
if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) {
eprint("setrlimit failed with errno=%d [%s]\n",
errno, strerror(errno));
return -1;
}
if (pthread_create(&hotplugthread, NULL, hotplughandler, NULL)) {
eprint("Failed to start hotplug handler thread\n");
return -1;
@@ -395,6 +554,22 @@ void perf_close(void)
}
static int enable_array(int *arr, int size)
{
int i, ec, rc = 0;
for (i = 0; i < size; ++i) {
ec = ioctl(arr[i], 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_enable_ctr(enum ctr_e ctr)
{
struct percpucounter *pcpu;
@@ -418,6 +593,24 @@ int perf_enable_ctr(enum ctr_e ctr)
ctr_state[ctr] = ENABLED;
++enabledcounter;
endforeachcpu();
} else if (ctr == PAI_USER) {
foreachcpu(pcpu) {
ec = enable_array(pcpu->pai_user, NUM_PAI_USER);
if (ec < 0)
rc = -1;
}
ctr_state[ctr] = ENABLED;
++enabledcounter;
endforeachcpu();
} else if (ctr == PAI_KERNEL) {
foreachcpu(pcpu) {
ec = enable_array(pcpu->pai_kernel, NUM_PAI_KERNEL);
if (ec < 0)
rc = -1;
}
ctr_state[ctr] = ENABLED;
++enabledcounter;
endforeachcpu();
} else {
rc = -1;
}
@@ -426,6 +619,22 @@ int perf_enable_ctr(enum ctr_e ctr)
}
static int disable_array(int *arr, int size)
{
int i, ec, rc = 0;
for (i = 0; i < size; ++i) {
ec = ioctl(arr[i], 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_disable_ctr(enum ctr_e ctr)
{
struct percpucounter *pcpu;
@@ -451,6 +660,28 @@ int perf_disable_ctr(enum ctr_e ctr)
if (enabledcounter == 0)
hotplugdetected = 0;
endforeachcpu();
} else if (ctr == PAI_USER) {
foreachcpu(pcpu) {
ec = disable_array(pcpu->pai_user, NUM_PAI_USER);
if (ec < 0)
rc = -1;
}
ctr_state[ctr] = DISABLED;
--enabledcounter;
if (enabledcounter == 0)
hotplugdetected = 0;
endforeachcpu();
} else if (ctr == PAI_KERNEL) {
foreachcpu(pcpu) {
ec = disable_array(pcpu->pai_kernel, NUM_PAI_KERNEL);
if (ec < 0)
rc = -1;
}
ctr_state[ctr] = DISABLED;
--enabledcounter;
if (enabledcounter == 0)
hotplugdetected = 0;
endforeachcpu();
} else {
rc = -1;
}
@@ -459,14 +690,30 @@ int perf_disable_ctr(enum ctr_e ctr)
}
int perf_reset_ctr(enum ctr_e ctr)
static int reset_array(int *arr, int size)
{
int ec, rc = 0, i;
for (i = 0; i < size; ++i) {
ec = ioctl(arr[i], 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_reset_ctr(enum ctr_e ctr, uint64_t *value)
{
struct percpucounter *pcpu;
int ec, rc = 0;
if (ctr == ALL_COUNTER) {
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
rc = perf_reset_ctr(ctr);
rc = perf_reset_ctr(ctr, value);
if (rc != 0)
return rc;
}
@@ -480,10 +727,25 @@ int perf_reset_ctr(enum ctr_e ctr)
}
}
endforeachcpu();
} else if (ctr == PAI_USER) {
foreachcpu(pcpu) {
ec = reset_array(pcpu->pai_user, NUM_PAI_USER);
if (ec < 0)
rc = -1;
}
endforeachcpu();
} else if (ctr == PAI_KERNEL) {
foreachcpu(pcpu) {
ec = reset_array(pcpu->pai_kernel, NUM_PAI_KERNEL);
if (ec < 0)
rc = -1;
}
endforeachcpu();
} else {
rc = -1;
}
if (rc == 0)
rc = perf_read_ctr(ctr, value);
return rc;
}
@@ -491,7 +753,7 @@ int perf_reset_ctr(enum ctr_e ctr)
int perf_read_ctr(enum ctr_e ctr, uint64_t *value)
{
struct percpucounter *pcpu;
int ec, rc = -1;
int ec, rc = 0;
uint64_t val;
if (!value)
@@ -500,6 +762,14 @@ int perf_read_ctr(enum ctr_e ctr, uint64_t *value)
*value = hotplugdetected;
return 0;
}
if (ctr == PAI_USER) {
*value = NUM_PAI_USER;
return 0;
}
if (ctr == PAI_KERNEL) {
*value = NUM_PAI_KERNEL;
return 0;
}
if (ctr >= ALL_COUNTER)
return -1;
*value = 0;
@@ -509,9 +779,9 @@ int perf_read_ctr(enum ctr_e ctr, uint64_t *value)
if (ec != sizeof(val)) {
eprint("Read() on perf file descriptor failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
} else {
*value += val;
rc = 0;
}
}
endforeachcpu();
@@ -525,7 +795,34 @@ int perf_ecc_supported(void)
}
int perf_ctr_state(enum ctr_e ctr) {
if (ctr < ALL_COUNTER)
if (ctr < NUM_COUNTER)
return ctr_state[ctr];
return UNSUPPORTED;
}
int perf_read_pai_ctr(unsigned int ctrnum, int user, uint64_t *value)
{
struct percpucounter *pcpu;
unsigned int maxctr;
int *arr, ec, rc = 0;
uint64_t val;
*value = 0;
maxctr = user ? NUM_PAI_USER : NUM_PAI_KERNEL;
if (ctrnum >= maxctr)
return -1;
foreachcpu(pcpu) {
arr = user ? pcpu->pai_user : pcpu->pai_kernel;
ec = read(arr[ctrnum], &val, sizeof(val));
if (ec != sizeof(val)) {
eprint("Read() on perf file descriptor failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
} else {
*value += val;
}
}
endforeachcpu();
return rc;
}