7

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.

Andrew Tomazos
  • 66,139
  • 40
  • 186
  • 319
user1450099
  • 71
  • 1
  • 2
  • Where are you migrating memory pages from and to? Are we talking simple page faults? Or NUMA machines trying to get non-local memory pages? You're going to have to describe in significantly more detail what you're trying to achieve. – sarnold Jun 12 '12 at 00:32
  • Does your machine provide a microkernel that would allow you to easily set up and test local and remote page accesses? – sarnold Jun 12 '12 at 00:36
  • do u mean the hops gathered from "numactl --hardware"? – user1450099 Jun 12 '12 at 00:39
  • @sarnold: is it just possible to only profile the page migrations and so on using some high level tools without really coding the kernel? – user1450099 Jun 12 '12 at 00:43
  • I'm not sure about what is _possible_ vs _easy_, but it feels to me that your best bets might be: (a) the datasheet of the machine in question (b) the smallest and least useful kernel you can find that runs on the machine -- you don't want a bunch of other things going on at the same time if you have to measure the times. – sarnold Jun 12 '12 at 00:44

1 Answers1

5

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 <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;
}
Brian Cain
  • 14,403
  • 3
  • 50
  • 88