/*
 * SPDX-License-Identifier: BSD-3-Clause
 * Copyright © 2016-2017 Inria.  All rights reserved.
 * See COPYING in top-level directory.
 */

#include "hwloc.h"

#include <stdio.h>
#include <assert.h>

#define LEN 1048576

int main(void)
{
  const struct hwloc_topology_support *support;
  char *buffer;
  hwloc_topology_t topology;
  hwloc_bitmap_t set = hwloc_bitmap_alloc();
  hwloc_bitmap_t total = hwloc_bitmap_alloc();
  hwloc_obj_t node;
  char *s;
  int err;

  err = hwloc_topology_init(&topology);
  assert(!err);
  err = hwloc_topology_load(topology);
  assert(!err);

  support = hwloc_topology_get_support(topology);
  if (!support->membind->get_area_memlocation)
    goto out;

  buffer = hwloc_alloc(topology, LEN);
  assert(buffer);
  printf("buffer %p length %d\n", buffer, LEN);

  err = hwloc_get_area_memlocation(topology, buffer, LEN, set, HWLOC_MEMBIND_BYNODESET);
  if (err < 0 && errno == ENOSYS) {
    fprintf(stderr, "hwloc_get_area_memlocation() failed with ENOSYS, aborting\n");
    goto out_with_buffer;
  }
  assert(!err);
  hwloc_bitmap_asprintf(&s, set);
  printf("address %p length %d allocated in nodeset %s\n", buffer, LEN, s);
  free(s);
  hwloc_bitmap_copy(total, set);

  node = NULL;
 next1:
  node = hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_NUMANODE, node);
  if (!node)
    goto out_with_buffer;
  if (!node->attr->numanode.local_memory)
    goto next1;
  printf("binding to 1st node and touching 1st quarter\n");
  err = hwloc_set_area_membind(topology, buffer, LEN, node->nodeset, HWLOC_MEMBIND_BIND, HWLOC_MEMBIND_BYNODESET);
  if (err < 0 && errno == ENOSYS) {
    fprintf(stderr, "hwloc_set_area_membind() failed with ENOSYS, aborting\n");
    goto out_with_buffer;
  }
  assert(!err);

  memset(buffer, 0, LEN/4);
  err = hwloc_get_area_memlocation(topology, buffer, 1, set, HWLOC_MEMBIND_BYNODESET);
  assert(!err);
  hwloc_bitmap_asprintf(&s, set);
  printf("address %p length %d allocated in nodeset %s\n", buffer, LEN/4, s);
  free(s);
  hwloc_bitmap_or(total, total, set);

 next2:
  node = hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_NUMANODE, node);
  if (!node)
    goto out_with_nomorenodes;
  if (!node->attr->numanode.local_memory)
    goto next2;
  printf("binding to 2nd node and touching 2nd quarter\n");
  err = hwloc_set_area_membind(topology, buffer, LEN, node->nodeset, HWLOC_MEMBIND_BIND, HWLOC_MEMBIND_BYNODESET);
  assert(!err);

  memset(buffer+LEN/4, 0, LEN/4);
  err = hwloc_get_area_memlocation(topology, buffer+LEN/4, LEN/4, set, HWLOC_MEMBIND_BYNODESET);
  assert(!err);
  hwloc_bitmap_asprintf(&s, set);
  printf("address %p length %d allocated in nodeset %s\n", buffer+LEN/4, LEN/4, s);
  free(s);
  hwloc_bitmap_or(total, total, set);

 next3:
  node = hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_NUMANODE, node);
  if (!node)
    goto out_with_nomorenodes;
  if (!node->attr->numanode.local_memory)
    goto next3;
  printf("binding to 3rd node and touching 3rd quarter\n");
  err = hwloc_set_area_membind(topology, buffer, LEN, node->nodeset, HWLOC_MEMBIND_BIND, HWLOC_MEMBIND_BYNODESET);
  assert(!err);

  memset(buffer+LEN/2, 0, LEN/4);
  err = hwloc_get_area_memlocation(topology, buffer+LEN/2, LEN/4, set, HWLOC_MEMBIND_BYNODESET);
  assert(!err);
  hwloc_bitmap_asprintf(&s, set);
  printf("address %p length %d allocated in nodeset %s\n", buffer+LEN/2, LEN/4, s);
  free(s);
  hwloc_bitmap_or(total, total, set);

 next4:
  node = hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_NUMANODE, node);
  if (!node)
    goto out_with_nomorenodes;
  if (!node->attr->numanode.local_memory)
    goto next4;
  printf("binding to 4th node and touching 4th quarter\n");
  err = hwloc_set_area_membind(topology, buffer, LEN, node->nodeset, HWLOC_MEMBIND_BIND, HWLOC_MEMBIND_BYNODESET);
  assert(!err);

  memset(buffer+3*LEN/4, 0, LEN/4);
  err = hwloc_get_area_memlocation(topology, buffer+3*LEN/4, LEN/4, set, HWLOC_MEMBIND_BYNODESET);
  assert(!err);
  hwloc_bitmap_asprintf(&s, set);
  printf("address %p length %d allocated in nodeset %s\n", buffer+3*LEN/4, LEN/4, s);
  free(s);
  hwloc_bitmap_or(total, total, set);

 out_with_nomorenodes:
  err = hwloc_get_area_memlocation(topology, buffer, LEN, set, HWLOC_MEMBIND_BYNODESET);
  assert(!err);
  hwloc_bitmap_asprintf(&s, set);
  printf("address %p length %d located on %s\n", buffer, LEN, s);
  free(s);
  assert(hwloc_bitmap_isincluded(total, set));

 out_with_buffer:
  hwloc_free(topology, buffer, LEN);

 out:
  hwloc_topology_destroy(topology);
  hwloc_bitmap_free(set);
  hwloc_bitmap_free(total);
  return 0;
}
