diff options
Diffstat (limited to 'library/numa.c')
-rw-r--r-- | library/numa.c | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/library/numa.c b/library/numa.c new file mode 100644 index 0000000..3fca413 --- /dev/null +++ b/library/numa.c @@ -0,0 +1,114 @@ +/* + * NUMA node support for <PIDS> & <STAT> interfaces + * + * Copyright © 2017-2023 Jim Warner <james.warner@comcast.net> + * + * This library 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef NUMA_DISABLE +#include <dlfcn.h> +#endif +#include <stdlib.h> + +#include "numa.h" + +/* + * We're structured so that if numa_init() is NOT called or that ./configure | + * --disable-numa WAS specified, then calls to both of our primary functions | + * of numa_max_node() plus numa_node_of_cpu() would always return a negative | + * 1 which signifies that NUMA information isn't available. That ./configure | + * option might be required when libdl.so (necessary for dlopen) is missing. | + */ + + +/* ------------------------------------------------------------------------- + + a strictly development #define, existing specifically for the top program | + ( and it has no affect if ./configure --disable-numa has been specified ) | */ +//#define PRETEND_NUMA // pretend there are 3 'discontiguous' numa nodes | +// ------------------------------------------------------------------------- + + + +static int null_max_node (void) { return -1; } +static int null_node_of_cpu (int n) { (void)n; return -1; } + + +#ifndef NUMA_DISABLE + #ifdef PRETEND_NUMA +static int fake_max_node (void) { return 3; } +static int fake_node_of_cpu (int n) { return (1 == (n % 4)) ? 0 : (n % 4); } + #endif +#endif + + +#ifndef NUMA_DISABLE +static void *libnuma_handle; +#endif +int (*numa_max_node) (void) = null_max_node; +int (*numa_node_of_cpu) (int) = null_node_of_cpu; + + +void numa_init (void) { + static int initialized; + + if (initialized) + return; + +#ifndef NUMA_DISABLE + #ifndef PRETEND_NUMA + // we'll try for the most recent version, then a version we know works... + if ((libnuma_handle = dlopen("libnuma.so", RTLD_LAZY)) + || (libnuma_handle = dlopen("libnuma.so.1", RTLD_LAZY))) { + numa_max_node = dlsym(libnuma_handle, "numa_max_node"); + numa_node_of_cpu = dlsym(libnuma_handle, "numa_node_of_cpu"); + if (numa_max_node == NULL + || (numa_node_of_cpu == NULL)) { + // this dlclose is safe - we've yet to call numa_node_of_cpu + // ( there's one other dlclose which has now been disabled ) + dlclose(libnuma_handle); + libnuma_handle = NULL; + numa_max_node = null_max_node; + numa_node_of_cpu = null_node_of_cpu; + } + } + #else + libnuma_handle = (void *)-1; + numa_max_node = fake_max_node; + numa_node_of_cpu = fake_node_of_cpu; + #endif +#endif + initialized = 1; +} // end: numa_init + + +void numa_uninit (void) { +#ifndef PRETEND_NUMA + /* note: we'll skip a dlcose() to avoid the following libnuma memory + * leak which is triggered after a call to numa_node_of_cpu(): + * ==1234== LEAK SUMMARY: + * ==1234== definitely lost: 512 bytes in 1 blocks + * ==1234== indirectly lost: 48 bytes in 2 blocks + * ==1234== ... + * [ thanks very much libnuma for all the pains you have caused us ] + */ +// if (libnuma_handle) +// dlclose(libnuma_handle); +#endif +} // end: numa_uninit + + +#if defined(PRETEND_NUMA) && defined(NUMA_DISABLE) +# warning 'PRETEND_NUMA' ignored, 'NUMA_DISABLE' is active +#endif |