libnuma: testdomain and partial implementation
authorReto Achermann <acreto@student.ethz.ch>
Sat, 13 Dec 2014 16:26:28 +0000 (17:26 +0100)
committerReto Achermann <acreto@student.ethz.ch>
Sat, 13 Dec 2014 16:26:28 +0000 (17:26 +0100)
initial commit of lib/numa with function stubs for the interface functions
adding implementations of some interface functions of libnuma

adding of tests/numatest domain to check libnuma

13 files changed:
errors/errno.fugu
hake/symbolic_targets.mk
include/numa.h
lib/numa/Hakefile [new file with mode: 0644]
lib/numa/alloc.c [new file with mode: 0644]
lib/numa/bitmap.c [new file with mode: 0644]
lib/numa/numa.c [new file with mode: 0644]
lib/numa/numa_debug.h [new file with mode: 0644]
lib/numa/numa_internal.h [new file with mode: 0644]
lib/numa/policy.c [new file with mode: 0644]
lib/numa/utilities.c [new file with mode: 0644]
usr/tests/numa/Hakefile [new file with mode: 0644]
usr/tests/numa/numatest.c [new file with mode: 0644]

index 452f08d..cd4a2be 100755 (executable)
@@ -1122,4 +1122,6 @@ errors numa NUMA_ERR_ {
     failure BITMAP_PARSE          "Parsing of the bitmap character string failed",
     failure BITMAP_RANGE          "The bitmap is too small to hold the data",
     failure NUMA_MEMBIND          "Setting the memory binding failed",
+    failure LIB_INIT              "Library initialization failure",
+    failure SKB                   "Failed to query or connect the SKB",
 };
index 07d2c49..54df8c6 100644 (file)
@@ -100,7 +100,8 @@ TESTS_COMMON= \
        sbin/yield_test
 
 TESTS_x86= \
-       sbin/tests/luatest
+       sbin/tests/luatest \
+       sbin/tests/numatest
 
 TESTS_x86_64= \
        $(TESTS_x86) \
index fcf2337..f65c763 100644 (file)
@@ -26,7 +26,7 @@
 typedef coreid_t nodeid_t;
 
 ///< the maximum number of nodes supported
-#define NUMA_MAX_NUMNODES 256
+#define NUMA_MAX_NUMNODES 16
 
 ///< specify the local node for allocation
 #define NUMA_NODE_LOCAL ((nodeid_t)-1)
@@ -35,14 +35,18 @@ typedef coreid_t nodeid_t;
 #define NUMA_NODE_INVALID ((uintptr_t)-1)
 
 typedef enum numa_policy {
-    NUMA_POLICY_DEFAULT,  ///< default numa policy
-    NUMA_POLICY_STRICT   ///< strict numa policy
+    NUMA_POLICY_DEFAULT,   ///< default numa policy
+    NUMA_POLICY_STRICT,    ///< strict numa policy
+    NUMA_POLICY_PREFERRED  ///< preferred memory policy
 } numa_policy_t;
 
 struct numa_bm {
 
 };
 
+///< typedef for the nodemask
+typedef uint32_t nodemask_t;
+
 /**
  * \brief checks if numa support is available
  *
@@ -73,7 +77,14 @@ coreid_t numa_max_cores(void);
  *
  * \return ID of the current node
  */
-nodeid_t numa_current_node();
+nodeid_t numa_current_node(void);
+
+/**
+ * \brief returns the size of the node mask
+ *
+ * \return size of the node mask
+ */
+nodeid_t numa_num_possible_nodes(void);
 
 /**
  * \brief Obtains the maximum number of nodes the system can handle
@@ -89,13 +100,6 @@ static inline nodeid_t numa_max_possible_node(void)
 }
 
 /**
- * \brief returns the size of the node mask
- *
- * \return size of the node mask
- */
-nodeid_t numa_num_possible_nodes();
-
-/**
  * \brief Obtains the number of all memory nodes in the system
  *
  * \return number of memory nodes in the system
@@ -147,7 +151,7 @@ extern struct numa_bm *numa_all_cpus_ptr;
  *
  * \returns number of CPUs the domain is allowed to use
  */
-coreid_t numa_num_task_cpus();
+coreid_t numa_num_task_cpus(void);
 
 /**
  * \brief returns the number of nodes on which the calling domain is allowed to
@@ -155,7 +159,7 @@ coreid_t numa_num_task_cpus();
  *
  * \returns number of nodes the domain is allowed to use
  */
-nodeid_t numa_num_task_nodes();
+nodeid_t numa_num_task_nodes(void);
 
 /**
  * \brief parses line , which is a character string
@@ -536,7 +540,7 @@ nodeid_t numa_node_of_cpu(coreid_t cpu);
  * \returns pointer to a new bitmask
  *          NULL on failure
  */
-struct numa_bm *numa_allocate_cpumask();
+struct numa_bm *numa_allocate_cpumask(void);
 
 /**
  * \brief frees a previously allocated CPU bitmask
@@ -551,7 +555,7 @@ void numa_free_cpumask(struct numa_bm *cpumask);
  * \returns pointer to a new bitmask
  *          NULL on failure
  */
-struct numa_bm *numa_allocate_nodemask();
+struct numa_bm *numa_allocate_nodemask(void);
 
 /**
  * \brief frees a previously allocated node bitmask
diff --git a/lib/numa/Hakefile b/lib/numa/Hakefile
new file mode 100644 (file)
index 0000000..1284f4c
--- /dev/null
@@ -0,0 +1,24 @@
+--------------------------------------------------------------------------
+-- Copyright (c) 2014, ETH Zurich.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Universitaetsstrasse 4, CH-8092 Zurich. Attn: Systems Group.
+--
+--------------------------------------------------------------------------
+
+[ build library { 
+    target = "numa",
+    cFiles = [ 
+        "numa.c",
+        "alloc.c",
+        "policy.c",
+        "utilities.c" 
+    ],
+    addLibraries = libDeps [
+        "skb"
+    ]
+    
+  }
+]
diff --git a/lib/numa/alloc.c b/lib/numa/alloc.c
new file mode 100644 (file)
index 0000000..5772234
--- /dev/null
@@ -0,0 +1,284 @@
+/**
+ * \file
+ * \brief General Numa functions
+ *
+ */
+
+/*
+ * Copyright (c) 2014, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <barrelfish/barrelfish.h>
+
+#include <numa.h>
+
+/** \brief   returns the current interleave mask
+ *
+ * \returns bitmask representing the current interleave state
+ *
+ * returns the current interleave mask if the task's memory allocation policy is
+ * page interleaved. Otherwise, this function returns an empty mask.
+ */
+struct numa_bm *numa_get_interleave_mask(void)
+{
+    assert(!"NYI");
+    return 0;
+}
+
+
+/**
+ * \brief sets the memory interleave mask for the current task to nodemask
+ *
+ * \param nodemask bitmask representing the nodes
+ *
+ * All new memory allocations are page interleaved over all nodes in the interleave
+ * mask. Interleaving can be turned off again by passing an empty mask.
+ *
+ * This bitmask is considered to be a hint. Fallback to other nodes may be possible
+ */
+void numa_set_interleave_mask(struct numa_bm *nodemask)
+{
+    assert(!"NYI");
+}
+
+
+/**
+ * \brief binds the current task and its children to the nodes specified in nodemask.
+ *
+ * \param nodemask  bitmap representing the nodes
+ */
+void numa_bind(struct numa_bm *nodemask)
+{
+    assert(!"NYI");
+}
+
+
+/**
+ * \brief sets the memory allocation policy for the calling task to local allocation.
+ */
+void numa_set_localalloc(void)
+{
+    assert(!"NYI");
+}
+
+
+/**
+ * \brief sets the memory allocation mask.
+ *
+ * \param nodemask  bitmap representing the nodes
+ *
+ * The task will only allocate memory from the nodes set in nodemask.
+ *
+ * an empty mask or not allowed nodes in the mask will result in an error
+ */
+errval_t numa_set_membind(struct numa_bm *nodemask)
+{
+    assert(!"NYI");
+    return 0;
+}
+
+
+/**
+ * \brief returns the mask of nodes from which memory can currently be allocated.
+ *
+ * \return bitmap of nodes from which can be allocated
+ */
+struct numa_bm *numa_get_membind(void){
+    assert(!"NYI");
+    return 0;
+}
+
+
+/**
+ * \brief allocates memory on a specific node.
+ *
+ * \param size  size of the region in bytes
+ * \param node  ID of the node to allocate from
+ *
+ * \returns pointer to memory region
+ *
+ * The size argument will be rounded up to a multiple of the system page size.
+ * if the specified node is externally denied to this process, this call will fail.
+ * The memory must be freed with numa_free(). On errors NULL is returned.
+ */
+void *numa_alloc_onnode(size_t size, nodeid_t node){
+    assert(!"NYI");
+    return 0;
+}
+
+
+/**
+ * \brief allocates size bytes of memory on the local node
+ *
+ * \param size  size of the memory region in bytes
+ *
+ * \returns pointer to memory region
+ *
+ * The memory must be freed with numa_free(). On errors NULL is returned.
+ */
+void *numa_alloc_local(size_t size){
+    assert(!"NYI");
+    return 0;
+}
+
+
+/**
+ * \brief allocates size bytes of memory page interleaved on all nodes.
+ *
+ * \param size   size of the memory region in bytes
+ *
+ * \returns pointer to the mapped memory region
+ *
+ * should only be used for large areas consisting of multiple pages.
+ * The memory must be freed with numa_free(). On errors NULL is returned.
+ */
+void *numa_alloc_interleaved(size_t size)
+{
+    assert(!"NYI");
+    return 0;
+}
+
+
+/**
+ * \brief allocates size bytes of memory page interleaved on all nodes.
+ *
+ * \param size     size of the memory region in bytes
+ * \param nodemask subset of nodes to consider for allocation
+ * \returns pointer to the mapped memory region
+ *
+ * should only be used for large areas consisting of multiple pages.
+ * The memory must be freed with numa_free(). On errors NULL is returned.
+ */
+void *numa_alloc_interleaved_subset(size_t size, struct numa_bm *nodemask)
+{
+    assert(!"NYI");
+    return 0;
+}
+
+
+/**
+ * \brief allocates size bytes of memory with the current NUMA policy.
+ *
+ * \param size  size of the memory region in bytes
+ *
+ * \returns pointer to the mapped memory region
+ *
+ * The memory must be freed with numa_free(). On errors NULL is returned.
+ */
+void *numa_alloc(size_t size)
+{
+    assert(!"NYI");
+    return 0;
+}
+
+
+/**
+ * \brief changes the size of the memory area.
+ *
+ * \param old_addr  pointer ot the old memory region
+ * \param old_size  size of the old memory region
+ * \param new_size  new size to allocate
+ */
+void *numa_realloc(void *old_addr, size_t old_size, size_t new_size)
+{
+    assert(!"NYI");
+    return 0;
+}
+
+
+/**
+ * \brief frees size bytes of memory starting at start
+ *
+ * \param start start of the memory region
+ * \param size  number of bytes to free
+ *
+ * the memory must be previously allocated by one of the numa_alloc* functions
+ */
+void numa_free(void *start, size_t size)
+{
+    assert(!"NYI");
+}
+
+
+
+/**
+ * \brief allocates a frame on a specific node
+ *
+ * \param dest      capref to store the frame
+ * \param size      size of the frame to allocated
+ * \param node      node on which the frame should be allocated
+ * \param ret_size  returned size of the frame capability
+ *
+ * \returns SYS_ERR_OK on SUCCESS
+ *          errval on FAILURE
+ */
+errval_t numa_frame_alloc_on_node(struct capref *dest,
+                                  size_t size,
+                                  nodeid_t node,
+                                  size_t *ret_size)
+{
+    assert(!"NYI");
+    return 0;
+}
+
+
+/**
+ * \brief frees a previously allocated frame
+ *
+ * \param frame capability to free
+ */
+errval_t numa_frame_free(struct capref frame)
+{
+    assert(!"NYI");
+    return 0;
+}
+
+
+/**
+ * \brief  moves a list of pages in the address space of the current domain
+ *
+ * \param did    the domain ID
+ * \param count  number of pages to move
+ * \param pages  list of pages
+ * \param nodes  list of nodes to which the pages can be moved
+ * \param status returns the outcome for each page
+ * \param flags  flags for moving the pages
+ *
+ * \returns SYS_ERR_OK on SUCCESS
+ */
+errval_t numa_move_pages(domainid_t did,
+                         size_t count,
+                         void **pages,
+                         const nodeid_t *nodes,
+                         errval_t *status,
+                         int flags)
+{
+    assert(!"NYI");
+    return 0;
+}
+
+
+/**
+ * \brief migrate a domain from one set of nodes to another
+ *
+ * \param did        the domain ID
+ * \param fromnodes  bitmap representing the current nodes
+ * \param tonodes    bitmap representing the
+ *
+ * \returns SYS_ERR_OK on SUCCESS
+ */
+errval_t numa_migrate_pages(domainid_t did,
+                            struct numa_bm *fromnodes,
+                            struct numa_bm *tonodes)
+{
+    assert(!"NYI");
+    return 0;
+}
diff --git a/lib/numa/bitmap.c b/lib/numa/bitmap.c
new file mode 100644 (file)
index 0000000..5e09d29
--- /dev/null
@@ -0,0 +1,210 @@
+/**
+ * \file
+ * \brief Bitmap manipulation
+ *
+ */
+
+/*
+ * Copyright (c) 2014, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <barrelfish/barrelfish.h>
+
+#include <numa.h>
+
+
+
+/**
+ * \brief parses a character string list of nodes into a bit mask.
+ *
+ * \param string character string to parse
+ *
+ * \returns NUMA bitmask on SUCCESS
+ *          NULL if the string is invalid
+ *
+ * The string is a comma-separated list of node numbers or node ranges
+ * Examples: 1-5,7,10 !4-5 +0-3
+ *
+ * If the string length is zero, then the numa_no_nodes_ptr is returned
+ */
+struct numa_bm *numa_parse_nodestring(char *string)
+{
+
+}
+
+/**
+ * \brief parses a character string list of cpus into a bit mask.
+ *
+ * \param string character string to parse
+ *
+ * \returns NUMA bitmask on SUCCESS
+ *          NULL if the string is invalid
+ *
+ * The string is a comma-separated list of cpu numbers or cpu ranges
+ * Examples: 1-5,7,10 !4-5 +0-3
+ */
+struct numa_bm *numa_parse_cpustring(char *string)
+{
+
+}
+
+struct numa_bm *numa_allocate_cpumask();
+
+/**
+ * \brief frees a previously allocated CPU bitmask
+ *
+ * \param cpumask pointer to a previously allocated CPU bitmask
+ */
+void numa_free_cpumask(struct numa_bm *cpumask);
+
+/**
+ * \brief allocates a bit mask to represent the nodes in the system
+ *
+ * \returns pointer to a new bitmask
+ *          NULL on failure
+ */
+struct numa_bm *numa_allocate_nodemask();
+
+/**
+ * \brief frees a previously allocated node bitmask
+ *
+ * \param nodemask pointer to a previously allocated node bitmask
+ */
+void numa_free_nodemask(struct numa_bm *nodemask);
+
+/**
+ * \brief allocates a bitmask structure and its associated bit mask
+ *
+ * \param n the number of bits
+ *
+ * \returns pointer to the bitmask
+ *          NULL on error
+ */
+struct numa_bm *numa_bitmask_alloc(unsigned int n);
+
+/**
+ * \brief sets all bits in the bit mask to 0.
+ *
+ * \param bmp   pointer to the bitmap
+ *
+ * \returns pointer to the cleared bit map
+ */
+struct numa_bm *numa_bitmask_clearall(struct numa_bm *bmp);
+
+/**
+ * \brief clears the n-th bit of a bitmask
+ *
+ * \param bmp   the bitmask
+ * \param n     the bit to clear
+ *
+ * \returns pointer to the bitmask
+ */
+struct numa_bm *numa_bitmask_clearbit(struct numa_bm *bmp, unsigned int n);
+
+/**
+ * \brief checks if two bitmasks are equal
+ *
+ * \param bmp1  bitmask 1
+ * \param bmp2  bitmask 2
+ *
+ * \return TRUE if the bitmasks are equal
+ *         FALSE if the are distinct
+ */
+bool numa_bitmask_equal(const struct numa_bm *bmp1, const struct numa_bm *bmp2);
+
+/**
+ * \brief frees the memory of a bitmask
+ *
+ * \param bmp the bitmask to be freed
+ */
+void numa_bitmask_free(struct numa_bm *bmp);
+
+/**
+ * \brief checks if the n-th bit is set in the bitmask
+ *
+ * \param bmp   the bitmap
+ * \param n     which bit to check
+ *
+ * \returns TRUE if the n-th bit is set
+ *          FALSE otherwise
+ */
+bool numa_bitmask_isbitset(const struct numa_bm *bmp, unsigned int n);
+
+/**
+ * \brief returns the size (in bytes) of the bit mask
+ *
+ * \param bmp   the bitmask
+ *
+ * \returns the size of the memory in bytes rounded up to a multiple of wordsize
+ */
+size_t numa_bitmask_nbytes(struct numa_bm *bmp);
+
+/**
+ * \brief sets all bits of a bitmask to 1
+ *
+ * \param bmp the bitmask
+ *
+ * \returns the bitmask
+ */
+struct numa_bm *numa_bitmask_setall(struct numa_bm *bmp);
+
+/**
+ * \brief sets the n-th bit of a bitmask to 1
+ *
+ * \param bmp   the bitmask
+ * \param n     which bit to activate
+ *
+ * \returns the bitmask
+ */
+struct numa_bm *numa_bitmask_setbit(struct numa_bm *bmp, unsigned int n);
+
+/**
+ * \brief copies the bitmask to a nodemask
+ *
+ * \param bmp       the bitmask to copy
+ * \param nodemask  the destination nodemask
+ *
+ * If the two areas differ in size, the copy is truncated to the size of the
+ * receiving field or zero-filled.
+ */
+void copy_bitmask_to_nodemask(struct numa_bm *bmp, nodemask_t *nodemask);
+
+/**
+ * \brief copies the contents of a nodemask into the bitmask
+ *
+ * \param nodemask  node mask to copy from
+ * \param bmp       bitmap to copy into
+ *
+ * If the two areas differ in size, the copy is truncated to the size of the
+ * receiving field or zero-filled.
+ */
+void copy_nodemask_to_bitmask(nodemask_t *nodemask, struct numa_bm *bmp);
+
+/**
+ * \brief copies one bitmask into another
+ *
+ * \param bmpfrom   the source bitmask
+ * \param bmpto     the destination bitmask
+ *
+ * If the two areas differ in size, the copy is truncated to the size of the
+ * receiving field or zero-filled.
+ */
+void copy_bitmask_to_bitmask(struct numa_bm *bmpfrom, struct numa_bm *bmpto);
+
+/**
+ * \brief returns a count of the bits that are set in the body of the bitmask
+ *
+ * \param bmp   the bitmask to count the set bits
+ *
+ * \return number of set bits in this bitmask
+ */
+uint32_t numa_bitmask_weight(const struct numa_bm *bmp);
+
diff --git a/lib/numa/numa.c b/lib/numa/numa.c
new file mode 100644 (file)
index 0000000..697bad4
--- /dev/null
@@ -0,0 +1,431 @@
+/**
+ * \file
+ * \brief General Numa functions
+ *
+ */
+
+/*
+ * Copyright (c) 2014, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <barrelfish/barrelfish.h>
+
+#include <numa.h>
+
+#include "numa_internal.h"
+
+uint8_t numa_initialized = 0x0;
+
+/**
+ * \brief bitmask that is allocated by the library with bits representing all nodes
+ *        on which the calling task may allocate memory.
+ */
+struct numa_bm *numa_all_nodes_ptr;
+
+/**
+ * \brief points to a bitmask that is allocated by the library and left all zeroes.
+ */
+struct numa_bm *numa_no_nodes_ptr;
+
+/**
+ * \brief points to a bitmask that is allocated by the library with bits
+ *        representing all cpus on which the calling task may execute.
+ */
+struct numa_bm *numa_all_cpus_ptr;
+
+/**
+ * \brief data structure representing the numa topology
+ */
+struct numa_topology numa_topology;
+
+/**
+ * \brief checks if numa support is available
+ *
+ * \returns NUMA_ERR_NOT_AVAILABLE  value all other functions are undefined
+ *          SYS_ERR_OK:             NUMA functionality is available
+ *
+ * this function must be called before any of the other functions of libnuma.
+ * during the call to numa_available the library also gets initialized
+ */
+errval_t numa_available(void)
+{
+
+    if (numa_initialized) {
+        return SYS_ERR_OK;
+    }
+
+    NUMA_DEBUG_INIT("Initializing libnuma...\n");
+
+    numa_get_topology_from_skb(&numa_topology);
+
+    NUMA_DEBUG_INIT("done.\n");
+    return SYS_ERR_OK;
+}
+
+/**
+ * \brief returns the highest node number available on the current system.
+ *
+ * \returns ID of the max NUMA node
+ */
+nodeid_t numa_max_node(void)
+{
+    // XXX: assume nodes are 0..n-1
+    return numa_topology.num_nodes - 1;
+}
+
+/**
+ * \brief returns the highest ID of the present cores
+ *
+ * \returns the maximum number of cores in the system
+ */
+coreid_t numa_max_cores(void)
+{
+    // XXX: assume the IDs are 0...n-1
+    return numa_topology.num_cores - 1;
+}
+
+/**
+ * \brief returns the current node the domain is running on
+ *
+ * \return ID of the current node
+ */
+nodeid_t numa_current_node(void)
+{
+    // XXX: do we need disp_get_core_id() here?
+    return numa_topology.cores[disp_get_current_core_id()].node->id;
+}
+
+/**
+ * \brief returns the size of the node mask
+ *
+ * \return size of the node mask
+ */
+nodeid_t numa_num_possible_nodes(void)
+{
+    return NUMA_MAX_NUMNODES;
+}
+
+/**
+ * \brief Obtains the number of all memory nodes in the system
+ *
+ * \return number of memory nodes in the system
+ *
+ * returns the number of memory nodes in the system. This count includes any nodes
+ * that are currently disabled.
+ */
+nodeid_t numa_num_configured_nodes(void)
+{
+    // XXX: we have all nodes configures
+    return numa_topology.num_nodes;
+}
+
+/**
+ * \brief obtains the nodes the domain is allowed to allocate memory from
+ *
+ * \returns bitmask representing the allowing nodes
+ *
+ * returns the mask of nodes from which the process is allowed to allocate memory
+ * in it's current cpuset context.
+ */
+struct numa_bm *numa_get_mems_allowed(void)
+{
+    assert(!"NYI");
+    return 0;
+}
+
+/**
+ * \brief returns the total numberof CPUs in the system
+ *
+ * \returns total number of CPUs in the system
+ *
+ * returns the number of cpus in the system. This count includes any cpus that are
+ * currently disabled.
+ */
+coreid_t numa_num_configured_cpus(void)
+{
+    // XXX we assume that we can schedule all cores
+    return numa_topology.num_cores;
+}
+
+/**
+ * \brief returns the number of cpus that the calling domain is allowed to use.
+ *
+ * \returns number of CPUs the domain is allowed to use
+ */
+coreid_t numa_num_task_cpus(void)
+{
+    // XXX: we do not have any restrictions yet, return all cores
+    return numa_topology.num_cores;
+}
+
+/**
+ * \brief returns the number of nodes on which the calling domain is allowed to
+ *        allocate memory
+ *
+ * \returns number of nodes the domain is allowed to use
+ */
+nodeid_t numa_num_task_nodes(void)
+{
+    // XXX: We do not have any restrictions yet. just return all nodes
+    return numa_topology.num_nodes;
+}
+
+/**
+ * \brief obtains the size of a node
+ *
+ * \param node  ID of the NUMA node
+ * \param freep returns the number of available bytes of the node
+ *
+ * \returns size of the node in bytes
+ *
+ * returns the memory size of a node. If the argument freep is not NULL, it used
+ * to return the amount of free memory on the node. On error it returns
+ * NUMA_NODE_INVALID
+ */
+size_t numa_node_size(nodeid_t node, uintptr_t *freep)
+{
+    if (node < numa_topology.num_nodes) {
+        NUMA_WARNING("Node ID exceeds number of available nodes");
+        return NUMA_NODE_INVALID;
+    }
+
+    if (freep) {
+        // TODO: figure out how much memory is left in the node
+    }
+
+    return numa_topology.nodes[node].mem_size;
+}
+
+/**
+ * \brief obtains the base address of the numa node
+ *
+ * \returns physical address of the start of the numa node
+ *          NUMA_NODE_INVALID if the node does not exist
+ */
+lpaddr_t numa_node_base(nodeid_t node)
+{
+    if (node < numa_topology.num_nodes) {
+        NUMA_WARNING("Node ID exceeds number of available nodes");
+        return NUMA_NODE_INVALID;
+    }
+
+    return numa_topology.nodes[node].mem_base;
+}
+
+/**
+ * \brief returns the preferred node of the current task.
+ *
+ * \returns node ID where memory is preferably allocated
+ */
+nodeid_t numa_preferred(void)
+{
+    return numa_current_node();
+}
+
+/**
+ * \brief  sets the preferred node for the current task to node
+ *
+ * \param node  ID of the node to set preferred
+ *
+ * The system will attempt to allocate memory from the preferred node, but will
+ * fall back to other nodes if no memory is available on the the preferred node
+ *
+ * Passing a node of -1 argument specifies local allocation
+ */
+void numa_set_preferred(nodeid_t node)
+{
+    if (node >= numa_topology.num_nodes) {
+        NUMA_WARNING("Node ID exceeds number of available nodes");
+        return;
+    }
+
+    numa_topology.preferred = node;
+}
+
+
+/**
+ * \brief runs the current domain on a specific node.
+ *
+ * \param node  ID of the node to run the domain on
+ *
+ * \returns SYS_ERR_OK on SUCCESS
+ *          errval on FAILURE
+ *
+ * Passing -1 permits the kernel to schedule on all nodes again
+ */
+errval_t numa_run_on_node(nodeid_t node)
+{
+    USER_PANIC("running the domain on a specific node is not supported yet\n");
+    return 0;
+}
+
+
+/**
+ * \brief runs the current domain only on nodes specified in nodemask.
+ *
+ * \param nodemask bitmap representing the nodes to run the domain on
+ *
+ * \returns SYS_ERR_OK on SUCCESS
+ *          errval on FAILURE
+ */
+errval_t numa_run_on_node_mask(struct numa_bm *nodemask)
+{
+    USER_PANIC("running the domain on a specific node is not supported yet\n");
+    return 0;
+}
+
+
+/**
+ * \brief returns a mask of CPUs on which the current task is allowed to run.
+ *
+ * \returns bitmap represening the coreids the domain is allowed to run
+ */
+struct numa_bm *numa_get_run_node_mask(void)
+{
+    return numa_all_nodes_ptr;
+}
+
+
+/**
+ * \brief specify the memory bind policy
+ *
+ * \param strict numa policy to apply
+ *
+ * specifies whether calls that bind memory to a specific node should use the
+ * preferred policy or a strict policy.
+ */
+void numa_set_bind_policy(numa_policy_t strict)
+{
+    if (strict == NUMA_POLICY_STRICT) {
+        numa_topology.bind = strict;
+    } else {
+        numa_topology.bind = NUMA_POLICY_PREFERRED;
+    }
+}
+
+
+/**
+ * \brief enable or disable the strict allocation policy
+ *
+ * \param strict numa policy to apply
+ *
+ * s a flag that says whether the functions allocating on specific nodes should
+ * use a strict policy. Strict means the allocation will fail if the memory cannot
+ * be allocated on the target node.
+ */
+void numa_set_strict(numa_policy_t strict)
+{
+    if (strict == NUMA_POLICY_STRICT) {
+        numa_topology.strict = strict;
+    } else {
+        numa_topology.strict = NUMA_POLICY_PREFERRED;
+    }
+}
+
+
+/**
+ * \brief reports the distance in the machine topology between two nodes
+ *
+ * \param from source node to measure the distance
+ * \param to   target node to measure the distance
+ *
+ * \returns distance between two nodes
+ *          0 iff cannot be deterimed
+ *
+ * The factors are a multiple of 10.  A node has distance 10 to itself.
+ */
+uint32_t numa_distance(nodeid_t from, nodeid_t to)
+{
+    assert(!"NYI");
+    return 0;
+}
+
+
+/**
+ * \brief retrieves a bitmask of the cpus on which a domain may run
+ *
+ * \param did   domain ID
+ * \param mask  returned bitmask
+ *
+ * \returns SYS_ERR_OK on success
+ *          errval on FAILURE
+ */
+errval_t numa_sched_getaffinity(domainid_t did, struct numa_bm *mask)
+{
+    assert(!"NYI");
+    return 0;
+}
+
+
+/**
+ * \brief sets a domain's allowed cpu's to those cpu's specified in mask.
+ *
+ * \param did   domain ID
+ * \param mask  bitmap representing the CPUs
+ *
+ * \returns SYS_ERR_OK on success
+ *          errval on FAILURE
+ */
+errval_t numa_sched_setaffinity(domainid_t did, struct numa_bm *mask)
+{
+    assert(!"NYI");
+    return 0;
+}
+
+
+/**
+ * \brief returns the page size
+ *
+ * \returns the number of bytes in a page
+ */
+size_t numa_pagesize(void)
+{
+    return numa_topology.pagesize;
+}
+
+
+
+/**
+ * \brief converts a node number to a bitmask of CPUs
+ *
+ * \param node  the ID of the node
+ * \param mask  bitmap representing the CPUs of this node
+ *
+ * \return  SYS_ERR_OK on SUCCESS
+ *          NUMA_ERR_BITMAP_RANGE on FAILURE (too small bitmap)
+ *
+ * The user must pass a bitmask structure with a mask buffer long enough to
+ * represent all possible cpu's
+ */
+errval_t numa_node_to_cpus(nodeid_t node, struct numa_bm *mask)
+{
+    assert(!"NYI");
+    return 0;
+}
+
+
+/**
+ * \brief returns the node that a cpu belongs to
+ *
+ * \param cpu   ID of the core
+ *
+ * \returns node ID on SUCCESS
+ *          NUMA_NODE_INVALID on FAILURE
+ */
+nodeid_t numa_node_of_cpu(coreid_t cpu)
+{
+    if (cpu < numa_topology.num_cores) {
+        return numa_topology.cores[cpu].node->id;
+    } else {
+        NUMA_WARNING("Core ID exceeds number of present cores");
+        return (nodeid_t)NUMA_NODE_INVALID;
+    }
+}
diff --git a/lib/numa/numa_debug.h b/lib/numa/numa_debug.h
new file mode 100644 (file)
index 0000000..cf3fc9a
--- /dev/null
@@ -0,0 +1,40 @@
+/**
+ * \file
+ * \brief internal header of libnuma
+ *
+ * This is derived from:
+ *
+ * Linux man pages "numa"
+ * libnuma from http://oss.sgi.com/projects/libnuma/
+ *
+ */
+
+/*
+ * Copyright (c) 2014, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich.
+ * Attn: Systems Group.
+ */
+
+#ifndef NUMA_DEBUG_H_
+#define NUMA_DEBUG_H_
+
+#define NUMA_DEBUG_ENABLED 1
+
+#if NUMA_DEBUG_ENABLED
+#define NUMA_DEBUG_PRINT(x...) debug_printf(x);
+#else
+#define NUMA_DEBUG_PRINT(x...)
+#endif
+
+#define NUMA_DEBUG_INIT(x...)  NUMA_DEBUG_PRINT("[numa  init] " x);
+
+#define NUMA_DEBUG_ALLOC(x...) NUMA_DEBUG_PRINT("[numa alloc] " x);
+
+#define NUMA_ERROR(x...) debug_printf("[numa error] %s :" x "\n",  __FUNCTION__);
+#define NUMA_WARNING(x...) debug_printf("[numa  warn] %s :" x "\n",  __FUNCTION__);
+
+#endif /* NUMA_DEBUG_H_ */
diff --git a/lib/numa/numa_internal.h b/lib/numa/numa_internal.h
new file mode 100644 (file)
index 0000000..58e6e72
--- /dev/null
@@ -0,0 +1,96 @@
+/**
+ * \file
+ * \brief internal header of libnuma
+ *
+ * This is derived from:
+ *
+ * Linux man pages "numa"
+ * libnuma from http://oss.sgi.com/projects/libnuma/
+ *
+ */
+
+/*
+ * Copyright (c) 2014, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich.
+ * Attn: Systems Group.
+ */
+
+#ifndef NUMA_INTERNAL_H_
+#define NUMA_INTERNAL_H_
+
+#include "numa_debug.h"
+
+/*
+ * ----------------------------------------------------------------------------
+ * Library global variable definitions
+ * ----------------------------------------------------------------------------
+ */
+extern uint8_t numa_initialized;
+
+/*
+ * ----------------------------------------------------------------------------
+ * Data structure definitions
+ * ----------------------------------------------------------------------------
+ */
+
+/**
+ * \brief numa topology information of the system
+ */
+struct numa_topology {
+    nodeid_t num_nodes;      ///< number of nodes in the system
+    coreid_t num_cores;      ///< number of cores in the system
+    nodeid_t preferred;      ///< the preferred node of the domain
+    numa_policy_t strict;    ///< numa policy
+    numa_policy_t bind;      ///< memory bind policy
+    size_t pagesize;         ///< numa page size
+    struct numa_node *nodes; ///< nodes in the system
+    struct numa_core *cores; ///< cores in the system
+};
+
+/**
+ * \brief represents a numa node
+ */
+struct numa_node {
+    nodeid_t id;             ///< id of the node
+    uint16_t apicid;         ///< apic id for the node (core 0)
+    coreid_t num_cores;      ///< number of cores within the
+    struct numa_core *cores; ///< pointer to the cores array
+    struct bitmask *coresbm; ///< bitmask for the cores
+    lpaddr_t mem_base;       ///< base address of the memory
+    lpaddr_t mem_size;       ///< size of the memory region
+};
+
+/**
+ * \brief represents a core
+ */
+struct numa_core {
+    coreid_t id;             ///< id of the core
+    uint16_t apicid;         ///< apic id of the core
+    struct numa_node *node;  ///< node of the core
+};
+
+extern struct numa_topology numa_topology;
+
+/*
+ * ----------------------------------------------------------------------------
+ * Queriying the SKB
+ * ----------------------------------------------------------------------------
+ */
+
+/**
+ * \brief obtains the system topology from the SKB
+ *
+ * \param topology pointer to the topology information structure
+ *
+ * \returns SYS_ERR_OK on SUCCESS
+ *          errval on FAILURE
+ */
+errval_t numa_get_topology_from_skb(struct numa_topology *topology);
+
+
+
+#endif /* NUMA_INTERNAL_H_ */
diff --git a/lib/numa/policy.c b/lib/numa/policy.c
new file mode 100644 (file)
index 0000000..856060f
--- /dev/null
@@ -0,0 +1,22 @@
+/**
+ * \file
+ * \brief General Numa functions
+ *
+ */
+
+/*
+ * Copyright (c) 2014, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <barrelfish/barrelfish.h>
+
+#include <numa.h>
+
diff --git a/lib/numa/utilities.c b/lib/numa/utilities.c
new file mode 100644 (file)
index 0000000..c2cb9c0
--- /dev/null
@@ -0,0 +1,61 @@
+/**
+ * \file
+ * \brief General Numa functions
+ *
+ */
+
+/*
+ * Copyright (c) 2014, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <barrelfish/barrelfish.h>
+#include <skb/skb.h>
+
+#include <numa.h>
+
+#include "numa_internal.h"
+
+/**
+ * \brief obtains the system topology from the SKB
+ *
+ * \param topology pointer to the topology information structure
+ *
+ * \returns SYS_ERR_OK on SUCCESS
+ *          errval on FAILURE
+ */
+errval_t numa_get_topology_from_skb(struct numa_topology *topology)
+{
+    errval_t err;
+
+    /* don't query if no return pointer is specified */
+    if (topology == NULL) {
+        return SYS_ERR_OK;
+    }
+
+
+    NUMA_DEBUG_INIT("getting topology from SKB...\n");
+
+    err = skb_client_connect();
+    if (err_is_fail(err)) {
+        return err_push(err, NUMA_ERR_SKB);
+    }
+
+    /* query SKB for topology information */
+
+    /* allocate struct */
+
+
+
+
+    assert(!"NYI");
+    return SYS_ERR_OK;
+}
+
diff --git a/usr/tests/numa/Hakefile b/usr/tests/numa/Hakefile
new file mode 100644 (file)
index 0000000..cb694ad
--- /dev/null
@@ -0,0 +1,19 @@
+--------------------------------------------------------------------------
+-- Copyright (c) 2013, ETH Zurich.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for luatest
+--
+--------------------------------------------------------------------------
+
+[
+    build application {
+        target = "tests/numatest",
+        cFiles = (find withSuffices [".c"]),
+        addLibraries = libDeps ["numa"]
+    }
+]
\ No newline at end of file
diff --git a/usr/tests/numa/numatest.c b/usr/tests/numa/numatest.c
new file mode 100644 (file)
index 0000000..1865b94
--- /dev/null
@@ -0,0 +1,30 @@
+/**
+ * \file
+ * \brief Test the LUA interpreter library
+ */
+/*
+ * Copyright (c) 2013, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+
+#include <numa.h>
+
+
+int main (void)
+{
+    debug_printf("numa test started...\n");
+
+    if (numa_available() == SYS_ERR_OK) {
+        debug_printf("num nodes=%u\n", numa_max_node());
+        debug_printf("num cores: %u\n", numa_max_cores());
+    } else {
+        debug_printf("numa not available\n");
+    }
+    return 0;
+}