Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NUMA Memory Page Migration Overhead

I have to find the overhead associated with NUMA memory page migration under Linux.

Can you please tell me which tools I can use?

If possible could you show an example.

like image 319
user1450099 Avatar asked Jun 12 '12 00:06

user1450099


People also ask

How do I stop NUMA balancing?

Automatic NUMA balancing can be enabled or disabled for the current session by writing 1 or 0 to /proc/sys/kernel/numa_balancing which will enable or disable the feature respectively. To permanently enable or disable it, use the kernel command line option numa_balancing=[enable|disable] .

What is NUMA interleave?

The node interleaving option exists on servers with a non-uniform memory access (NUMA) system architecture. The Intel Nehalem and AMD Opteron are both NUMA architectures. In a NUMA architecture multiple nodes exists. Each node contains a CPU and memory and is connected via a NUMA interconnect.

What is NUMA policy?

A NUMA memory policy consists of a “mode”, optional mode flags, and an optional set of nodes. The mode determines the behavior of the policy, the optional mode flags determine the behavior of the mode, and the optional set of nodes can be viewed as the arguments to the policy behavior.

What is NUMA in Linux?

Non-Uniform Memory Access (NUMA) refers to multiprocessor systems whose memory is divided into multiple memory nodes. The access time of a memory node depends on the relative locations of the accessing CPU and the accessed node.


1 Answers

If you want to understand whether your system is doing excessive remote node memory accesses and you're using intel CPUs, Intel's PMU has a utility called vtbwrun to report the QPI/uncore activity.

If you want to see how long it takes to execute a page migration, you can measure the duration of calls to numa_move_pages (provided by the numactl package).

Here's an example:

/*
 * Test program to test the moving of a processes pages.
 *
 * (C) 2006 Silicon Graphics, Inc.
 *          Christoph Lameter <[email protected]>
 */
#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;
}
like image 128
Brian Cain Avatar answered Sep 28 '22 02:09

Brian Cain