mirror of https://gitee.com/openkylin/numactl.git
121 lines
2.8 KiB
C
121 lines
2.8 KiB
C
/* Discover distances
|
|
Copyright (C) 2005 Andi Kleen, SuSE Labs.
|
|
|
|
libnuma is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; version
|
|
2.1.
|
|
|
|
libnuma is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should find a copy of v2.1 of the GNU Lesser General Public License
|
|
somewhere on your Linux system; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
All calls are undefined when numa_available returns an error. */
|
|
#define _GNU_SOURCE 1
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include "numa.h"
|
|
#include "numaint.h"
|
|
|
|
static int distance_numnodes;
|
|
static int *distance_table;
|
|
|
|
static void parse_numbers(char *s, int *iptr)
|
|
{
|
|
int i, d, j;
|
|
char *end;
|
|
int maxnode = numa_max_node();
|
|
int numnodes = 0;
|
|
|
|
for (i = 0; i <= maxnode; i++)
|
|
if (numa_bitmask_isbitset(numa_nodes_ptr, i))
|
|
numnodes++;
|
|
|
|
for (i = 0, j = 0; i <= maxnode; i++, j++) {
|
|
d = strtoul(s, &end, 0);
|
|
/* Skip unavailable nodes */
|
|
while (j<=maxnode && !numa_bitmask_isbitset(numa_nodes_ptr, j))
|
|
j++;
|
|
if (s == end)
|
|
break;
|
|
*(iptr+j) = d;
|
|
s = end;
|
|
}
|
|
}
|
|
|
|
static int read_distance_table(void)
|
|
{
|
|
int nd, len;
|
|
char *line = NULL;
|
|
size_t linelen = 0;
|
|
int maxnode = numa_max_node() + 1;
|
|
int *table = NULL;
|
|
int err = -1;
|
|
|
|
for (nd = 0;; nd++) {
|
|
char fn[100];
|
|
FILE *dfh;
|
|
sprintf(fn, "/sys/devices/system/node/node%d/distance", nd);
|
|
dfh = fopen(fn, "r");
|
|
if (!dfh) {
|
|
if (errno == ENOENT)
|
|
err = 0;
|
|
if (!err && nd<maxnode)
|
|
continue;
|
|
else
|
|
break;
|
|
}
|
|
len = getdelim(&line, &linelen, '\n', dfh);
|
|
fclose(dfh);
|
|
if (len <= 0)
|
|
break;
|
|
|
|
if (!table) {
|
|
table = calloc(maxnode * maxnode, sizeof(int));
|
|
if (!table) {
|
|
errno = ENOMEM;
|
|
break;
|
|
}
|
|
}
|
|
|
|
parse_numbers(line, table + nd * maxnode);
|
|
}
|
|
free(line);
|
|
if (err) {
|
|
numa_warn(W_distance,
|
|
"Cannot parse distance information in sysfs: %s",
|
|
strerror(errno));
|
|
free(table);
|
|
return err;
|
|
}
|
|
/* Update the global table pointer. Race window here with
|
|
other threads, but in the worst case we leak one distance
|
|
array one time, which is tolerable. This avoids a
|
|
dependency on pthreads. */
|
|
if (distance_table) {
|
|
free(table);
|
|
return 0;
|
|
}
|
|
distance_numnodes = maxnode;
|
|
distance_table = table;
|
|
return 0;
|
|
}
|
|
|
|
int numa_distance(int a, int b)
|
|
{
|
|
if (!distance_table) {
|
|
int err = read_distance_table();
|
|
if (err < 0)
|
|
return 0;
|
|
}
|
|
if ((unsigned)a >= distance_numnodes || (unsigned)b >= distance_numnodes)
|
|
return 0;
|
|
return distance_table[a * distance_numnodes + b];
|
|
}
|