Back to index

numactl  2.0.8~rc4
distance.c
Go to the documentation of this file.
00001 /* Discover distances
00002    Copyright (C) 2005 Andi Kleen, SuSE Labs.
00003 
00004    libnuma is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; version
00007    2.1.
00008 
00009    libnuma is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should find a copy of v2.1 of the GNU Lesser General Public License
00015    somewhere on your Linux system; if not, write to the Free Software
00016    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00017 
00018    All calls are undefined when numa_available returns an error. */
00019 #define _GNU_SOURCE 1
00020 #include <stdio.h>
00021 #include <stdlib.h>
00022 #include <errno.h>
00023 #include "numa.h"
00024 #include "numaint.h"
00025 
00026 static int distance_numnodes;
00027 static int *distance_table;
00028 
00029 static void parse_numbers(char *s, int *iptr)
00030 {
00031        int i, d, j;
00032        char *end;
00033        int maxnode = numa_max_node();
00034        int numnodes = 0;
00035 
00036        for (i = 0; i <= maxnode; i++)
00037               if (numa_bitmask_isbitset(numa_nodes_ptr, i))
00038                      numnodes++;
00039 
00040        for (i = 0, j = 0; i <= maxnode; i++, j++) {
00041               d = strtoul(s, &end, 0);
00042               /* Skip unavailable nodes */
00043               while (j<=maxnode && !numa_bitmask_isbitset(numa_nodes_ptr, j))
00044                      j++;
00045               *(iptr+j) = d;
00046               if (s == end)
00047                      break;
00048               s = end;
00049        }
00050 }
00051 
00052 static int read_distance_table(void)
00053 {
00054        int nd, len;
00055        char *line = NULL;
00056        size_t linelen = 0;
00057        int maxnode = numa_max_node() + 1;
00058        int *table = NULL;
00059        int err = -1;
00060 
00061        for (nd = 0;; nd++) {
00062               char fn[100];
00063               FILE *dfh;
00064               sprintf(fn, "/sys/devices/system/node/node%d/distance", nd);
00065               dfh = fopen(fn, "r");
00066               if (!dfh) {
00067                      if (errno == ENOENT && nd > 0)
00068                             err = 0;
00069                      if (!err && nd<maxnode)
00070                             continue;
00071                      else
00072                             break;
00073               }
00074               len = getdelim(&line, &linelen, '\n', dfh);
00075               fclose(dfh);
00076               if (len <= 0)
00077                      break;
00078 
00079               if (!table) {
00080                      table = calloc(maxnode * maxnode, sizeof(int));
00081                      if (!table) {
00082                             errno = ENOMEM;
00083                             break;
00084                      }
00085               }
00086 
00087               parse_numbers(line, table + nd * maxnode);
00088        }
00089        free(line);
00090        if (err)  {
00091               numa_warn(W_distance,
00092                        "Cannot parse distance information in sysfs: %s",
00093                        strerror(errno));
00094               free(table);
00095               return err;
00096        }
00097        /* Update the global table pointer.  Race window here with
00098           other threads, but in the worst case we leak one distance
00099           array one time, which is tolerable. This avoids a
00100           dependency on pthreads. */
00101        if (distance_table) {
00102               free(table);
00103               return 0;
00104        }
00105        distance_numnodes = maxnode;
00106        distance_table = table;
00107        return 0;            
00108 }
00109 
00110 int numa_distance(int a, int b)
00111 {
00112        if (!distance_table) {
00113               int err = read_distance_table();
00114               if (err < 0)
00115                      return 0;
00116        }
00117        return distance_table[a * distance_numnodes + b];
00118 }