forked from numactl/numactl
-
Notifications
You must be signed in to change notification settings - Fork 1
/
distance.c
120 lines (107 loc) · 2.83 KB
/
distance.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/* 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) || (!distance_table))
return 0;
}
if ((unsigned)a >= distance_numnodes || (unsigned)b >= distance_numnodes)
return 0;
return distance_table[a * distance_numnodes + b];
}