/**
 * Copyright (C) Mellanox Technologies Ltd. 2001-2018.  ALL RIGHTS RESERVED.
 *
 * See file LICENSE for terms.
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include "numa.h"

#include <ucs/debug/assert.h>
#include <ucs/debug/log.h>
#include <stdint.h>
#include <sched.h>


const char *ucs_numa_policy_names[] = {
    [UCS_NUMA_POLICY_DEFAULT]   = "default",
    [UCS_NUMA_POLICY_PREFERRED] = "preferred",
    [UCS_NUMA_POLICY_BIND]      = "bind",
    [UCS_NUMA_POLICY_LAST]      = NULL,
};

#if HAVE_NUMA


static void ucs_numa_populate_cpumap(int16_t cpu_numa_nodes[])
{
    struct bitmask *cpumask;
    int numa_node, cpu;
    int ret;

    cpumask = numa_allocate_cpumask();

    for (numa_node = 0; numa_node <= numa_max_node(); ++numa_node) {
        if (!numa_bitmask_isbitset(numa_all_nodes_ptr, numa_node)) {
            continue;
        }

        ret = numa_node_to_cpus(numa_node, cpumask);
        if (ret == -1) {
            ucs_warn("failed to get CPUs for NUMA node %d: %m", numa_node);
            continue;
        }

        for (cpu = 0; cpu < numa_num_configured_cpus(); ++cpu) {
            if (numa_bitmask_isbitset(cpumask, cpu)) {
                cpu_numa_nodes[cpu] = numa_node + 1;
            }
        }
    }

    numa_free_cpumask(cpumask);
}


int ucs_numa_node_of_cpu(int cpu)
{
    /* we can initialize statically only to the value 0, so the NUMA node
     * numbers will be stored as 1..N instead of 0..N-1 */
    static int16_t cpu_numa_nodes[__CPU_SETSIZE] = {0};

    UCS_STATIC_ASSERT(NUMA_NUM_NODES <= INT16_MAX);
    ucs_assert(cpu < __CPU_SETSIZE);

    if (cpu_numa_nodes[cpu] == 0) {
        ucs_numa_populate_cpumap(cpu_numa_nodes);
    }
    return cpu_numa_nodes[cpu] - 1;
}

#endif
