libtopology provides a hierarchical view of the machine, NUMA memory nodes, sockets, shared caches, cores and simultaneous multithreading. It also gathers various attributes such as cache and memory information.
libtopology supports the following operating systems:
For development and debugging purposes, libtopology also offers the ability to work on fake topologies:
libtopology may also display the topology in a convenient format, either in graphical mode, or by exporting in PDF, PNG, FIG, ... format, or in text mode (see Examples below).
libtopology offers a programming interface for manipulating topologies and objects. It also brings a powerful cpu bitmap API that is used to describe topology objects location on physical/logical processors. See the Interface example interface below. It may also be used to binding applications onto certain cores or memory nodes. Several utility programs are also provided to ease command-line manipulation of topology objects, binding of processes, ...
Note that autoconf >=2.60, automake >=1.10 and libtool >=2.2.6 are required in that case.
Installation by itself is as usual:
Lstopo's fig support is always available. To get support for pdf, ps and png support, cairo is needed. To get support for xml, libxml2 is needed.
lstopo
tool may show the following outputs:
System(15GB) Socket#0 + L3(4096KB) L2(1024KB) + L1(16KB) + Core#0 P#0 P#8 L2(1024KB) + L1(16KB) + Core#1 P#4 P#12 Socket#1 + L3(4096KB) L2(1024KB) + L1(16KB) + Core#0 P#1 P#9 L2(1024KB) + L1(16KB) + Core#1 P#5 P#13 Socket#2 + L3(4096KB) L2(1024KB) + L1(16KB) + Core#0 P#2 P#10 L2(1024KB) + L1(16KB) + Core#1 P#6 P#14 Socket#3 + L3(4096KB) L2(1024KB) + L1(16KB) + Core#0 P#3 P#11 L2(1024KB) + L1(16KB) + Core#1 P#7 P#15
On a 8-socket 2-core Opteron NUMA machine, the lstopo
tool may show the following outputs:
System(62GB)
Node#0(8190MB) + Socket#0
L2(1024KB) + L1(64KB) + Core#0 + P#0
L2(1024KB) + L1(64KB) + Core#1 + P#1
Node#1(8192MB) + Socket#1
L2(1024KB) + L1(64KB) + Core#0 + P#2
L2(1024KB) + L1(64KB) + Core#1 + P#3
Node#2(8192MB) + Socket#2
L2(1024KB) + L1(64KB) + Core#0 + P#4
L2(1024KB) + L1(64KB) + Core#1 + P#5
Node#3(8192MB) + Socket#3
L2(1024KB) + L1(64KB) + Core#0 + P#6
L2(1024KB) + L1(64KB) + Core#1 + P#7
Node#4(8192MB) + Socket#4
L2(1024KB) + L1(64KB) + Core#0 + P#8
L2(1024KB) + L1(64KB) + Core#1 + P#9
Node#5(8192MB) + Socket#5
L2(1024KB) + L1(64KB) + Core#0 + P#10
L2(1024KB) + L1(64KB) + Core#1 + P#11
Node#6(8192MB) + Socket#6
L2(1024KB) + L1(64KB) + Core#0 + P#12
L2(1024KB) + L1(64KB) + Core#1 + P#13
Node#7(8192MB) + Socket#7
L2(1024KB) + L1(64KB) + Core#0 + P#14
L2(1024KB) + L1(64KB) + Core#1 + P#15
On a 2-socket quad-core Xeon (pre-Nehalem ones assembling 2 dual-core dies into each socket):
System(15GB) Socket#0 L2(4096KB) L1(32KB) + Core#0 + P#0 L1(32KB) + Core#1 + P#4 L2(4096KB) L1(32KB) + Core#2 + P#2 L1(32KB) + Core#3 + P#6 Socket#1 L2(4096KB) L1(32KB) + Core#0 + P#1 L1(32KB) + Core#1 + P#5 L2(4096KB) L1(32KB) + Core#2 + P#3 L1(32KB) + Core#3 + P#7
topo-hello.c
that just prints the topology and binds itself to the first processor of the second core of the machine.Libtopology provides a pkg-config object, so compiling the example boils down to
CFLAGS+=$(pkg-config --cflags topology) LDLIBS+=$(pkg-config --libs topology) cc topo-hello.c $(CFLAGS) -o topo-hello $(LDLIBS)
/* topo-hello.c */ #include <topology.h> static void print_children(topo_topology_t topology, topo_obj_t obj, int depth) { char string[128]; int i; topo_obj_snprintf(string, sizeof(string), topology, obj, "#", 0); printf("%*s%s\n", 2*depth, "", string); for (i = 0; i < obj->arity; i++) print_children(topology, obj->children[i], depth + 1); } int main(void) { /* Topology object */ topo_topology_t topology; /* Allocate and initialize topology object. */ topo_topology_init(&topology); /* ... Optionally, put detection configuration here to e.g. ignore some objects types, define a synthetic topology, etc.... The default is to detect all the objects of the machine that the caller is allowed to access. See Configure Topology Detection. */ /* Perform the topology detection. */ topo_topology_load(topology); /* Optionally, get some additional topology information * in case we need the topology depth later. */ struct topo_topology_info topoinfo; topo_topology_get_info(topology, &topoinfo); /* Walk the topology with an array style, from level 0 (always the * system level) to the lowest level (always the proc level). */ unsigned depth, i; char string[128]; for (depth = 0; depth < topoinfo.depth; depth++) { for (i = 0; i < topo_get_depth_nbobjs(topology, depth); i++) { topo_obj_snprintf(string, sizeof(string), topology, topo_get_obj_by_depth(topology, depth, i), "#", 0); printf("%s\n", string); } } /* Walk the topology with a tree style. */ print_children(topology, topo_get_system_obj(topology), 0); /* Print the number of sockets. */ depth = topo_get_type_depth(topology, TOPO_OBJ_SOCKET); if (depth == TOPO_TYPE_DEPTH_UNKNOWN) printf("The number of sockets is unknown\n"); else printf("%u socket(s)\n", topo_get_depth_nbobjs(topology, depth)); /* Find out where cores are, or else smaller sets of CPUs if the OS * doesn't have the notion of core. */ depth = topo_get_type_or_below_depth(topology, TOPO_OBJ_CORE); /* Get last one. */ topo_obj_t obj = topo_get_obj_by_depth(topology, depth, topo_get_depth_nbobjs(topology, depth) - 1); if (!obj) return 0; /* Get its cpuset. */ topo_cpuset_t cpuset = obj->cpuset; /* Get only one logical processor (in case the core is SMT/hyperthreaded). */ topo_cpuset_singlify(&cpuset); /* And try to bind ourself there. */ if (topo_set_cpubind(topology, &cpuset, 0)) { char s[TOPO_CPUSET_STRING_LENGTH + 1]; topo_cpuset_snprintf(s, sizeof(s), &obj->cpuset); printf("Couldn't bind to cpuset %s\n", s); } /* Destroy topology object. */ topo_topology_destroy(topology); return 0; }
Further documentation is available in html, manual pages, and pdf format in the source tarball in doc/doxygen-doc/ (after doxygen compilation for svn checkouts) and are installed in $prefix/share/doc/topology/ and the usual manual repository.
The basic interface is available in topology.h, a lot of traversal examples are available as inlines in topology/helper.h . On Linux, additional helpers are available in topology/linux-libnuma.h and on glibc-based systems, additional helpers are available in topology/glibc-sched.h
To precisely define the vocabulary used by libtopology, a Glossary is available and should probably be read first.
libtopology
is developed by the INRIA Runtime Team-Project (http://runtime.bordeaux.inria.fr/) (headed by Raymond Namyst http://dept-info.labri.fr/~namyst/).