Import Upstream version 2.0.12

This commit is contained in:
Lu zhiping 2022-06-27 15:01:33 +08:00
commit 43ff68b8ba
86 changed files with 55574 additions and 0 deletions

72
INSTALL.md Normal file
View File

@ -0,0 +1,72 @@
## Building `numactl`
TL;DR:
```shell
$ ./configure
$ make
# make install
```
Start by configuring the build running the configure script:
```shell
$ ./configure
```
You can pass options to configure to define build options, to pass it
compiler paths, compiler flags and to define the installation layout. Run
`./configure --help` for more details on how to customize the build.
Once build is completed, build `numactl` with:
```shell
$ make
```
If you would like to increase verbosity by printing the full build command
lines, pass `make` the `V=1` parameter:
```shell
$ make V=1
```
You can build and run the tests included with numactl with the following
command:
```shell
$ make check
```
The results will be saved in `test/*.log` files and a `test-suite.log` will be
generated with the summary of test passes and failures.
Install numactl to the system by running the following command as root:
```shell
# make install
```
You can also install it to a staging directory, in which case it is not
required to be root while running the install steps. Just pass a DESTDIR
variable while running `make install` with the path to the staging
directory.
```shell
$ make install DESTDIR=/path/to/staging/numactl
```
## Using a snapshot from the Git repository
First, the build system files need to be generated using the `./autogen.sh`
script, which calls `autoreconf` with the appropriate options to generate the
configure script and the templates for `Makefile`, `config.h`, etc.
Once those files are generated, follow the normal steps to configure and
build numactl.
In order to create a distribution tarball, use `make dist` from a configured
build tree. Use `make distcheck` to build a distribution tarball and confirm
that rebuilding from that archive works as expected, that building from
out-of-tree works, that test cases pass.

161
Makefile.am Normal file
View File

@ -0,0 +1,161 @@
ACLOCAL_AMFLAGS = -I m4
CLEANFILES =
AM_CPPFLAGS = -Wall
bin_PROGRAMS = numactl numastat numademo migratepages migspeed memhog
lib_LTLIBRARIES = libnuma.la
include_HEADERS = numa.h numacompat1.h numaif.h
noinst_HEADERS = numaint.h util.h
dist_man_MANS = move_pages.2 numa.3 numactl.8 numastat.8 migratepages.8 migspeed.8
EXTRA_DIST = README.md INSTALL.md
numactl_SOURCES = numactl.c util.c shm.c shm.h
numactl_LDADD = libnuma.la
numastat_SOURCES = numastat.c
numastat_CFLAGS = $(AM_CFLAGS) -std=gnu99
numademo_SOURCES = numademo.c stream_lib.c stream_lib.h mt.c mt.h clearcache.c clearcache.h
numademo_CPPFLAGS = $(AM_CPPFLAGS) -DHAVE_STREAM_LIB -DHAVE_MT -DHAVE_CLEAR_CACHE
numademo_CFLAGS = -O3 -ffast-math -funroll-loops
if HAVE_TREE_VECTORIZE
numademo_CFLAGS += -ftree-vectorize
endif
numademo_LDADD = libnuma.la -lm
migratepages_SOURCES = migratepages.c util.c
migratepages_LDADD = libnuma.la
migspeed_SOURCES = migspeed.c util.c
migspeed_LDADD = libnuma.la -lrt
memhog_SOURCES = memhog.c util.c
memhog_LDADD = libnuma.la
libnuma_la_SOURCES = libnuma.c syscall.c distance.c affinity.c affinity.h sysfs.c sysfs.h rtnetlink.c rtnetlink.h versions.ldscript
libnuma_la_LDFLAGS = -version-info 1:0:0 -Wl,--version-script,$(srcdir)/versions.ldscript -Wl,-init,numa_init -Wl,-fini,numa_fini
check_PROGRAMS = \
test/distance \
test/ftok \
test/mbind_mig_pages \
test/migrate_pages \
test/move_pages \
test/mynode \
test/node-parse \
test/nodemap \
test/pagesize \
test/prefered \
test/randmap \
test/realloc_test \
test/tbitmap \
test/tshared
EXTRA_DIST += \
test/README \
test/bind_range \
test/checkaffinity \
test/checktopology \
test/numademo \
test/printcpu \
test/regress \
test/regress2 \
test/regress-io \
test/runltp \
test/shmtest
test_distance_SOURCES = test/distance.c
test_distance_LDADD = libnuma.la
test_ftok_SOURCES = test/ftok.c
test_ftok_LDADD = libnuma.la
test_mbind_mig_pages_SOURCES = test/mbind_mig_pages.c
test_mbind_mig_pages_LDADD = libnuma.la
test_migrate_pages_SOURCES = test/migrate_pages.c
test_migrate_pages_LDADD = libnuma.la
test_move_pages_SOURCES = test/move_pages.c
test_move_pages_LDADD = libnuma.la
test_mynode_SOURCES = test/mynode.c
test_mynode_LDADD = libnuma.la
test_node_parse_SOURCES = test/node-parse.c util.c
test_node_parse_LDADD = libnuma.la
test_nodemap_SOURCES = test/nodemap.c
test_nodemap_LDADD = libnuma.la
test_pagesize_SOURCES = test/pagesize.c
test_pagesize_LDADD = libnuma.la
test_prefered_SOURCES = test/prefered.c
test_prefered_LDADD = libnuma.la
test_randmap_SOURCES = test/randmap.c
test_randmap_LDADD = libnuma.la
test_realloc_test_SOURCES = test/realloc_test.c
test_realloc_test_LDADD = libnuma.la
test_tbitmap_SOURCES = test/tbitmap.c util.c
test_tbitmap_LDADD = libnuma.la
test_tshared_SOURCES = test/tshared.c
test_tshared_LDADD = libnuma.la
# Legacy make rules for test cases.
# These will be superceded by "make check".
regress1: $(check_PROGRAMS)
cd test && ./regress
regress2: $(check_PROGRAMS)
cd test && ./regress2
test_numademo: numademo
./numademo -t -e 10M
test: all $(check_PROGRAMS) regress1 regress2 test_numademo
TESTS_ENVIRONMENT = builddir='$(builddir)'; export builddir;
TESTS = \
test/bind_range \
test/checkaffinity \
test/checktopology \
test/distance \
test/nodemap \
test/numademo \
test/regress \
test/tbitmap
# These are known to be broken:
# test/prefered
# test/randmap
SED_PROCESS = \
$(AM_V_GEN)$(SED) \
-e 's,@VERSION\@,$(VERSION),g' \
-e 's,@prefix\@,$(prefix),g' \
-e 's,@exec_prefix\@,$(exec_prefix),g' \
-e 's,@libdir\@,$(libdir),g' \
-e 's,@includedir\@,$(includedir),g' \
< $< > $@ || rm $@
%.pc: %.pc.in Makefile
$(SED_PROCESS)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = numa.pc
EXTRA_DIST += numa.pc.in
CLEANFILES += numa.pc

1904
Makefile.in Normal file

File diff suppressed because it is too large Load Diff

48
README.md Normal file
View File

@ -0,0 +1,48 @@
# numactl
[![Build Status](https://travis-ci.org/numactl/numactl.svg?branch=master)](https://travis-ci.org/numactl/numactl)
Simple NUMA policy support. It consists of a numactl program to run other
programs with a specific NUMA policy and a libnuma shared library ("NUMA API")
to set NUMA policy in applications.
The libnuma binary interface is supposed to stay binary compatible.
Incompatible changes will use new symbol version numbers.
In addition there are various test and utility programs, like `numastat` to
display NUMA allocation statistics and `memhog`.
In `test/` there is a small regression test suite.
Note that `regress` assumes a unloaded machine with memory free on each node.
Otherwise you will get spurious failures in the non-strict policies (prefered,
interleave.)
See the manpages [`numactl.8`](https://linux.die.net/man/8/numactl) and
[`numa.3`](https://linux.die.net/man/3/numa) for details.
# License, Copyrights, Acknowledgements
`numactl` and the demo programs are under the GNU General Public License, v.2.
`libnuma` is under the GNU Lesser General Public License, v2.1.
The manpages are under the same license as the Linux manpages (see the files.)
`numademo` links with a library derived from the C version of STREAM by John D.
McCalpin and Joe R. Zagar for one sub benchmark. See `stream_lib.c` for the
license. In particular when you publish `numademo` output you might need to pay
attention there or filter out the STREAM results.
It also uses a public domain Mersenne Twister implementation from Michael
Brundage.
Version 2.0.10-rc2: (C)2014 SGI
Author:
Andi Kleen, SUSE Labs
Version 2.0.0 by Cliff Wickman (`cpw@sgi.com`), Christoph Lameter
(`clameter@sgi.com`) and Lee Schermerhorn (`lee.schermerhorn@hp.com`).

1160
aclocal.m4 vendored Normal file

File diff suppressed because it is too large Load Diff

347
affinity.c Normal file
View File

@ -0,0 +1,347 @@
/* Support for specifying IO affinity by various means.
Copyright 2010 Intel Corporation
Author: Andi Kleen
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 */
/* Notebook:
- Separate real errors from no NUMA with fallback
- Infiniband
- FCoE?
- Support for other special IO devices
- Specifying cpu subsets inside the IO node?
- Handle multiple IO nodes (needs kernel changes)
- Better support for multi-path IO?
*/
#define _GNU_SOURCE 1
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <dirent.h>
#include <linux/rtnetlink.h>
#include <linux/netlink.h>
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <ctype.h>
#include <assert.h>
#include <regex.h>
#include <sys/sysmacros.h>
#include "numa.h"
#include "numaint.h"
#include "sysfs.h"
#include "affinity.h"
#include "rtnetlink.h"
static int badchar(const char *s)
{
if (strpbrk(s, "/."))
return 1;
return 0;
}
static int node_parse_failure(int ret, char *cls, const char *dev)
{
if (!cls)
cls = "";
if (ret == -2)
numa_warn(W_node_parse1,
"Kernel does not know node mask for%s%s device `%s'",
*cls ? " " : "", cls, dev);
else
numa_warn(W_node_parse2,
"Cannot read node mask for %s device `%s'",
cls, dev);
return -1;
}
/* Generic sysfs class lookup */
static int
affinity_class(struct bitmask *mask, char *cls, const char *dev)
{
int ret;
while (isspace(*dev))
dev++;
if (badchar(dev)) {
numa_warn(W_badchar, "Illegal characters in `%s' specification",
dev);
return -1;
}
/* Somewhat hackish: extract device from symlink path.
Better would be a direct backlink. This knows slightly too
much about the actual sysfs layout. */
char path[1024];
char *fn = NULL;
if (asprintf(&fn, "/sys/class/%s/%s", cls, dev) > 0 &&
readlink(fn, path, sizeof path) > 0) {
regex_t re;
regmatch_t match[2];
char *p;
regcomp(&re, "(/devices/pci[0-9a-fA-F:/]+\\.[0-9]+)/",
REG_EXTENDED);
ret = regexec(&re, path, 2, match, 0);
regfree(&re);
if (ret == 0) {
free(fn);
assert(match[0].rm_so > 0);
assert(match[0].rm_eo > 0);
path[match[1].rm_eo + 1] = 0;
p = path + match[0].rm_so;
ret = sysfs_node_read(mask, "/sys/%s/numa_node", p);
if (ret < 0)
return node_parse_failure(ret, NULL, p);
return ret;
}
}
free(fn);
ret = sysfs_node_read(mask, "/sys/class/%s/%s/device/numa_node",
cls, dev);
if (ret < 0)
return node_parse_failure(ret, cls, dev);
return 0;
}
/* Turn file (or device node) into class name */
static int affinity_file(struct bitmask *mask, char *cls, const char *file)
{
struct stat st;
DIR *dir;
int n;
unsigned maj = 0, min = 0;
dev_t d;
struct dirent *dep;
cls = "block";
char fn[sizeof("/sys/class/") + strlen(cls)];
if (stat(file, &st) < 0) {
numa_warn(W_blockdev1, "Cannot stat file %s", file);
return -1;
}
d = st.st_dev;
if (S_ISCHR(st.st_mode)) {
/* Better choice than misc? Most likely misc will not work
anyways unless the kernel is fixed. */
cls = "misc";
d = st.st_rdev;
} else if (S_ISBLK(st.st_mode))
d = st.st_rdev;
sprintf(fn, "/sys/class/%s", cls);
dir = opendir(fn);
if (!dir) {
numa_warn(W_blockdev2, "Cannot enumerate %s devices in sysfs",
cls);
return -1;
}
while ((dep = readdir(dir)) != NULL) {
char *name = dep->d_name;
int ret;
if (*name == '.')
continue;
char *dev;
char fn2[sizeof("/sys/class/block//dev") + strlen(name)];
n = -1;
if (sprintf(fn2, "/sys/class/block/%s/dev", name) < 0)
break;
dev = sysfs_read(fn2);
if (dev) {
n = sscanf(dev, "%u:%u", &maj, &min);
free(dev);
}
if (n != 2) {
numa_warn(W_blockdev3, "Cannot parse sysfs device %s",
name);
continue;
}
if (major(d) != maj || minor(d) != min)
continue;
ret = affinity_class(mask, "block", name);
closedir(dir);
return ret;
}
closedir(dir);
numa_warn(W_blockdev5, "Cannot find block device %x:%x in sysfs for `%s'",
maj, min, file);
return -1;
}
/* Look up interface of route using rtnetlink. */
static int find_route(struct sockaddr *dst, int *iifp)
{
struct rtattr *rta;
const int hdrlen = NLMSG_LENGTH(sizeof(struct rtmsg));
struct {
struct nlmsghdr msg;
struct rtmsg rt;
char buf[256];
} req = {
.msg = {
.nlmsg_len = hdrlen,
.nlmsg_type = RTM_GETROUTE,
.nlmsg_flags = NLM_F_REQUEST,
},
.rt = {
.rtm_family = dst->sa_family,
},
};
struct sockaddr_nl adr = {
.nl_family = AF_NETLINK,
};
if (rta_put_address(&req.msg, RTA_DST, dst) < 0) {
numa_warn(W_netlink1, "Cannot handle network family %x",
dst->sa_family);
return -1;
}
if (rtnetlink_request(&req.msg, sizeof req, &adr) < 0) {
numa_warn(W_netlink2, "Cannot request rtnetlink route: %s",
strerror(errno));
return -1;
}
/* Fish the interface out of the netlink soup. */
rta = NULL;
while ((rta = rta_get(&req.msg, rta, hdrlen)) != NULL) {
if (rta->rta_type == RTA_OIF) {
memcpy(iifp, RTA_DATA(rta), sizeof(int));
return 0;
}
}
numa_warn(W_netlink3, "rtnetlink query did not return interface");
return -1;
}
static int iif_to_name(int iif, struct ifreq *ifr)
{
int n;
int sk = socket(PF_INET, SOCK_DGRAM, 0);
if (sk < 0)
return -1;
ifr->ifr_ifindex = iif;
n = ioctl(sk, SIOCGIFNAME, ifr);
close(sk);
return n;
}
/* Resolve an IP address to the nodes of a network device.
This generally only attempts to handle simple cases:
no multi-path, no bounding etc. In these cases only
the first interface or none is chosen. */
static int affinity_ip(struct bitmask *mask, char *cls, const char *id)
{
struct addrinfo *ai;
int n;
int iif;
struct ifreq ifr;
if ((n = getaddrinfo(id, NULL, NULL, &ai)) != 0) {
numa_warn(W_net1, "Cannot resolve %s: %s",
id, gai_strerror(n));
return -1;
}
if (find_route(&ai->ai_addr[0], &iif) < 0)
goto out_ai;
if (iif_to_name(iif, &ifr) < 0) {
numa_warn(W_net2, "Cannot resolve network interface %d", iif);
goto out_ai;
}
freeaddrinfo(ai);
return affinity_class(mask, "net", ifr.ifr_name);
out_ai:
freeaddrinfo(ai);
return -1;
}
/* Look up affinity for a PCI device */
static int affinity_pci(struct bitmask *mask, char *cls, const char *id)
{
unsigned seg, bus, dev, func;
int n, ret;
/* Func is optional. */
if ((n = sscanf(id, "%x:%x:%x.%x",&seg,&bus,&dev,&func)) == 4 || n == 3) {
if (n == 3)
func = 0;
}
/* Segment is optional too */
else if ((n = sscanf(id, "%x:%x.%x",&bus,&dev,&func)) == 3 || n == 2) {
seg = 0;
if (n == 2)
func = 0;
} else {
numa_warn(W_pci1, "Cannot parse PCI device `%s'", id);
return -1;
}
ret = sysfs_node_read(mask,
"/sys/devices/pci%04x:%02x/%04x:%02x:%02x.%x/numa_node",
seg, bus, seg, bus, dev, func);
if (ret < 0)
return node_parse_failure(ret, cls, id);
return 0;
}
static struct handler {
char first;
char *name;
char *cls;
int (*handler)(struct bitmask *mask, char *cls, const char *desc);
} handlers[] = {
{ 'n', "netdev:", "net", affinity_class },
{ 'i', "ip:", NULL, affinity_ip },
{ 'f', "file:", NULL, affinity_file },
{ 'b', "block:", "block", affinity_class },
{ 'p', "pci:", NULL, affinity_pci },
{}
};
hidden int resolve_affinity(const char *id, struct bitmask *mask)
{
struct handler *h;
for (h = &handlers[0]; h->first; h++) {
int len;
if (id[0] != h->first)
continue;
len = strlen(h->name);
if (!strncmp(id, h->name, len)) {
int ret = h->handler(mask, h->cls, id + len);
if (ret == -2) {
numa_warn(W_nonode, "Kernel does not know node for %s\n",
id + len);
}
return ret;
}
}
return NO_IO_AFFINITY;
}

5
affinity.h Normal file
View File

@ -0,0 +1,5 @@
enum {
NO_IO_AFFINITY = -2
};
int resolve_affinity(const char *id, struct bitmask *mask);

347
build-aux/compile Executable file
View File

@ -0,0 +1,347 @@
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
scriptversion=2012-10-14.11; # UTC
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
nl='
'
# We need space, tab and new line, in precisely that order. Quoting is
# there to prevent tools from complaining about whitespace usage.
IFS=" "" $nl"
file_conv=
# func_file_conv build_file lazy
# Convert a $build file to $host form and store it in $file
# Currently only supports Windows hosts. If the determined conversion
# type is listed in (the comma separated) LAZY, no conversion will
# take place.
func_file_conv ()
{
file=$1
case $file in
/ | /[!/]*) # absolute file, and not a UNC file
if test -z "$file_conv"; then
# lazily determine how to convert abs files
case `uname -s` in
MINGW*)
file_conv=mingw
;;
CYGWIN*)
file_conv=cygwin
;;
*)
file_conv=wine
;;
esac
fi
case $file_conv/,$2, in
*,$file_conv,*)
;;
mingw/*)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin/*)
file=`cygpath -m "$file" || echo "$file"`
;;
wine/*)
file=`winepath -w "$file" || echo "$file"`
;;
esac
;;
esac
}
# func_cl_dashL linkdir
# Make cl look for libraries in LINKDIR
func_cl_dashL ()
{
func_file_conv "$1"
if test -z "$lib_path"; then
lib_path=$file
else
lib_path="$lib_path;$file"
fi
linker_opts="$linker_opts -LIBPATH:$file"
}
# func_cl_dashl library
# Do a library search-path lookup for cl
func_cl_dashl ()
{
lib=$1
found=no
save_IFS=$IFS
IFS=';'
for dir in $lib_path $LIB
do
IFS=$save_IFS
if $shared && test -f "$dir/$lib.dll.lib"; then
found=yes
lib=$dir/$lib.dll.lib
break
fi
if test -f "$dir/$lib.lib"; then
found=yes
lib=$dir/$lib.lib
break
fi
if test -f "$dir/lib$lib.a"; then
found=yes
lib=$dir/lib$lib.a
break
fi
done
IFS=$save_IFS
if test "$found" != yes; then
lib=$lib.lib
fi
}
# func_cl_wrapper cl arg...
# Adjust compile command to suit cl
func_cl_wrapper ()
{
# Assume a capable shell
lib_path=
shared=:
linker_opts=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
eat=1
case $2 in
*.o | *.[oO][bB][jJ])
func_file_conv "$2"
set x "$@" -Fo"$file"
shift
;;
*)
func_file_conv "$2"
set x "$@" -Fe"$file"
shift
;;
esac
;;
-I)
eat=1
func_file_conv "$2" mingw
set x "$@" -I"$file"
shift
;;
-I*)
func_file_conv "${1#-I}" mingw
set x "$@" -I"$file"
shift
;;
-l)
eat=1
func_cl_dashl "$2"
set x "$@" "$lib"
shift
;;
-l*)
func_cl_dashl "${1#-l}"
set x "$@" "$lib"
shift
;;
-L)
eat=1
func_cl_dashL "$2"
;;
-L*)
func_cl_dashL "${1#-L}"
;;
-static)
shared=false
;;
-Wl,*)
arg=${1#-Wl,}
save_ifs="$IFS"; IFS=','
for flag in $arg; do
IFS="$save_ifs"
linker_opts="$linker_opts $flag"
done
IFS="$save_ifs"
;;
-Xlinker)
eat=1
linker_opts="$linker_opts $2"
;;
-*)
set x "$@" "$1"
shift
;;
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
func_file_conv "$1"
set x "$@" -Tp"$file"
shift
;;
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
func_file_conv "$1" mingw
set x "$@" "$file"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -n "$linker_opts"; then
linker_opts="-link$linker_opts"
fi
exec "$@" $linker_opts
exit 1
}
eat=
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: compile [--help] [--version] PROGRAM [ARGS]
Wrapper for compilers which do not understand '-c -o'.
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
arguments, and rename the output as expected.
If you are trying to build a whole package this is not the
right script to run: please start by reading the file 'INSTALL'.
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "compile $scriptversion"
exit $?
;;
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
func_cl_wrapper "$@" # Doesn't return...
;;
esac
ofile=
cfile=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
# So we strip '-o arg' only if arg is an object.
eat=1
case $2 in
*.o | *.obj)
ofile=$2
;;
*)
set x "$@" -o "$2"
shift
;;
esac
;;
*.c)
cfile=$1
set x "$@" "$1"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -z "$ofile" || test -z "$cfile"; then
# If no '-o' option was seen then we might have been invoked from a
# pattern rule where we don't need one. That is ok -- this is a
# normal compilation that the losing compiler can handle. If no
# '.c' file was seen then we are probably linking. That is also
# ok.
exec "$@"
fi
# Name of file we expect compiler to create.
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
# Create the lock directory.
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
# that we are using for the .o file. Also, base the name on the expected
# object file name, since that is what matters with a parallel build.
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
while true; do
if mkdir "$lockdir" >/dev/null 2>&1; then
break
fi
sleep 1
done
# FIXME: race condition here if user kills between mkdir and trap.
trap "rmdir '$lockdir'; exit 1" 1 2 15
# Run the compile.
"$@"
ret=$?
if test -f "$cofile"; then
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
elif test -f "${cofile}bj"; then
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
fi
rmdir "$lockdir"
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

1463
build-aux/config.guess vendored Executable file

File diff suppressed because it is too large Load Diff

1848
build-aux/config.sub vendored Executable file

File diff suppressed because it is too large Load Diff

791
build-aux/depcomp Executable file
View File

@ -0,0 +1,791 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2016-01-11.22; # UTC
# Copyright (C) 1999-2017 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program 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 General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by 'PROGRAMS ARGS'.
object Object file output by 'PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputting dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "depcomp $scriptversion"
exit $?
;;
esac
# Get the directory component of the given path, and save it in the
# global variables '$dir'. Note that this directory component will
# be either empty or ending with a '/' character. This is deliberate.
set_dir_from ()
{
case $1 in
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
*) dir=;;
esac
}
# Get the suffix-stripped basename of the given path, and save it the
# global variable '$base'.
set_base_from ()
{
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
}
# If no dependency file was actually created by the compiler invocation,
# we still have to create a dummy depfile, to avoid errors with the
# Makefile "include basename.Plo" scheme.
make_dummy_depfile ()
{
echo "#dummy" > "$depfile"
}
# Factor out some common post-processing of the generated depfile.
# Requires the auxiliary global variable '$tmpdepfile' to be set.
aix_post_process_depfile ()
{
# If the compiler actually managed to produce a dependency file,
# post-process it.
if test -f "$tmpdepfile"; then
# Each line is of the form 'foo.o: dependency.h'.
# Do two passes, one to just change these to
# $object: dependency.h
# and one to simply output
# dependency.h:
# which is needed to avoid the deleted-header problem.
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
} > "$depfile"
rm -f "$tmpdepfile"
else
make_dummy_depfile
fi
}
# A tabulation character.
tab=' '
# A newline character.
nl='
'
# Character ranges might be problematic outside the C locale.
# These definitions help.
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
lower=abcdefghijklmnopqrstuvwxyz
digits=0123456789
alpha=${upper}${lower}
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Avoid interferences from the environment.
gccflag= dashmflag=
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
cygpath_u="cygpath -u -f -"
if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvisualcpp
fi
if test "$depmode" = msvc7msys; then
# This is just like msvc7 but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvc7
fi
if test "$depmode" = xlc; then
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
gccflag=-qmakedep=gcc,-MF
depmode=gcc
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
## the command line argument order; so add the flags where they
## appear in depend2.am. Note that the slowdown incurred here
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
for arg
do
case $arg in
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
*) set fnord "$@" "$arg" ;;
esac
shift # fnord
shift # $arg
done
"$@"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
## (see the conditional assignment to $gccflag above).
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say). Also, it might not be
## supported by the other compilers which use the 'gcc' depmode.
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The second -e expression handles DOS-style file names with drive
# letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the "deleted header file" problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
## Some versions of gcc put a space before the ':'. On the theory
## that the space means something, we add a space to the output as
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like '#:fec' to the end of the
# dependency line.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
| tr "$nl" ' ' >> "$depfile"
echo >> "$depfile"
# The second pass generates a dummy entry for each header file.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile"
;;
xlc)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts '$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.u
tmpdepfile2=$base.u
tmpdepfile3=$dir.libs/$base.u
"$@" -Wc,-M
else
tmpdepfile1=$dir$base.u
tmpdepfile2=$dir$base.u
tmpdepfile3=$dir$base.u
"$@" -M
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
aix_post_process_depfile
;;
tcc)
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
# FIXME: That version still under development at the moment of writing.
# Make that this statement remains true also for stable, released
# versions.
# It will wrap lines (doesn't matter whether long or short) with a
# trailing '\', as in:
#
# foo.o : \
# foo.c \
# foo.h \
#
# It will put a trailing '\' even on the last line, and will use leading
# spaces rather than leading tabs (at least since its commit 0394caf7
# "Emit spaces for -MD").
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
# We have to change lines of the first kind to '$object: \'.
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
# And for each line of the second kind, we have to emit a 'dep.h:'
# dummy dependency, to avoid the deleted-header problem.
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
rm -f "$tmpdepfile"
;;
## The order of this option in the case statement is important, since the
## shell code in configure will try each of these formats in the order
## listed in this file. A plain '-MD' option would be understood by many
## compilers, so we must ensure this comes after the gcc and icc options.
pgcc)
# Portland's C compiler understands '-MD'.
# Will always output deps to 'file.d' where file is the root name of the
# source file under compilation, even if file resides in a subdirectory.
# The object file name does not affect the name of the '.d' file.
# pgcc 10.2 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using '\' :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
set_dir_from "$object"
# Use the source, not the object, to determine the base name, since
# that's sadly what pgcc will do too.
set_base_from "$source"
tmpdepfile=$base.d
# For projects that build the same source file twice into different object
# files, the pgcc approach of using the *source* file root name can cause
# problems in parallel builds. Use a locking strategy to avoid stomping on
# the same $tmpdepfile.
lockdir=$base.d-lock
trap "
echo '$0: caught signal, cleaning up...' >&2
rmdir '$lockdir'
exit 1
" 1 2 13 15
numtries=100
i=$numtries
while test $i -gt 0; do
# mkdir is a portable test-and-set.
if mkdir "$lockdir" 2>/dev/null; then
# This process acquired the lock.
"$@" -MD
stat=$?
# Release the lock.
rmdir "$lockdir"
break
else
# If the lock is being held by a different process, wait
# until the winning process is done or we timeout.
while test -d "$lockdir" && test $i -gt 0; do
sleep 1
i=`expr $i - 1`
done
fi
i=`expr $i - 1`
done
trap - 1 2 13 15
if test $i -le 0; then
echo "$0: failed to acquire lock after $numtries attempts" >&2
echo "$0: check lockdir '$lockdir'" >&2
exit 1
fi
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp2)
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
# compilers, which have integrated preprocessors. The correct option
# to use with these is +Maked; it writes dependencies to a file named
# 'foo.d', which lands next to the object file, wherever that
# happens to be.
# Much of this is similar to the tru64 case; see comments there.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir.libs/$base.d
"$@" -Wc,+Maked
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
"$@" +Maked
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
# Add 'dependent.h:' lines.
sed -ne '2,${
s/^ *//
s/ \\*$//
s/$/:/
p
}' "$tmpdepfile" >> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile" "$tmpdepfile2"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in 'foo.d' instead, so we check for that too.
# Subdirectories are respected.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
# Libtool generates 2 separate objects for the 2 libraries. These
# two compilations output dependencies in $dir.libs/$base.o.d and
# in $dir$base.o.d. We have to check for both files, because
# one of the two compilations can be disabled. We should prefer
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
# automatically cleaned when .libs/ is deleted, while ignoring
# the former would cause a distcleancheck panic.
tmpdepfile1=$dir$base.o.d # libtool 1.5
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
"$@" -Wc,-MD
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
tmpdepfile3=$dir$base.d
"$@" -MD
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
# Same post-processing that is required for AIX mode.
aix_post_process_depfile
;;
msvc7)
if test "$libtool" = yes; then
showIncludes=-Wc,-showIncludes
else
showIncludes=-showIncludes
fi
"$@" $showIncludes > "$tmpdepfile"
stat=$?
grep -v '^Note: including file: ' "$tmpdepfile"
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The first sed program below extracts the file names and escapes
# backslashes for cygpath. The second sed program outputs the file
# name when reading, but also accumulates all include files in the
# hold buffer in order to output them again at the end. This only
# works with sed implementations that can handle large buffers.
sed < "$tmpdepfile" -n '
/^Note: including file: *\(.*\)/ {
s//\1/
s/\\/\\\\/g
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
s/\(.*\)/'"$tab"'\1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
s/.*/'"$tab"'/
G
p
}' >> "$depfile"
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
rm -f "$tmpdepfile"
;;
msvc7msys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for ':'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
"$@" $dashmflag |
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this sed invocation
# correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no eat=no
for arg
do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
if test $eat = yes; then
eat=no
continue
fi
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-arch)
eat=yes ;;
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix=`echo "$object" | sed 's/^.*\././'`
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process the last invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed '1,2d' "$tmpdepfile" \
| tr ' ' "$nl" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
"$@" -E \
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
| sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
IFS=" "
for arg
do
case "$arg" in
-o)
shift
;;
$object)
shift
;;
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
done
"$@" -E 2>/dev/null |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
echo "$tab" >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvcmsys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:

508
build-aux/install-sh Executable file
View File

@ -0,0 +1,508 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2014-09-12.12; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# 'make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
tab=' '
nl='
'
IFS=" $tab$nl"
# Set DOITPROG to "echo" to test this script.
doit=${DOITPROG-}
doit_exec=${doit:-exec}
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_mkdir=
# Desired mode of installed file.
mode=0755
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
stripcmd=
src=
dst=
dir_arg=
dst_arg=
copy_on_change=false
is_target_a_directory=possibly
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve the last data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
"
while test $# -ne 0; do
case $1 in
-c) ;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
-s) stripcmd=$stripprog;;
-t)
is_target_a_directory=always
dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) is_target_a_directory=never;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
# We allow the use of options -d and -T together, by making -d
# take the precedence; this is for compatibility with GNU install.
if test -n "$dir_arg"; then
if test -n "$dst_arg"; then
echo "$0: target directory not allowed when installing a directory." >&2
exit 1
fi
fi
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done
fi
if test $# -eq 0; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call 'install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
if test $# -gt 1 || test "$is_target_a_directory" = always; then
if test ! -d "$dst_arg"; then
echo "$0: $dst_arg: Is not a directory." >&2
exit 1
fi
fi
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
case $mode in
# Optimize common cases.
*644) cp_umask=133;;
*755) cp_umask=22;;
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
fi
for src
do
# Protect names problematic for 'test' and other utilities.
case $src in
-* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
dst=$src
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dst_arg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test "$is_target_a_directory" = never; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
dstdir=`dirname "$dst"`
test -d "$dstdir"
dstdir_status=$?
fi
fi
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
# $RANDOM is not portable (e.g. dash); use it when possible to
# lower collision chance
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
# As "mkdir -p" follows symlinks and we work in /tmp possibly; so
# create the $tmpdir first (and fail if unsuccessful) to make sure
# that nobody tries to guess the $tmpdir name.
if (umask $mkdir_umask &&
$mkdirprog $mkdir_mode "$tmpdir" &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
test_tmpdir="$tmpdir/a"
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# The umask is ridiculous, or mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
oIFS=$IFS
IFS=/
set -f
set fnord $dstdir
shift
set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
if test -n "$dir_arg"; then
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
else
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

11156
build-aux/ltmain.sh Normal file

File diff suppressed because it is too large Load Diff

215
build-aux/missing Executable file
View File

@ -0,0 +1,215 @@
#! /bin/sh
# Common wrapper for a few potentially missing GNU programs.
scriptversion=2013-10-28.13; # UTC
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program 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 General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try '$0 --help' for more information"
exit 1
fi
case $1 in
--is-lightweight)
# Used by our autoconf macros to check whether the available missing
# script is modern enough.
exit 0
;;
--run)
# Back-compat with the calling convention used by older automake.
shift
;;
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
to PROGRAM being missing or too old.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
Supported PROGRAM values:
aclocal autoconf autoheader autom4te automake makeinfo
bison yacc flex lex help2man
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
'g' are ignored when checking the name.
Send bug reports to <bug-automake@gnu.org>."
exit $?
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing $scriptversion (GNU Automake)"
exit $?
;;
-*)
echo 1>&2 "$0: unknown '$1' option"
echo 1>&2 "Try '$0 --help' for more information"
exit 1
;;
esac
# Run the given program, remember its exit status.
"$@"; st=$?
# If it succeeded, we are done.
test $st -eq 0 && exit 0
# Also exit now if we it failed (or wasn't found), and '--version' was
# passed; such an option is passed most likely to detect whether the
# program is present and works.
case $2 in --version|--help) exit $st;; esac
# Exit code 63 means version mismatch. This often happens when the user
# tries to use an ancient version of a tool on a file that requires a
# minimum version.
if test $st -eq 63; then
msg="probably too old"
elif test $st -eq 127; then
# Program was missing.
msg="missing on your system"
else
# Program was found and executed, but failed. Give up.
exit $st
fi
perl_URL=http://www.perl.org/
flex_URL=http://flex.sourceforge.net/
gnu_software_URL=http://www.gnu.org/software
program_details ()
{
case $1 in
aclocal|automake)
echo "The '$1' program is part of the GNU Automake package:"
echo "<$gnu_software_URL/automake>"
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
echo "<$gnu_software_URL/autoconf>"
echo "<$gnu_software_URL/m4/>"
echo "<$perl_URL>"
;;
autoconf|autom4te|autoheader)
echo "The '$1' program is part of the GNU Autoconf package:"
echo "<$gnu_software_URL/autoconf/>"
echo "It also requires GNU m4 and Perl in order to run:"
echo "<$gnu_software_URL/m4/>"
echo "<$perl_URL>"
;;
esac
}
give_advice ()
{
# Normalize program name to check for.
normalized_program=`echo "$1" | sed '
s/^gnu-//; t
s/^gnu//; t
s/^g//; t'`
printf '%s\n' "'$1' is $msg."
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
case $normalized_program in
autoconf*)
echo "You should only need it if you modified 'configure.ac',"
echo "or m4 files included by it."
program_details 'autoconf'
;;
autoheader*)
echo "You should only need it if you modified 'acconfig.h' or"
echo "$configure_deps."
program_details 'autoheader'
;;
automake*)
echo "You should only need it if you modified 'Makefile.am' or"
echo "$configure_deps."
program_details 'automake'
;;
aclocal*)
echo "You should only need it if you modified 'acinclude.m4' or"
echo "$configure_deps."
program_details 'aclocal'
;;
autom4te*)
echo "You might have modified some maintainer files that require"
echo "the 'autom4te' program to be rebuilt."
program_details 'autom4te'
;;
bison*|yacc*)
echo "You should only need it if you modified a '.y' file."
echo "You may want to install the GNU Bison package:"
echo "<$gnu_software_URL/bison/>"
;;
lex*|flex*)
echo "You should only need it if you modified a '.l' file."
echo "You may want to install the Fast Lexical Analyzer package:"
echo "<$flex_URL>"
;;
help2man*)
echo "You should only need it if you modified a dependency" \
"of a man page."
echo "You may want to install the GNU Help2man package:"
echo "<$gnu_software_URL/help2man/>"
;;
makeinfo*)
echo "You should only need it if you modified a '.texi' file, or"
echo "any other file indirectly affecting the aspect of the manual."
echo "You might want to install the Texinfo package:"
echo "<$gnu_software_URL/texinfo/>"
echo "The spurious makeinfo call might also be the consequence of"
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
echo "want to install GNU make:"
echo "<$gnu_software_URL/make/>"
;;
*)
echo "You might have modified some files without having the proper"
echo "tools for further handling them. Check the 'README' file, it"
echo "often tells you about the needed prerequisites for installing"
echo "this package. You may also peek at any GNU archive site, in"
echo "case some other package contains this missing '$1' program."
;;
esac
}
give_advice "$1" | sed -e '1s/^/WARNING: /' \
-e '2,$s/^/ /' >&2
# Propagate the correct exit status (expected to be 127 for a program
# not found, 63 for a program that failed due to version mismatch).
exit $st
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

148
build-aux/test-driver Executable file
View File

@ -0,0 +1,148 @@
#! /bin/sh
# test-driver - basic testsuite driver script.
scriptversion=2013-07-13.22; # UTC
# Copyright (C) 2011-2014 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
# Make unconditional expansion of undefined variables an error. This
# helps a lot in preventing typo-related bugs.
set -u
usage_error ()
{
echo "$0: $*" >&2
print_usage >&2
exit 2
}
print_usage ()
{
cat <<END
Usage:
test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
[--expect-failure={yes|no}] [--color-tests={yes|no}]
[--enable-hard-errors={yes|no}] [--]
TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
The '--test-name', '--log-file' and '--trs-file' options are mandatory.
END
}
test_name= # Used for reporting.
log_file= # Where to save the output of the test script.
trs_file= # Where to save the metadata of the test run.
expect_failure=no
color_tests=no
enable_hard_errors=yes
while test $# -gt 0; do
case $1 in
--help) print_usage; exit $?;;
--version) echo "test-driver $scriptversion"; exit $?;;
--test-name) test_name=$2; shift;;
--log-file) log_file=$2; shift;;
--trs-file) trs_file=$2; shift;;
--color-tests) color_tests=$2; shift;;
--expect-failure) expect_failure=$2; shift;;
--enable-hard-errors) enable_hard_errors=$2; shift;;
--) shift; break;;
-*) usage_error "invalid option: '$1'";;
*) break;;
esac
shift
done
missing_opts=
test x"$test_name" = x && missing_opts="$missing_opts --test-name"
test x"$log_file" = x && missing_opts="$missing_opts --log-file"
test x"$trs_file" = x && missing_opts="$missing_opts --trs-file"
if test x"$missing_opts" != x; then
usage_error "the following mandatory options are missing:$missing_opts"
fi
if test $# -eq 0; then
usage_error "missing argument"
fi
if test $color_tests = yes; then
# Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
red='' # Red.
grn='' # Green.
lgn='' # Light green.
blu='' # Blue.
mgn='' # Magenta.
std='' # No color.
else
red= grn= lgn= blu= mgn= std=
fi
do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
trap "st=129; $do_exit" 1
trap "st=130; $do_exit" 2
trap "st=141; $do_exit" 13
trap "st=143; $do_exit" 15
# Test script is run here.
"$@" >$log_file 2>&1
estatus=$?
if test $enable_hard_errors = no && test $estatus -eq 99; then
tweaked_estatus=1
else
tweaked_estatus=$estatus
fi
case $tweaked_estatus:$expect_failure in
0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
0:*) col=$grn res=PASS recheck=no gcopy=no;;
77:*) col=$blu res=SKIP recheck=no gcopy=yes;;
99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;;
*:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;;
*:*) col=$red res=FAIL recheck=yes gcopy=yes;;
esac
# Report the test outcome and exit status in the logs, so that one can
# know whether the test passed or failed simply by looking at the '.log'
# file, without the need of also peaking into the corresponding '.trs'
# file (automake bug#11814).
echo "$res $test_name (exit status: $estatus)" >>$log_file
# Report outcome to console.
echo "${col}${res}${std}: $test_name"
# Register the test result, and other relevant metadata.
echo ":test-result: $res" > $trs_file
echo ":global-test-result: $res" >> $trs_file
echo ":recheck: $recheck" >> $trs_file
echo ":copy-in-global-log: $gcopy" >> $trs_file
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

77
clearcache.c Normal file
View File

@ -0,0 +1,77 @@
/* Clear the CPU cache for benchmark purposes. Pretty simple minded.
* Might not work in some complex cache topologies.
* When you switch CPUs it's a good idea to clear the cache after testing
* too.
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "clearcache.h"
unsigned cache_size(void)
{
unsigned cs = 0;
#ifdef _SC_LEVEL1_DCACHE_SIZE
cs += sysconf(_SC_LEVEL1_DCACHE_SIZE);
#endif
#ifdef _SC_LEVEL2_DCACHE_SIZE
cs += sysconf(_SC_LEVEL2_DCACHE_SIZE);
#endif
#ifdef _SC_LEVEL3_DCACHE_SIZE
cs += sysconf(_SC_LEVEL3_DCACHE_SIZE);
#endif
#ifdef _SC_LEVEL4_DCACHE_SIZE
cs += sysconf(_SC_LEVEL4_DCACHE_SIZE);
#endif
if (cs == 0) {
static int warned;
if (!warned) {
printf("Cannot determine CPU cache size\n");
warned = 1;
}
cs = 64*1024*1024;
}
cs *= 2; /* safety factor */
return cs;
}
void fallback_clearcache(void)
{
static unsigned char *clearmem;
unsigned cs = cache_size();
unsigned i;
if (!clearmem)
clearmem = malloc(cs);
if (!clearmem) {
printf("Warning: cannot allocate %u bytes of clear cache buffer\n", cs);
return;
}
for (i = 0; i < cs; i += 32)
clearmem[i] = 1;
}
void clearcache(unsigned char *mem, unsigned size)
{
#if defined(__i386__) || defined(__x86_64__)
unsigned i, cl, eax, feat;
/* get clflush unit and feature */
asm("cpuid" : "=a" (eax), "=b" (cl), "=d" (feat) : "0" (1) : "cx");
if (!(feat & (1 << 19)))
fallback_clearcache();
cl = ((cl >> 8) & 0xff) * 8;
for (i = 0; i < size; i += cl)
asm("clflush %0" :: "m" (mem[i]));
#elif defined(__ia64__)
unsigned long cl, endcl;
// flush probable 128 byte cache lines (but possibly 64 bytes)
cl = (unsigned long)mem;
endcl = (unsigned long)(mem + (size-1));
for (; cl <= endcl; cl += 64)
asm ("fc %0" :: "r"(cl) : "memory" );
#else
#warning "Consider adding a clearcache implementation for your architecture"
fallback_clearcache();
#endif
}

1
clearcache.h Normal file
View File

@ -0,0 +1 @@
void clearcache(unsigned char *mem, unsigned size);

64
config.h.in Normal file
View File

@ -0,0 +1,64 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#undef LT_OBJDIR
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* If the compiler supports a TLS storage class define it to that here */
#undef TLS
/* Version number of package */
#undef VERSION

15050
configure vendored Executable file

File diff suppressed because it is too large Load Diff

27
configure.ac Normal file
View File

@ -0,0 +1,27 @@
AC_PREREQ([2.64])
AC_INIT([numactl], [2.0.12])
AC_CONFIG_SRCDIR([numactl.c])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([foreign 1.11 silent-rules subdir-objects parallel-tests])
AM_SILENT_RULES([yes])
LT_PREREQ([2.2])
LT_INIT
AC_PROG_CC
# Override CFLAGS so that we can specify custom CFLAGS for numademo.
AX_AM_OVERRIDE_VAR([CFLAGS])
AX_TLS
AX_CHECK_COMPILE_FLAG([-ftree-vectorize], [tree_vectorize="true"])
AM_CONDITIONAL([HAVE_TREE_VECTORIZE], [test x"${tree_vectorize}" = x"true"])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

120
distance.c Normal file
View File

@ -0,0 +1,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)
return 0;
}
if ((unsigned)a >= distance_numnodes || (unsigned)b >= distance_numnodes)
return 0;
return distance_table[a * distance_numnodes + b];
}

2037
libnuma.c Normal file

File diff suppressed because it is too large Load Diff

155
m4/ax_am_override_var.m4 Normal file
View File

@ -0,0 +1,155 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_am_override_var.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_AM_OVERRIDE_VAR([varname1 varname ... ])
# AX_AM_OVERRIDE_FINALIZE
#
# DESCRIPTION
#
# This autoconf macro generalizes the approach given in
# <http://lists.gnu.org/archive/html/automake/2005-09/msg00108.html> which
# moves user specified values for variable 'varname' given at configure
# time into the corresponding AM_${varname} variable and clears out
# 'varname', allowing further manipulation by the configure script so that
# target specific variables can be given specialized versions. 'varname
# may still be specified on the make command line and will be appended as
# usual.
#
# As an example usage, consider a project which might benefit from
# different compiler flags for different components. Typically this is
# done via target specific flags, e.g.
#
# libgtest_la_CXXFLAGS = \
# -I $(top_srcdir)/tests \
# -I $(top_builddir)/tests \
# $(GTEST_CXXFLAGS)
#
# automake will automatically append $(CXXFLAGS) -- provided by the user
# -- to the build rule for libgtest_la. That might be problematic, as
# CXXFLAGS may contain compiler options which are inappropriate for
# libgtest_la.
#
# The approach laid out in the referenced mailing list message is to
# supply a base value for a variable during _configure_ time, during which
# it is possible to amend it for specific targets. The user may
# subsequently specify a value for the variable during _build_ time, which
# make will apply (via the standard automake rules) to all appropriate
# targets.
#
# For example,
#
# AX_AM_OVERRIDE_VAR([CXXFLAGS])
#
# will store the value of CXXFLAGS specified at configure time into the
# AM_CXXFLAGS variable, AC_SUBST it, and clear CXXFLAGS. configure may
# then create a target specific set of flags based upon AM_CXXFLAGS, e.g.
#
# # googletest uses variadic macros, which g++ -pedantic-errors
# # is very unhappy about
# AC_SUBST([GTEST_CXXFLAGS],
# [`AS_ECHO_N(["$AM_CXXFLAGS"]) \
# | sed s/-pedantic-errors/-pedantic/`
# ]
# )
#
# which would be used in a Makefile.am as above. Since CXXFLAGS is
# cleared, the configure time value will not affect the build for
# libgtest_la.
#
# Prior to _any other command_ which may set ${varname}, call
#
# AX_AM_OVERRIDE_VAR([varname])
#
# This will preserve the value (if any) passed to configure in
# AM_${varname} and AC_SUBST([AM_${varname}). You may pass a space
# separated list of variable names, or may call AX_AM_OVERRIDE_VAR
# multiple times for the same effect.
#
# If any subsequent configure commands set ${varname} and you wish to
# capture the resultant value into AM_${varname} in the case where
# ${varname} was _not_ provided at configure time, call
#
# AX_AM_OVERRIDE_FINALIZE
#
# after _all_ commands which might affect any of the variables specified
# in calls to AX_AM_OVERRIDE_VAR. This need be done only once, but
# repeated calls will not cause harm.
#
# There is a bit of trickery required to allow further manipulation of the
# AM_${varname} in a Makefile.am file. If AM_CFLAGS is used as is in a
# Makefile.am, e.g.
#
# libfoo_la_CFLAGS = $(AM_CFLAGS)
#
# then automake will emit code in Makefile.in which sets AM_CFLAGS from
# the configure'd value.
#
# If however, AM_CFLAGS is manipulated (i.e. appended to), you will have
# to explicitly arrange for the configure'd value to be substituted:
#
# AM_CFLAGS = @AM_CFLAGS@
# AM_CFLAGS += -lfoo
#
# or else automake will complain about using += before =.
#
# LICENSE
#
# Copyright (c) 2013 Smithsonian Astrophysical Observatory
# Copyright (c) 2013 Diab Jerius <djerius@cfa.harvard.edu>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 1
AC_DEFUN([_AX_AM_OVERRIDE_INITIALIZE],
[
m4_define([_mst_am_override_vars],[])
])
# _AX_AM_OVERRIDE_VAR(varname)
AC_DEFUN([_AX_AM_OVERRIDE_VAR],
[
m4_define([_mst_am_override_vars], m4_defn([_mst_am_override_vars]) $1 )
_mst_am_override_$1_set=false
AS_IF( [test "${$1+set}" = set],
[AC_SUBST([AM_$1],["$$1"])
$1=
_mst_am_override_$1_set=:
]
)
]) # _AX_AM_OVERRIDE_VAR
# _AX_AM_OVERRIDE_FINALIZE(varname)
AC_DEFUN([_AX_AM_OVERRIDE_FINALIZE],
[
AS_IF([$_mst_am_override_$1_set = :],
[],
[AC_SUBST([AM_$1],["$$1"])
$1=
_mst_am_override_$1_set=
]
)
AC_SUBST($1)
]) # _AX_AM_OVERRIDE_FINALIZE
AC_DEFUN([AX_AM_OVERRIDE_VAR],
[
AC_REQUIRE([_AX_AM_OVERRIDE_INITIALIZE])
m4_map_args_w([$1],[_AX_AM_OVERRIDE_VAR(],[)])
])# AX_OVERRIDE_VAR
# AX_AM_OVERRIDE_FINALIZE
AC_DEFUN([AX_AM_OVERRIDE_FINALIZE],
[
AC_REQUIRE([_AX_AM_OVERRIDE_INITIALIZE])
m4_map_args_w(_mst_am_override_vars,[_AX_AM_OVERRIDE_FINALIZE(],[)])
]) # AX_AM_OVERRIDE_FINALIZE

View File

@ -0,0 +1,74 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
#
# DESCRIPTION
#
# Check whether the given FLAG works with the current language's compiler
# or gives an error. (Warnings, however, are ignored)
#
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
# success/failure.
#
# If EXTRA-FLAGS is defined, it is added to the current language's default
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program 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 General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 3
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
[AS_VAR_SET(CACHEVAR,[yes])],
[AS_VAR_SET(CACHEVAR,[no])])
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes],
[m4_default([$2], :)],
[m4_default([$3], :)])
AS_VAR_POPDEF([CACHEVAR])dnl
])dnl AX_CHECK_COMPILE_FLAGS

76
m4/ax_tls.m4 Normal file
View File

@ -0,0 +1,76 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_tls.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_TLS([action-if-found], [action-if-not-found])
#
# DESCRIPTION
#
# Provides a test for the compiler support of thread local storage (TLS)
# extensions. Defines TLS if it is found. Currently knows about GCC/ICC
# and MSVC. I think SunPro uses the same as GCC, and Borland apparently
# supports either.
#
# LICENSE
#
# Copyright (c) 2008 Alan Woodland <ajw05@aber.ac.uk>
# Copyright (c) 2010 Diego Elio Petteno` <flameeyes@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program 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 General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 10
AC_DEFUN([AX_TLS], [
AC_MSG_CHECKING(for thread local storage (TLS) class)
AC_CACHE_VAL(ac_cv_tls, [
ax_tls_keywords="__thread __declspec(thread) none"
for ax_tls_keyword in $ax_tls_keywords; do
AS_CASE([$ax_tls_keyword],
[none], [ac_cv_tls=none ; break],
[AC_TRY_COMPILE(
[#include <stdlib.h>
static void
foo(void) {
static ] $ax_tls_keyword [ int bar;
exit(1);
}],
[],
[ac_cv_tls=$ax_tls_keyword ; break],
ac_cv_tls=none
)])
done
])
AC_MSG_RESULT($ac_cv_tls)
AS_IF([test "$ac_cv_tls" != "none"],
AC_DEFINE_UNQUOTED([TLS], $ac_cv_tls, [If the compiler supports a TLS storage class define it to that here])
m4_ifnblank([$1], [$1]),
m4_ifnblank([$2], [$2])
)
])

8387
m4/libtool.m4 vendored Normal file

File diff suppressed because it is too large Load Diff

437
m4/ltoptions.m4 vendored Normal file
View File

@ -0,0 +1,437 @@
# Helper functions for option handling. -*- Autoconf -*-
#
# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
# Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 8 ltoptions.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
# ------------------------------------------
m4_define([_LT_MANGLE_OPTION],
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
# ---------------------------------------
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
# matching handler defined, dispatch to it. Other OPTION-NAMEs are
# saved as a flag.
m4_define([_LT_SET_OPTION],
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
_LT_MANGLE_DEFUN([$1], [$2]),
[m4_warning([Unknown $1 option '$2'])])[]dnl
])
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
# ------------------------------------------------------------
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
m4_define([_LT_IF_OPTION],
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
# -------------------------------------------------------
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
# are set.
m4_define([_LT_UNLESS_OPTIONS],
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
[m4_define([$0_found])])])[]dnl
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
])[]dnl
])
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
# ----------------------------------------
# OPTION-LIST is a space-separated list of Libtool options associated
# with MACRO-NAME. If any OPTION has a matching handler declared with
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
# the unknown option and exit.
m4_defun([_LT_SET_OPTIONS],
[# Set options
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[_LT_SET_OPTION([$1], _LT_Option)])
m4_if([$1],[LT_INIT],[
dnl
dnl Simply set some default values (i.e off) if boolean options were not
dnl specified:
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
])
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
])
dnl
dnl If no reference was made to various pairs of opposing options, then
dnl we run the default mode handler for the pair. For example, if neither
dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
dnl archives by default:
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
[_LT_ENABLE_FAST_INSTALL])
_LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
[_LT_WITH_AIX_SONAME([aix])])
])
])# _LT_SET_OPTIONS
## --------------------------------- ##
## Macros to handle LT_INIT options. ##
## --------------------------------- ##
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
# -----------------------------------------
m4_define([_LT_MANGLE_DEFUN],
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
# -----------------------------------------------
m4_define([LT_OPTION_DEFINE],
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
])# LT_OPTION_DEFINE
# dlopen
# ------
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
])
AU_DEFUN([AC_LIBTOOL_DLOPEN],
[_LT_SET_OPTION([LT_INIT], [dlopen])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the 'dlopen' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
# win32-dll
# ---------
# Declare package support for building win32 dll's.
LT_OPTION_DEFINE([LT_INIT], [win32-dll],
[enable_win32_dll=yes
case $host in
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
AC_CHECK_TOOL(AS, as, false)
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
AC_CHECK_TOOL(OBJDUMP, objdump, false)
;;
esac
test -z "$AS" && AS=as
_LT_DECL([], [AS], [1], [Assembler program])dnl
test -z "$DLLTOOL" && DLLTOOL=dlltool
_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
test -z "$OBJDUMP" && OBJDUMP=objdump
_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
])# win32-dll
AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
_LT_SET_OPTION([LT_INIT], [win32-dll])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the 'win32-dll' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
# _LT_ENABLE_SHARED([DEFAULT])
# ----------------------------
# implement the --enable-shared flag, and supports the 'shared' and
# 'disable-shared' LT_INIT options.
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_SHARED],
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([shared],
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_shared=yes ;;
no) enable_shared=no ;;
*)
enable_shared=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_shared=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
_LT_DECL([build_libtool_libs], [enable_shared], [0],
[Whether or not to build shared libraries])
])# _LT_ENABLE_SHARED
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
# Old names:
AC_DEFUN([AC_ENABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
])
AC_DEFUN([AC_DISABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], [disable-shared])
])
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_SHARED], [])
dnl AC_DEFUN([AM_DISABLE_SHARED], [])
# _LT_ENABLE_STATIC([DEFAULT])
# ----------------------------
# implement the --enable-static flag, and support the 'static' and
# 'disable-static' LT_INIT options.
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_STATIC],
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([static],
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_static=yes ;;
no) enable_static=no ;;
*)
enable_static=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_static=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
_LT_DECL([build_old_libs], [enable_static], [0],
[Whether or not to build static libraries])
])# _LT_ENABLE_STATIC
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
# Old names:
AC_DEFUN([AC_ENABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
])
AC_DEFUN([AC_DISABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], [disable-static])
])
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_STATIC], [])
dnl AC_DEFUN([AM_DISABLE_STATIC], [])
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
# ----------------------------------
# implement the --enable-fast-install flag, and support the 'fast-install'
# and 'disable-fast-install' LT_INIT options.
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_FAST_INSTALL],
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([fast-install],
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_fast_install=yes ;;
no) enable_fast_install=no ;;
*)
enable_fast_install=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_fast_install=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
_LT_DECL([fast_install], [enable_fast_install], [0],
[Whether or not to optimize for fast installation])dnl
])# _LT_ENABLE_FAST_INSTALL
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
# Old names:
AU_DEFUN([AC_ENABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the 'fast-install' option into LT_INIT's first parameter.])
])
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the 'disable-fast-install' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
# _LT_WITH_AIX_SONAME([DEFAULT])
# ----------------------------------
# implement the --with-aix-soname flag, and support the `aix-soname=aix'
# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'.
m4_define([_LT_WITH_AIX_SONAME],
[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
shared_archive_member_spec=
case $host,$enable_shared in
power*-*-aix[[5-9]]*,yes)
AC_MSG_CHECKING([which variant of shared library versioning to provide])
AC_ARG_WITH([aix-soname],
[AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
[shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
[case $withval in
aix|svr4|both)
;;
*)
AC_MSG_ERROR([Unknown argument to --with-aix-soname])
;;
esac
lt_cv_with_aix_soname=$with_aix_soname],
[AC_CACHE_VAL([lt_cv_with_aix_soname],
[lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
with_aix_soname=$lt_cv_with_aix_soname])
AC_MSG_RESULT([$with_aix_soname])
if test aix != "$with_aix_soname"; then
# For the AIX way of multilib, we name the shared archive member
# based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
# and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
# Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
# the AIX toolchain works better with OBJECT_MODE set (default 32).
if test 64 = "${OBJECT_MODE-32}"; then
shared_archive_member_spec=shr_64
else
shared_archive_member_spec=shr
fi
fi
;;
*)
with_aix_soname=aix
;;
esac
_LT_DECL([], [shared_archive_member_spec], [0],
[Shared archive member basename, for filename based shared library versioning on AIX])dnl
])# _LT_WITH_AIX_SONAME
LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
# _LT_WITH_PIC([MODE])
# --------------------
# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
# LT_INIT options.
# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'.
m4_define([_LT_WITH_PIC],
[AC_ARG_WITH([pic],
[AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
[lt_p=${PACKAGE-default}
case $withval in
yes|no) pic_mode=$withval ;;
*)
pic_mode=default
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for lt_pkg in $withval; do
IFS=$lt_save_ifs
if test "X$lt_pkg" = "X$lt_p"; then
pic_mode=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[pic_mode=m4_default([$1], [default])])
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
])# _LT_WITH_PIC
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
# Old name:
AU_DEFUN([AC_LIBTOOL_PICMODE],
[_LT_SET_OPTION([LT_INIT], [pic-only])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the 'pic-only' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
## ----------------- ##
## LTDL_INIT Options ##
## ----------------- ##
m4_define([_LTDL_MODE], [])
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
[m4_define([_LTDL_MODE], [nonrecursive])])
LT_OPTION_DEFINE([LTDL_INIT], [recursive],
[m4_define([_LTDL_MODE], [recursive])])
LT_OPTION_DEFINE([LTDL_INIT], [subproject],
[m4_define([_LTDL_MODE], [subproject])])
m4_define([_LTDL_TYPE], [])
LT_OPTION_DEFINE([LTDL_INIT], [installable],
[m4_define([_LTDL_TYPE], [installable])])
LT_OPTION_DEFINE([LTDL_INIT], [convenience],
[m4_define([_LTDL_TYPE], [convenience])])

124
m4/ltsugar.m4 vendored Normal file
View File

@ -0,0 +1,124 @@
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
#
# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software
# Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 6 ltsugar.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
# lt_join(SEP, ARG1, [ARG2...])
# -----------------------------
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
# associated separator.
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
# versions in m4sugar had bugs.
m4_define([lt_join],
[m4_if([$#], [1], [],
[$#], [2], [[$2]],
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
m4_define([_lt_join],
[m4_if([$#$2], [2], [],
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
# lt_car(LIST)
# lt_cdr(LIST)
# ------------
# Manipulate m4 lists.
# These macros are necessary as long as will still need to support
# Autoconf-2.59, which quotes differently.
m4_define([lt_car], [[$1]])
m4_define([lt_cdr],
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
[$#], 1, [],
[m4_dquote(m4_shift($@))])])
m4_define([lt_unquote], $1)
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
# ------------------------------------------
# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'.
# Note that neither SEPARATOR nor STRING are expanded; they are appended
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
# than defined and empty).
#
# This macro is needed until we can rely on Autoconf 2.62, since earlier
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
m4_define([lt_append],
[m4_define([$1],
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
# ----------------------------------------------------------
# Produce a SEP delimited list of all paired combinations of elements of
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
# has the form PREFIXmINFIXSUFFIXn.
# Needed until we can rely on m4_combine added in Autoconf 2.62.
m4_define([lt_combine],
[m4_if(m4_eval([$# > 3]), [1],
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
[[m4_foreach([_Lt_prefix], [$2],
[m4_foreach([_Lt_suffix],
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
# -----------------------------------------------------------------------
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
m4_define([lt_if_append_uniq],
[m4_ifdef([$1],
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
[lt_append([$1], [$2], [$3])$4],
[$5])],
[lt_append([$1], [$2], [$3])$4])])
# lt_dict_add(DICT, KEY, VALUE)
# -----------------------------
m4_define([lt_dict_add],
[m4_define([$1($2)], [$3])])
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
# --------------------------------------------
m4_define([lt_dict_add_subkey],
[m4_define([$1($2:$3)], [$4])])
# lt_dict_fetch(DICT, KEY, [SUBKEY])
# ----------------------------------
m4_define([lt_dict_fetch],
[m4_ifval([$3],
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
# -----------------------------------------------------------------
m4_define([lt_if_dict_fetch],
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
[$5],
[$6])])
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
# --------------------------------------------------------------
m4_define([lt_dict_filter],
[m4_if([$5], [], [],
[lt_join(m4_quote(m4_default([$4], [[, ]])),
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
])

23
m4/ltversion.m4 vendored Normal file
View File

@ -0,0 +1,23 @@
# ltversion.m4 -- version numbers -*- Autoconf -*-
#
# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# @configure_input@
# serial 4179 ltversion.m4
# This file is part of GNU Libtool
m4_define([LT_PACKAGE_VERSION], [2.4.6])
m4_define([LT_PACKAGE_REVISION], [2.4.6])
AC_DEFUN([LTVERSION_VERSION],
[macro_version='2.4.6'
macro_revision='2.4.6'
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
_LT_DECL(, macro_revision, 0)
])

99
m4/lt~obsolete.m4 vendored Normal file
View File

@ -0,0 +1,99 @@
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
#
# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software
# Foundation, Inc.
# Written by Scott James Remnant, 2004.
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 5 lt~obsolete.m4
# These exist entirely to fool aclocal when bootstrapping libtool.
#
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN),
# which have later been changed to m4_define as they aren't part of the
# exported API, or moved to Autoconf or Automake where they belong.
#
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
# using a macro with the same name in our local m4/libtool.m4 it'll
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
# and doesn't know about Autoconf macros at all.)
#
# So we provide this file, which has a silly filename so it's always
# included after everything else. This provides aclocal with the
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
# because those macros already exist, or will be overwritten later.
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
#
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
# Yes, that means every name once taken will need to remain here until
# we give up compatibility with versions before 1.7, at which point
# we need to keep only those names which we still refer to.
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])

145
memhog.c Normal file
View File

@ -0,0 +1,145 @@
/* Copyright (C) 2003,2004 Andi Kleen, SuSE Labs.
Allocate memory with policy for testing.
numactl is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; version
2.
numactl 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
General Public License for more details.
You should find a copy of v2 of the GNU 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 */
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/fcntl.h>
#include <string.h>
#include <stdbool.h>
#include "numa.h"
#include "numaif.h"
#include "util.h"
#define terr(x) perror(x)
enum {
UNIT = 10*1024*1024,
};
#ifndef MADV_NOHUGEPAGE
#define MADV_NOHUGEPAGE 15
#endif
int repeat = 1;
void usage(void)
{
printf("memhog [-rNUM] size[kmg] [policy [nodeset]]\n");
printf("-rNUM repeat memset NUM times\n");
printf("-H disable transparent hugepages\n");
print_policies();
exit(1);
}
long length;
void hog(void *map)
{
long i;
for (i = 0; i < length; i += UNIT) {
long left = length - i;
if (left > UNIT)
left = UNIT;
putchar('.');
fflush(stdout);
memset(map + i, 0xff, left);
}
putchar('\n');
}
int main(int ac, char **av)
{
char *map;
struct bitmask *nodes, *gnodes;
int policy, gpolicy;
int ret = 0;
int loose = 0;
int i;
int fd = -1;
bool disable_hugepage = false;
nodes = numa_allocate_nodemask();
gnodes = numa_allocate_nodemask();
while (av[1] && av[1][0] == '-') {
switch (av[1][1]) {
case 'f':
fd = open(av[1]+2, O_RDWR);
if (fd < 0)
perror(av[1]+2);
break;
case 'r':
repeat = atoi(av[1] + 2);
break;
case 'H':
disable_hugepage = true;
break;
default:
usage();
}
av++;
}
if (!av[1]) usage();
length = memsize(av[1]);
if (av[2] && numa_available() < 0) {
printf("Kernel doesn't support NUMA policy\n");
exit(1);
} else
loose = 1;
policy = parse_policy(av[2], av[3]);
if (policy != MPOL_DEFAULT)
nodes = numa_parse_nodestring(av[3]);
if (!nodes) {
printf ("<%s> is invalid\n", av[3]);
exit(1);
}
if (fd >= 0)
map = mmap(NULL,length,PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
else
map = mmap(NULL, length, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS,
0, 0);
if (map == (char*)-1)
err("mmap");
if (mbind(map, length, policy, nodes->maskp, nodes->size, 0) < 0)
terr("mbind");
if (disable_hugepage)
madvise(map, length, MADV_NOHUGEPAGE);
gpolicy = -1;
if (get_mempolicy(&gpolicy, gnodes->maskp, gnodes->size, map, MPOL_F_ADDR) < 0)
terr("get_mempolicy");
if (!loose && policy != gpolicy) {
ret = 1;
printf("policy %d gpolicy %d\n", policy, gpolicy);
}
if (!loose && !numa_bitmask_equal(gnodes, nodes)) {
printf("nodes differ %lx, %lx!\n",
gnodes->maskp[0], nodes->maskp[0]);
ret = 1;
}
for (i = 0; i < repeat; i++)
hog(map);
exit(ret);
}

75
migratepages.8 Normal file
View File

@ -0,0 +1,75 @@
.\" t
.\" Copyright 2005-2006 Christoph Lameter, Silicon Graphics, Inc.
.\"
.\" based on Andi Kleen's numactl manpage
.\"
.TH MIGRATEPAGES 8 "Jan 2005" "SGI" "Linux Administrator's Manual"
.SH NAME
migratepages \- Migrate the physical location a processes pages
.SH SYNOPSIS
.B migratepages
pid from-nodes to-nodes
.SH DESCRIPTION
.B migratepages
moves the physical location of a processes pages without any changes of the
virtual address space of the process. Moving the pages allows one to change
the distances of a process to its memory. Performance may be optimized by moving
a processes pages to the node where it is executing.
If multiple nodes are specified for from-nodes or to-nodes then
an attempt is made to preserve the relative location of
each page in each nodeset.
For example if we move from nodes 2-5 to 7,9,12-13 then the preferred mode of
operation is to move pages from 2->7, 3->9, 4->12 and 5->13. However, this
is only posssible if enough memory is available.
.TP
Valid node specifiers
.TS
tab(:);
l l.
all:All nodes
number:Node number
number1{,number2}:Node number1 and Node number2
number1-number2:Nodes from number1 to number2
! nodes:Invert selection of the following specification.
.TE
.SH NOTES
Requires an NUMA policy aware kernel with support for page migration
(linux 2.6.16 and later).
migratepages will only move pages that are not shared with other
processes if called by a user without administrative priviledges (but
with the right to modify the process).
migratepages will move all pages if invoked from root (or a user with
administrative priviledges).
.SH FILES
.I /proc/<pid>/numa_maps
for information about the NUMA memory use of a process.
.SH COPYRIGHT
Copyright 2005-2006 Christoph Lameter, Silicon Graphics, Inc.
migratepages is under the GNU General Public License, v.2
.SH SEE ALSO
.I numactl(8)
,
.I set_mempolicy(2)
,
.I get_mempolicy(2)
,
.I mbind(2)
,
.I sched_setaffinity(2)
,
.I sched_getaffinity(2)
,
.I proc(5)
,
.I ftok(3)
,
.I shmat(2)
,
.I taskset(1)

105
migratepages.c Normal file
View File

@ -0,0 +1,105 @@
/*
* Copyright (C) 2005 Christoph Lameter, Silicon Graphics, Incorporated.
* based on Andi Kleen's numactl.c.
*
* Manual process migration
*
* migratepages is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; version 2.
*
* migratepages 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
* General Public License for more details.
*
* You should find a copy of v2 of the GNU 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
*/
#define _GNU_SOURCE
#include <getopt.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include "numa.h"
#include "numaif.h"
#include "numaint.h"
#include "util.h"
struct option opts[] = {
{"help", 0, 0, 'h' },
{ 0 }
};
void usage(void)
{
fprintf(stderr,
"usage: migratepages pid from-nodes to-nodes\n"
"\n"
"nodes is a comma delimited list of node numbers or A-B ranges or all.\n"
);
exit(1);
}
void checknuma(void)
{
static int numa = -1;
if (numa < 0) {
if (numa_available() < 0)
complain("This system does not support NUMA functionality");
}
numa = 0;
}
int main(int argc, char *argv[])
{
int c;
char *end;
int rc;
int pid;
struct bitmask *fromnodes;
struct bitmask *tonodes;
while ((c = getopt_long(argc,argv,"h", opts, NULL)) != -1) {
switch (c) {
default:
usage();
}
}
argv += optind;
argc -= optind;
if (argc != 3)
usage();
checknuma();
pid = strtoul(argv[0], &end, 0);
if (*end || end == argv[0])
usage();
fromnodes = numa_parse_nodestring(argv[1]);
if (!fromnodes) {
printf ("<%s> is invalid\n", argv[1]);
exit(1);
}
tonodes = numa_parse_nodestring(argv[2]);
if (!tonodes) {
printf ("<%s> is invalid\n", argv[2]);
exit(1);
}
rc = numa_migrate_pages(pid, fromnodes, tonodes);
if (rc < 0) {
perror("migrate_pages");
return 1;
}
return 0;
}

31
migspeed.8 Normal file
View File

@ -0,0 +1,31 @@
.\" t
.\" Copyright 2005-2007 Christoph Lameter, Silicon Graphics, Inc.
.\"
.\" based on Andi Kleen's numactl manpage
.\"
.TH MIGSPEED 8 "April 2005" "SGI" "Linux Administrator's Manual"
.SH NAME
migspeed \- Test the speed of page migration
.SH SYNOPSIS
.B migspeed
-p pages from-nodes to-nodes
.SH DESCRIPTION
.B migspeed
attempts to move a sample of pages from the indicated node to the target node
and measures the time it takes to perform the move.
.B -p pages
The default sample is 1000 pages. Override that with another number.
.SH NOTES
Requires an NUMA policy aware kernel with support for page migration
(Linux 2.6.16 and later).
.SH COPYRIGHT
Copyright 2007 Christoph Lameter, Silicon Graphics, Inc.
migratepages is under the GNU General Public License, v.2
.SH SEE ALSO
.I numactl(8)

187
migspeed.c Normal file
View File

@ -0,0 +1,187 @@
/*
* Migration test program
*
* (C) 2007 Silicon Graphics, Inc. Christoph Lameter <clameter@sgi.com>
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "numa.h"
#include "numaif.h"
#include <time.h>
#include <errno.h>
#include <malloc.h>
#include <unistd.h>
#include "util.h"
char *memory;
unsigned long pages = 1000;
unsigned long pagesize;
const char *optstr = "hvp:";
char *cmd;
int verbose;
struct timespec start,end;
void usage(void)
{
printf("usage %s [-p pages] [-h] [-v] from-nodes to-nodes\n", cmd);
printf(" from and to nodes may specified in form N or N-N\n");
printf(" -p pages number of pages to try (defaults to %ld)\n",
pages);
printf(" -v verbose\n");
printf(" -h usage\n");
exit(1);
}
void displaymap(void)
{
FILE *f = fopen("/proc/self/numa_maps","r");
if (!f) {
printf("/proc/self/numa_maps not accessible.\n");
exit(1);
}
while (!feof(f))
{
char buffer[2000];
if (!fgets(buffer, sizeof(buffer), f))
break;
if (!strstr(buffer, "bind"))
continue ;
printf("%s", buffer);
}
fclose(f);
}
int main(int argc, char *argv[])
{
char *p;
int option;
struct timespec result;
unsigned long bytes;
double duration, mbytes;
struct bitmask *from;
struct bitmask *to;
pagesize = getpagesize();
/* Command line processing */
opterr = 1;
cmd = argv[0];
while ((option = getopt(argc, argv, optstr)) != EOF)
switch (option) {
case 'h' :
case '?' :
usage();
case 'v' :
verbose++;
break;
case 'p' :
pages = strtoul(optarg, &p, 0);
if (p == optarg || *p)
usage();
break;
}
if (!argv[optind])
usage();
if (verbose > 1)
printf("numa_max_node = %d\n", numa_max_node());
numa_exit_on_error = 1;
from = numa_parse_nodestring(argv[optind]);
if (!from) {
printf ("<%s> is invalid\n", argv[optind]);
exit(1);
}
if (errno) {
perror("from mask");
exit(1);
}
if (verbose)
printmask("From", from);
if (!argv[optind+1])
usage();
to = numa_parse_nodestring(argv[optind+1]);
if (!to) {
printf ("<%s> is invalid\n", argv[optind+1]);
exit(1);
}
if (errno) {
perror("to mask");
exit(1);
}
if (verbose)
printmask("To", to);
bytes = pages * pagesize;
if (verbose)
printf("Allocating %lu pages of %lu bytes of memory\n",
pages, pagesize);
memory = memalign(pagesize, bytes);
if (!memory) {
printf("Out of Memory\n");
exit(2);
}
if (mbind(memory, bytes, MPOL_BIND, from->maskp, from->size, 0) < 0)
numa_error("mbind");
if (verbose)
printf("Dirtying memory....\n");
for (p = memory; p <= memory + bytes; p += pagesize)
*p = 1;
if (verbose)
printf("Starting test\n");
displaymap();
clock_gettime(CLOCK_REALTIME, &start);
if (mbind(memory, bytes, MPOL_BIND, to->maskp, to->size, MPOL_MF_MOVE) <0)
numa_error("memory move");
clock_gettime(CLOCK_REALTIME, &end);
displaymap();
result.tv_sec = end.tv_sec - start.tv_sec;
result.tv_nsec = end.tv_nsec - start.tv_nsec;
if (result.tv_nsec < 0) {
result.tv_sec--;
result.tv_nsec += 1000000000;
}
if (result.tv_nsec >= 1000000000) {
result.tv_sec++;
result.tv_nsec -= 1000000000;
}
duration = result.tv_sec + result.tv_nsec / 1000000000.0;
mbytes = bytes / (1024*1024.0);
printf("%1.1f Mbyte migrated in %1.2f secs. %3.1f Mbytes/second\n",
mbytes,
duration,
mbytes / duration);
return 0;
}

155
move_pages.2 Normal file
View File

@ -0,0 +1,155 @@
.\" Hey Emacs! This file is -*- nroff -*- source.
.\"
.\" This manpage is Copyright (C) 2006 Silicon Graphics, Inc.
.\" Christoph Lameter
.\"
.\" Permission is granted to make and distribute verbatim copies of this
.\" manual provided the copyright notice and this permission notice are
.\" preserved on all copies.
.\"
.\" Permission is granted to copy and distribute modified versions of this
.\" manual under the conditions for verbatim copying, provided that the
.\" entire resulting derived work is distributed under the terms of a
.\" permission notice identical to this one.
.\"
.TH MOVE_PAGES 2 2006-10-31 "Linux 2.6.18" "Linux Programmer's Manual"
.SH NAME
move_pages \- Move individual pages of a process to another node
.SH SYNOPSIS
.B #include <numaif.h>
.sp
.BI "long move_pages(int " pid ", unsigned long count, void ** " pages ", const int * " nodes ", int * " status ", int " flags );
.SH DESCRIPTION
.BR move_pages ()
moves
.I count
pages to the
.I nodes.
The result of the move is reflected in
.I status.
The
.I flags
indicate constraints on the pages to be moved.
.I pid
is the process id in which pages are to be moved. Sufficient rights
must exist to move pages of another process. This means the moving
process either has root priviledges, has SYS_NICE administrative rights or
the same owner. If pid is 0 then we move pages of the current process.
.I count
is the number of pages to move. It defines the size of the three
arrays
.I pages,
.I nodes
and
.I status.
.I pages
is an array of pointers to the pages that should be moved. These are pointers
that should be aligned to page boundaries. Addresses are specified as seen by
the process specified by
.I pid.
.I nodes
is either an array of integers that specify the desired location for each
page or it is NULL. Each integer is a node number. If NULL is specified then
move_pages will not move any pages but return the node of each page in
the
.I status
array. Having the status of each page may be necessary to determine
pages that need to be moved.
.I status
is an array of integers that return the status of each page. The array
only contains valid values if
.I move_pages
did not return an error code.
.I flags
specify what types of pages to move.
.B MPOL_MF_MOVE
means that only pages that are in exclusive use by the process
are to be moved.
.B MPOL_MF_MOVE_ALL
means that pages shared between multiple processes can also be moved.
The process must have root priviledges or SYS_NICE priviledges.
.SH Page states in the status array
.TP
.B 0..MAX_NUMNODES
Indicates that the location of the page is on this node.
.TP
.B -ENOENT
The page is not present.
.TP
.B -EACCES
The page is mapped by multiple processes and can only be moved
if
.I MPOL_MF_MOVE_ALL
is specified.
.TP
.B -EBUSY
The page is currently busy and cannot be moved. Try again later.
This occurs if a page is undergoing I/O or another kernel subsystem
is holding a reference to the page.
.TP
.B -EFAULT
This is a zero page or the memory area is not mapped by the process.
.TP
.B -ENOMEM
Unable to allocate memory on target node.
.TP
.B -EIO
Unable to write back a page. The page has to be written back
in order to move ti since the page is dirty and the filesystem
has not provide a migration function that would allow the move
of dirty pages.
.TP
.B -EINVAL
A dirty page cannot be moved. The filesystem does not
provide a migration function and has no ability to write back pages.
.SH "RETURN VALUE"
On success
.B move_pages
returns zero.
.SH ERRORS
.TP
.B -ENOENT
No pages were found that require moving. All pages are either already
on the target node, not present, had an invalid address or could not be
moved because they were mapped by multiple processes.
.TP
.B -EINVAL
Flags other than
.I MPOL_MF_MOVE
and
.I MPOL_MF_MOVE_ALL
was specified or an attempt was made to migrate pages of a kernel thread.
.TP
.B -EPERM
.I MPOL_MF_MOVE_ALL
specified without sufficient privileges or an attempt to move a process
belonging to another user.
.TP
.B -EACCESS
On of the target nodes is not allowed by the current cpuset.
.TP
.B -ENODEV
On of the target nodes is not online.
.TP
.B -ESRCH
Process does not exist.
.TP
.B -E2BIG
Too many pages to move.
.TP
.B -EFAULT
Parameter array could not be accessed.
.SH "SEE ALSO"
.BR numa_maps (5),
.BR migratepages (8),
.BR numa_stat (8),
.BR numa (3)

46
mt.c Normal file
View File

@ -0,0 +1,46 @@
/* Mersenne twister implementation from Michael Brundage. Public Domain.
MT is a very fast pseudo random number generator. This version works
on 32bit words. Changes by AK. */
#include <stdlib.h>
#include "mt.h"
int mt_index;
unsigned int mt_buffer[MT_LEN];
void mt_init(void)
{
int i;
srand(1);
for (i = 0; i < MT_LEN; i++)
mt_buffer[i] = rand();
mt_index = 0;
}
#define MT_IA 397
#define MT_IB (MT_LEN - MT_IA)
#define UPPER_MASK 0x80000000
#define LOWER_MASK 0x7FFFFFFF
#define MATRIX_A 0x9908B0DF
#define TWIST(b,i,j) ((b)[i] & UPPER_MASK) | ((b)[j] & LOWER_MASK)
#define MAGIC(s) (((s)&1)*MATRIX_A)
void mt_refill(void)
{
int i;
unsigned int s;
unsigned int * b = mt_buffer;
mt_index = 0;
i = 0;
for (; i < MT_IB; i++) {
s = TWIST(b, i, i+1);
b[i] = b[i + MT_IA] ^ (s >> 1) ^ MAGIC(s);
}
for (; i < MT_LEN-1; i++) {
s = TWIST(b, i, i+1);
b[i] = b[i - MT_IB] ^ (s >> 1) ^ MAGIC(s);
}
s = TWIST(b, MT_LEN-1, 0);
b[MT_LEN-1] = b[MT_IA-1] ^ (s >> 1) ^ MAGIC(s);
}

20
mt.h Normal file
View File

@ -0,0 +1,20 @@
#define MT_LEN 624
extern void mt_init(void);
extern void mt_refill();
extern int mt_index;
extern unsigned int mt_buffer[MT_LEN];
static inline unsigned int mt_random(void)
{
unsigned int * b = mt_buffer;
int idx = mt_index;
if (idx == MT_LEN*sizeof(unsigned int)) {
mt_refill();
idx = 0;
}
mt_index += sizeof(unsigned int);
return *(unsigned int *)((unsigned char *)b + idx);
}

1058
numa.3 Normal file

File diff suppressed because it is too large Load Diff

479
numa.h Normal file
View File

@ -0,0 +1,479 @@
/* Copyright (C) 2003,2004 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 */
#ifndef _NUMA_H
#define _NUMA_H 1
/* allow an application to test for the current programming interface: */
#define LIBNUMA_API_VERSION 2
/* Simple NUMA policy library */
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
#if defined(__x86_64__) || defined(__i386__)
#define NUMA_NUM_NODES 128
#else
#define NUMA_NUM_NODES 2048
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
unsigned long n[NUMA_NUM_NODES/(sizeof(unsigned long)*8)];
} nodemask_t;
struct bitmask {
unsigned long size; /* number of bits in the map */
unsigned long *maskp;
};
/* operations on struct bitmask */
int numa_bitmask_isbitset(const struct bitmask *, unsigned int);
struct bitmask *numa_bitmask_setall(struct bitmask *);
struct bitmask *numa_bitmask_clearall(struct bitmask *);
struct bitmask *numa_bitmask_setbit(struct bitmask *, unsigned int);
struct bitmask *numa_bitmask_clearbit(struct bitmask *, unsigned int);
unsigned int numa_bitmask_nbytes(struct bitmask *);
unsigned int numa_bitmask_weight(const struct bitmask *);
struct bitmask *numa_bitmask_alloc(unsigned int);
void numa_bitmask_free(struct bitmask *);
int numa_bitmask_equal(const struct bitmask *, const struct bitmask *);
void copy_nodemask_to_bitmask(nodemask_t *, struct bitmask *);
void copy_bitmask_to_nodemask(struct bitmask *, nodemask_t *);
void copy_bitmask_to_bitmask(struct bitmask *, struct bitmask *);
/* compatibility for codes that used them: */
static inline void nodemask_zero(nodemask_t *mask)
{
struct bitmask tmp;
tmp.maskp = (unsigned long *)mask;
tmp.size = sizeof(nodemask_t) * 8;
numa_bitmask_clearall(&tmp);
}
static inline void nodemask_zero_compat(nodemask_t *mask)
{
struct bitmask tmp;
tmp.maskp = (unsigned long *)mask;
tmp.size = sizeof(nodemask_t) * 8;
numa_bitmask_clearall(&tmp);
}
static inline void nodemask_set_compat(nodemask_t *mask, int node)
{
mask->n[node / (8*sizeof(unsigned long))] |=
(1UL<<(node%(8*sizeof(unsigned long))));
}
static inline void nodemask_clr_compat(nodemask_t *mask, int node)
{
mask->n[node / (8*sizeof(unsigned long))] &=
~(1UL<<(node%(8*sizeof(unsigned long))));
}
static inline int nodemask_isset_compat(const nodemask_t *mask, int node)
{
if ((unsigned)node >= NUMA_NUM_NODES)
return 0;
if (mask->n[node / (8*sizeof(unsigned long))] &
(1UL<<(node%(8*sizeof(unsigned long)))))
return 1;
return 0;
}
static inline int nodemask_equal(const nodemask_t *a, const nodemask_t *b)
{
struct bitmask tmp_a, tmp_b;
tmp_a.maskp = (unsigned long *)a;
tmp_a.size = sizeof(nodemask_t) * 8;
tmp_b.maskp = (unsigned long *)b;
tmp_b.size = sizeof(nodemask_t) * 8;
return numa_bitmask_equal(&tmp_a, &tmp_b);
}
static inline int nodemask_equal_compat(const nodemask_t *a, const nodemask_t *b)
{
struct bitmask tmp_a, tmp_b;
tmp_a.maskp = (unsigned long *)a;
tmp_a.size = sizeof(nodemask_t) * 8;
tmp_b.maskp = (unsigned long *)b;
tmp_b.size = sizeof(nodemask_t) * 8;
return numa_bitmask_equal(&tmp_a, &tmp_b);
}
/* NUMA support available. If this returns a negative value all other function
in this library are undefined. */
int numa_available(void);
/* Basic NUMA state */
/* Get max available node */
int numa_max_node(void);
int numa_max_possible_node(void);
/* Return preferred node */
int numa_preferred(void);
/* Return node size and free memory */
long long numa_node_size64(int node, long long *freep);
long numa_node_size(int node, long *freep);
int numa_pagesize(void);
/* Set with all nodes from which the calling process may allocate memory.
Only valid after numa_available. */
extern struct bitmask *numa_all_nodes_ptr;
/* Set with all nodes the kernel has exposed to userspace */
extern struct bitmask *numa_nodes_ptr;
/* For source compatibility */
extern nodemask_t numa_all_nodes;
/* Set with all cpus. */
extern struct bitmask *numa_all_cpus_ptr;
/* Set with no nodes */
extern struct bitmask *numa_no_nodes_ptr;
/* Source compatibility */
extern nodemask_t numa_no_nodes;
/* Only run and allocate memory from a specific set of nodes. */
void numa_bind(struct bitmask *nodes);
/* Set the NUMA node interleaving mask. 0 to turn off interleaving */
void numa_set_interleave_mask(struct bitmask *nodemask);
/* Return the current interleaving mask */
struct bitmask *numa_get_interleave_mask(void);
/* allocate a bitmask big enough for all nodes */
struct bitmask *numa_allocate_nodemask(void);
static inline void numa_free_nodemask(struct bitmask *b)
{
numa_bitmask_free(b);
}
/* Some node to preferably allocate memory from for task. */
void numa_set_preferred(int node);
/* Set local memory allocation policy for task */
void numa_set_localalloc(void);
/* Only allocate memory from the nodes set in mask. 0 to turn off */
void numa_set_membind(struct bitmask *nodemask);
/* Return current membind */
struct bitmask *numa_get_membind(void);
/* Return allowed memories [nodes] */
struct bitmask *numa_get_mems_allowed(void);
int numa_get_interleave_node(void);
/* NUMA memory allocation. These functions always round to page size
and are relatively slow. */
/* Alloc memory page interleaved on nodes in mask */
void *numa_alloc_interleaved_subset(size_t size, struct bitmask *nodemask);
/* Alloc memory page interleaved on all nodes. */
void *numa_alloc_interleaved(size_t size);
/* Alloc memory located on node */
void *numa_alloc_onnode(size_t size, int node);
/* Alloc memory on local node */
void *numa_alloc_local(size_t size);
/* Allocation with current policy */
void *numa_alloc(size_t size);
/* Change the size of a memory area preserving the memory policy */
void *numa_realloc(void *old_addr, size_t old_size, size_t new_size);
/* Free memory allocated by the functions above */
void numa_free(void *mem, size_t size);
/* Low level functions, primarily for shared memory. All memory
processed by these must not be touched yet */
/* Interleave an memory area. */
void numa_interleave_memory(void *mem, size_t size, struct bitmask *mask);
/* Allocate a memory area on a specific node. */
void numa_tonode_memory(void *start, size_t size, int node);
/* Allocate memory on a mask of nodes. */
void numa_tonodemask_memory(void *mem, size_t size, struct bitmask *mask);
/* Allocate a memory area on the current node. */
void numa_setlocal_memory(void *start, size_t size);
/* Allocate memory area with current memory policy */
void numa_police_memory(void *start, size_t size);
/* Run current task only on nodes in mask */
int numa_run_on_node_mask(struct bitmask *mask);
/* Run current task on nodes in mask without any cpuset awareness */
int numa_run_on_node_mask_all(struct bitmask *mask);
/* Run current task only on node */
int numa_run_on_node(int node);
/* Return current mask of nodes the task can run on */
struct bitmask * numa_get_run_node_mask(void);
/* When strict fail allocation when memory cannot be allocated in target node(s). */
void numa_set_bind_policy(int strict);
/* Fail when existing memory has incompatible policy */
void numa_set_strict(int flag);
/* maximum nodes (size of kernel nodemask_t) */
int numa_num_possible_nodes();
/* maximum cpus (size of kernel cpumask_t) */
int numa_num_possible_cpus();
/* nodes in the system */
int numa_num_configured_nodes();
/* maximum cpus */
int numa_num_configured_cpus();
/* maximum cpus allowed to current task */
int numa_num_task_cpus();
int numa_num_thread_cpus(); /* backward compatibility */
/* maximum nodes allowed to current task */
int numa_num_task_nodes();
int numa_num_thread_nodes(); /* backward compatibility */
/* allocate a bitmask the size of the kernel cpumask_t */
struct bitmask *numa_allocate_cpumask();
static inline void numa_free_cpumask(struct bitmask *b)
{
numa_bitmask_free(b);
}
/* Convert node to CPU mask. -1/errno on failure, otherwise 0. */
int numa_node_to_cpus(int, struct bitmask *);
/* report the node of the specified cpu. -1/errno on invalid cpu. */
int numa_node_of_cpu(int cpu);
/* Report distance of node1 from node2. 0 on error.*/
int numa_distance(int node1, int node2);
/* Error handling. */
/* This is an internal function in libnuma that can be overwritten by an user
program. Default is to print an error to stderr and exit if numa_exit_on_error
is true. */
void numa_error(char *where);
/* When true exit the program when a NUMA system call (except numa_available)
fails */
extern int numa_exit_on_error;
/* Warning function. Can also be overwritten. Default is to print on stderr
once. */
void numa_warn(int num, char *fmt, ...);
/* When true exit the program on a numa_warn() call */
extern int numa_exit_on_warn;
int numa_migrate_pages(int pid, struct bitmask *from, struct bitmask *to);
int numa_move_pages(int pid, unsigned long count, void **pages,
const int *nodes, int *status, int flags);
int numa_sched_getaffinity(pid_t, struct bitmask *);
int numa_sched_setaffinity(pid_t, struct bitmask *);
/* Convert an ascii list of nodes to a bitmask */
struct bitmask *numa_parse_nodestring(const char *);
/* Convert an ascii list of nodes to a bitmask without current nodeset
* dependency */
struct bitmask *numa_parse_nodestring_all(const char *);
/* Convert an ascii list of cpu to a bitmask */
struct bitmask *numa_parse_cpustring(const char *);
/* Convert an ascii list of cpu to a bitmask without current taskset
* dependency */
struct bitmask *numa_parse_cpustring_all(const char *);
/*
* The following functions are for source code compatibility
* with releases prior to version 2.
* Such codes should be compiled with NUMA_VERSION1_COMPATIBILITY defined.
*/
static inline void numa_set_interleave_mask_compat(nodemask_t *nodemask)
{
struct bitmask tmp;
tmp.maskp = (unsigned long *)nodemask;
tmp.size = sizeof(nodemask_t) * 8;
numa_set_interleave_mask(&tmp);
}
static inline nodemask_t numa_get_interleave_mask_compat()
{
struct bitmask *tp;
nodemask_t mask;
tp = numa_get_interleave_mask();
copy_bitmask_to_nodemask(tp, &mask);
numa_bitmask_free(tp);
return mask;
}
static inline void numa_bind_compat(nodemask_t *mask)
{
struct bitmask *tp;
tp = numa_allocate_nodemask();
copy_nodemask_to_bitmask(mask, tp);
numa_bind(tp);
numa_bitmask_free(tp);
}
static inline void numa_set_membind_compat(nodemask_t *mask)
{
struct bitmask tmp;
tmp.maskp = (unsigned long *)mask;
tmp.size = sizeof(nodemask_t) * 8;
numa_set_membind(&tmp);
}
static inline nodemask_t numa_get_membind_compat()
{
struct bitmask *tp;
nodemask_t mask;
tp = numa_get_membind();
copy_bitmask_to_nodemask(tp, &mask);
numa_bitmask_free(tp);
return mask;
}
static inline void *numa_alloc_interleaved_subset_compat(size_t size,
const nodemask_t *mask)
{
struct bitmask tmp;
tmp.maskp = (unsigned long *)mask;
tmp.size = sizeof(nodemask_t) * 8;
return numa_alloc_interleaved_subset(size, &tmp);
}
static inline int numa_run_on_node_mask_compat(const nodemask_t *mask)
{
struct bitmask tmp;
tmp.maskp = (unsigned long *)mask;
tmp.size = sizeof(nodemask_t) * 8;
return numa_run_on_node_mask(&tmp);
}
static inline nodemask_t numa_get_run_node_mask_compat()
{
struct bitmask *tp;
nodemask_t mask;
tp = numa_get_run_node_mask();
copy_bitmask_to_nodemask(tp, &mask);
numa_bitmask_free(tp);
return mask;
}
static inline void numa_interleave_memory_compat(void *mem, size_t size,
const nodemask_t *mask)
{
struct bitmask tmp;
tmp.maskp = (unsigned long *)mask;
tmp.size = sizeof(nodemask_t) * 8;
numa_interleave_memory(mem, size, &tmp);
}
static inline void numa_tonodemask_memory_compat(void *mem, size_t size,
const nodemask_t *mask)
{
struct bitmask tmp;
tmp.maskp = (unsigned long *)mask;
tmp.size = sizeof(nodemask_t) * 8;
numa_tonodemask_memory(mem, size, &tmp);
}
static inline int numa_sched_getaffinity_compat(pid_t pid, unsigned len,
unsigned long *mask)
{
struct bitmask tmp;
tmp.maskp = (unsigned long *)mask;
tmp.size = len * 8;
return numa_sched_getaffinity(pid, &tmp);
}
static inline int numa_sched_setaffinity_compat(pid_t pid, unsigned len,
unsigned long *mask)
{
struct bitmask tmp;
tmp.maskp = (unsigned long *)mask;
tmp.size = len * 8;
return numa_sched_setaffinity(pid, &tmp);
}
static inline int numa_node_to_cpus_compat(int node, unsigned long *buffer,
int buffer_len)
{
struct bitmask tmp;
tmp.maskp = (unsigned long *)buffer;
tmp.size = buffer_len * 8;
return numa_node_to_cpus(node, &tmp);
}
/* end of version 1 compatibility functions */
/*
* To compile an application that uses libnuma version 1:
* add -DNUMA_VERSION1_COMPATIBILITY to your Makefile's CFLAGS
*/
#ifdef NUMA_VERSION1_COMPATIBILITY
#include <numacompat1.h>
#endif
#ifdef __cplusplus
}
#endif
#endif

10
numa.pc.in Normal file
View File

@ -0,0 +1,10 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: numa
Description: NUMA policy library
Version: @VERSION@
Cflags: -I${includedir}
Libs: -L${libdir} -lnuma

18
numacompat1.h Normal file
View File

@ -0,0 +1,18 @@
#define numa_set_interleave_mask(m) numa_set_interleave_mask_compat(m)
#define numa_get_interleave_mask() numa_get_interleave_mask_compat()
#define numa_bind(m) numa_bind_compat(m)
#define numa_get_membind(m) numa_get_membind_compat(m)
#define numa_set_membind(m) numa_set_membind_compat(m)
#define numa_alloc_interleaved_subset(s,m) numa_alloc_interleaved_subset_compat(s,m)
#define numa_run_on_node_mask(m) numa_run_on_node_mask_compat(m)
#define numa_get_run_node_mask() numa_get_run_node_mask_compat()
#define numa_interleave_memory(st,si,m) numa_interleave_memory_compat(st,si,m)
#define numa_tonodemask_memory(st,si,m) numa_tonodemask_memory_compat(st,si,m)
#define numa_sched_getaffinity(p,l,m) numa_sched_getaffinity_compat(p,l,m)
#define numa_sched_setaffinity(p,l,m) numa_sched_setaffinity_compat(p,l,m)
#define numa_node_to_cpus(n,b,bl) numa_node_to_cpus_compat(n,b,bl)
#define nodemask_zero(m) nodemask_zero_compat(m)
#define nodemask_set(m, n) nodemask_set_compat(m, n)
#define nodemask_clr(m, n) nodemask_clr_compat(m, n)
#define nodemask_isset(m, n) nodemask_isset_compat(m, n)
#define nodemask_equal(a, b) nodemask_equal_compat(a, b)

354
numactl.8 Normal file
View File

@ -0,0 +1,354 @@
.\" t
.\" Copyright 2003,2004 Andi Kleen, SuSE Labs.
.\"
.\" Permission is granted to make and distribute verbatim copies of this
.\" manual provided the copyright notice and this permission notice are
.\" preserved on all copies.
.\"
.\" Permission is granted to copy and distribute modified versions of this
.\" manual under the conditions for verbatim copying, provided that the
.\" entire resulting derived work is distributed under the terms of a
.\" permission notice identical to this one.
.\"
.\" Since the Linux kernel and libraries are constantly changing, this
.\" manual page may be incorrect or out-of-date. The author(s) assume no
.\" responsibility for errors or omissions, or for damages resulting from
.\" the use of the information contained herein.
.\"
.\" Formatted or processed versions of this manual, if unaccompanied by
.\" the source, must acknowledge the copyright and authors of this work.
.TH NUMACTL 8 "Mar 2004" "SuSE Labs" "Linux Administrator's Manual"
.SH NAME
numactl \- Control NUMA policy for processes or shared memory
.SH SYNOPSIS
.B numactl
[
.B \-\-all
] [
.B \-\-interleave nodes
] [
.B \-\-preferred node
] [
.B \-\-membind nodes
] [
.B \-\-cpunodebind nodes
] [
.B \-\-physcpubind cpus
] [
.B \-\-localalloc
] [\-\-] command {arguments ...}
.br
.B numactl \-\-show
.br
.B numactl \-\-hardware
.br
.B numactl
[
.B \-\-huge
] [
.B \-\-offset offset
] [
.B \-\-shmmode shmmode
] [
.B \-\-length length
] [
.B \-\-strict
]
.br
[
.B \-\-shmid id
]
.B \-\-shm shmkeyfile
|
.B \-\-file tmpfsfile
.br
[
.B \-\-touch
] [
.B \-\-dump
] [
.B \-\-dump-nodes
]
memory policy
.SH DESCRIPTION
.B numactl
runs processes with a specific NUMA scheduling or memory placement policy.
The policy is set for command and inherited by all of its children.
In addition it can set persistent policy for shared memory segments or files.
.PP
Use -- before command if using command options that could be confused
with numactl options.
.PP
.I nodes
may be specified as N,N,N or N-N or N,N-N or N-N,N-N and so forth.
Relative
.I nodes
may be specifed as +N,N,N or +N-N or +N,N-N and so forth. The + indicates that
the node numbers are relative to the process' set of allowed nodes in its
current cpuset.
A !N-N notation indicates the inverse of N-N, in other words all nodes
except N-N. If used with + notation, specify !+N-N. When
.I same
is specified the previous nodemask specified on the command line is used.
all means all nodes in the current cpuset.
.PP
Instead of a number a node can also be:
.TS
tab(|);
l l.
netdev:DEV|The node connected to network device DEV.
file:PATH |The node the block device of PATH.
ip:HOST |The node of the network device of HOST
block:PATH|The node of block device PATH
pci:[seg:]bus:dev[:func]|The node of a PCI device.
.TE
Note that block resolves the kernel block device names only
for udev names in /dev use
.I file:
.TP
Policy settings are:
.TP
.B \-\-all, \-a
Unset default cpuset awareness, so user can use all possible CPUs/nodes
for following policy settings.
.TP
.B \-\-interleave=nodes, \-i nodes
Set a memory interleave policy. Memory will be allocated using round robin
on
.I nodes.
When memory cannot be allocated on the current interleave target fall back
to other nodes.
Multiple nodes may be specified on --interleave, --membind and --cpunodebind.
.TP
.B \-\-membind=nodes, \-m nodes
Only allocate memory from nodes. Allocation will fail when there
is not enough memory available on these nodes.
.I nodes
may be specified as noted above.
.TP
.B \-\-cpunodebind=nodes, \-N nodes
Only execute
.I command
on the CPUs of
.I nodes.
Note that nodes may consist of multiple CPUs.
.I nodes
may be specified as noted above.
.TP
.B \-\-physcpubind=cpus, \-C cpus
Only execute
.I process
on
.I cpus.
This accepts cpu numbers as shown in the
.I processor
fields of
.I /proc/cpuinfo,
or relative cpus as in relative to the current cpuset.
You may specify "all", which means all cpus in the current cpuset.
Physical
.I cpus
may be specified as N,N,N or N-N or N,N-N or N-N,N-N and so forth.
Relative
.I cpus
may be specifed as +N,N,N or +N-N or +N,N-N and so forth. The + indicates that
the cpu numbers are relative to the process' set of allowed cpus in its
current cpuset.
A !N-N notation indicates the inverse of N-N, in other words all cpus
except N-N. If used with + notation, specify !+N-N.
.TP
.B \-\-localalloc, \-l
Always allocate on the current node.
.TP
.B \-\-preferred=node
Preferably allocate memory on
.I node,
but if memory cannot be allocated there fall back to other nodes.
This option takes only a single node number.
Relative notation may be used.
.TP
.B \-\-show, \-s
Show NUMA policy settings of the current process.
.TP
.B \-\-hardware, \-H
Show inventory of available nodes on the system.
.TP 0
Numactl can set up policy for a SYSV shared memory segment or a file in shmfs/hugetlbfs.
This policy is persistent and will be used by
all mappings from that shared memory. The order of options matters here.
The specification must at least include either of
.I \-\-shm,
.I \-\-shmid,
.I \-\-file
to specify the shared memory segment or file and a memory policy like described
above (
.I \-\-interleave,
.I \-\-localalloc,
.I \-\-preferred,
.I \-\-membind
).
.TP
.B \-\-huge
When creating a SYSV shared memory segment use huge pages.
Only valid before \-\-shmid or \-\-shm
.TP
.B \-\-offset
Specify offset into the shared memory segment. Default 0.
Valid units are
.I m
(for MB),
.I g
(for GB),
.I k
(for KB),
otherwise it specifies bytes.
.TP
.B \-\-strict
Give an error when a page in the policied area in the shared memory
segment already was faulted in with a conflicting policy. Default
is to silently ignore this.
.TP
.B \-\-shmmode shmmode
Only valid before \-\-shmid or \-\-shm
When creating a shared memory segment set it to numeric mode
.I shmmode.
.TP
.B \-\-length length
Apply policy to
.I length
range in the shared memory segment or make
the segment length long
Default is to use the remaining length
Required when a shared memory segment is created and specifies the length
of the new segment then. Valid units are
.I m
(for MB),
.I g
(for GB),
.I k
(for KB),
otherwise it specifies bytes.
.TP
.B \-\-shmid id
Create or use an shared memory segment with numeric ID
.I id
.TP
.B \-\-shm shmkeyfile
Create or use an shared memory segment, with the ID generated
using
.I ftok(3)
from shmkeyfile
.TP
.B \-\-file tmpfsfile
Set policy for a file in tmpfs or hugetlbfs
.TP
.B \-\-touch
Touch pages to enforce policy early. Default is to not touch them, the policy
is applied when an applications maps and accesses a page.
.TP
.B \-\-dump
Dump policy in the specified range.
.TP
.B \-\-dump-nodes
Dump all nodes of the specific range (very verbose!)
.TP
Valid node specifiers
.TS
tab(:);
l l.
all:All nodes
number:Node number
number1{,number2}:Node number1 and Node number2
number1-number2:Nodes from number1 to number2
! nodes:Invert selection of the following specification.
.TE
.SH EXAMPLES
numactl \-\-physcpubind=+0-4,8-12 myapplic arguments
Run myapplic on cpus 0-4 and 8-12 of the current cpuset.
numactl \-\-interleave=all bigdatabase arguments
Run big database with its memory interleaved on all CPUs.
numactl \-\-cpunodebind=0 \-\-membind=0,1 process
Run process on node 0 with memory allocated on node 0 and 1.
numactl \-\-cpunodebind=0 \-\-membind=0,1 -- process -l
Run process as above, but with an option (-l) that would be confused with
a numactl option.
numactl \-\-cpunodebind=netdev:eth0 \-\-membind=netdev:eth0 network-server
Run network-server on the node of network device eth0 with its memory
also in the same node.
numactl \-\-preferred=1 numactl \-\-show
Set preferred node 1 and show the resulting state.
numactl --interleave=all --shm /tmp/shmkey
Interleave all of the sysv shared memory region specified by
/tmp/shmkey over all nodes.
Place a tmpfs file on 2 nodes:
numactl --membind=2 dd if=/dev/zero of=/dev/shm/A bs=1M count=1024
numactl --membind=3 dd if=/dev/zero of=/dev/shm/A seek=1024 bs=1M count=1024
numactl --localalloc /dev/shm/file
Reset the policy for the shared memory file
.I file
to the default localalloc policy.
.SH NOTES
Requires an NUMA policy aware kernel.
Command is not executed using a shell. If you want to use shell metacharacters
in the child use sh -c as wrapper.
Setting policy for a hugetlbfs file does currently not work because
it cannot be extended by truncate.
Shared memory segments larger than numactl's address space cannot
be completely policied. This could be a problem on 32bit architectures.
Changing it piece by piece may work.
The old
.I --cpubind
which accepts node numbers, not cpu numbers, is deprecated
and replaced with the new
.I --cpunodebind
and
.I --physcpubind
options.
.SH FILES
.I /proc/cpuinfo
for the listing of active CPUs. See
.I proc(5)
for details.
.I /sys/devices/system/node/node*/numastat
for NUMA memory hit statistics.
.SH COPYRIGHT
Copyright 2002,2004 Andi Kleen, SuSE Labs.
numactl and the demo programs are under the GNU General Public License, v.2
.SH SEE ALSO
.I set_mempolicy(2)
,
.I get_mempolicy(2)
,
.I mbind(2)
,
.I sched_setaffinity(2)
,
.I sched_getaffinity(2)
,
.I proc(5)
,
.I ftok(3)
,
.I shmat(2)
,
.I migratepages(8)

662
numactl.c Normal file
View File

@ -0,0 +1,662 @@
/* Copyright (C) 2003,2004,2005 Andi Kleen, SuSE Labs.
Command line NUMA policy control.
numactl is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; version
2.
numactl 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
General Public License for more details.
You should find a copy of v2 of the GNU 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 */
#define _GNU_SOURCE
#include <getopt.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <ctype.h>
#include "numa.h"
#include "numaif.h"
#include "numaint.h"
#include "util.h"
#include "shm.h"
#define CPUSET 0
#define ALL 1
int exitcode;
struct option opts[] = {
{"all", 0, 0, 'a'},
{"interleave", 1, 0, 'i' },
{"preferred", 1, 0, 'p' },
{"cpubind", 1, 0, 'c' },
{"cpunodebind", 1, 0, 'N' },
{"physcpubind", 1, 0, 'C' },
{"membind", 1, 0, 'm'},
{"show", 0, 0, 's' },
{"localalloc", 0,0, 'l'},
{"hardware", 0,0,'H' },
{"shm", 1, 0, 'S'},
{"file", 1, 0, 'f'},
{"offset", 1, 0, 'o'},
{"length", 1, 0, 'L'},
{"strict", 0, 0, 't'},
{"shmmode", 1, 0, 'M'},
{"dump", 0, 0, 'd'},
{"dump-nodes", 0, 0, 'D'},
{"shmid", 1, 0, 'I'},
{"huge", 0, 0, 'u'},
{"touch", 0, 0, 'T'},
{"verify", 0, 0, 'V'}, /* undocumented - for debugging */
{ 0 }
};
void usage(void)
{
fprintf(stderr,
"usage: numactl [--all | -a] [--interleave= | -i <nodes>] [--preferred= | -p <node>]\n"
" [--physcpubind= | -C <cpus>] [--cpunodebind= | -N <nodes>]\n"
" [--membind= | -m <nodes>] [--localalloc | -l] command args ...\n"
" numactl [--show | -s]\n"
" numactl [--hardware | -H]\n"
" numactl [--length | -l <length>] [--offset | -o <offset>] [--shmmode | -M <shmmode>]\n"
" [--strict | -t]\n"
" [--shmid | -I <id>] --shm | -S <shmkeyfile>\n"
" [--shmid | -I <id>] --file | -f <tmpfsfile>\n"
" [--huge | -u] [--touch | -T] \n"
" memory policy | --dump | -d | --dump-nodes | -D\n"
"\n"
"memory policy is --interleave | -i, --preferred | -p, --membind | -m, --localalloc | -l\n"
"<nodes> is a comma delimited list of node numbers or A-B ranges or all.\n"
"Instead of a number a node can also be:\n"
" netdev:DEV the node connected to network device DEV\n"
" file:PATH the node the block device of path is connected to\n"
" ip:HOST the node of the network device host routes through\n"
" block:PATH the node of block device path\n"
" pci:[seg:]bus:dev[:func] The node of a PCI device\n"
"<cpus> is a comma delimited list of cpu numbers or A-B ranges or all\n"
"all ranges can be inverted with !\n"
"all numbers and ranges can be made cpuset-relative with +\n"
"the old --cpubind argument is deprecated.\n"
"use --cpunodebind or --physcpubind instead\n"
"<length> can have g (GB), m (MB) or k (KB) suffixes\n");
exit(1);
}
void usage_msg(char *msg, ...)
{
va_list ap;
va_start(ap,msg);
fprintf(stderr, "numactl: ");
vfprintf(stderr, msg, ap);
putchar('\n');
usage();
}
void show_physcpubind(void)
{
int ncpus = numa_num_configured_cpus();
for (;;) {
struct bitmask *cpubuf;
cpubuf = numa_bitmask_alloc(ncpus);
if (numa_sched_getaffinity(0, cpubuf) < 0) {
if (errno == EINVAL && ncpus < 1024*1024) {
ncpus *= 2;
continue;
}
err("sched_get_affinity");
}
printmask("physcpubind", cpubuf);
break;
}
}
void show(void)
{
unsigned long prefnode;
struct bitmask *membind, *interleave, *cpubind;
unsigned long cur;
int policy;
if (numa_available() < 0) {
show_physcpubind();
printf("No NUMA support available on this system.\n");
exit(1);
}
cpubind = numa_get_run_node_mask();
prefnode = numa_preferred();
interleave = numa_get_interleave_mask();
membind = numa_get_membind();
cur = numa_get_interleave_node();
policy = 0;
if (get_mempolicy(&policy, NULL, 0, 0, 0) < 0)
perror("get_mempolicy");
printf("policy: %s\n", policy_name(policy));
printf("preferred node: ");
switch (policy) {
case MPOL_PREFERRED:
if (prefnode != -1) {
printf("%ld\n", prefnode);
break;
}
/*FALL THROUGH*/
case MPOL_DEFAULT:
printf("current\n");
break;
case MPOL_INTERLEAVE:
printf("%ld (interleave next)\n",cur);
break;
case MPOL_BIND:
printf("%d\n", find_first(membind));
break;
}
if (policy == MPOL_INTERLEAVE) {
printmask("interleavemask", interleave);
printf("interleavenode: %ld\n", cur);
}
show_physcpubind();
printmask("cpubind", cpubind); // for compatibility
printmask("nodebind", cpubind);
printmask("membind", membind);
}
char *fmt_mem(unsigned long long mem, char *buf)
{
if (mem == -1L)
sprintf(buf, "<not available>");
else
sprintf(buf, "%llu MB", mem >> 20);
return buf;
}
static void print_distances(int maxnode)
{
int i,k;
int fst = 0;
for (i = 0; i <= maxnode; i++)
if (numa_bitmask_isbitset(numa_nodes_ptr, i)) {
fst = i;
break;
}
if (numa_distance(maxnode,fst) == 0) {
printf("No distance information available.\n");
return;
}
printf("node distances:\n");
printf("node ");
for (i = 0; i <= maxnode; i++)
if (numa_bitmask_isbitset(numa_nodes_ptr, i))
printf("% 3d ", i);
printf("\n");
for (i = 0; i <= maxnode; i++) {
if (!numa_bitmask_isbitset(numa_nodes_ptr, i))
continue;
printf("% 3d: ", i);
for (k = 0; k <= maxnode; k++)
if (numa_bitmask_isbitset(numa_nodes_ptr, i) &&
numa_bitmask_isbitset(numa_nodes_ptr, k))
printf("% 3d ", numa_distance(i,k));
printf("\n");
}
}
void print_node_cpus(int node)
{
int i, err;
struct bitmask *cpus;
cpus = numa_allocate_cpumask();
err = numa_node_to_cpus(node, cpus);
if (err >= 0) {
for (i = 0; i < cpus->size; i++)
if (numa_bitmask_isbitset(cpus, i))
printf(" %d", i);
}
putchar('\n');
}
void hardware(void)
{
int i;
int numnodes=0;
int prevnode=-1;
int skip=0;
int maxnode = numa_max_node();
if (numa_available() < 0) {
printf("No NUMA available on this system\n");
exit(1);
}
for (i=0; i<=maxnode; i++)
if (numa_bitmask_isbitset(numa_nodes_ptr, i))
numnodes++;
printf("available: %d nodes (", numnodes);
for (i=0; i<=maxnode; i++) {
if (numa_bitmask_isbitset(numa_nodes_ptr, i)) {
if (prevnode == -1) {
printf("%d", i);
prevnode=i;
continue;
}
if (i > prevnode + 1) {
if (skip) {
printf("%d", prevnode);
skip=0;
}
printf(",%d", i);
prevnode=i;
continue;
}
if (i == prevnode + 1) {
if (!skip) {
printf("-");
skip=1;
}
prevnode=i;
}
if ((i == maxnode) && skip)
printf("%d", prevnode);
}
}
printf(")\n");
for (i = 0; i <= maxnode; i++) {
char buf[64];
long long fr;
unsigned long long sz = numa_node_size64(i, &fr);
if (!numa_bitmask_isbitset(numa_nodes_ptr, i))
continue;
printf("node %d cpus:", i);
print_node_cpus(i);
printf("node %d size: %s\n", i, fmt_mem(sz, buf));
printf("node %d free: %s\n", i, fmt_mem(fr, buf));
}
print_distances(maxnode);
}
void checkerror(char *s)
{
if (errno) {
perror(s);
exit(1);
}
}
void checknuma(void)
{
static int numa = -1;
if (numa < 0) {
if (numa_available() < 0)
complain("This system does not support NUMA policy");
}
numa = 0;
}
int set_policy = -1;
void setpolicy(int pol)
{
if (set_policy != -1)
usage_msg("Conflicting policies");
set_policy = pol;
}
void nopolicy(void)
{
if (set_policy >= 0)
usage_msg("specify policy after --shm/--file");
}
int did_cpubind = 0;
int did_strict = 0;
int do_shm = 0;
int do_dump = 0;
int shmattached = 0;
int did_node_cpu_parse = 0;
int parse_all = 0;
char *shmoption;
void check_cpubind(int flag)
{
if (flag)
usage_msg("cannot do --cpubind on shared memory\n");
}
void noshm(char *opt)
{
if (shmattached)
usage_msg("%s must be before shared memory specification", opt);
shmoption = opt;
}
void dontshm(char *opt)
{
if (shmoption)
usage_msg("%s shm option is not allowed before %s", shmoption, opt);
}
void needshm(char *opt)
{
if (!shmattached)
usage_msg("%s must be after shared memory specification", opt);
}
void check_all_parse(int flag)
{
if (did_node_cpu_parse)
usage_msg("--all/-a option must be before all cpu/node specifications");
}
void get_short_opts(struct option *o, char *s)
{
*s++ = '+';
while (o->name) {
if (isprint(o->val)) {
*s++ = o->val;
if (o->has_arg)
*s++ = ':';
}
o++;
}
*s = '\0';
}
void check_shmbeyond(char *msg)
{
if (shmoffset >= shmlen) {
fprintf(stderr,
"numactl: region offset %#llx beyond its length %#llx at %s\n",
shmoffset, shmlen, msg);
exit(1);
}
}
static struct bitmask *numactl_parse_nodestring(char *s, int flag)
{
static char *last;
if (s[0] == 's' && !strcmp(s, "same")) {
if (!last)
usage_msg("same needs previous node specification");
s = last;
} else {
last = s;
}
if (flag == ALL)
return numa_parse_nodestring_all(s);
else
return numa_parse_nodestring(s);
}
int main(int ac, char **av)
{
int c, i, nnodes=0;
long node=-1;
char *end;
char shortopts[array_len(opts)*2 + 1];
struct bitmask *mask = NULL;
get_short_opts(opts,shortopts);
while ((c = getopt_long(ac, av, shortopts, opts, NULL)) != -1) {
switch (c) {
case 's': /* --show */
show();
exit(0);
case 'H': /* --hardware */
nopolicy();
hardware();
exit(0);
case 'i': /* --interleave */
checknuma();
if (parse_all)
mask = numactl_parse_nodestring(optarg, ALL);
else
mask = numactl_parse_nodestring(optarg, CPUSET);
if (!mask) {
printf ("<%s> is invalid\n", optarg);
usage();
}
errno = 0;
did_node_cpu_parse = 1;
setpolicy(MPOL_INTERLEAVE);
if (shmfd >= 0)
numa_interleave_memory(shmptr, shmlen, mask);
else
numa_set_interleave_mask(mask);
checkerror("setting interleave mask");
break;
case 'N': /* --cpunodebind */
case 'c': /* --cpubind */
dontshm("-c/--cpubind/--cpunodebind");
checknuma();
if (parse_all)
mask = numactl_parse_nodestring(optarg, ALL);
else
mask = numactl_parse_nodestring(optarg, CPUSET);
if (!mask) {
printf ("<%s> is invalid\n", optarg);
usage();
}
errno = 0;
check_cpubind(do_shm);
did_cpubind = 1;
did_node_cpu_parse = 1;
numa_run_on_node_mask_all(mask);
checkerror("sched_setaffinity");
break;
case 'C': /* --physcpubind */
{
struct bitmask *cpubuf;
dontshm("-C/--physcpubind");
if (parse_all)
cpubuf = numa_parse_cpustring_all(optarg);
else
cpubuf = numa_parse_cpustring(optarg);
if (!cpubuf) {
printf ("<%s> is invalid\n", optarg);
usage();
}
errno = 0;
check_cpubind(do_shm);
did_cpubind = 1;
did_node_cpu_parse = 1;
numa_sched_setaffinity(0, cpubuf);
checkerror("sched_setaffinity");
free(cpubuf);
break;
}
case 'm': /* --membind */
checknuma();
setpolicy(MPOL_BIND);
if (parse_all)
mask = numactl_parse_nodestring(optarg, ALL);
else
mask = numactl_parse_nodestring(optarg, CPUSET);
if (!mask) {
printf ("<%s> is invalid\n", optarg);
usage();
}
errno = 0;
did_node_cpu_parse = 1;
numa_set_bind_policy(1);
if (shmfd >= 0) {
numa_tonodemask_memory(shmptr, shmlen, mask);
} else {
numa_set_membind(mask);
}
numa_set_bind_policy(0);
checkerror("setting membind");
break;
case 'p': /* --preferred */
checknuma();
setpolicy(MPOL_PREFERRED);
if (parse_all)
mask = numactl_parse_nodestring(optarg, ALL);
else
mask = numactl_parse_nodestring(optarg, CPUSET);
if (!mask) {
printf ("<%s> is invalid\n", optarg);
usage();
}
for (i=0; i<mask->size; i++) {
if (numa_bitmask_isbitset(mask, i)) {
node = i;
nnodes++;
}
}
if (nnodes != 1)
usage();
numa_bitmask_free(mask);
errno = 0;
did_node_cpu_parse = 1;
numa_set_bind_policy(0);
if (shmfd >= 0)
numa_tonode_memory(shmptr, shmlen, node);
else
numa_set_preferred(node);
checkerror("setting preferred node");
break;
case 'l': /* --local */
checknuma();
setpolicy(MPOL_DEFAULT);
errno = 0;
if (shmfd >= 0)
numa_setlocal_memory(shmptr, shmlen);
else
numa_set_localalloc();
checkerror("local allocation");
break;
case 'S': /* --shm */
check_cpubind(did_cpubind);
nopolicy();
attach_sysvshm(optarg, "--shm");
shmattached = 1;
break;
case 'f': /* --file */
check_cpubind(did_cpubind);
nopolicy();
attach_shared(optarg, "--file");
shmattached = 1;
break;
case 'L': /* --length */
noshm("--length");
shmlen = memsize(optarg);
break;
case 'M': /* --shmmode */
noshm("--shmmode");
shmmode = strtoul(optarg, &end, 8);
if (end == optarg || *end)
usage();
break;
case 'd': /* --dump */
if (shmfd < 0)
complain(
"Cannot do --dump without shared memory.\n");
dump_shm();
do_dump = 1;
break;
case 'D': /* --dump-nodes */
if (shmfd < 0)
complain(
"Cannot do --dump-nodes without shared memory.\n");
dump_shm_nodes();
do_dump = 1;
break;
case 't': /* --strict */
did_strict = 1;
numa_set_strict(1);
break;
case 'I': /* --shmid */
shmid = strtoul(optarg, &end, 0);
if (end == optarg || *end)
usage();
break;
case 'u': /* --huge */
noshm("--huge");
shmflags |= SHM_HUGETLB;
break;
case 'o': /* --offset */
noshm("--offset");
shmoffset = memsize(optarg);
break;
case 'T': /* --touch */
needshm("--touch");
check_shmbeyond("--touch");
numa_police_memory(shmptr, shmlen);
break;
case 'V': /* --verify */
needshm("--verify");
if (set_policy < 0)
complain("Need a policy first to verify");
check_shmbeyond("--verify");
numa_police_memory(shmptr, shmlen);
if (!mask)
complain("Need a mask to verify");
else
verify_shm(set_policy, mask);
break;
case 'a': /* --all */
check_all_parse(did_node_cpu_parse);
parse_all = 1;
break;
default:
usage();
}
}
av += optind;
ac -= optind;
if (shmfd >= 0) {
if (*av)
usage();
exit(exitcode);
}
if (did_strict)
fprintf(stderr,
"numactl: warning. Strict flag for process ignored.\n");
if (do_dump)
usage_msg("cannot do --dump|--dump-shm for process");
if (shmoption)
usage_msg("shm related option %s for process", shmoption);
if (*av == NULL)
usage();
execvp(*av, av);
complain("execution of `%s': %s\n", av[0], strerror(errno));
return 0; /* not reached */
}

570
numademo.c Normal file
View File

@ -0,0 +1,570 @@
/* Copyright (C) 2003,2004 Andi Kleen, SuSE Labs.
Test/demo program for libnuma. This is also a more or less useful benchmark
of the NUMA characteristics of your machine. It benchmarks most possible
NUMA policy memory configurations with various benchmarks.
Compile standalone with cc -O2 numademo.c -o numademo -lnuma -lm
numactl is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; version
2.
numactl 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
General Public License for more details.
You should find a copy of v2 of the GNU 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 */
#define _GNU_SOURCE 1
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/time.h>
#include "numa.h"
#ifdef HAVE_STREAM_LIB
#include "stream_lib.h"
#endif
#ifdef HAVE_MT
#include "mt.h"
#endif
#ifdef HAVE_CLEAR_CACHE
#include "clearcache.h"
#else
static inline void clearcache(void *a, unsigned size) {}
#endif
#define FRACT_NODES 8
#define FRACT_MASKS 32
int fract_nodes;
int *node_to_use;
unsigned long msize;
/* Should get this from cpuinfo, but on !x86 it's not there */
enum {
CACHELINESIZE = 64,
};
enum test {
MEMSET = 0,
MEMCPY,
FORWARD,
BACKWARD,
STREAM,
RANDOM2,
PTRCHASE,
} thistest;
char *delim = " ";
int force;
int regression_testing=0;
char *testname[] = {
"memset",
"memcpy",
"forward",
"backward",
#ifdef HAVE_STREAM_LIB
"stream",
#endif
#ifdef HAVE_MT
"random2",
#endif
"ptrchase",
NULL,
};
void output(char *title, char *result)
{
if (!isspace(delim[0]))
printf("%s%s%s\n", title,delim, result);
else
printf("%-42s%s\n", title, result);
}
#ifdef HAVE_STREAM_LIB
void do_stream(char *name, unsigned char *mem)
{
int i;
char title[100], buf[100];
double res[STREAM_NRESULTS];
stream_verbose = 0;
clearcache(mem, msize);
stream_init(mem);
stream_test(res);
sprintf(title, "%s%s%s", name, delim, "STREAM");
buf[0] = '\0';
for (i = 0; i < STREAM_NRESULTS; i++) {
if (buf[0])
strcat(buf,delim);
sprintf(buf+strlen(buf), "%s%s%.2f%sMB/s",
stream_names[i], delim, res[i], delim);
}
output(title, buf);
clearcache(mem, msize);
}
#endif
/* Set up a randomly distributed list to fool prefetchers */
union node {
union node *next;
struct {
unsigned nexti;
unsigned val;
};
};
static int cmp_node(const void *ap, const void *bp)
{
union node *a = (union node *)ap;
union node *b = (union node *)bp;
return a->val - b->val;
}
void **ptrchase_init(unsigned char *mem)
{
long i;
union node *nodes = (union node *)mem;
long nmemb = msize / sizeof(union node);
srand(1234);
for (i = 0; i < nmemb; i++) {
nodes[i].val = rand();
nodes[i].nexti = i + 1;
}
qsort(nodes, nmemb, sizeof(union node), cmp_node);
for (i = 0; i < nmemb; i++) {
union node *n = &nodes[i];
n->next = n->nexti >= nmemb ? NULL : &nodes[n->nexti];
}
return (void **)nodes;
}
static inline unsigned long long timerfold(struct timeval *tv)
{
return tv->tv_sec * 1000000ULL + tv->tv_usec;
}
#define LOOPS 10
void memtest(char *name, unsigned char *mem)
{
long k;
struct timeval start, end, res;
unsigned long long max, min, sum, r;
int i;
char title[128], result[128];
if (!mem) {
fprintf(stderr,
"Failed to allocate %lu bytes of memory. Test \"%s\" exits.\n",
msize, name);
return;
}
#ifdef HAVE_STREAM_LIB
if (thistest == STREAM) {
do_stream(name, mem);
goto out;
}
#endif
max = 0;
min = ~0UL;
sum = 0;
/*
* Note: 0th pass allocates the pages, don't measure
*/
for (i = 0; i < LOOPS+1; i++) {
clearcache(mem, msize);
switch (thistest) {
case PTRCHASE:
{
void **ptr;
ptr = ptrchase_init(mem);
gettimeofday(&start,NULL);
while (*ptr)
ptr = (void **)*ptr;
gettimeofday(&end,NULL);
/* Side effect to trick the optimizer */
*ptr = "bla";
break;
}
case MEMSET:
gettimeofday(&start,NULL);
memset(mem, 0xff, msize);
gettimeofday(&end,NULL);
break;
case MEMCPY:
gettimeofday(&start,NULL);
memcpy(mem, mem + msize/2, msize/2);
gettimeofday(&end,NULL);
break;
case FORWARD:
/* simple kernel to just fetch cachelines and write them back.
will trigger hardware prefetch */
gettimeofday(&start,NULL);
for (k = 0; k < msize; k+=CACHELINESIZE)
mem[k]++;
gettimeofday(&end,NULL);
break;
case BACKWARD:
gettimeofday(&start,NULL);
for (k = msize-5; k > 0; k-=CACHELINESIZE)
mem[k]--;
gettimeofday(&end,NULL);
break;
#ifdef HAVE_MT
case RANDOM2:
{
unsigned * __restrict m = (unsigned *)mem;
unsigned max = msize / sizeof(unsigned);
unsigned mask;
mt_init();
mask = 1;
while (mask < max)
mask = (mask << 1) | 1;
/*
* There's no guarantee all memory is touched, but
* we assume (hope) that the distribution of the MT
* is good enough to touch most.
*/
gettimeofday(&start,NULL);
for (k = 0; k < max; k++) {
unsigned idx = mt_random() & mask;
if (idx >= max)
idx -= max;
m[idx]++;
}
gettimeofday(&end,NULL);
}
#endif
default:
break;
}
if (!i)
continue; /* don't count allocation pass */
timersub(&end, &start, &res);
r = timerfold(&res);
if (r > max) max = r;
if (r < min) min = r;
sum += r;
}
sprintf(title, "%s%s%s", name, delim, testname[thistest]);
#define H(t) (((double)msize) / ((double)t))
#define D3 delim,delim,delim
sprintf(result, "Avg%s%.2f%sMB/s%sMax%s%.2f%sMB/s%sMin%s%.2f%sMB/s",
delim,
H(sum/LOOPS),
D3,
H(min),
D3,
H(max),
delim);
#undef H
#undef D3
output(title,result);
#ifdef HAVE_STREAM_LIB
out:
#endif
/* Just to make sure that when we switch CPUs that the old guy
doesn't still keep it around. */
clearcache(mem, msize);
numa_free(mem, msize);
}
int popcnt(unsigned long val)
{
int i = 0, cnt = 0;
while (val >> i) {
if ((1UL << i) & val)
cnt++;
i++;
}
return cnt;
}
int max_node, numnodes;
void get_node_list()
{
int a, got_nodes = 0;
long free_node_sizes;
numnodes = numa_num_configured_nodes();
node_to_use = (int *)malloc(numnodes * sizeof(int));
max_node = numa_max_node();
for (a = 0; a <= max_node; a++) {
if(numa_node_size(a, &free_node_sizes) != -1)
node_to_use[got_nodes++] = a;
}
}
void test(enum test type)
{
unsigned long mask;
int i, k;
char buf[512];
struct bitmask *nodes;
nodes = numa_allocate_nodemask();
thistest = type;
if (regression_testing) {
printf("\nTest %s doing 1 of %d nodes and 1 of %d masks.\n",
testname[thistest], fract_nodes, FRACT_MASKS);
}
memtest("memory with no policy", numa_alloc(msize));
memtest("local memory", numa_alloc_local(msize));
memtest("memory interleaved on all nodes", numa_alloc_interleaved(msize));
for (i = 0; i < numnodes; i++) {
if (regression_testing && (node_to_use[i] % fract_nodes)) {
/* for regression testing (-t) do only every eighth node */
continue;
}
sprintf(buf, "memory on node %d", node_to_use[i]);
memtest(buf, numa_alloc_onnode(msize, node_to_use[i]));
}
for (mask = 1, i = 0; mask < (1UL<<numnodes); mask++, i++) {
int w;
char buf2[20];
if (popcnt(mask) == 1)
continue;
if (regression_testing && (i > 50)) {
break;
}
if (regression_testing && (i % FRACT_MASKS)) {
/* for regression testing (-t)
do only every 32nd mask permutation */
continue;
}
numa_bitmask_clearall(nodes);
for (w = 0; mask >> w; w++) {
if ((mask >> w) & 1)
numa_bitmask_setbit(nodes, w);
}
sprintf(buf, "memory interleaved on");
for (k = 0; k < numnodes; k++)
if ((1UL<<node_to_use[k]) & mask) {
sprintf(buf2, " %d", node_to_use[k]);
strcat(buf, buf2);
}
memtest(buf, numa_alloc_interleaved_subset(msize, nodes));
}
for (i = 0; i < numnodes; i++) {
if (regression_testing && (node_to_use[i] % fract_nodes)) {
/* for regression testing (-t) do only every eighth node */
continue;
}
printf("setting preferred node to %d\n", node_to_use[i]);
numa_set_preferred(node_to_use[i]);
memtest("memory without policy", numa_alloc(msize));
}
numa_set_interleave_mask(numa_all_nodes_ptr);
memtest("manual interleaving to all nodes", numa_alloc(msize));
if (numnodes > 0) {
numa_bitmask_clearall(nodes);
numa_bitmask_setbit(nodes, 0);
numa_bitmask_setbit(nodes, 1);
numa_set_interleave_mask(nodes);
memtest("manual interleaving on node 0/1", numa_alloc(msize));
printf("current interleave node %d\n", numa_get_interleave_node());
}
numa_set_interleave_mask(numa_no_nodes_ptr);
nodes = numa_allocate_nodemask();
for (i = 0; i < numnodes; i++) {
int oldhn = numa_preferred();
if (regression_testing && (node_to_use[i] % fract_nodes)) {
/* for regression testing (-t) do only every eighth node */
continue;
}
numa_run_on_node(node_to_use[i]);
printf("running on node %d, preferred node %d\n",node_to_use[i], oldhn);
memtest("local memory", numa_alloc_local(msize));
memtest("memory interleaved on all nodes",
numa_alloc_interleaved(msize));
if (numnodes >= 2) {
numa_bitmask_clearall(nodes);
numa_bitmask_setbit(nodes, 0);
numa_bitmask_setbit(nodes, 1);
memtest("memory interleaved on node 0/1",
numa_alloc_interleaved_subset(msize, nodes));
}
for (k = 0; k < numnodes; k++) {
if (node_to_use[k] == node_to_use[i])
continue;
if (regression_testing && (node_to_use[k] % fract_nodes)) {
/* for regression testing (-t)
do only every eighth node */
continue;
}
sprintf(buf, "alloc on node %d", node_to_use[k]);
numa_bitmask_clearall(nodes);
numa_bitmask_setbit(nodes, node_to_use[k]);
numa_set_membind(nodes);
memtest(buf, numa_alloc(msize));
numa_set_membind(numa_all_nodes_ptr);
}
numa_set_localalloc();
memtest("local allocation", numa_alloc(msize));
numa_set_preferred((node_to_use[i]+1) % numnodes );
memtest("setting wrong preferred node", numa_alloc(msize));
numa_set_preferred(node_to_use[i]);
memtest("setting correct preferred node", numa_alloc(msize));
numa_set_preferred(-1);
if (!delim[0])
printf("\n\n\n");
}
/* numa_run_on_node_mask is not tested */
}
void usage(void)
{
int i;
printf("usage: numademo [-S] [-f] [-c] [-e] [-t] msize[kmg] {tests}\nNo tests means run all.\n");
printf("-c output CSV data. -f run even without NUMA API. -S run stupid tests. -e exit on error\n");
printf("-t regression test; do not run all node combinations\n");
printf("valid tests:");
for (i = 0; testname[i]; i++)
printf(" %s", testname[i]);
putchar('\n');
exit(1);
}
/* duplicated to make numademo standalone */
long memsize(char *s)
{
char *end;
long length = strtoul(s,&end,0);
switch (toupper(*end)) {
case 'G': length *= 1024; /*FALL THROUGH*/
case 'M': length *= 1024; /*FALL THROUGH*/
case 'K': length *= 1024; break;
}
return length;
}
int main(int ac, char **av)
{
int simple_tests = 0;
while (av[1] && av[1][0] == '-') {
ac--;
switch (av[1][1]) {
case 'c':
delim = ",";
break;
case 'f':
force = 1;
break;
case 'S':
simple_tests = 1;
break;
case 'e':
numa_exit_on_error = 1;
numa_exit_on_warn = 1;
break;
case 't':
regression_testing = 1;
break;
default:
usage();
break;
}
++av;
}
if (!av[1])
usage();
if (numa_available() < 0) {
printf("your system does not support the numa API.\n");
if (!force)
exit(1);
}
get_node_list();
printf("%d nodes available\n", numnodes);
fract_nodes = (((numnodes-1)/8)*2) + FRACT_NODES;
if (numnodes <= 3)
regression_testing = 0; /* set -t auto-off for small systems */
msize = memsize(av[1]);
if (!msize)
usage();
#ifdef HAVE_STREAM_LIB
stream_setmem(msize);
#endif
if (av[2] == NULL) {
test(MEMSET);
test(MEMCPY);
if (simple_tests) {
test(FORWARD);
test(BACKWARD);
}
#ifdef HAVE_MT
test(RANDOM2);
#endif
#ifdef HAVE_STREAM_LIB
test(STREAM);
#endif
if (msize >= sizeof(union node)) {
test(PTRCHASE);
} else {
fprintf(stderr, "You must set msize at least %lu bytes for ptrchase test.\n",
sizeof(union node));
exit(1);
}
} else {
int k;
for (k = 2; k < ac; k++) {
int i;
int found = 0;
for (i = 0; testname[i]; i++) {
if (!strcmp(testname[i],av[k])) {
test(i);
found = 1;
break;
}
}
if (!found) {
fprintf(stderr,"unknown test `%s'\n", av[k]);
usage();
}
}
}
return 0;
}

48
numaif.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef NUMAIF_H
#define NUMAIF_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* Kernel interface for NUMA API */
/* System calls */
extern long get_mempolicy(int *mode, unsigned long *nmask,
unsigned long maxnode, void *addr, unsigned flags);
extern long mbind(void *start, unsigned long len, int mode,
const unsigned long *nmask, unsigned long maxnode, unsigned flags);
extern long set_mempolicy(int mode, const unsigned long *nmask,
unsigned long maxnode);
extern long migrate_pages(int pid, unsigned long maxnode,
const unsigned long *frommask,
const unsigned long *tomask);
extern long move_pages(int pid, unsigned long count,
void **pages, const int *nodes, int *status, int flags);
/* Policies */
#define MPOL_DEFAULT 0
#define MPOL_PREFERRED 1
#define MPOL_BIND 2
#define MPOL_INTERLEAVE 3
#define MPOL_MAX MPOL_INTERLEAVE
/* Flags for get_mem_policy */
#define MPOL_F_NODE (1<<0) /* return next il node or node of address */
/* Warning: MPOL_F_NODE is unsupported and
subject to change. Don't use. */
#define MPOL_F_ADDR (1<<1) /* look up vma using address */
#define MPOL_F_MEMS_ALLOWED (1<<2) /* query nodes allowed in cpuset */
/* Flags for mbind */
#define MPOL_MF_STRICT (1<<0) /* Verify existing pages in the mapping */
#define MPOL_MF_MOVE (1<<1) /* Move pages owned by this process to conform to mapping */
#define MPOL_MF_MOVE_ALL (1<<2) /* Move every page to conform to mapping */
#ifdef __cplusplus
}
#endif
#endif

57
numaint.h Normal file
View File

@ -0,0 +1,57 @@
/* Internal interfaces of libnuma */
extern int numa_sched_setaffinity_v1(pid_t pid, unsigned len, const unsigned long *mask);
extern int numa_sched_getaffinity_v1(pid_t pid, unsigned len, const unsigned long *mask);
extern int numa_sched_setaffinity_v1_int(pid_t pid, unsigned len,const unsigned long *mask);
extern int numa_sched_getaffinity_v1_int(pid_t pid, unsigned len,const unsigned long *mask);
extern int numa_sched_setaffinity_v2(pid_t pid, struct bitmask *mask);
extern int numa_sched_getaffinity_v2(pid_t pid, struct bitmask *mask);
extern int numa_sched_setaffinity_v2_int(pid_t pid, struct bitmask *mask);
extern int numa_sched_getaffinity_v2_int(pid_t pid, struct bitmask *mask);
#define SHM_HUGETLB 04000 /* segment will use huge TLB pages */
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
#define CPU_BYTES(x) (round_up(x, BITS_PER_LONG)/8)
#define CPU_LONGS(x) (CPU_BYTES(x) / sizeof(long))
#define make_internal_alias(x) extern __typeof (x) x##_int __attribute((alias(#x), visibility("hidden")))
#define hidden __attribute__((visibility("hidden")))
enum numa_warn {
W_nosysfs,
W_noproc,
W_badmeminfo,
W_nosysfs2,
W_cpumap,
W_numcpus,
W_noderunmask,
W_distance,
W_memory,
W_cpuparse,
W_nodeparse,
W_blockdev1,
W_blockdev2,
W_blockdev3,
W_blockdev4,
W_blockdev5,
W_netlink1,
W_netlink2,
W_netlink3,
W_net1,
W_net2,
W_class1,
W_class2,
W_pci1,
W_pci2,
W_node_parse1,
W_node_parse2,
W_nonode,
W_badchar,
};
#define howmany(x,y) (((x)+((y)-1))/(y))
#define bitsperlong (8 * sizeof(unsigned long))
#define bitsperint (8 * sizeof(unsigned int))
#define longsperbits(n) howmany(n, bitsperlong)
#define bytesperbits(x) ((x+7)/8)

158
numastat.8 Normal file
View File

@ -0,0 +1,158 @@
.TH "numastat" "8" "1.0.0" "Bill Gray" "Administration"
.SH NAME
.LP
\fBnumastat\fP \- Show per-NUMA-node memory statistics for processes and the operating system
.SH "SYNTAX"
.LP
\fBnumastat\fP
.br
.LP
\fBnumastat\fP [\fI\-V\fP]
.br
.LP
\fBnumastat\fP [\fI\<PID>|<pattern>...\fP]
.br
.LP
\fBnumastat\fP [\fI\-c\fP] [\fI\-m\fP] [\fI\-n\fP] [\fI\-p <PID>|<pattern>\fP] [\fI\-s[<node>]\fP] [\fI\-v\fP] [\fI\-z\fP] [\fI\<PID>|<pattern>...\fP]
.br
.SH "DESCRIPTION"
.LP
.B numastat
with no command options or arguments at all, displays per-node NUMA hit and
miss system statistics from the kernel memory allocator. This default
\fBnumastat\fP behavior is strictly compatible with the previous long-standing
\fBnumastat\fP perl script, written by Andi Kleen. The default \fBnumastat\fP
statistics shows per-node numbers (in units of pages of memory) in these categories:
.LP
.B numa_hit
is memory successfully allocated on this node as intended.
.LP
.B numa_miss
is memory allocated on this node despite the process preferring some different node. Each
.I numa_miss
has a
.I numa_foreign
on another node.
.LP
.B numa_foreign
is memory intended for this node, but actually allocated on some different node. Each
.I numa_foreign
has a
.I numa_miss
on another node.
.LP
.B interleave_hit
is interleaved memory successfully allocated on this node as intended.
.LP
.B local_node
is memory allocated on this node while a process was running on it.
.LP
.B other_node
is memory allocated on this node while a process was running on some other node.
.LP
Any supplied options or arguments with the \fBnumastat\fP command will
significantly change both the content and the format of the display. Specified
options will cause display units to change to megabytes of memory, and will
change other specific behaviors of \fBnumastat\fP as described below.
.SH "OPTIONS"
.LP
.TP
\fB\-c\fR
Minimize table display width by dynamically shrinking column widths based on
data contents. With this option, amounts of memory will be rounded to the
nearest megabyte (rather than the usual display with two decimal places).
Column width and inter-column spacing will be somewhat unpredictable with this
option, but the more dense display will be very useful on systems with many
NUMA nodes.
.TP
\fB\-m\fR
Show the meminfo-like system-wide memory usage information. This option
produces a per-node breakdown of memory usage information similar to that found
in /proc/meminfo.
.TP
\fB\-n\fR
Show the original \fBnumastat\fP statistics info. This will show the same
information as the default \fBnumastat\fP behavior but the units will be megabytes of
memory, and there will be other formatting and layout changes versus the
original \fBnumastat\fP behavior.
.TP
\fB\-p\fR <\fBPID\fP> or <\fBpattern\fP>
Show per-node memory allocation information for the specified PID or pattern.
If the \-p argument is only digits, it is assumed to be a numerical PID. If
the argument characters are not only digits, it is assumed to be a text
fragment pattern to search for in process command lines. For example,
\fBnumastat -p qemu\fP will attempt to find and show information for processes
with "qemu" in the command line. Any command line arguments remaining after
\fBnumastat\fP option flag processing is completed, are assumed to be
additional <\fBPID\fP> or <\fBpattern\fP> process specifiers. In this sense,
the \fB\-p\fP option flag is optional: \fBnumastat qemu\fP is equivalent to
\fBnumastat -p qemu\fP
.TP
\fB\-s[<node>]\fR
Sort the table data in descending order before displaying it, so the biggest
memory consumers are listed first. With no specified <node>, the table will be
sorted by the total column. If the optional <node> argument is supplied, the
data will be sorted by the <node> column. Note that <node> must follow the
\fB\-s\fP immediately with no intermediate white space (e.g., \fBnumastat
\-s2\fP). Because \fB\-s\fP can allow an optional argument, it must always be
the last option character in a compound option character string. For example,
instead of \fBnumastat \-msc\fP (which probably will not work as you expect),
use \fBnumastat \-mcs\fP
.TP
\fB\-v\fR
Make some reports more verbose. In particular, process information for
multiple processes will display detailed information for each process.
Normally when per-node information for multiple processes is displayed, only
the total lines are shown.
.TP
\fB\-V\fR
Display \fBnumastat\fP version information and exit.
.TP
\fB\-z\fR
Skip display of table rows and columns of only zero valuess. This can be used
to greatly reduce the amount of uninteresting zero data on systems with many
NUMA nodes. Note that when rows or columns of zeros are still displayed with
this option, that probably means there is at least one value in the row or
column that is actually non-zero, but rounded to zero for display.
.SH NOTES
\fBnumastat\fP attempts to fold each table display so it will be conveniently
readable on the output terminal. Normally a terminal width of 80 characters is
assumed. When the \fBresize\fP command is available, \fBnumastat\fP attempts
to dynamically determine and fine tune the output tty width from \fBresize\fP
output. If \fBnumastat\fP output is not to a tty, very long output lines can
be produced, depending on how many NUMA nodes are present. In all cases,
output width can be explicitly specified via the \fBNUMASTAT_WIDTH\fP
environment variable. For example, \fBNUMASTAT_WIDTH=100 numastat\fP. On
systems with many NUMA nodes, \fBnumastat \-c \-z ....\fP can be very helpful
to selectively reduce the amount of displayed information.
.SH "ENVIRONMENT VARIABLES"
.LP
.TP
NUMASTAT_WIDTH
.SH "FILES"
.LP
\fI/proc/*/numa_maps\fP
.br
\fI/sys/devices/system/node/node*/meminfo\fP
.br
\fI/sys/devices/system/node/node*/numastat\fP
.SH "EXAMPLES"
.I numastat \-c \-z \-m \-n
.br
.I numastat \-czs libvirt kvm qemu
.br
.I watch \-n1 numastat
.br
.I watch \-n1 \-\-differences=cumulative numastat
.SH "AUTHORS"
.LP
The original \fBnumastat\fP perl script was written circa 2003 by Andi Kleen
<andi.kleen@intel.com>. The current \fBnumastat\fP program was written in 2012
by Bill Gray <bgray@redhat.com> to be compatible by default with the original,
and to add options to display per-node system memory usage and per-node process
memory allocation.
.SH "SEE ALSO"
.LP
.BR numactl (8),
.BR set_mempolicy( 2),
.BR numa (3)

1480
numastat.c Normal file

File diff suppressed because it is too large Load Diff

89
rtnetlink.c Normal file
View File

@ -0,0 +1,89 @@
/* Simple LPGLed rtnetlink library */
#include <sys/socket.h>
#include <linux/rtnetlink.h>
#include <linux/netlink.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#define hidden __attribute__((visibility("hidden")))
#include "rtnetlink.h"
hidden void *rta_put(struct nlmsghdr *m, int type, int len)
{
struct rtattr *rta = (void *)m + NLMSG_ALIGN(m->nlmsg_len);
int rtalen = RTA_LENGTH(len);
rta->rta_type = type;
rta->rta_len = rtalen;
m->nlmsg_len = NLMSG_ALIGN(m->nlmsg_len) + RTA_ALIGN(rtalen);
return RTA_DATA(rta);
}
hidden struct rtattr *rta_get(struct nlmsghdr *m, struct rtattr *p, int offset)
{
struct rtattr *rta;
if (p) {
rta = RTA_NEXT(p, m->nlmsg_len);
if (!RTA_OK(rta, m->nlmsg_len))
return NULL;
} else {
rta = (void *)m + NLMSG_ALIGN(offset);
}
return rta;
}
hidden int
rta_put_address(struct nlmsghdr *msg, int type, struct sockaddr *adr)
{
switch (adr->sa_family) {
case AF_INET: {
struct in_addr *i = rta_put(msg, type, 4);
*i = ((struct sockaddr_in *)adr)->sin_addr;
break;
}
case AF_INET6: {
struct in6_addr *i6 = rta_put(msg, type, 16);
*i6 = ((struct sockaddr_in6 *)adr)->sin6_addr;
break;
}
default:
return -1;
}
return 0;
}
/* Assumes no truncation. Make the buffer large enough. */
hidden int
rtnetlink_request(struct nlmsghdr *msg, int buflen, struct sockaddr_nl *adr)
{
int rsk;
int n;
int e;
/* Use a private socket to avoid having to keep state
for a sequence number. */
rsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (rsk < 0)
return -1;
n = sendto(rsk, msg, msg->nlmsg_len, 0, (struct sockaddr *)adr,
sizeof(struct sockaddr_nl));
if (n >= 0) {
socklen_t adrlen = sizeof(struct sockaddr_nl);
n = recvfrom(rsk, msg, buflen, 0, (struct sockaddr *)adr,
&adrlen);
}
e = errno;
close(rsk);
errno = e;
if (n < 0)
return -1;
/* Assume we only get a single reply back. This is (hopefully?)
safe because it's a single use socket. */
if (msg->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *err = NLMSG_DATA(msg);
errno = -err->error;
return -1;
}
return 0;
}

5
rtnetlink.h Normal file
View File

@ -0,0 +1,5 @@
hidden int
rta_put_address(struct nlmsghdr *msg, int type, struct sockaddr *adr);
hidden struct rtattr *rta_get(struct nlmsghdr *m, struct rtattr *p, int offset);
hidden void *rta_put(struct nlmsghdr *m, int type, int len);
hidden int rtnetlink_request(struct nlmsghdr *msg, int buflen, struct sockaddr_nl *adr);

325
shm.c Normal file
View File

@ -0,0 +1,325 @@
/* Copyright (C) 2003,2004 Andi Kleen, SuSE Labs.
Manage shared memory policy for numactl.
The actual policy is set in numactl itself, this just sets up and maps
the shared memory segments and dumps them.
numactl is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; version
2.
numactl 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
General Public License for more details.
You should find a copy of v2 of the GNU 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 */
#define _GNU_SOURCE 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include "numa.h"
#include "numaif.h"
#include "numaint.h"
#include "util.h"
#include "shm.h"
int shmfd = -1;
long shmid = 0;
char *shmptr;
unsigned long long shmlen;
mode_t shmmode = 0600;
unsigned long long shmoffset;
int shmflags;
static int shm_pagesize;
long huge_page_size(void)
{
size_t len = 0;
char *line = NULL;
FILE *f = fopen("/proc/meminfo", "r");
if (f != NULL) {
while (getdelim(&line, &len, '\n', f) > 0) {
int ps;
if (sscanf(line, "Hugepagesize: %d kB", &ps) == 1)
return ps * 1024;
}
free(line);
fclose(f);
}
return getpagesize();
}
static void check_region(char *opt)
{
if (((unsigned long)shmptr % shm_pagesize) || (shmlen % shm_pagesize)) {
fprintf(stderr, "numactl: policy region not page aligned\n");
exit(1);
}
if (!shmlen) {
fprintf(stderr,
"numactl: policy region length not specified before %s\n",
opt);
exit(1);
}
}
static key_t sysvkey(char *name)
{
int fd;
key_t key = ftok(name, shmid);
if (key >= 0)
return key;
fprintf(stderr, "numactl: Creating shm key file %s mode %04o\n",
name, shmmode);
fd = creat(name, shmmode);
if (fd < 0)
nerror("cannot create key for shm %s\n", name);
key = ftok(name, shmid);
if (key < 0)
nerror("cannot get key for newly created shm key file %s",
name);
return key;
}
/* Attach a sysv style shared memory segment. */
void attach_sysvshm(char *name, char *opt)
{
struct shmid_ds s;
key_t key = sysvkey(name);
shmfd = shmget(key, shmlen, shmflags);
if (shmfd < 0 && errno == ENOENT) {
if (shmlen == 0)
complain(
"need a --length to create a sysv shared memory segment");
fprintf(stderr,
"numactl: Creating shared memory segment %s id %ld mode %04o length %.fMB\n",
name, shmid, shmmode, ((double)shmlen) / (1024*1024) );
shmfd = shmget(key, shmlen, IPC_CREAT|shmmode|shmflags);
if (shmfd < 0)
nerror("cannot create shared memory segment");
}
if (shmlen == 0) {
if (shmctl(shmfd, IPC_STAT, &s) < 0)
err("shmctl IPC_STAT");
shmlen = s.shm_segsz;
}
shmptr = shmat(shmfd, NULL, SHM_RDONLY);
if (shmptr == (void*)-1)
err("shmat");
shmptr += shmoffset;
shm_pagesize = (shmflags & SHM_HUGETLB) ? huge_page_size() : getpagesize();
check_region(opt);
}
/* Attach a shared memory file. */
void attach_shared(char *name, char *opt)
{
struct stat64 st;
shmfd = open(name, O_RDONLY);
if (shmfd < 0) {
errno = 0;
if (shmlen == 0)
complain("need a --length to create a shared file");
shmfd = open(name, O_RDWR|O_CREAT, shmmode);
if (shmfd < 0)
nerror("cannot create file %s", name);
}
if (fstat64(shmfd, &st) < 0)
err("shm stat");
if (shmlen > st.st_size) {
if (ftruncate64(shmfd, shmlen) < 0) {
/* XXX: we could do it by hand, but it would it
would be impossible to apply policy then.
need to fix that in the kernel. */
perror("ftruncate");
}
}
shm_pagesize = st.st_blksize;
check_region(opt);
/* RED-PEN For shmlen > address space may need to map in pieces.
Left for some poor 32bit soul. */
shmptr = mmap64(NULL, shmlen, PROT_READ, MAP_SHARED, shmfd, shmoffset);
if (shmptr == (char*)-1)
err("shm mmap");
}
static void
dumppol(unsigned long long start, unsigned long long end, int pol, struct bitmask *mask)
{
if (pol == MPOL_DEFAULT)
return;
printf("%016llx-%016llx: %s ",
shmoffset+start,
shmoffset+end,
policy_name(pol));
printmask("", mask);
}
/* Dump policies in a shared memory segment. */
void dump_shm(void)
{
struct bitmask *nodes, *prevnodes;
int prevpol = -1, pol;
unsigned long long c, start;
start = 0;
if (shmlen == 0) {
printf("nothing to dump\n");
return;
}
nodes = numa_allocate_nodemask();
prevnodes = numa_allocate_nodemask();
for (c = 0; c < shmlen; c += shm_pagesize) {
if (get_mempolicy(&pol, nodes->maskp, nodes->size, c+shmptr,
MPOL_F_ADDR) < 0)
err("get_mempolicy on shm");
if (pol == prevpol)
continue;
if (prevpol != -1)
dumppol(start, c, prevpol, prevnodes);
prevnodes = nodes;
prevpol = pol;
start = c;
}
dumppol(start, c, prevpol, prevnodes);
}
static void dumpnode(unsigned long long start, unsigned long long end, int node)
{
printf("%016llx-%016llx: %d\n", shmoffset+start, shmoffset+end, node);
}
/* Dump nodes in a shared memory segment. */
void dump_shm_nodes(void)
{
int prevnode = -1, node;
unsigned long long c, start;
start = 0;
if (shmlen == 0) {
printf("nothing to dump\n");
return;
}
for (c = 0; c < shmlen; c += shm_pagesize) {
if (get_mempolicy(&node, NULL, 0, c+shmptr,
MPOL_F_ADDR|MPOL_F_NODE) < 0)
err("get_mempolicy on shm");
if (node == prevnode)
continue;
if (prevnode != -1)
dumpnode(start, c, prevnode);
prevnode = node;
start = c;
}
dumpnode(start, c, prevnode);
}
static void vwarn(char *ptr, char *fmt, ...)
{
va_list ap;
unsigned long off = (unsigned long)ptr - (unsigned long)shmptr;
va_start(ap,fmt);
printf("numactl verify %lx(%lx): ", (unsigned long)ptr, off);
vprintf(fmt, ap);
va_end(ap);
exitcode = 1;
}
static unsigned interleave_next(unsigned cur, struct bitmask *mask)
{
int numa_num_nodes = numa_num_possible_nodes();
++cur;
while (!numa_bitmask_isbitset(mask, cur)) {
cur = (cur+1) % numa_num_nodes;
}
return cur;
}
/* Verify policy in a shared memory segment */
void verify_shm(int policy, struct bitmask *nodes)
{
char *p;
int ilnode, node;
int pol2;
struct bitmask *nodes2;
nodes2 = numa_allocate_nodemask();
if (policy == MPOL_INTERLEAVE) {
if (get_mempolicy(&ilnode, NULL, 0, shmptr,
MPOL_F_ADDR|MPOL_F_NODE)
< 0)
err("get_mempolicy");
}
for (p = shmptr; p - (char *)shmptr < shmlen; p += shm_pagesize) {
if (get_mempolicy(&pol2, nodes2->maskp, nodes2->size, p,
MPOL_F_ADDR) < 0)
err("get_mempolicy");
if (pol2 != policy) {
vwarn(p, "wrong policy %s, expected %s\n",
policy_name(pol2), policy_name(policy));
return;
}
if (memcmp(nodes2, nodes, numa_bitmask_nbytes(nodes))) {
vwarn(p, "mismatched node mask\n");
printmask("expected", nodes);
printmask("real", nodes2);
}
if (get_mempolicy(&node, NULL, 0, p, MPOL_F_ADDR|MPOL_F_NODE) < 0)
err("get_mempolicy");
switch (policy) {
case MPOL_INTERLEAVE:
if (node < 0 || !numa_bitmask_isbitset(nodes2, node))
vwarn(p, "interleave node out of range %d\n", node);
if (node != ilnode) {
vwarn(p, "expected interleave node %d, got %d\n",
ilnode,node);
return;
}
ilnode = interleave_next(ilnode, nodes2);
break;
case MPOL_PREFERRED:
case MPOL_BIND:
if (!numa_bitmask_isbitset(nodes2, node)) {
vwarn(p, "unexpected node %d\n", node);
printmask("expected", nodes2);
}
break;
case MPOL_DEFAULT:
break;
}
}
}

17
shm.h Normal file
View File

@ -0,0 +1,17 @@
extern int shmfd;
extern long shmid;
extern char *shmptr;
extern unsigned long long shmlen;
extern mode_t shmmode;
extern unsigned long long shmoffset;
extern int shmflags;
extern void dump_shm(void);
extern void dump_shm_nodes(void);
extern void attach_shared(char *, char *);
extern void attach_sysvshm(char *, char *);
extern void verify_shm(int policy, struct bitmask *);
/* in numactl.c */
extern int exitcode;

266
stream_lib.c Normal file
View File

@ -0,0 +1,266 @@
#include <stdio.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include <sys/time.h>
#include <stdlib.h>
#include "stream_lib.h"
static inline double mysecond()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec + tv.tv_usec * 1.e-6;
}
/*
* Program: Stream
* Programmer: Joe R. Zagar
* Revision: 4.0-BETA, October 24, 1995
* Original code developed by John D. McCalpin
*
* This program measures memory transfer rates in MB/s for simple
* computational kernels coded in C. These numbers reveal the quality
* of code generation for simple uncacheable kernels as well as showing
* the cost of floating-point operations relative to memory accesses.
*
* INSTRUCTIONS:
*
* 1) Stream requires a good bit of memory to run. Adjust the
* value of 'N' (below) to give a 'timing calibration' of
* at least 20 clock-ticks. This will provide rate estimates
* that should be good to about 5% precision.
*
* Hacked by AK to be a library
*/
long N = 8000000;
#define NTIMES 10
#define OFFSET 0
/*
* 3) Compile the code with full optimization. Many compilers
* generate unreasonably bad code before the optimizer tightens
* things up. If the results are unreasonably good, on the
* other hand, the optimizer might be too smart for me!
*
* Try compiling with:
* cc -O stream_d.c second_wall.c -o stream_d -lm
*
* This is known to work on Cray, SGI, IBM, and Sun machines.
*
*
* 4) Mail the results to mccalpin@cs.virginia.edu
* Be sure to include:
* a) computer hardware model number and software revision
* b) the compiler flags
* c) all of the output from the test case.
* Thanks!
*
*/
int checktick();
# define HLINE "-------------------------------------------------------------\n"
# ifndef MIN
# define MIN(x,y) ((x)<(y)?(x):(y))
# endif
# ifndef MAX
# define MAX(x,y) ((x)>(y)?(x):(y))
# endif
static double *a, *b, *c;
static double rmstime[4] = { 0 }, maxtime[4] = {
0}, mintime[4] = {
FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX};
static char *label[4] = { "Copy: ", "Scale: ",
"Add: ", "Triad: "
};
char *stream_names[] = { "Copy","Scale","Add","Triad" };
static double bytes[4];
int stream_verbose = 1;
#define Vprintf(x...) do { if (stream_verbose) printf(x); } while(0)
void stream_check(void)
{
int quantum;
int BytesPerWord;
register int j;
double t;
/* --- SETUP --- determine precision and check timing --- */
Vprintf(HLINE);
BytesPerWord = sizeof(double);
Vprintf("This system uses %d bytes per DOUBLE PRECISION word.\n",
BytesPerWord);
Vprintf(HLINE);
Vprintf("Array size = %lu, Offset = %d\n", N, OFFSET);
Vprintf("Total memory required = %.1f MB.\n",
(3 * N * BytesPerWord) / 1048576.0);
Vprintf("Each test is run %d times, but only\n", NTIMES);
Vprintf("the *best* time for each is used.\n");
/* Get initial value for system clock. */
for (j = 0; j < N; j++) {
a[j] = 1.0;
b[j] = 2.0;
c[j] = 0.0;
}
Vprintf(HLINE);
if ((quantum = checktick()) >= 1)
Vprintf("Your clock granularity/precision appears to be "
"%d microseconds.\n", quantum);
else
Vprintf("Your clock granularity appears to be "
"less than one microsecond.\n");
t = mysecond();
for (j = 0; j < N; j++)
a[j] = 2.0E0 * a[j];
t = 1.0E6 * (mysecond() - t);
Vprintf("Each test below will take on the order"
" of %d microseconds.\n", (int) t);
Vprintf(" (= %d clock ticks)\n", (int) (t / quantum));
Vprintf("Increase the size of the arrays if this shows that\n");
Vprintf("you are not getting at least 20 clock ticks per test.\n");
Vprintf(HLINE);
Vprintf("WARNING -- The above is only a rough guideline.\n");
Vprintf("For best results, please be sure you know the\n");
Vprintf("precision of your system timer.\n");
Vprintf(HLINE);
}
void stream_test(double *res)
{
register int j, k;
double scalar, times[4][NTIMES];
/* --- MAIN LOOP --- repeat test cases NTIMES times --- */
scalar = 3.0;
for (k = 0; k < NTIMES; k++) {
times[0][k] = mysecond();
for (j = 0; j < N; j++)
c[j] = a[j];
times[0][k] = mysecond() - times[0][k];
times[1][k] = mysecond();
for (j = 0; j < N; j++)
b[j] = scalar * c[j];
times[1][k] = mysecond() - times[1][k];
times[2][k] = mysecond();
for (j = 0; j < N; j++)
c[j] = a[j] + b[j];
times[2][k] = mysecond() - times[2][k];
times[3][k] = mysecond();
for (j = 0; j < N; j++)
a[j] = b[j] + scalar * c[j];
times[3][k] = mysecond() - times[3][k];
}
/* --- SUMMARY --- */
for (k = 0; k < NTIMES; k++) {
for (j = 0; j < 4; j++) {
rmstime[j] =
rmstime[j] + (times[j][k] * times[j][k]);
mintime[j] = MIN(mintime[j], times[j][k]);
maxtime[j] = MAX(maxtime[j], times[j][k]);
}
}
Vprintf
("Function Rate (MB/s) RMS time Min time Max time\n");
for (j = 0; j < 4; j++) {
double speed = 1.0E-06 * bytes[j] / mintime[j];
rmstime[j] = sqrt(rmstime[j] / (double) NTIMES);
Vprintf("%s%11.4f %11.4f %11.4f %11.4f\n", label[j],
speed,
rmstime[j], mintime[j], maxtime[j]);
if (res)
res[j] = speed;
}
}
# define M 20
int checktick()
{
int i, minDelta, Delta;
double t1, t2, timesfound[M];
/* Collect a sequence of M unique time values from the system. */
for (i = 0; i < M; i++) {
t1 = mysecond();
while (((t2 = mysecond()) - t1) < 1.0E-6);
timesfound[i] = t1 = t2;
}
/*
* Determine the minimum difference between these M values.
* This result will be our estimate (in microseconds) for the
* clock granularity.
*/
minDelta = 1000000;
for (i = 1; i < M; i++) {
Delta =
(int) (1.0E6 * (timesfound[i] - timesfound[i - 1]));
minDelta = MIN(minDelta, MAX(Delta, 0));
}
return (minDelta);
}
void stream_setmem(unsigned long size)
{
N = (size - OFFSET) / (3*sizeof(double));
}
long stream_memsize(void)
{
return 3*(sizeof(double) * (N+OFFSET)) ;
}
long stream_init(void *mem)
{
int i;
for (i = 0; i < 4; i++) {
rmstime[i] = 0;
maxtime[i] = 0;
mintime[i] = FLT_MAX;
}
bytes[0] = 2 * sizeof(double) * N;
bytes[1] = 2 * sizeof(double) * N;
bytes[2] = 3 * sizeof(double) * N;
bytes[3] = 3 * sizeof(double) * N;
a = mem;
b = (double *)mem + (N+OFFSET);
c = (double *)mem + 2*(N+OFFSET);
stream_check();
return 0;
}

8
stream_lib.h Normal file
View File

@ -0,0 +1,8 @@
long stream_memsize(void);
long stream_init(void *mem);
#define STREAM_NRESULTS 4
void stream_test(double *res);
void stream_check(void);
void stream_setmem(unsigned long size);
extern int stream_verbose;
extern char *stream_names[];

266
syscall.c Normal file
View File

@ -0,0 +1,266 @@
/* Copyright (C) 2003,2004 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 */
#include <unistd.h>
#include <sys/types.h>
#include <asm/unistd.h>
#include <errno.h>
#include "numa.h"
#include "numaif.h"
#include "numaint.h"
#define WEAK __attribute__((weak))
#if !defined(__NR_mbind) || !defined(__NR_set_mempolicy) || \
!defined(__NR_get_mempolicy) || !defined(__NR_migrate_pages) || \
!defined(__NR_move_pages)
#if defined(__x86_64__)
#define __NR_sched_setaffinity 203
#define __NR_sched_getaffinity 204
/* Official allocation */
#define __NR_mbind 237
#define __NR_set_mempolicy 238
#define __NR_get_mempolicy 239
#define __NR_migrate_pages 256
#define __NR_move_pages 279
#elif defined(__ia64__)
#define __NR_sched_setaffinity 1231
#define __NR_sched_getaffinity 1232
#define __NR_migrate_pages 1280
#define __NR_move_pages 1276
/* Official allocation */
#define __NR_mbind 1259
#define __NR_get_mempolicy 1260
#define __NR_set_mempolicy 1261
#elif defined(__i386__)
#define __NR_mbind 274
#define __NR_get_mempolicy 275
#define __NR_set_mempolicy 276
#define __NR_migrate_pages 294
#define __NR_move_pages 317
#elif defined(__powerpc__)
#define __NR_mbind 259
#define __NR_get_mempolicy 260
#define __NR_set_mempolicy 261
#define __NR_migrate_pages 258
/* FIXME: powerpc is missing move pages!!!
#define __NR_move_pages xxx
*/
#elif defined(__mips__)
#if _MIPS_SIM == _ABIO32
/*
* Linux o32 style syscalls are in the range from 4000 to 4999.
*/
#define __NR_Linux 4000
#define __NR_mbind (__NR_Linux + 268)
#define __NR_get_mempolicy (__NR_Linux + 269)
#define __NR_set_mempolicy (__NR_Linux + 270)
#define __NR_migrate_pages (__NR_Linux + 287)
#endif
#if _MIPS_SIM == _ABI64
/*
* Linux 64-bit syscalls are in the range from 5000 to 5999.
*/
#define __NR_Linux 5000
#define __NR_mbind (__NR_Linux + 227)
#define __NR_get_mempolicy (__NR_Linux + 228)
#define __NR_set_mempolicy (__NR_Linux + 229)
#define __NR_migrate_pages (__NR_Linux + 246)
#endif
#if _MIPS_SIM == _ABIN32
/*
* Linux N32 syscalls are in the range from 6000 to 6999.
*/
#define __NR_Linux 6000
#define __NR_mbind (__NR_Linux + 231)
#define __NR_get_mempolicy (__NR_Linux + 232)
#define __NR_set_mempolicy (__NR_Linux + 233)
#define __NR_migrate_pages (__NR_Linux + 250)
#endif
#elif defined(__hppa__)
#define __NR_migrate_pages 272
#elif defined(__arm__)
/* https://bugs.debian.org/796802 */
#warning "ARM does not implement the migrate_pages() syscall"
#elif !defined(DEPS_RUN)
#error "Add syscalls for your architecture or update kernel headers"
#endif
#endif
#ifndef __GLIBC_PREREQ
# define __GLIBC_PREREQ(x,y) 0
#endif
#if defined(__GLIBC__) && __GLIBC_PREREQ(2, 11)
/* glibc 2.11 seems to have working 6 argument sycall. Use the
glibc supplied syscall in this case.
The version cut-off is rather arbitary and could be probably
earlier. */
#define syscall6 syscall
#elif defined(__x86_64__)
/* 6 argument calls on x86-64 are often buggy in both glibc and
asm/unistd.h. Add a working version here. */
long syscall6(long call, long a, long b, long c, long d, long e, long f)
{
long res;
asm volatile ("movq %[d],%%r10 ; movq %[e],%%r8 ; movq %[f],%%r9 ; syscall"
: "=a" (res)
: "0" (call),"D" (a),"S" (b), "d" (c),
[d] "g" (d), [e] "g" (e), [f] "g" (f) :
"r11","rcx","r8","r10","r9","memory" );
if (res < 0) {
errno = -res;
res = -1;
}
return res;
}
#elif defined(__i386__)
/* i386 has buggy syscall6 in glibc too. This is tricky to do
in inline assembly because it clobbers so many registers. Do it
out of line. */
asm(
"__syscall6:\n"
" pushl %ebp\n"
" pushl %edi\n"
" pushl %esi\n"
" pushl %ebx\n"
" movl (0+5)*4(%esp),%eax\n"
" movl (1+5)*4(%esp),%ebx\n"
" movl (2+5)*4(%esp),%ecx\n"
" movl (3+5)*4(%esp),%edx\n"
" movl (4+5)*4(%esp),%esi\n"
" movl (5+5)*4(%esp),%edi\n"
" movl (6+5)*4(%esp),%ebp\n"
" int $0x80\n"
" popl %ebx\n"
" popl %esi\n"
" popl %edi\n"
" popl %ebp\n"
" ret"
);
extern long __syscall6(long n, long a, long b, long c, long d, long e, long f);
long syscall6(long call, long a, long b, long c, long d, long e, long f)
{
long res = __syscall6(call,a,b,c,d,e,f);
if (res < 0) {
errno = -res;
res = -1;
}
return res;
}
#else
#define syscall6 syscall
#endif
long WEAK get_mempolicy(int *policy, unsigned long *nmask,
unsigned long maxnode, void *addr,
unsigned flags)
{
return syscall(__NR_get_mempolicy, policy, nmask,
maxnode, addr, flags);
}
long WEAK mbind(void *start, unsigned long len, int mode,
const unsigned long *nmask, unsigned long maxnode, unsigned flags)
{
return syscall6(__NR_mbind, (long)start, len, mode, (long)nmask,
maxnode, flags);
}
long WEAK set_mempolicy(int mode, const unsigned long *nmask,
unsigned long maxnode)
{
long i;
i = syscall(__NR_set_mempolicy,mode,nmask,maxnode);
return i;
}
long WEAK migrate_pages(int pid, unsigned long maxnode,
const unsigned long *frommask, const unsigned long *tomask)
{
#if defined(__NR_migrate_pages)
return syscall(__NR_migrate_pages, pid, maxnode, frommask, tomask);
#else
errno = ENOSYS;
return -1;
#endif
}
long WEAK move_pages(int pid, unsigned long count,
void **pages, const int *nodes, int *status, int flags)
{
return syscall(__NR_move_pages, pid, count, pages, nodes, status, flags);
}
/* SLES8 glibc doesn't define those */
int numa_sched_setaffinity_v1(pid_t pid, unsigned len, const unsigned long *mask)
{
return syscall(__NR_sched_setaffinity,pid,len,mask);
}
__asm__(".symver numa_sched_setaffinity_v1,numa_sched_setaffinity@libnuma_1.1");
int numa_sched_setaffinity_v2(pid_t pid, struct bitmask *mask)
{
return syscall(__NR_sched_setaffinity, pid, numa_bitmask_nbytes(mask),
mask->maskp);
}
__asm__(".symver numa_sched_setaffinity_v2,numa_sched_setaffinity@@libnuma_1.2");
int numa_sched_getaffinity_v1(pid_t pid, unsigned len, const unsigned long *mask)
{
return syscall(__NR_sched_getaffinity,pid,len,mask);
}
__asm__(".symver numa_sched_getaffinity_v1,numa_sched_getaffinity@libnuma_1.1");
int numa_sched_getaffinity_v2(pid_t pid, struct bitmask *mask)
{
/* len is length in bytes */
return syscall(__NR_sched_getaffinity, pid, numa_bitmask_nbytes(mask),
mask->maskp);
/* sched_getaffinity returns sizeof(cpumask_t) */
}
__asm__(".symver numa_sched_getaffinity_v2,numa_sched_getaffinity@@libnuma_1.2");
make_internal_alias(numa_sched_getaffinity_v1);
make_internal_alias(numa_sched_getaffinity_v2);
make_internal_alias(numa_sched_setaffinity_v1);
make_internal_alias(numa_sched_setaffinity_v2);

69
sysfs.c Normal file
View File

@ -0,0 +1,69 @@
/* Utility functions for reading sysfs values */
#define _GNU_SOURCE 1
#include <stdio.h>
#include <sys/fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <ctype.h>
#include "numa.h"
#include "numaint.h"
#define SYSFS_BLOCK 4096
hidden char *sysfs_read(char *name)
{
char *buf;
int n;
int fd;
fd = open(name, O_RDONLY);
buf = malloc(SYSFS_BLOCK);
if (!buf)
return NULL;
n = read(fd, buf, SYSFS_BLOCK - 1);
close(fd);
if (n <= 0) {
free(buf);
return NULL;
}
buf[n] = 0;
return buf;
}
hidden int sysfs_node_read(struct bitmask *mask, char *fmt, ...)
{
int n;
va_list ap;
char *p, *fn, *m, *end;
int num;
va_start(ap, fmt);
n = vasprintf(&fn, fmt, ap);
va_end(ap);
if (n < 0)
return -1;
p = sysfs_read(fn);
free(fn);
if (!p)
return -1;
m = p;
do {
num = strtol(m, &end, 0);
if (m == end)
return -1;
if (num < 0)
return -2;
if (num >= numa_num_task_nodes())
return -1;
numa_bitmask_setbit(mask, num);
/* Continuation not supported by kernel yet. */
m = end;
while (isspace(*m) || *m == ',')
m++;
} while (isdigit(*m));
free(p);
return 0;
}

3
sysfs.h Normal file
View File

@ -0,0 +1,3 @@
struct bitmask;
hidden char *sysfs_read(char *name);
hidden int sysfs_node_read(struct bitmask *mask, char *fmt, ...);

21
test/README Normal file
View File

@ -0,0 +1,21 @@
Various simple test scripts to verify some parts of the NUMA API.
To do a full regression test run make test
You should have at least two nodes on a NUMA system for the test suite.
The tests in regress assume that there is enough memory free on nodes 0/1.
They consider PREFERRED/INTERLEAVE not hitting the first choice node an
error.
They also require a relatively idle machine to avoid too much
noise from memory allocation from other processes. Without
that regress1 might fail.
You can run the tests under valgrind with VALGRIND=valgrind make test
Older valgrind versions incorrectly report a uninitialized byte error
on set_mempolicy. That is a false positive.
TBD: more detailed unit tests for mbind / shm / {get,set}_mempolicy
Currently everything is tested using numactl only.

109
test/bind_range Executable file
View File

@ -0,0 +1,109 @@
#!/bin/bash
# This simple script checks --all/-a option which is used for
# supressing of default cpuset awareness of options --cpunodebind,
# --physcpubind, --interleave, --preferred and --membind.
# NOTE: Test needs two nodes and two cpus at least
testdir=`dirname "$0"`
: ${srcdir:=${testdir}/..}
: ${builddir:=${srcdir}}
export PATH=${builddir}:$PATH
export old_mask
eval_test() {
# echo "Running $1.."
$1
if [ $? == 1 ] ; then
echo -e "$1 FAILED!"
reset_mask
exit 1
fi
echo -e "$1 PASSED"
}
function check_arg_order
{
numactl --all --physcpubind=$HIGHESTCPU ls > /dev/null 2>&1
if [ $? == 1 ] ; then
return 1;
fi
numactl --physcpubind=$HIGHESTCPU --all ls > /dev/null 2>&1
if [ $? == 0 ] ; then
return 1;
fi
return 0
}
function check_physcpubind
{
reset_mask
set_cpu_affinity 0
numactl --physcpubind=$HIGHESTCPU ls > /dev/null 2>&1
if [ $? == 0 ] ; then # shouldn't pass so easy
return 1;
fi
numactl --all --physcpubind=$HIGHESTCPU ls > /dev/null 2>&1
if [ $? == 1 ] ; then # shouldn't fail
return 1;
fi
return 0
}
function check_cpunodebind
{
local low_cpu_range
local high_cpu
reset_mask
low_cpu_range=$(cat /sys/devices/system/node/node$LOWESTNODE/cpulist)
set_cpu_affinity $low_cpu_range
numactl --cpunodebind=$HIGHESTNODE ls > /dev/null 2>&1
if [ $? == 1 ] ; then # should pass
return 1;
fi
numactl --all --cpunodebind=$HIGHESTNODE ls > /dev/null 2>&1
if [ $? == 1 ] ; then # should pass for sure
return 1;
fi
return 0
}
function set_cpu_affinity
{
taskset -p -c $1 $$ > /dev/null
#echo -e "\taffinity of shell was set to" $1
}
function get_mask
{
old_mask=$(taskset -p $$ | cut -f2 -d: | sed -e 's/^[ \t]*//')
}
function reset_mask
{
taskset -p $old_mask $$ > /dev/null
#echo -e "\taffinity of shell was reset to" $old_mask
}
HIGHESTCPU=$(grep 'processor' /proc/cpuinfo | tail -n1 | cut -f2 -d':')
HIGHESTCPU=$(echo $HIGHESTCPU | cut -f2 -d' ')
HIGHESTNODE=$(numactl -H | grep -e 'node [0-9]* cpus' | tail -n1 | cut -f2 -d' ')
LOWESTNODE=$(numactl -H | grep -e 'node [0-9]* cpus' | head -n1 | cut -f2 -d' ')
get_mask
eval_test check_arg_order
eval_test check_physcpubind
eval_test check_cpunodebind
reset_mask
exit 0

31
test/checkaffinity Executable file
View File

@ -0,0 +1,31 @@
#!/bin/bash
# check if affinity works
testdir=`dirname "$0"`
: ${srcdir:=${testdir}/..}
: ${builddir:=${srcdir}}
export PATH=${builddir}:$PATH
S=`numactl --show | grep nodebind:`
NODES=`echo $S | sed -e "s/nodebind://"`
S=`numactl --show | grep physcpubind:`
CPUS=`echo $S | sed -e "s/physcpubind://"`
for i in $CPUS ; do
if [ "$(numactl --physcpubind=$i "${testdir}"/printcpu)" != "$i" ] ; then
echo "--physcpubind for $i doesn't work"
exit 1
fi
if [ "$(numactl --physcpubind=$i numactl --show | awk '/^physcpubind/ { print $2 }' )" != "$i" ] ; then
echo "--show doesn't agree with physcpubind for cpu $i"
exit 1
fi
done
for i in $NODES ; do
if [ $(numactl --cpunodebind=$i numactl --show | awk '/nodebind/ { print $2 }' ) != $i ] ; then
echo "--show doesn't agree with cpunodebind for node $i"
exit 1
fi
done

42
test/checktopology Executable file
View File

@ -0,0 +1,42 @@
#!/bin/bash
# check numactl --hardware output
# this checks most of the topology discovery in libnuma
testdir=`dirname "$0"`
: ${srcdir:=${testdir}/..}
: ${builddir:=${srcdir}}
export PATH=${builddir}:$PATH
numcpus=$(grep -c processor /proc/cpuinfo)
numnodes=$(ls -1d /sys/devices/system/node/node[0-9]* | wc -l)
nccpus=$(numactl --hardware | grep cpus | sed 's/node.*cpus://' | wc -w )
ncnodes=$(numactl --hardware | grep -c 'node.*size' )
if [ $numnodes != $ncnodes ] ; then
echo "numactl --hardware doesnt report all nodes"
exit 1
fi
if [ $numcpus != $nccpus -a \( $[$nccpus / $numnodes] != $numcpus \) ] ; then
echo "numactl --hardware cpus look bogus"
exit 1
fi
numactl --hardware | grep cpus | while read n ; do
node=${n/ cpus*/}
node=${node/ /}
cpus=${n/*: /}
k=0
for i in $cpus ; do
if [ ! -h "/sys/devices/system/node/$node/cpu$i" ] ; then
echo "$node doesn't have cpu $i"
exit 1
fi
k=$[$k+1]
done
if [ $k != $(echo $cpus | wc -w) ] ; then
echo "$node missing cpu"
exit 1
fi
done

42
test/distance.c Normal file
View File

@ -0,0 +1,42 @@
/* Test numa_distance */
#include <numa.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int numnodes, maxnode, a, b, got_nodes = 0;
int *node_to_use;
long size, free_node_sizes;
if (numa_available() < 0) {
printf("no numa support in kernel\n");
exit(1);
}
numnodes = numa_num_configured_nodes();
maxnode = numa_max_node();
node_to_use = (int *)malloc(numnodes * sizeof(int));
for (a = 0; a <= maxnode; a++) {
size = numa_node_size(a, &free_node_sizes);
if(size != -1)
node_to_use[got_nodes++] = a;
}
for (a = 0; a < got_nodes; a++){
printf("%03d: ", node_to_use[a]);
if (numa_distance(node_to_use[a], node_to_use[a]) != 10) {
printf("%d: self distance is not 10 (%d)\n",
node_to_use[a], numa_distance(node_to_use[a],node_to_use[a]));
exit(1);
}
for (b = 0; b < got_nodes; b++) {
int d1 = numa_distance(node_to_use[a], node_to_use[b]);
int d2 = numa_distance(node_to_use[b], node_to_use[a]);
printf("%03d ", d1);
if (d1 != d2) {
printf("\n(%d,%d)->(%d,%d) wrong!\n",node_to_use[a],node_to_use[b],d1,d2);
exit(1);
}
}
printf("\n");
}
return 0;
}

8
test/ftok.c Normal file
View File

@ -0,0 +1,8 @@
#include <sys/ipc.h>
#include <stdio.h>
int main(int ac, char **av)
{
while (*++av)
printf("0x%x\n", ftok(*av, 0));
return 0;
}

129
test/mbind_mig_pages.c Normal file
View File

@ -0,0 +1,129 @@
/*
* Test program to test the moving of pages using mbind.
*
* (C) 2006 Silicon Graphics, Inc.
* Christoph Lameter <clameter@sgi.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <numa.h>
#include <numaif.h>
#include <unistd.h>
#include <asm/unistd.h>
unsigned int pagesize;
unsigned int page_count = 32;
char *page_base;
char *pages;
void **addr;
int *status;
int *nodes;
int errors;
int nr_nodes;
struct bitmask *old_nodes;
struct bitmask *new_nodes;
int main(int argc, char **argv)
{
int i, rc;
pagesize = getpagesize();
nr_nodes = numa_max_node()+1;
old_nodes = numa_bitmask_alloc(nr_nodes);
new_nodes = numa_bitmask_alloc(nr_nodes);
numa_bitmask_setbit(old_nodes, 0);
numa_bitmask_setbit(new_nodes, 1);
if (nr_nodes < 2) {
printf("A minimum of 2 nodes is required for this test.\n");
exit(1);
}
setbuf(stdout, NULL);
printf("mbind migration test ......\n");
if (argc > 1)
sscanf(argv[1], "%d", &page_count);
page_base = malloc((pagesize + 1) * page_count);
addr = malloc(sizeof(char *) * page_count);
status = malloc(sizeof(int *) * page_count);
nodes = malloc(sizeof(int *) * page_count);
if (!page_base || !addr || !status || !nodes) {
printf("Unable to allocate memory\n");
exit(1);
}
pages = (void *) ((((long)page_base) & ~((long)(pagesize - 1))) + pagesize);
for (i = 0; i < page_count; i++) {
if (i != 2)
/* We leave page 2 unallocated */
pages[ i * pagesize ] = (char) i;
addr[i] = pages + i * pagesize;
nodes[i] = 0;
status[i] = -123;
}
/* Move pages toi node zero */
numa_move_pages(0, page_count, addr, nodes, status, 0);
printf("\nPage status before page migration\n");
printf("---------------------------------\n");
rc = numa_move_pages(0, page_count, addr, NULL, status, 0);
if (rc < 0) {
perror("move_pages");
exit(1);
}
for (i = 0; i < page_count; i++) {
printf("Page %d vaddr=%p node=%d\n", i, pages + i * pagesize, status[i]);
if (i != 2 && status[i]) {
printf("Bad page state. Page %d status %d\n",i, status[i]);
exit(1);
}
}
/* Move to node zero */
printf("\nMoving pages via mbind to node 0 ...\n");
rc = mbind(pages, page_count * pagesize, MPOL_BIND, old_nodes->maskp,
old_nodes->size + 1, MPOL_MF_MOVE | MPOL_MF_STRICT);
if (rc < 0) {
perror("mbind");
errors++;
}
printf("\nMoving pages via mbind from node 0 to 1 ...\n");
rc = mbind(pages, page_count * pagesize, MPOL_BIND, new_nodes->maskp,
new_nodes->size + 1, MPOL_MF_MOVE | MPOL_MF_STRICT);
if (rc < 0) {
perror("mbind");
errors++;
}
numa_move_pages(0, page_count, addr, NULL, status, 0);
for (i = 0; i < page_count; i++) {
printf("Page %d vaddr=%lx node=%d\n", i,
(unsigned long)(pages + i * pagesize), status[i]);
if (i != 2) {
if (pages[ i* pagesize ] != (char) i) {
printf("*** Page content corrupted.\n");
errors++;
} else if (status[i] != 1) {
printf("*** Page on wrong node.\n");
errors++;
}
}
}
if (!errors)
printf("Test successful.\n");
else
printf("%d errors.\n", errors);
return errors > 0 ? 1 : 0;
}

124
test/migrate_pages.c Normal file
View File

@ -0,0 +1,124 @@
/*
* Test program to test the moving of a processes pages.
*
* (C) 2006 Silicon Graphics, Inc.
* Christoph Lameter <clameter@sgi.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <numa.h>
#include <unistd.h>
#include <errno.h>
unsigned int pagesize;
unsigned int page_count = 32;
char *page_base;
char *pages;
void **addr;
int *status;
int *nodes;
int errors;
int nr_nodes;
struct bitmask *old_nodes;
struct bitmask *new_nodes;
int main(int argc, char **argv)
{
int i, rc;
pagesize = getpagesize();
nr_nodes = numa_max_node()+1;
old_nodes = numa_bitmask_alloc(nr_nodes);
new_nodes = numa_bitmask_alloc(nr_nodes);
numa_bitmask_setbit(old_nodes, 1);
numa_bitmask_setbit(new_nodes, 0);
if (nr_nodes < 2) {
printf("A minimum of 2 nodes is required for this test.\n");
exit(1);
}
setbuf(stdout, NULL);
printf("migrate_pages() test ......\n");
if (argc > 1)
sscanf(argv[1], "%d", &page_count);
page_base = malloc((pagesize + 1) * page_count);
addr = malloc(sizeof(char *) * page_count);
status = malloc(sizeof(int *) * page_count);
nodes = malloc(sizeof(int *) * page_count);
if (!page_base || !addr || !status || !nodes) {
printf("Unable to allocate memory\n");
exit(1);
}
pages = (void *) ((((long)page_base) & ~((long)(pagesize - 1))) + pagesize);
for (i = 0; i < page_count; i++) {
if (i != 2)
/* We leave page 2 unallocated */
pages[ i * pagesize ] = (char) i;
addr[i] = pages + i * pagesize;
nodes[i] = 1;
status[i] = -123;
}
/* Move to starting node */
rc = numa_move_pages(0, page_count, addr, nodes, status, 0);
if (rc < 0 && errno != ENOENT) {
perror("move_pages");
exit(1);
}
/* Verify correct startup locations */
printf("Page location at the beginning of the test\n");
printf("------------------------------------------\n");
numa_move_pages(0, page_count, addr, NULL, status, 0);
for (i = 0; i < page_count; i++) {
printf("Page %d vaddr=%p node=%d\n", i, pages + i * pagesize, status[i]);
if (i != 2 && status[i] != 1) {
printf("Bad page state before migrate_pages. Page %d status %d\n",i, status[i]);
exit(1);
}
}
/* Move to node zero */
numa_move_pages(0, page_count, addr, nodes, status, 0);
printf("\nMigrating the current processes pages ...\n");
rc = numa_migrate_pages(0, old_nodes, new_nodes);
if (rc < 0) {
perror("numa_migrate_pages failed");
errors++;
}
/* Get page state after migration */
numa_move_pages(0, page_count, addr, NULL, status, 0);
for (i = 0; i < page_count; i++) {
printf("Page %d vaddr=%lx node=%d\n", i,
(unsigned long)(pages + i * pagesize), status[i]);
if (i != 2) {
if (pages[ i* pagesize ] != (char) i) {
printf("*** Page contents corrupted.\n");
errors++;
} else if (status[i]) {
printf("*** Page on the wrong node\n");
errors++;
}
}
}
if (!errors)
printf("Test successful.\n");
else
printf("%d errors.\n", errors);
return errors > 0 ? 1 : 0;
}

101
test/move_pages.c Normal file
View File

@ -0,0 +1,101 @@
/*
* Test program to test the moving of individual pages in a process.
*
* (C) 2006 Silicon Graphics, Inc.
* Christoph Lameter <clameter@sgi.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include "numa.h"
#include <unistd.h>
#include <asm/unistd.h>
unsigned int pagesize;
unsigned int page_count = 32;
char *page_base;
char *pages;
void **addr;
int *status;
int *nodes;
int errors;
int nr_nodes;
int main(int argc, char **argv)
{
int i, rc;
pagesize = getpagesize();
nr_nodes = numa_max_node();
if (nr_nodes < 2) {
printf("A minimum of 2 nodes is required for this test.\n");
exit(1);
}
setbuf(stdout, NULL);
printf("move_pages() test ......\n");
if (argc > 1)
sscanf(argv[1], "%d", &page_count);
printf("pages=%d (%s)\n", page_count, argv[1]);
page_base = malloc((pagesize + 1) * page_count);
addr = malloc(sizeof(char *) * page_count);
status = malloc(sizeof(int *) * page_count);
nodes = malloc(sizeof(int *) * page_count);
if (!page_base || !addr || !status || !nodes) {
printf("Unable to allocate memory\n");
exit(1);
}
pages = (void *) ((((long)page_base) & ~((long)(pagesize - 1))) + pagesize);
for (i = 0; i < page_count; i++) {
if (i != 2)
/* We leave page 2 unallocated */
pages[ i * pagesize ] = (char) i;
addr[i] = pages + i * pagesize;
nodes[i] = (i % nr_nodes);
status[i] = -123;
}
printf("\nMoving pages to start node ...\n");
rc = numa_move_pages(0, page_count, addr, NULL, status, 0);
if (rc < 0)
perror("move_pages");
for (i = 0; i < page_count; i++)
printf("Page %d vaddr=%p node=%d\n", i, pages + i * pagesize, status[i]);
printf("\nMoving pages to target nodes ...\n");
rc = numa_move_pages(0, page_count, addr, nodes, status, 0);
if (rc < 0) {
perror("move_pages");
errors++;
}
for (i = 0; i < page_count; i++) {
if (i != 2) {
if (pages[ i* pagesize ] != (char) i)
errors++;
else if (nodes[i] != (i % nr_nodes))
errors++;
}
}
for (i = 0; i < page_count; i++) {
printf("Page %d vaddr=%lx node=%d\n", i,
(unsigned long)(pages + i * pagesize), status[i]);
}
if (!errors)
printf("Test successful.\n");
else
printf("%d errors.\n", errors);
return errors > 0 ? 1 : 0;
}

15
test/mynode.c Normal file
View File

@ -0,0 +1,15 @@
#include <numa.h>
#include <numaif.h>
#include <stdio.h>
int main(void)
{
int nd;
char *man = numa_alloc(1000);
*man = 1;
if (get_mempolicy(&nd, NULL, 0, man, MPOL_F_NODE|MPOL_F_ADDR) < 0)
perror("get_mempolicy");
else
printf("my node %d\n", nd);
return 0;
}

26
test/node-parse.c Normal file
View File

@ -0,0 +1,26 @@
/* Test wrapper for the nodemask parser */
#include <stdio.h>
#include "numa.h"
#include "util.h"
/* For util.c. Fixme. */
void usage(void)
{
exit(1);
}
int main(int ac, char **av)
{
int err = 0;
while (*++av) {
struct bitmask *mask = numa_parse_nodestring(*av);
if (!mask) {
printf("Failed to convert `%s'\n", *av);
err |= 1;
continue;
}
printmask("result", mask);
numa_bitmask_free(mask);
}
return err;
}

30
test/nodemap.c Normal file
View File

@ -0,0 +1,30 @@
#include "numa.h"
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i, k, w, ncpus;
struct bitmask *cpus;
int maxnode = numa_num_configured_nodes()-1;
if (numa_available() < 0) {
printf("no numa\n");
exit(1);
}
cpus = numa_allocate_cpumask();
ncpus = cpus->size;
for (i = 0; i <= maxnode ; i++) {
if (numa_node_to_cpus(i, cpus) < 0) {
printf("node %d failed to convert\n",i);
}
printf("%d: ", i);
w = 0;
for (k = 0; k < ncpus; k++)
if (numa_bitmask_isbitset(cpus, k))
printf(" %s%d", w>0?",":"", k);
putchar('\n');
}
return 0;
}

8
test/numademo Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
testdir=`dirname "$0"`
: ${srcdir:=${testdir}/..}
: ${builddir:=${srcdir}}
export PATH=${builddir}:$PATH
exec "${builddir}"/numademo -t -e 10M

8
test/pagesize.c Normal file
View File

@ -0,0 +1,8 @@
#include <unistd.h>
#include <stdio.h>
int main(void)
{
printf("%d\n", getpagesize());
return 0;
}

63
test/prefered.c Normal file
View File

@ -0,0 +1,63 @@
/* Test prefer policy */
#include "numa.h"
#include "numaif.h"
#include <sys/mman.h>
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#define err(x) perror(x),exit(1)
int main(void)
{
int max = numa_max_node();
int maxmask = numa_num_possible_nodes();
struct bitmask *nodes, *mask;
int pagesize = getpagesize();
int i;
int pol;
int node;
int err = 0;
nodes = numa_bitmask_alloc(maxmask);
mask = numa_bitmask_alloc(maxmask);
for (i = max; i >= 0; --i) {
char *mem = mmap(NULL, pagesize*(max+1), PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
char *adr = mem;
if (mem == (char *)-1)
err("mmap");
printf("%d offset %lx\n", i, (long)(adr - mem));
numa_bitmask_clearall(nodes);
numa_bitmask_clearall(mask);
numa_bitmask_setbit(nodes, i);
if (mbind(adr, pagesize, MPOL_PREFERRED, nodes->maskp,
nodes->size, 0) < 0)
err("mbind");
++*adr;
if (get_mempolicy(&pol, mask->maskp, mask->size, adr, MPOL_F_ADDR) < 0)
err("get_mempolicy");
assert(pol == MPOL_PREFERRED);
assert(numa_bitmask_isbitset(mask, i));
node = 0x123;
if (get_mempolicy(&node, NULL, 0, adr, MPOL_F_ADDR|MPOL_F_NODE) < 0)
err("get_mempolicy2");
printf("got node %d expected %d\n", node, i);
if (node != i)
err = 1;
}
return err;
}

5
test/printcpu Executable file
View File

@ -0,0 +1,5 @@
#!/bin/bash
#print cpu it is running on
declare -a arr
arr=( $(< /proc/self/stat) )
echo ${arr[38]}

175
test/randmap.c Normal file
View File

@ -0,0 +1,175 @@
/* Randomly change policy */
#include <stdio.h>
#include "numa.h"
#include "numaif.h"
#include <sys/mman.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#define SIZE (100*1024*1024)
#define PAGES (SIZE/pagesize)
#define perror(x) printf("%s: %s\n", x, strerror(errno))
#define err(x) perror(x),exit(1)
struct page {
unsigned long mask;
int policy;
};
struct page *pages;
char *map;
int pagesize;
void setpol(unsigned long offset, unsigned long length, int policy, unsigned long nodes)
{
long i, end;
printf("off:%lx length:%lx policy:%d nodes:%lx\n",
offset, length, policy, nodes);
if (mbind(map + offset*pagesize, length*pagesize, policy,
&nodes, 8, 0) < 0) {
printf("mbind: %s offset %lx length %lx policy %d nodes %lx\n",
strerror(errno),
offset*pagesize, length*pagesize,
policy, nodes);
return;
}
for (i = offset; i < offset+length; i++) {
pages[i].mask = nodes;
pages[i].policy = policy;
}
i = offset - 20;
if (i < 0)
i = 0;
end = offset+length+20;
if (end > PAGES)
end = PAGES;
for (; i < end; i++) {
int pol2;
unsigned long nodes2;
if (get_mempolicy(&pol2, &nodes2, sizeof(long)*8, map+i*pagesize,
MPOL_F_ADDR) < 0)
err("get_mempolicy");
if (pol2 != pages[i].policy) {
printf("%lx: got policy %d expected %d, nodes got %lx expected %lx\n",
i, pol2, pages[i].policy, nodes2, pages[i].mask);
}
if (policy != MPOL_DEFAULT && nodes2 != pages[i].mask) {
printf("%lx: nodes %lx, expected %lx, policy %d\n",
i, nodes2, pages[i].mask, policy);
}
}
}
static unsigned char pop4[16] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
};
int popcnt(unsigned long val)
{
int count = 0;
while (val) {
count += pop4[val & 0xf];
val >>= 4;
}
return count;
}
void testmap(void)
{
pages = calloc(1, PAGES * sizeof(struct page));
if (!pages)
exit(100);
printf("simple tests\n");
#define MB ((1024*1024)/pagesize)
setpol(0, PAGES, MPOL_INTERLEAVE, 3);
setpol(0, MB, MPOL_BIND, 1);
setpol(MB, MB, MPOL_BIND, 1);
setpol(MB, MB, MPOL_DEFAULT, 0);
setpol(MB, MB, MPOL_PREFERRED, 2);
setpol(MB/2, MB, MPOL_DEFAULT, 0);
setpol(MB+MB/2, MB, MPOL_BIND, 2);
setpol(MB/2+100, 100, MPOL_PREFERRED, 1);
setpol(100, 200, MPOL_PREFERRED, 1);
printf("done\n");
for (;;) {
unsigned long offset = random() % PAGES;
int policy = random() % (MPOL_MAX+1);
unsigned long nodes = random() % 4;
long length = random() % (PAGES - offset);
/* validate */
switch (policy) {
case MPOL_DEFAULT:
nodes = 0;
break;
case MPOL_INTERLEAVE:
case MPOL_BIND:
if (nodes == 0)
continue;
break;
case MPOL_PREFERRED:
if (popcnt(nodes) != 1)
continue;
break;
}
setpol(offset, length, policy, nodes);
}
}
int main(int ac, char **av)
{
unsigned long seed;
pagesize = getpagesize();
#if 0
map = mmap(NULL, SIZE, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, 0, 0);
if (map == (char*)-1)
err("mmap");
#else
int shmid = shmget(IPC_PRIVATE, SIZE, IPC_CREAT|0666);
if (shmid < 0) err("shmget");
map = shmat(shmid, NULL, SHM_RDONLY);
shmctl(shmid, IPC_RMID, NULL);
if (map == (char *)-1) err("shmat");
printf("map %p\n", map);
#endif
if (av[1]) {
char *end;
unsigned long timeout = strtoul(av[1], &end, 0);
switch (*end) {
case 'h': timeout *= 3600; break;
case 'm': timeout *= 60; break;
}
printf("running for %lu seconds\n", timeout);
alarm(timeout);
} else
printf("running forever\n");
if (av[1] && av[2])
seed = strtoul(av[2], 0, 0);
else
seed = time(0);
printf("random seed %lu\n", seed);
srandom(seed);
testmap();
/* test shm etc. */
return 0;
}

108
test/realloc_test.c Normal file
View File

@ -0,0 +1,108 @@
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include "numa.h"
#include "numaif.h"
#define DEFAULT_NR_PAGES 1024
static int parse_int(const char *str)
{
char *endptr;
long ret = strtol(str, &endptr, 0);
if (*endptr != '\0') {
fprintf(stderr, "[error] strtol() failed: parse error: %s\n", endptr);
exit(1);
}
if (errno == ERANGE)
fprintf(stderr, "[warning] strtol() out of range\n");
if (ret > INT_MAX || ret < INT_MIN) {
fprintf(stderr, "[warning] parse_int() out of range\n");
ret = (ret > 0) ? INT_MAX : INT_MIN;
}
return (int) ret;
}
int main(int argc, char **argv)
{
char *mem;
int page_size = numa_pagesize();
int node = 0;
int nr_pages = DEFAULT_NR_PAGES;
if (numa_available() < 0) {
fprintf(stderr, "numa is not available");
exit(1);
}
if (argc > 1)
node = parse_int(argv[1]);
if (argc > 2)
nr_pages = parse_int(argv[2]);
mem = numa_alloc_onnode(page_size, node);
/* Store the policy of the newly allocated area */
unsigned long nodemask;
int mode;
int nr_nodes = numa_num_possible_nodes();
if (get_mempolicy(&mode, &nodemask, nr_nodes, mem,
MPOL_F_NODE | MPOL_F_ADDR) < 0) {
perror("get_mempolicy() failed");
exit(1);
}
/* Print some info */
printf("Page size: %d\n", page_size);
printf("Pages realloc'ed: %d\n", nr_pages);
printf("Allocate data in node: %d\n", node);
int i;
int nr_inplace = 0;
int nr_moved = 0;
for (i = 0; i < nr_pages; i++) {
/* Enlarge mem with one more page */
char *new_mem = numa_realloc(mem, (i+1)*page_size, (i+2)*page_size);
if (!new_mem) {
perror("numa_realloc() failed");
exit(1);
}
if (new_mem == mem)
++nr_inplace;
else
++nr_moved;
mem = new_mem;
/* Check the policy of the realloc'ed area */
unsigned long realloc_nodemask;
int realloc_mode;
if (get_mempolicy(&realloc_mode, &realloc_nodemask,
nr_nodes, mem, MPOL_F_NODE | MPOL_F_ADDR) < 0) {
perror("get_mempolicy() failed");
exit(1);
}
assert(realloc_nodemask == nodemask &&
realloc_mode == mode && "policy changed");
}
/* Shrink to the original size */
mem = numa_realloc(mem, (nr_pages + 1)*page_size, page_size);
if (!mem) {
perror("numa_realloc() failed");
exit(1);
}
numa_free(mem, page_size);
printf("In-place reallocs: %d\n", nr_inplace);
printf("Moved reallocs: %d\n", nr_moved);
return 0;
}

220
test/regress Executable file
View File

@ -0,0 +1,220 @@
#!/bin/bash
# simple regression test for numactl/numaapi
# must be run from 'test' directory of numactl source package,
# after build [just use 'make test']
# note the statistics checks may fail when the system is under
# memory pressure
# Copyright 2003,2004 Andi Kleen, SuSE Labs.
testdir=`dirname "$0"`
: ${srcdir:=${testdir}/..}
: ${builddir:=${srcdir}}
export PATH=${builddir}:$PATH
: ${NUMACTL:=${builddir}/numactl}
VALGRIND=${VALGRIND:-}
MB=$[1024*1024]
SIZE=$[15 * $MB]
DEMOSIZE=$[10 * $MB]
STAT_INTERVAL=5
PAGESIZE=$("${builddir}/test/pagesize")
PAGES=$[ $SIZE / $PAGESIZE ]
HALFPAGES=$[ $PAGES / 2 ]
HALFPAGES=$[ $HALFPAGES - 100 ]
DOUBLEPAGES=$[ $PAGES * 2 ]
DOUBLEPAGES=$[ $DOUBLEPAGES - 200 ]
NEEDPAGES=$[ $DOUBLEPAGES + $DOUBLEPAGES / 5 ] # 20% spare
EXIT=0
declare -i maxnode
declare -a node
declare -a nlist
# =====================================================================
numactl() {
$VALGRIND $NUMACTL "$@"
}
failed() {
echo '=======FAILED'
echo "Check if machine doesn't have background jobs and try again"
EXIT=1
}
# nstat statname node
nstat() {
sleep $STAT_INTERVAL
declare -a fields
numastat | grep $1 | while read -a fields ; do
echo ${fields[$[1 + $2]]}
done
}
probe_hardware()
{
declare -i n=0
numnodes=$(numactl --hardware | awk '/^available/ { print $2 }')
maxnode=$(expr $numnodes - 1)
nlist=( $(numactl --hardware | grep "^node" | tail -1 |awk '{$1=""; print }') )
# find nodes with at least NEEDPAGES of free memory
for i in $(seq 0 $maxnode) ; do
free=$(numactl --hardware | fgrep " ${nlist[$i]} free" | awk '{print $4}')
free=$(( free * MB ))
if [[ $((free / PAGESIZE)) -ge $NEEDPAGES ]]; then
node[$n]=${nlist[$i]}
n=$((n + 1 ))
fi
done
numnodes=$n
maxnode=$(expr $numnodes - 1)
if [ $numnodes -lt 2 ] ; then
echo "need at least two nodes with at least $NEEDPAGES each of"
echo "free memory for mempolicy regression tests"
exit 77 # Skip test
fi
}
# =========================================================================
_test_process_state() {
echo '=>testing numactl' "$@" "memhog -H $SIZE"
numactl "$@" memhog -H $SIZE || failed
}
test_process_state()
{
declare -i n0=${node[0]} n1=${node[1]}
_test_process_state --interleave=$n1
a0=`nstat interleave_hit 0`
a1=`nstat interleave_hit 1`
_test_process_state --interleave=$n0,$n1
b0=`nstat interleave_hit 0`
b1=`nstat interleave_hit 1`
if [ $(expr $b1 - $a1) -lt $HALFPAGES ]; then
echo "interleaving test failed $n1 $b1 $a1"
failed
fi
if [ $(expr $b0 - $a0) -lt $HALFPAGES ]; then
echo "interleaving test failed $n0 $b0 $a0"
failed
fi
_test_process_state --interleave=all
_test_process_state --membind=all
a=$(expr $(nstat numa_hit 0) + $(nstat numa_hit 1))
_test_process_state --membind=$n0,$n1
b=$(expr $(nstat numa_hit 0) + $(nstat numa_hit 1))
if [ $(expr $b - $a) -lt $PAGES ]; then
echo "membind test failed $n1 $b $a ($PAGES)"
failed
fi
for i in $(seq 0 $maxnode) ; do
declare -i ni=${node[$i]}
a=`nstat numa_hit $i`
_test_process_state --membind=$ni
_test_process_state --preferred=$ni
b=`nstat numa_hit $i`
if [ $(expr $b - $a) -lt $DOUBLEPAGES ]; then
echo "membind/preferred on node $ni failed $b $a"
failed
fi
done
_test_process_state --localalloc
}
# =========================================================================
# test mbind
_test_mbind() {
echo '=>testing memhog -H' "$@"
memhog -H $SIZE "$@" || failed
}
test_mbind()
{
declare -i n0=${node[0]} n1=${node[1]}
a0=`nstat interleave_hit 0`
a1=`nstat interleave_hit 1`
_test_mbind interleave $n0,$n1
b0=`nstat interleave_hit 0`
b1=`nstat interleave_hit 1`
if [ $(expr $b1 - $a1) -lt $HALFPAGES ]; then
echo "interleaving test 2 failed $n1 $b1 $a1 expected $HALFPAGES"
failed
fi
if [ $(expr $b0 - $a0) -lt $HALFPAGES ]; then
echo "interleaving test 2 failed $n0 $b0 $a0"
failed
fi
_test_mbind interleave all
a=$(expr $(nstat numa_hit 0) + $(nstat numa_hit 1))
_test_mbind membind $n0,$n1
b=$(expr $(nstat numa_hit 0) + $(nstat numa_hit 1))
if [ $(expr $b - $a) -lt $PAGES ]; then
echo "membind test 2 failed $b $a ($PAGES)"
failed
fi
for i in $(seq 0 $maxnode) ; do
declare -i ni=${node[$i]}
a=`nstat numa_hit $i`
_test_mbind membind $ni
_test_mbind preferred $ni
b=`nstat numa_hit $i`
if [ $(expr $b - $a) -lt $DOUBLEPAGES ]; then
echo "membind/preferred test 2 on node $ni failed $b $a"
failed
fi
done
}
# =========================================================================
main()
{
# Get the interval vm statistics refresh at
if [ -e /proc/sys/vm/stat_interval ]; then
STAT_INTERVAL=`cat /proc/sys/vm/stat_interval`
STAT_INTERVAL=`expr $STAT_INTERVAL \* 2`
fi
probe_hardware
numactl --cpubind=${node[0]} /bin/true
numactl --cpubind=${node[1]} /bin/true
numactl -s
numactl --hardware
numastat > A
test_process_state
test_mbind
numastat > B
diff -u A B
rm A B
if [ "$EXIT" = 0 ] ; then
echo '========SUCCESS'
else
echo '========FAILURE'
exit 1
fi
}
# =========================================================================
main

47
test/regress-io Normal file
View File

@ -0,0 +1,47 @@
#!/bin/bash
# test IO affinity parsing
# tests may fail depending on machine setup
testdir=`dirname "$0"`
: ${srcdir:=${testdir}/..}
: ${builddir:=${srcdir}}
export PATH=${builddir}:$PATH
E=0
check() {
echo testing $@
if "$@" ; then
true
else
echo failed
E=1
fi
}
fail() {
echo testing failure of $@
if "$@" ; then
echo failed
E=1
else
true
fi
}
check "${builddir}/test/node-parse" file:.
check "${builddir}/test/node-parse" ip:8.8.8.8
fail "${builddir}/test/node-parse" ip:127.0.0.1
IF=$(ip link ls | grep eth | cut -d: -f2 | head -1)
check "${builddir}/test/node-parse" "netdev:$IF"
fail "${builddir}/test/node-parse" netdev:lo
DEV=$(df | awk '/\/$/ { print $1 }')
check "${builddir}/test/node-parse" file:$DEV
check "${builddir}/test/node-parse" block:$(basename $DEV)
check "${builddir}/test/node-parse" pci:0:0.0
if [ "$E" = 0 ] ; then echo SUCCESS ; else echo FAILURE ; fi
exit $E

28
test/regress2 Executable file
View File

@ -0,0 +1,28 @@
#!/bin/sh
# More regression tests for libnuma/numa api
VALGRIND=${VALGRIND:-}
testdir=`dirname "$0"`
: ${srcdir:=${testdir}/..}
: ${builddir:=${srcdir}}
export PATH=${builddir}:$PATH
T() {
echo "$@"
if ! $VALGRIND "$@" ; then
echo $1 FAILED!!!!
exit 1
fi
echo
}
# still broken
#T "${builddir}/test/prefered"
T "${builddir}/test/distance"
T "${builddir}/test/nodemap"
T "${srcdir}/test/checkaffinity"
T "${srcdir}/test/checktopology"
T "${builddir}/test/tbitmap"
T "${srcdir}/test/bind_range"
#T "${builddir}/test/randmap"

21
test/runltp Executable file
View File

@ -0,0 +1,21 @@
#!/bin/sh
# run the Linux Test Project with various numactl settings. will run for a few hours.
# must run as root
# You can download LTP from http://ltp.sourceforge.net
# Change LTP below to the source directory of a compiled LTP distribution
LTP=/src/ltp
LEN=2h
LTPOPT="-q -p -t $LEN"
export PATH=`pwd`/..:$PATH
cd $LTP
for i in 1 2 3 ; do
numactl --interleave=all ./runltp $LTPOPT -l n.interleave.all.$i
numactl --interleave=0,1 ./runltp $LTPOPT -l n.interleave.01.$i
numactl --preferred=0 --cpubind=1 ./runltp $LTPOPT -l n.preferred.$i
# the VM test that allocates all memory may fail
numactl --membind=1 --cpubind=0 ./runltp $LTPOPT -l n.membind1.$i
numactl --membind=0,1 ./runltp $LTPOPT -l n.membind01.$i
done

104
test/shmtest Executable file
View File

@ -0,0 +1,104 @@
#!/bin/sh
# basic shared memory policy test
# hugetlbfs and tmpfs must be mounted on these mount points
TMPFS=/dev/shm
HUGE=/huge
#valgrind 3.0.1 doesn't implement mbind() yet on x86-64
#VALGRIND="valgrind --tool=memcheck"
VALGRIND=
set -e
export PATH=`pwd`/..:$PATH
numactl() {
$VALGRIND ../numactl "$@"
}
failure() {
numastat > after
set +e
diff -u before after
echo
echo TEST FAILED
exit 1
}
success() {
echo test succeeded
}
checkpoint() {
numastat > before
}
trap failure EXIT
basictest() {
echo initial
checkpoint
numactl --length=20m $1 --dump
echo interleave
checkpoint
numactl --offset=2m --length=2m $1 --strict --interleave=0,1 --verify --dump
echo interleave verify
checkpoint
numactl $1 --dump
echo membind setup
checkpoint
numactl --offset 4m --length=2m $1 --strict --membind=1 --verify --dump
echo membind verify
checkpoint
numactl $1 --dump
echo preferred setup
checkpoint
numactl --offset 6m --length 2m $1 --strict --preferred=1 --verify --dump
echo preferred verify
checkpoint
numactl $1 --dump
# check overlaps here
}
cleanupshm() {
if [ -f $1 ] ; then
ipcrm -M `./ftok $1` || true
rm $1
fi
}
banner() {
echo
echo ++++++++++++ $1 +++++++++++++++
echo
}
banner shm
cleanupshm A
basictest --shm=A
cleanupshm A
banner hugeshm
cleanupshm B
basictest "--huge --shm=B"
cleanupshm B
banner tmpfs
basictest "--file $TMPFS/B"
rm $TMPFS/B
# first need a way to create holey hugetlbfs files.
#banner hugetlbfs
#basictest "--file $HUGE/B"
#rm /hugetlbfs/B
rm before
trap success EXIT

103
test/tbitmap.c Normal file
View File

@ -0,0 +1,103 @@
/* Unit test bitmap parser */
#define _GNU_SOURCE 1
//#include <asm/bitops.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <ctype.h>
#include "numa.h"
#include "util.h"
/* For util.c. Fixme. */
void usage(void)
{
exit(1);
}
#define ALIGN(x,a) (((x)+(a)-1)&~((a)-1))
#define test_bit(i,p) ((p)[(i) / BITS_PER_LONG] & (1UL << ((i)%BITS_PER_LONG)))
#define set_bit(i,p) ((p)[(i) / BITS_PER_LONG] |= (1UL << ((i)%BITS_PER_LONG)))
#define clear_bit(i,p) ((p)[(i) / BITS_PER_LONG] &= ~(1UL << ((i)%BITS_PER_LONG)))
typedef unsigned u32;
#define BITS_PER_LONG (sizeof(long)*8)
#define round_up(x,y) (((x) + (y) - 1) & ~((y)-1))
#define CPU_BYTES(x) (round_up(x, BITS_PER_LONG)/8)
#define CPU_LONGS(x) (CPU_BYTES(x) / sizeof(long))
/* Following routine extracted from Linux 2.6.16 */
#define CHUNKSZ 32
#define nbits_to_hold_value(val) fls(val)
#define unhex(c) (isdigit(c) ? (c - '0') : (toupper(c) - 'A' + 10))
#define BASEDEC 10 /* fancier cpuset lists input in decimal */
/**
* bitmap_scnprintf - convert bitmap to an ASCII hex string.
* @buf: byte buffer into which string is placed
* @buflen: reserved size of @buf, in bytes
* @mask: pointer to struct bitmask to convert
*
* Hex digits are grouped into comma-separated sets of eight digits per set.
*/
int bitmap_scnprintf(char *buf, unsigned int buflen, struct bitmask *mask)
{
int i, word, bit, len = 0;
unsigned long val;
const char *sep = "";
int chunksz;
u32 chunkmask;
chunksz = mask->size & (CHUNKSZ - 1);
if (chunksz == 0)
chunksz = CHUNKSZ;
i = ALIGN(mask->size, CHUNKSZ) - CHUNKSZ;
for (; i >= 0; i -= CHUNKSZ) {
chunkmask = ((1ULL << chunksz) - 1);
word = i / BITS_PER_LONG;
bit = i % BITS_PER_LONG;
val = (mask->maskp[word] >> bit) & chunkmask;
len += snprintf(buf+len, buflen-len, "%s%0*lx", sep,
(chunksz+3)/4, val);
chunksz = CHUNKSZ;
sep = ",";
}
return len;
}
extern int numa_parse_bitmap(char *buf, struct bitmask *mask);
#define MASKSIZE 300
int main(void)
{
char buf[1024];
struct bitmask *mask, *mask2;
int i;
mask = numa_bitmask_alloc(MASKSIZE);
mask2 = numa_bitmask_alloc(MASKSIZE);
printf("Testing bitmap functions\n");
for (i = 0; i < MASKSIZE; i++) {
numa_bitmask_clearall(mask);
numa_bitmask_clearall(mask2);
numa_bitmask_setbit(mask, i);
assert(find_first(mask) == i);
bitmap_scnprintf(buf, sizeof(buf), mask);
strcat(buf,"\n");
if (numa_parse_bitmap(buf, mask2) < 0)
assert(0);
if (memcmp(mask->maskp, mask2->maskp, numa_bitmask_nbytes(mask))) {
bitmap_scnprintf(buf, sizeof(buf), mask2);
printf("mask2 differs: %s\n", buf);
assert(0);
}
}
printf("Passed\n");
return 0;
}

50
test/tshared.c Normal file
View File

@ -0,0 +1,50 @@
#include <numa.h>
#include <numaif.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#define err(x) perror(x),exit(1)
enum SZ {
MEMSZ = 100<<20,
NTHR = 10,
};
/* test if shared interleaving state works. */
int main(void)
{
int i, k;
char *mem;
int pagesz = getpagesize();
int max_node;
if (numa_available() < 0) {
printf("no NUMA API available\n");
exit(1);
}
max_node = numa_max_node();
mem = numa_alloc_interleaved(MEMSZ);
for (i = 0; i < NTHR; i++) {
if (fork() == 0) {
for (k = i*pagesz; k < MEMSZ; k += pagesz * NTHR) {
mem[k] = 1;
}
_exit(0);
}
}
for (i = 0; i < NTHR; i++)
wait(NULL);
k = 0;
for (i = 0; i < MEMSZ; i += pagesz) {
int nd;
if (get_mempolicy(&nd, NULL, 0, mem + i, MPOL_F_NODE|MPOL_F_ADDR) < 0)
err("get_mempolicy");
if (nd != k)
printf("offset %d node %d expected %d\n", i, nd, k);
k = (k+1)%(max_node+1);
}
return 0;
}

131
util.c Normal file
View File

@ -0,0 +1,131 @@
/* Copyright (C) 2003,2004 Andi Kleen, SuSE Labs.
numactl is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; version
2.
numactl 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
General Public License for more details.
You should find a copy of v2 of the GNU 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 */
#include "numa.h"
#include "numaif.h"
#include "util.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
void printmask(char *name, struct bitmask *mask)
{
int i;
printf("%s: ", name);
for (i = 0; i < mask->size; i++)
if (numa_bitmask_isbitset(mask, i))
printf("%d ", i);
putchar('\n');
}
int find_first(struct bitmask *mask)
{
int i;
for (i = 0; i < mask->size; i++)
if (numa_bitmask_isbitset(mask, i))
return i;
return -1;
}
void complain(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "numactl: ");
vfprintf(stderr,fmt,ap);
putchar('\n');
va_end(ap);
exit(1);
}
void nerror(char *fmt, ...)
{
int err = errno;
va_list ap;
va_start(ap,fmt);
fprintf(stderr, "numactl: ");
vfprintf(stderr, fmt, ap);
va_end(ap);
if (err)
fprintf(stderr,": %s\n", strerror(err));
else
fputc('\n', stderr);
exit(1);
}
long memsize(char *s)
{
char *end;
long length = strtoul(s,&end,0);
switch (toupper(*end)) {
case 'G': length *= 1024; /*FALL THROUGH*/
case 'M': length *= 1024; /*FALL THROUGH*/
case 'K': length *= 1024; break;
}
return length;
}
static struct policy {
char *name;
int policy;
int noarg;
} policies[] = {
{ "interleave", MPOL_INTERLEAVE, },
{ "membind", MPOL_BIND, },
{ "preferred", MPOL_PREFERRED, },
{ "default", MPOL_DEFAULT, 1 },
{ NULL },
};
static char *policy_names[] = { "default", "preferred", "bind", "interleave" };
char *policy_name(int policy)
{
static char buf[32];
if (policy >= array_len(policy_names)) {
sprintf(buf, "[%d]", policy);
return buf;
}
return policy_names[policy];
}
int parse_policy(char *name, char *arg)
{
int k;
struct policy *p = NULL;
if (!name)
return MPOL_DEFAULT;
for (k = 0; policies[k].name; k++) {
p = &policies[k];
if (!strcmp(p->name, name))
break;
}
if (!p || !p->name || (!arg && !p->noarg))
usage();
return p->policy;
}
void print_policies(void)
{
int i;
printf("Policies:");
for (i = 0; policies[i].name; i++)
printf(" %s", policies[i].name);
printf("\n");
}

20
util.h Normal file
View File

@ -0,0 +1,20 @@
extern void printmask(char *name, struct bitmask *mask);
extern int find_first(struct bitmask *mask);
extern struct bitmask *nodemask(char *s);
extern struct bitmask *cpumask(char *s, int *ncpus);
extern int read_sysctl(char *name);
extern void complain(char *fmt, ...);
extern void nerror(char *fmt, ...);
/* defined in main module, but called by util.c */
extern void usage(void);
extern long memsize(char *s);
extern int parse_policy(char *name, char *arg);
extern void print_policies(void);
extern char *policy_name(int policy);
#define err(x) perror("numactl: " x),exit(1)
#define array_len(x) (sizeof(x)/sizeof(*(x)))
#define round_up(x,y) (((x) + (y) - 1) & ~((y)-1))

175
versions.ldscript Normal file
View File

@ -0,0 +1,175 @@
# Symbols defined in the library which aren't specifically bound to a
# version node are effectively bound to an unspecified base version of
# the library. It is possible to bind all otherwise unspecified symbols
# to a given version node using `global: *' somewhere in the version script.
#
# The interfaces at the "v1" level.
# At this level we present these functions to the linker (and thus to an
# application).
# Any functions not defined in the global list (i.e. "local") will be internal
# to the library (i.e. not exported but used within the library).
# Thus the real function names, "numa_bind_v1" etc, are local and won't
# be known to the linker.
# the first 16 have v1 aliases
# 3 of the 5 system calls that libnuma provides are common to all versions:
libnuma_1.1 {
global:
set_mempolicy;
get_mempolicy;
mbind;
numa_all_nodes;
numa_alloc;
numa_alloc_interleaved;
numa_alloc_interleaved_subset;
numa_alloc_local;
numa_alloc_onnode;
numa_available;
numa_bind;
numa_distance;
numa_error;
numa_exit_on_error;
numa_free;
numa_get_interleave_mask;
numa_get_interleave_node;
numa_get_membind;
numa_get_run_node_mask;
numa_interleave_memory;
numa_max_node;
numa_migrate_pages;
numa_no_nodes;
numa_node_size64;
numa_node_size;
numa_node_to_cpus;
numa_pagesize;
numa_parse_bitmap;
numa_police_memory;
numa_preferred;
numa_run_on_node;
numa_run_on_node_mask;
numa_sched_getaffinity;
numa_sched_setaffinity;
numa_set_bind_policy;
numa_set_interleave_mask;
numa_set_localalloc;
numa_set_membind;
numa_set_preferred;
numa_set_strict;
numa_setlocal_memory;
numa_tonode_memory;
numa_tonodemask_memory;
numa_warn;
numa_exit_on_warn;
local:
*;
};
# The interfaces at the "v2" level.
# The first 17 have v2 aliases
# We add the bitmask_ functions
# and the move_pages and migrate_pages system calls
# 1.2 depends on 1.1
libnuma_1.2 {
global:
copy_bitmask_to_nodemask;
copy_nodemask_to_bitmask;
copy_bitmask_to_bitmask;
set_mempolicy;
get_mempolicy;
mbind;
move_pages;
migrate_pages;
numa_all_cpus_ptr;
numa_all_nodes_ptr;
numa_alloc;
numa_alloc_interleaved;
numa_alloc_interleaved_subset;
numa_alloc_local;
numa_alloc_onnode;
numa_realloc;
numa_allocate_cpumask;
numa_allocate_nodemask;
numa_available;
numa_bind;
numa_bitmask_alloc;
numa_bitmask_clearall;
numa_bitmask_clearbit;
numa_bitmask_equal;
numa_bitmask_free;
numa_bitmask_isbitset;
numa_bitmask_nbytes;
numa_bitmask_setall;
numa_bitmask_setbit;
numa_bitmask_weight;
numa_distance;
numa_error;
numa_exit_on_error;
numa_free;
numa_get_interleave_mask;
numa_get_interleave_node;
numa_get_membind;
numa_get_mems_allowed;
numa_get_run_node_mask;
numa_interleave_memory;
numa_max_node;
numa_max_possible_node;
numa_migrate_pages;
numa_move_pages;
numa_no_nodes_ptr;
numa_node_size64;
numa_node_size;
numa_node_to_cpus;
numa_node_of_cpu;
numa_nodes_ptr;
numa_num_configured_cpus;
numa_num_configured_nodes;
numa_num_possible_nodes;
numa_num_task_cpus;
numa_num_task_nodes;
numa_num_thread_cpus;
numa_num_thread_nodes;
numa_pagesize;
numa_parse_bitmap;
numa_parse_cpustring;
numa_parse_nodestring;
numa_police_memory;
numa_preferred;
numa_run_on_node;
numa_run_on_node_mask;
numa_sched_getaffinity;
numa_sched_setaffinity;
numa_set_bind_policy;
numa_set_interleave_mask;
numa_set_localalloc;
numa_set_membind;
numa_set_preferred;
numa_set_strict;
numa_setlocal_memory;
numa_tonode_memory;
numa_tonodemask_memory;
numa_warn;
local:
*;
} libnuma_1.1;
# New parsing interface for cpu/numastrings
# was added into version 1.3
libnuma_1.3 {
global:
numa_parse_cpustring_all;
numa_parse_nodestring_all;
numa_num_possible_cpus;
local:
*;
} libnuma_1.2;
# New interface with customizable cpuset awareness
# was added into version 1.4
libnuma_1.4 {
global:
numa_run_on_node_mask_all;
local:
*;
} libnuma_1.3;