493 lines
9.4 KiB
C
493 lines
9.4 KiB
C
#include "config.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <dirent.h>
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
|
|
#include "bitmask.h"
|
|
#include "cpuset.h"
|
|
#include "common.h"
|
|
#include "cpuinfo.h"
|
|
|
|
#if HAVE_LINUX_MEMPOLICY_H
|
|
|
|
#define CPUINFO_FILE "/proc/cpuinfo"
|
|
#define SCHEDSTAT_FILE "/proc/schedstat"
|
|
#define CGROUPINFO_FILE "/proc/cgroups"
|
|
#define SYS_CPU_DIR "/sys/devices/system/cpu"
|
|
#define LIST_PRESENT_CPU_FILE "/sys/devices/system/cpu/present"
|
|
#define LIST_ONLINE_CPU_FILE "/sys/devices/system/cpu/online"
|
|
|
|
struct cpuinfo *cpus;
|
|
int ncpus;
|
|
int cpus_nbits;
|
|
|
|
/* get cpu_baseinfo from /proc/cpuinfo */
|
|
static int get_cpu_baseinfo(void)
|
|
{
|
|
FILE *fp = NULL;
|
|
char buf[BUFFSIZE];
|
|
char *istr = NULL, *valstr = NULL, *saveptr = NULL;
|
|
int ci = 0;
|
|
int data = 0;
|
|
|
|
/* get the number of cpus including offline cpus */
|
|
if (!ncpus) {
|
|
ncpus = get_ncpus();
|
|
if (ncpus <= 0)
|
|
return -1;
|
|
}
|
|
|
|
if (cpus != NULL) {
|
|
free(cpus);
|
|
cpus = NULL;
|
|
}
|
|
|
|
/* allocate the memory space for cpus */
|
|
cpus = malloc(sizeof(*cpus) * ncpus);
|
|
if (cpus == NULL)
|
|
return -1;
|
|
memset(cpus, 0, sizeof(*cpus) * ncpus);
|
|
|
|
/* open file /proc/cpuinfo */
|
|
if ((fp = fopen(CPUINFO_FILE, "r")) == NULL)
|
|
return -1;
|
|
|
|
/* get cpuinfo */
|
|
while (fgets(buf, sizeof(buf), fp) != NULL) {
|
|
istr = strtok_r(buf, "\t", &saveptr);
|
|
valstr = strchr(saveptr, ':');
|
|
if (valstr == NULL)
|
|
continue;
|
|
valstr++;
|
|
sscanf(valstr, " %d\n", &data);
|
|
if (!strcmp(istr, "processor")) {
|
|
if (data >= ncpus) {
|
|
warnx("Warn: wrong cpu index");
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
ci = data;
|
|
cpus[ci].online = 1;
|
|
}
|
|
}
|
|
|
|
fclose(fp);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* get the cpu bitmask of the online processors
|
|
*
|
|
* return value: 0 - success
|
|
* -1 - failed
|
|
*/
|
|
int online_cpumask(struct bitmask *cpumask)
|
|
{
|
|
FILE *fp = NULL;
|
|
char buf[BUFFSIZE];
|
|
int i;
|
|
|
|
if (cpumask == NULL)
|
|
return -1;
|
|
/*
|
|
* open file /sys/devices/system/cpu/online and get online
|
|
* cpulist.
|
|
*/
|
|
if ((fp = fopen(LIST_ONLINE_CPU_FILE, "r")) == NULL) {
|
|
if (get_cpu_baseinfo() != 0)
|
|
return -1;
|
|
for (i = 0; i < ncpus; i++) {
|
|
if (cpus[i].online)
|
|
bitmask_setbit(cpumask, i);
|
|
}
|
|
} else {
|
|
if (fgets(buf, sizeof(buf), fp) == NULL) {
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
fclose(fp);
|
|
|
|
/* parse present cpu list to bitmap */
|
|
buf[strlen(buf) - 1] = '\0';
|
|
if (bitmask_parselist(buf, cpumask) != 0)
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* get the cpu bitmask of the present processors including offline CPUs
|
|
*
|
|
* return value: 0 - success
|
|
* -1 - failed
|
|
*/
|
|
int present_cpumask(struct bitmask *cpumask)
|
|
{
|
|
FILE *fp = NULL;
|
|
char buf[BUFFSIZE];
|
|
char c_relpath[PATH_MAX];
|
|
int cpu = -1;
|
|
|
|
if (cpumask == NULL)
|
|
return -1;
|
|
/*
|
|
* open file /sys/devices/system/cpu/present and get present
|
|
* cpulist.
|
|
*/
|
|
if ((fp = fopen(LIST_PRESENT_CPU_FILE, "r")) == NULL) {
|
|
while_each_childdir(SYS_CPU_DIR, "/", c_relpath,
|
|
sizeof(c_relpath)) {
|
|
if (!strncmp(c_relpath + 1, "cpu", 3)
|
|
&& sscanf(c_relpath + 4, "%d", &cpu) > 0) {
|
|
if (cpu >= 0)
|
|
bitmask_setbit(cpumask, cpu);
|
|
}
|
|
}
|
|
end_while_each_childdir} else {
|
|
if (fgets(buf, sizeof(buf), fp) == NULL) {
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
fclose(fp);
|
|
|
|
/* parse present cpu list to bitmap */
|
|
buf[strlen(buf) - 1] = '\0';
|
|
if (bitmask_parselist(buf, cpumask) != 0)
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* get the number of the processors including offline CPUs
|
|
* We get this number from /sys/devices/system/cpu/present.
|
|
* By analyzing the present cpu list, we get the number of all cpus
|
|
*/
|
|
int get_ncpus(void)
|
|
{
|
|
struct bitmask *bmp = NULL;
|
|
int n = 0;
|
|
|
|
/* get the bitmask's len */
|
|
cpus_nbits = cpuset_cpus_nbits();
|
|
if (cpus_nbits <= 0)
|
|
return -1;
|
|
|
|
/* allocate the space for bitmask */
|
|
bmp = bitmask_alloc(cpus_nbits);
|
|
if (bmp == NULL)
|
|
return -1;
|
|
|
|
if (present_cpumask(bmp)) {
|
|
bitmask_free(bmp);
|
|
return -1;
|
|
}
|
|
|
|
/* Number of highest set bit +1 is the number of the CPUs */
|
|
n = bitmask_last(bmp) + 1;
|
|
bitmask_free(bmp);
|
|
|
|
return n;
|
|
}
|
|
|
|
/* get the sched domain's info for each cpu */
|
|
static int get_sched_domains(void)
|
|
{
|
|
FILE *fp = NULL;
|
|
char buf[BUFFSIZE];
|
|
char str1[20], str2[BUFFSIZE];
|
|
int ci = 0;
|
|
|
|
/* get the bitmask's len */
|
|
if (!cpus_nbits) {
|
|
cpus_nbits = cpuset_cpus_nbits();
|
|
if (cpus_nbits <= 0) {
|
|
warnx("get cpus nbits failed.");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* open file /proc/schedstat */
|
|
if ((fp = fopen(SCHEDSTAT_FILE, "r")) == NULL)
|
|
return -1;
|
|
|
|
/* get cpuinfo */
|
|
while (fgets(buf, sizeof(buf), fp) != NULL) {
|
|
sscanf(buf, "%s %s", str1, str2);
|
|
if (!strncmp(str1, "cpu", 3)) {
|
|
ci = atoi(str1 + 3);
|
|
if (ci < 0 || ci >= ncpus) {
|
|
fprintf(stderr, "Warn: wrong cpu index");
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
} else if (!strncmp(str1, "domain", 6)) {
|
|
if (!cpus[ci].sched_domain) {
|
|
cpus[ci].sched_domain =
|
|
bitmask_alloc(cpus_nbits);
|
|
if (!cpus[ci].sched_domain) {
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
}
|
|
if (bitmask_parsehex(str2, cpus[ci].sched_domain)) {
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
fclose(fp);
|
|
return 0;
|
|
}
|
|
|
|
int getcpuinfo(void)
|
|
{
|
|
int i;
|
|
int node = -1;
|
|
|
|
/* get the number of cpus including offline cpus */
|
|
if (!ncpus) {
|
|
ncpus = get_ncpus();
|
|
if (ncpus <= 0)
|
|
return -1;
|
|
}
|
|
|
|
if (cpus == NULL) {
|
|
if (get_cpu_baseinfo() != 0) {
|
|
warn("get base infomation of cpus from /proc/cpuinfo "
|
|
"failed.");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* which node is every cpu belong to? */
|
|
for (i = 0; i < ncpus; i++) {
|
|
node = cpuset_cpu2node(i);
|
|
if (node == -1)
|
|
warnx("cpu2node failed(cpu = %d)", i);
|
|
cpus[i].nodeid = node;
|
|
}
|
|
|
|
/* get sched domain's infomation for each cpu */
|
|
if (get_sched_domains()) {
|
|
warnx("get sched domain's info for each cpu failed.");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* get the number of the cpuset groups */
|
|
static int get_num_cpusets(void)
|
|
{
|
|
FILE *fp = NULL;
|
|
char buf[BUFFSIZE];
|
|
char subsys_name[BUFFSIZE];
|
|
int num_cgroups = 0;
|
|
int hierarchy;
|
|
int enabled;
|
|
|
|
/* open file /proc/cgroups and get num cpusets */
|
|
if ((fp = fopen(CGROUPINFO_FILE, "r")) == NULL)
|
|
return -1;
|
|
|
|
while (fgets(buf, sizeof(buf), fp) != NULL) {
|
|
if (!strncmp(buf, "cpuset", 6)) {
|
|
sscanf(buf, "%s\t%d\t%d\t%d\n", subsys_name,
|
|
&hierarchy, &num_cgroups, &enabled);
|
|
}
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
return num_cgroups;
|
|
}
|
|
|
|
static struct cpuset **cpusets;
|
|
static int ncpusets;
|
|
|
|
static int find_domain_cpusets(char *relpath)
|
|
{
|
|
struct cpuset *cp = NULL;
|
|
char c_relpath[PATH_MAX];
|
|
int ret = 0;
|
|
|
|
if (relpath == NULL) {
|
|
errno = -EFAULT;
|
|
return -1;
|
|
}
|
|
|
|
cp = cpuset_alloc();
|
|
if (cp == NULL) {
|
|
errno = -ENOMEM;
|
|
return -1;
|
|
}
|
|
|
|
if (cpuset_query(cp, relpath)) {
|
|
cpuset_free(cp);
|
|
return -1;
|
|
}
|
|
|
|
if (cpuset_cpus_weight(cp) == 0)
|
|
return 0;
|
|
|
|
if (cpuset_cpus_weight(cp) > 0
|
|
&& cpuset_get_iopt(cp, "sched_load_balance") == 1) {
|
|
cpusets[ncpusets] = cp;
|
|
ncpusets++;
|
|
return 0;
|
|
}
|
|
|
|
while_each_childdir(cpuset_mountpoint(), relpath, c_relpath,
|
|
sizeof(c_relpath)) {
|
|
if ((ret = find_domain_cpusets(c_relpath)))
|
|
break;
|
|
}
|
|
end_while_each_childdir;
|
|
|
|
return ret;
|
|
}
|
|
|
|
struct bitmask **domains;
|
|
int ndomains;
|
|
|
|
int partition_domains(void)
|
|
{
|
|
int num_cpusets = 0;
|
|
int i, j;
|
|
struct bitmask *cpusa = NULL, *cpusb = NULL, *cpusc = NULL;
|
|
int *flg = NULL;
|
|
int ret = 0;
|
|
|
|
num_cpusets = get_num_cpusets();
|
|
if (num_cpusets == 0) {
|
|
warnx("cpuset subsystem is't compiled into kernel.");
|
|
return -1;
|
|
}
|
|
|
|
if (!cpus_nbits) {
|
|
cpus_nbits = cpuset_cpus_nbits();
|
|
if (!cpus_nbits) {
|
|
warnx("nbits of cpus is wrong.");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
cpusa = bitmask_alloc(cpus_nbits);
|
|
if (cpusa == NULL) {
|
|
warnx("bitmask_alloc for partition domains failed.");
|
|
return -1;
|
|
}
|
|
|
|
cpusb = bitmask_alloc(cpus_nbits);
|
|
if (cpusb == NULL) {
|
|
warnx("bitmask_alloc for partition domains failed.");
|
|
ret = -1;
|
|
goto errcpusb;
|
|
}
|
|
|
|
cpusc = bitmask_alloc(cpus_nbits);
|
|
if (cpusb == NULL) {
|
|
warnx("bitmask_alloc for partition domains failed.");
|
|
ret = -1;
|
|
goto errcpusc;
|
|
}
|
|
|
|
cpusets = malloc(num_cpusets * sizeof(*cpusets));
|
|
if (cpusets == NULL) {
|
|
warnx("alloc cpusets space failed.");
|
|
ret = -1;
|
|
goto errcpusets;
|
|
}
|
|
|
|
if ((ret = find_domain_cpusets("/"))) {
|
|
warnx("find domain cpusets failed.");
|
|
goto errfindcpusets;
|
|
}
|
|
|
|
flg = malloc(num_cpusets * sizeof(int));
|
|
if (flg == NULL) {
|
|
warnx("alloc flg failed.");
|
|
ret = -1;
|
|
goto errfindcpusets;
|
|
}
|
|
memset(flg, 0, num_cpusets * sizeof(int));
|
|
|
|
ndomains = ncpusets;
|
|
restart:
|
|
for (i = 0; i < ncpusets; i++) {
|
|
struct cpuset *cpa = cpusets[i];
|
|
|
|
if (flg[i])
|
|
continue;
|
|
|
|
cpuset_getcpus(cpa, cpusa);
|
|
|
|
for (j = i + 1; j < ncpusets; j++) {
|
|
struct cpuset *cpb = cpusets[j];
|
|
|
|
if (flg[j])
|
|
continue;
|
|
|
|
cpuset_getcpus(cpb, cpusb);
|
|
if (bitmask_intersects(cpusa, cpusb)) {
|
|
bitmask_or(cpusc, cpusa, cpusb);
|
|
cpuset_setcpus(cpa, cpusc);
|
|
flg[j] = 1;
|
|
ndomains--;
|
|
goto restart;
|
|
}
|
|
}
|
|
}
|
|
|
|
domains = malloc(ndomains * sizeof(*domains));
|
|
if (domains == NULL) {
|
|
warnx("alloc domains space failed.");
|
|
ret = -1;
|
|
goto errdomains;
|
|
}
|
|
|
|
for (i = 0, j = 0; i < ncpusets; i++) {
|
|
if (flg[i])
|
|
continue;
|
|
domains[j] = bitmask_alloc(cpus_nbits);
|
|
if (cpuset_getcpus(cpusets[i], domains[j])) {
|
|
warnx("cpuset getcpus failed.");
|
|
ret = -1;
|
|
goto errgetdomains;
|
|
}
|
|
j++;
|
|
}
|
|
goto errdomains;
|
|
|
|
errgetdomains:
|
|
for (i = 0; i < j; i++)
|
|
bitmask_free(domains[i]);
|
|
free(domains);
|
|
domains = NULL;
|
|
errdomains:
|
|
free(flg);
|
|
errfindcpusets:
|
|
for (i = 0; i < ncpusets; i++)
|
|
cpuset_free(cpusets[i]);
|
|
free(cpusets);
|
|
cpusets = NULL;
|
|
ncpusets = 0;
|
|
errcpusets:
|
|
bitmask_free(cpusc);
|
|
errcpusc:
|
|
bitmask_free(cpusb);
|
|
errcpusb:
|
|
bitmask_free(cpusa);
|
|
return ret;
|
|
}
|
|
|
|
#endif
|