mirror of https://gitee.com/openkylin/numactl.git
Import Upstream version 2.0.12
This commit is contained in:
commit
43ff68b8ba
|
@ -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.
|
||||
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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`).
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
enum {
|
||||
NO_IO_AFFINITY = -2
|
||||
};
|
||||
|
||||
int resolve_affinity(const char *id, struct bitmask *mask);
|
|
@ -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:
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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:
|
|
@ -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:
|
File diff suppressed because it is too large
Load Diff
|
@ -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:
|
|
@ -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='[0;31m' # Red.
|
||||
grn='[0;32m' # Green.
|
||||
lgn='[1;32m' # Light green.
|
||||
blu='[1;34m' # Blue.
|
||||
mgn='[0;35m' # Magenta.
|
||||
std='[m' # 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:
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
void clearcache(unsigned char *mem, unsigned size);
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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];
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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])
|
||||
)
|
||||
])
|
File diff suppressed because it is too large
Load Diff
|
@ -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])])
|
|
@ -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
|
||||
])
|
|
@ -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)
|
||||
])
|
|
@ -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])])
|
|
@ -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);
|
||||
}
|
|
@ -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)
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
||||
|
|
@ -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 */
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
|
@ -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[];
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
struct bitmask;
|
||||
hidden char *sysfs_read(char *name);
|
||||
hidden int sysfs_node_read(struct bitmask *mask, char *fmt, ...);
|
|
@ -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.
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/sh
|
||||
|
||||
testdir=`dirname "$0"`
|
||||
: ${srcdir:=${testdir}/..}
|
||||
: ${builddir:=${srcdir}}
|
||||
export PATH=${builddir}:$PATH
|
||||
|
||||
exec "${builddir}"/numademo -t -e 10M
|
|
@ -0,0 +1,8 @@
|
|||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("%d\n", getpagesize());
|
||||
return 0;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
#print cpu it is running on
|
||||
declare -a arr
|
||||
arr=( $(< /proc/self/stat) )
|
||||
echo ${arr[38]}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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"
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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");
|
||||
}
|
|
@ -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))
|
|
@ -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;
|
Loading…
Reference in New Issue