mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
libcpumf: Create library libcpumf for CPU Measurement functions
Add a function to detect the existence of the CPU Measurement Sampling Facility on a system. Add a function which extracts the CPU Measurement Sampling Facility characteristics on a system, such as - minimum sample speed - maximum sample speed - current CPU speed - basic sample size in bytes - diagnostic sample size in bytes Add a function to detect the existence of the CPU Measurement Sampling Facility on a system and return the current sampling buffer management characteristics, such as: - minimum supported sampling buffer size - maximum supported sampling buffer size Add a function to detect the existence of the CPU Measurement Counting Facility on a system. Add a function which extracts the CPU Measurement Counting Facility characteristics on a system, such as - counter first version number - counter second version number - counter set authorization level Add a function the returm the PMU type number of a CPU Measurement Facility device driver. These numbers may vary between boots. Signed-off-by: Thomas Richter <tmricht@linux.ibm.com> Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
50a4740443
commit
c7fe21b019
2
Makefile
2
Makefile
@@ -10,7 +10,7 @@ include common.mak
|
||||
#
|
||||
BASELIB_DIRS = libutil libseckey
|
||||
LIB_DIRS = libvtoc libzds libdasd libvmdump libccw libvmcp libekmfweb \
|
||||
libkmipclient
|
||||
libkmipclient libcpumf
|
||||
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
|
||||
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
|
||||
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
|
||||
|
||||
106
include/lib/libcpumf.h
Normal file
106
include/lib/libcpumf.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/* Copyright IBM Corp. 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.
|
||||
*/
|
||||
|
||||
#ifndef LIBCPUMF_H
|
||||
#define LIBCPUMF_H
|
||||
|
||||
#include <sched.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define S390_CPUMF_CF "/sys/devices/cpum_cf/"
|
||||
#define S390_CPUMF_CFDIAG "/sys/devices/cpum_cf_diag/"
|
||||
#define S390_CPUMF_SF "/sys/devices/cpum_sf/"
|
||||
#define S390_CPUS_POSSIBLE "/sys/devices/system/cpu/possible"
|
||||
#define S390_CPUS_ONLINE "/sys/devices/system/cpu/online"
|
||||
#define S390_CPUMSF_BUFFERSZ "/sys/module/kernel/parameters/cpum_sfb_size"
|
||||
|
||||
/**
|
||||
* Read out the PMU type from a given file.
|
||||
*
|
||||
* Return the PMU type number assigned to this PMU by the kernel. This is
|
||||
* a non zero number.
|
||||
* If the PMU does not exist return -1 and set errno.
|
||||
*
|
||||
* @param[in] dirname Name of the event directory in sysfs
|
||||
*/
|
||||
int libcpumf_pmutype(const char *dirname);
|
||||
|
||||
/**
|
||||
* Read out the CPU list from a given file name, for example from files
|
||||
* /sys/devices/system/cpu/online or /sys/devices/system/cpu/possible.
|
||||
*
|
||||
* Return the cpu_set_t created from parsing the CPU list in the second
|
||||
* parameter.
|
||||
* Return code of zero indicates proper conversion and -1 indicates an
|
||||
* error.
|
||||
*
|
||||
* @param[in] buffer Comma separated string of a CPU list
|
||||
* @param[in] filename Name of a sysfs CPU list file name
|
||||
* @param[out] mask Converted buffer into cpu_set_t mask structure
|
||||
*/
|
||||
int libcpumf_cpuset(const char *buffer, cpu_set_t *mask);
|
||||
int libcpumf_cpuset_fn(const char *filename, cpu_set_t *mask);
|
||||
|
||||
/**
|
||||
* Read CPU Measurement Counting Facility hardware information
|
||||
*
|
||||
* Return true if CPU Measurement Counter facility information has been
|
||||
* retrieved and is valid.
|
||||
*
|
||||
* Return false if the information could not be extracted from the file.
|
||||
*
|
||||
* @param[out] cfvn Contains CPUMF counter first version number
|
||||
* @param[out] csvn Contains CPUMF counter second version number
|
||||
* @param[out] auth Contains CPUMF counter set authorization level
|
||||
*/
|
||||
bool libcpumf_cpumcf_info(int *cfvn, int *csvn, int *auth);
|
||||
|
||||
/**
|
||||
* Return true if CPU Measurement Counter Facility is available.
|
||||
*/
|
||||
bool libcpumf_have_cpumcf(void);
|
||||
|
||||
/**
|
||||
* Read CPU Measurement Sampling Facility hardware information
|
||||
*
|
||||
* Read all necessary information from /sysfs file /proc/service_levels
|
||||
* to return CPU Measurement Counter Sampling facility information
|
||||
* characteristics.
|
||||
* Return true on success and false when the data can not be retrieved.
|
||||
*
|
||||
* @param[out] min Minimum supported sampling interval
|
||||
* @param[out] max Maximum supported sampling interval
|
||||
* @param[out] speed Current CPU speed, number of CPU cylces per
|
||||
* microsecond
|
||||
* @param[out] basic_sz Basic sample size in bytes
|
||||
* @param[out] diag_sz Diagnostic sample size in bytes
|
||||
*/
|
||||
bool libcpumf_cpumsf_info(unsigned long *min, unsigned long *max,
|
||||
unsigned long *speed, int *basic_sz, int *diag_sz);
|
||||
|
||||
/**
|
||||
* Return true if CPU Measurement Sampling Facility is available.
|
||||
*/
|
||||
bool libcpumf_have_cpumsf(void);
|
||||
|
||||
/**
|
||||
* Return true if CPU Measurement Sampling Facility buffer sizes are
|
||||
* available.
|
||||
*/
|
||||
bool libcpumf_have_sfb(void);
|
||||
|
||||
/**
|
||||
* Read CPU Measurement Sampling Facility supported sampling buffer sizes.
|
||||
*
|
||||
* Return the minimum and maximum CPU Measurement sampling facitity buffer
|
||||
* sizes supported.
|
||||
* Return true on success and false otherwise.
|
||||
*
|
||||
* @param[out] min Minimum supported sampling buffer size
|
||||
* @param[out] max Maximum supported sampling buffer size
|
||||
*/
|
||||
bool libcpumf_sfb_info(unsigned long *min, unsigned long *max);
|
||||
#endif
|
||||
19
libcpumf/Makefile
Normal file
19
libcpumf/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
include ../common.mak
|
||||
|
||||
lib = libcpumf.a
|
||||
|
||||
examples = libcpumf_example
|
||||
|
||||
all: $(lib)
|
||||
examples: $(lib) $(examples)
|
||||
|
||||
objects = libcpumf_pmutype.o libcpumf_cpuset.o libcpumf_support.o
|
||||
|
||||
$(lib): $(objects)
|
||||
|
||||
install: all
|
||||
|
||||
libcpumf_example: libcpumf_example.o $(lib)
|
||||
|
||||
clean:
|
||||
rm -f *.o $(lib) $(examples)
|
||||
75
libcpumf/libcpumf_cpuset.c
Normal file
75
libcpumf/libcpumf_cpuset.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/* Copyright IBM Corp. 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.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "lib/libcpumf.h"
|
||||
|
||||
int libcpumf_cpuset(const char *parm, cpu_set_t *mask)
|
||||
{
|
||||
char *cp, *buffer = strdup(parm);
|
||||
int to, from, rc;
|
||||
|
||||
if (!buffer) /* Errno set to ENOMEM */
|
||||
return -1;
|
||||
/* Check for invalid characters, such as 11.12 instead 11-12
|
||||
* but allow blanks and newline. Newline is appended
|
||||
* when the string is taken from sysfs files, for example
|
||||
* /sys/devices/system/cpu/online
|
||||
*/
|
||||
if (strspn(buffer, "0123456789-,\n ") != strlen(buffer)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
CPU_ZERO(mask);
|
||||
for (; (cp = strtok(buffer, ",")); buffer = NULL) {
|
||||
char *dash = strchr(cp, '-'); /* Range character? */
|
||||
bool is_ok;
|
||||
|
||||
if (dash) {
|
||||
rc = sscanf(cp, "%d-%d", &from, &to);
|
||||
is_ok = rc == 2;
|
||||
} else {
|
||||
rc = sscanf(cp, "%d", &to);
|
||||
from = to;
|
||||
is_ok = rc == 1;
|
||||
}
|
||||
if (!is_ok) {
|
||||
errno = ERANGE;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
for (; from <= to; ++from)
|
||||
CPU_SET(from, mask);
|
||||
}
|
||||
rc = 0;
|
||||
out:
|
||||
free(buffer);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int libcpumf_cpuset_fn(const char *filename, cpu_set_t *mask)
|
||||
{
|
||||
char *txt = NULL;
|
||||
ssize_t ret = -1;
|
||||
size_t len = 0;
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
if (!fp)
|
||||
return ret;
|
||||
/* Read out file, one line expected */
|
||||
ret = getline(&txt, &len, fp);
|
||||
fclose(fp);
|
||||
if (ret > 0)
|
||||
ret = libcpumf_cpuset(txt, mask);
|
||||
free(txt);
|
||||
return ret;
|
||||
}
|
||||
76
libcpumf/libcpumf_example.c
Normal file
76
libcpumf/libcpumf_example.c
Normal file
@@ -0,0 +1,76 @@
|
||||
/* Copyright IBM Corp. 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lib/libcpumf.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned long min, max, speed, sfb_min, sfb_max;
|
||||
int rc, pmu, cfvn, csvn, auth;
|
||||
cpu_set_t set;
|
||||
|
||||
pmu = libcpumf_pmutype(S390_CPUMF_CF);
|
||||
if (pmu >= 0)
|
||||
printf("PMU %stype %d\n", S390_CPUMF_CF, pmu);
|
||||
else
|
||||
printf("PMU %stype error %d\n", S390_CPUMF_CF, errno);
|
||||
pmu = libcpumf_pmutype(S390_CPUMF_SF);
|
||||
if (pmu >= 0)
|
||||
printf("PMU %stype %d\n", S390_CPUMF_SF, pmu);
|
||||
else
|
||||
printf("PMU %stype error %d\n", S390_CPUMF_SF, errno);
|
||||
pmu = libcpumf_pmutype(S390_CPUMF_CFDIAG);
|
||||
if (pmu >= 0)
|
||||
printf("PMU %stype %d\n", S390_CPUMF_CFDIAG, pmu);
|
||||
else
|
||||
printf("PMU %stype error %d\n", S390_CPUMF_CFDIAG, errno);
|
||||
|
||||
rc = libcpumf_cpuset_fn(S390_CPUS_ONLINE, &set);
|
||||
if (rc == 0) {
|
||||
puts("Online CPUs:");
|
||||
for (int i = 0; i < CPU_SETSIZE; ++i)
|
||||
if (CPU_ISSET(i, &set))
|
||||
printf("%d ", i);
|
||||
putchar('\n');
|
||||
}
|
||||
rc = libcpumf_cpuset("0-7,9,11-12 ,15", &set);
|
||||
if (rc == 0) {
|
||||
puts("String CPUs:");
|
||||
for (int i = 0; i < CPU_SETSIZE; ++i)
|
||||
if (CPU_ISSET(i, &set))
|
||||
printf("%d ", i);
|
||||
putchar('\n');
|
||||
} else {
|
||||
printf("libcpumf_cpuset input invalid %d\n", errno);
|
||||
}
|
||||
|
||||
printf("CPUMCF support %d\n", libcpumf_have_cpumcf());
|
||||
rc = libcpumf_cpumcf_info(&cfvn, &csvn, &auth);
|
||||
printf("libcpumf_cpumcf_info %d", rc);
|
||||
if (rc)
|
||||
printf(" cfvn %d csvn %d authorization %#x", cfvn, csvn, auth);
|
||||
putchar('\n');
|
||||
|
||||
printf("CPUMSF support %d\n", libcpumf_have_cpumsf());
|
||||
rc = libcpumf_cpumsf_info(&min, &max, &speed, &cfvn, &csvn);
|
||||
printf("libcpumf_cpumsf_info %d", rc);
|
||||
if (rc)
|
||||
printf(" min %ld max %ld speed %#lx basic %d diag %d", min,
|
||||
max, speed, cfvn, csvn);
|
||||
putchar('\n');
|
||||
|
||||
printf("CPUMSF have sfb %d\n", libcpumf_have_sfb());
|
||||
rc = libcpumf_sfb_info(&sfb_min, &sfb_max);
|
||||
printf("libcpumf_sfb_info %d", rc);
|
||||
if (rc)
|
||||
printf(" sfb_min %lu sfb_max %lu", sfb_min, sfb_max);
|
||||
putchar('\n');
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
33
libcpumf/libcpumf_pmutype.c
Normal file
33
libcpumf/libcpumf_pmutype.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/* Copyright IBM Corp. 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.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lib/libcpumf.h"
|
||||
|
||||
int libcpumf_pmutype(const char *dirname)
|
||||
{
|
||||
FILE *file;
|
||||
char *fn;
|
||||
int ret;
|
||||
|
||||
ret = asprintf(&fn, "%s/type", dirname);
|
||||
if (ret == -1) /* No memory, errno set */
|
||||
return ret;
|
||||
file = fopen(fn, "r");
|
||||
free(fn);
|
||||
ret = -1; /* Errno set on file open error */
|
||||
if (file) {
|
||||
/* Read out a single number from that file */
|
||||
if (fscanf(file, "%u", &ret) != 1)
|
||||
/* Unexpected format error, set errno */
|
||||
errno = -ERANGE;
|
||||
fclose(file);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
141
libcpumf/libcpumf_support.c
Normal file
141
libcpumf/libcpumf_support.c
Normal file
@@ -0,0 +1,141 @@
|
||||
/* Copyright IBM Corp. 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <err.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "lib/libcpumf.h"
|
||||
|
||||
#define SERVICELEVEL "/proc/service_levels"
|
||||
|
||||
bool libcpumf_cpumcf_info(int *cfvn, int *csvn, int *auth)
|
||||
{
|
||||
char *linep = NULL;
|
||||
bool rc = false;
|
||||
size_t line_sz;
|
||||
ssize_t nbytes;
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(SERVICELEVEL, "r");
|
||||
if (!fp)
|
||||
err(EXIT_FAILURE, SERVICELEVEL);
|
||||
|
||||
while ((nbytes = getline(&linep, &line_sz, fp)) != EOF) {
|
||||
if (!strncmp(linep, "CPU-MF: Counter facility:", 25)) {
|
||||
int cnt = sscanf(linep, "CPU-MF: Counter facility:"
|
||||
" version=%d.%d authorization=%x",
|
||||
cfvn, csvn, auth);
|
||||
if (cnt != 3) {
|
||||
warnx("Can not parse line %s", linep);
|
||||
goto out;
|
||||
}
|
||||
rc = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
out:
|
||||
fclose(fp);
|
||||
free(linep);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool libcpumf_have_cpumcf(void)
|
||||
{
|
||||
int cfvn, csvn, auth;
|
||||
|
||||
return libcpumf_cpumcf_info(&cfvn, &csvn, &auth);
|
||||
}
|
||||
|
||||
bool libcpumf_cpumsf_info(unsigned long *min, unsigned long *max,
|
||||
unsigned long *speed, int *basic_sz, int *diag_sz)
|
||||
{
|
||||
char *linep = NULL;
|
||||
bool rc = true;
|
||||
size_t line_sz;
|
||||
ssize_t nbytes;
|
||||
int hit = 0;
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(SERVICELEVEL, "r");
|
||||
if (!fp)
|
||||
err(EXIT_FAILURE, SERVICELEVEL);
|
||||
|
||||
while ((nbytes = getline(&linep, &line_sz, fp)) != EOF) {
|
||||
int ok;
|
||||
|
||||
if (!strncmp(linep, "CPU-MF: Sampling facility: min", 30)) {
|
||||
ok = sscanf(linep, "CPU-MF: Sampling facility:"
|
||||
" min_rate=%ld max_rate=%ld cpu_speed=%ld",
|
||||
min, max, speed);
|
||||
if (ok != 3) {
|
||||
warnx("Can not parse line %s", linep);
|
||||
goto out;
|
||||
}
|
||||
hit += 1;
|
||||
}
|
||||
if (!strncmp(linep, "CPU-MF: Sampling facility: mode=basic", 37)) {
|
||||
ok = sscanf(linep, "CPU-MF: Sampling facility:"
|
||||
" mode=basic sample_size=%u", basic_sz);
|
||||
if (ok != 1) {
|
||||
warnx("Can not parse line %s", linep);
|
||||
goto out;
|
||||
}
|
||||
hit += 1;
|
||||
}
|
||||
if (!strncmp(linep, "CPU-MF: Sampling facility: mode=diag", 36)) {
|
||||
ok = sscanf(linep, "CPU-MF: Sampling facility:"
|
||||
" mode=diagnostic sample_size=%u",
|
||||
diag_sz);
|
||||
if (ok != 1) {
|
||||
warnx("Can not parse line %s", linep);
|
||||
goto out;
|
||||
}
|
||||
hit += 1;
|
||||
}
|
||||
}
|
||||
out:
|
||||
fclose(fp);
|
||||
free(linep);
|
||||
if (hit != 3)
|
||||
rc = false;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool libcpumf_have_cpumsf(void)
|
||||
{
|
||||
unsigned long a, b, c;
|
||||
int basic_sz, diag_sz;
|
||||
|
||||
return libcpumf_cpumsf_info(&a, &b, &c, &basic_sz, &diag_sz);
|
||||
}
|
||||
|
||||
bool libcpumf_have_sfb(void)
|
||||
{
|
||||
unsigned long a, b;
|
||||
|
||||
return libcpumf_sfb_info(&a, &b);
|
||||
}
|
||||
|
||||
bool libcpumf_sfb_info(unsigned long *min, unsigned long *max)
|
||||
{
|
||||
int rc = false;
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(S390_CPUMSF_BUFFERSZ, "r");
|
||||
if (!fp)
|
||||
err(EXIT_FAILURE, "%s", S390_CPUMSF_BUFFERSZ);
|
||||
if (fscanf(fp, "%lu,%lu", min, max) == 2)
|
||||
rc = true;
|
||||
fclose(fp);
|
||||
return rc;
|
||||
}
|
||||
Reference in New Issue
Block a user