Blame src/memkind_bandwidth.c

Packit 345191
/*
Packit 345191
 * Copyright (C) 2019 Intel Corporation.
Packit 345191
 * All rights reserved.
Packit 345191
 *
Packit 345191
 * Redistribution and use in source and binary forms, with or without
Packit 345191
 * modification, are permitted provided that the following conditions are met:
Packit 345191
 * 1. Redistributions of source code must retain the above copyright notice(s),
Packit 345191
 *    this list of conditions and the following disclaimer.
Packit 345191
 * 2. Redistributions in binary form must reproduce the above copyright notice(s),
Packit 345191
 *    this list of conditions and the following disclaimer in the documentation
Packit 345191
 *    and/or other materials provided with the distribution.
Packit 345191
 *
Packit 345191
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS
Packit 345191
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
Packit 345191
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
Packit 345191
 * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit 345191
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit 345191
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
Packit 345191
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
Packit 345191
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
Packit 345191
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
Packit 345191
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 345191
 */
Packit 345191
Packit 345191
#include <errno.h>
Packit 345191
#include <limits.h>
Packit 345191
#include <stdint.h>
Packit 345191
Packit 345191
#include <memkind/internal/memkind_log.h>
Packit 345191
#include <memkind/internal/memkind_private.h>
Packit 345191
#include <memkind/internal/memkind_bandwidth.h>
Packit 345191
Packit 345191
struct numanode_bandwidth_t {
Packit 345191
    int numanode;
Packit 345191
    int bandwidth;
Packit 345191
};
Packit 345191
Packit 345191
struct bandwidth_nodes_t {
Packit 345191
    int bandwidth;
Packit 345191
    int num_numanodes;
Packit 345191
    int *numanodes;
Packit 345191
};
Packit 345191
Packit 345191
VEC(vec_cpu_node, int);
Packit 345191
Packit 345191
#define BANDWIDTH_NODE_HIGH_VAL       2
Packit 345191
#define BANDWIDTH_NODE_LOW_VAL        1
Packit 345191
#define BANDWIDTH_NODE_NOT_PRESENT    0
Packit 345191
Packit 345191
static void bandwidth_assign_arbitrary_values(int *bandwidth,
Packit 345191
                                              struct bitmask *numa_nodes_bm)
Packit 345191
{
Packit 345191
    unsigned i;
Packit 345191
    int nodes_num = numa_num_configured_nodes();
Packit 345191
Packit 345191
    for (i = 0; i
Packit 345191
        if (numa_bitmask_isbitset(numa_nodes_bm, i)) {
Packit 345191
            bandwidth[i] = BANDWIDTH_NODE_HIGH_VAL;
Packit 345191
            nodes_num--;
Packit 345191
        }
Packit 345191
    }
Packit 345191
Packit 345191
    for (i = 0; i
Packit 345191
        if (!numa_bitmask_isbitset(numa_nodes_bm, i)) {
Packit 345191
            bandwidth[i] = BANDWIDTH_NODE_LOW_VAL;
Packit 345191
            nodes_num--;
Packit 345191
        }
Packit 345191
        if (nodes_num==0) break;
Packit 345191
    }
Packit 345191
}
Packit 345191
Packit 345191
int bandwidth_fill(int *bandwidth, get_node_bitmask get_bitmask)
Packit 345191
{
Packit 345191
    struct bitmask *high_val_node_mask = numa_allocate_nodemask();
Packit 345191
    int ret = get_bitmask(high_val_node_mask);
Packit 345191
    if(ret == 0) {
Packit 345191
        bandwidth_assign_arbitrary_values(bandwidth, high_val_node_mask);
Packit 345191
    }
Packit 345191
    numa_bitmask_free(high_val_node_mask);
Packit 345191
Packit 345191
    return ret;
Packit 345191
}
Packit 345191
Packit 345191
static int bandwidth_fill_values_from_enviroment(int *bandwidth,
Packit 345191
                                                 char *nodes_env)
Packit 345191
{
Packit 345191
    struct bitmask *numa_nodes_bm = numa_parse_nodestring(nodes_env);
Packit 345191
Packit 345191
    if (!numa_nodes_bm) {
Packit 345191
        log_err("Invalid value of environment variable.");
Packit 345191
        return MEMKIND_ERROR_ENVIRON;
Packit 345191
    } else {
Packit 345191
        bandwidth_assign_arbitrary_values(bandwidth, numa_nodes_bm);
Packit 345191
        numa_bitmask_free(numa_nodes_bm);
Packit 345191
    }
Packit 345191
Packit 345191
    return 0;
Packit 345191
}
Packit 345191
Packit 345191
static int bandwidth_fill_nodes(int *bandwidth, fill_bandwidth_values fill,
Packit 345191
                                const char *env)
Packit 345191
{
Packit 345191
    char *high_value_nodes_env = secure_getenv(env);
Packit 345191
    if (high_value_nodes_env) {
Packit 345191
        log_info("Environment variable %s detected: %s.", env, high_value_nodes_env);
Packit 345191
        return bandwidth_fill_values_from_enviroment(bandwidth, high_value_nodes_env);
Packit 345191
    }
Packit 345191
    return fill(bandwidth);
Packit 345191
}
Packit 345191
Packit 345191
static int bandwidth_compare_numanode(const void *a, const void *b)
Packit 345191
{
Packit 345191
    /***************************************************************************
Packit 345191
    *  qsort comparison function for numa_node_bandwidth structures.  Sorts in *
Packit 345191
    *  order of bandwidth and then numanode.                                   *
Packit 345191
    ***************************************************************************/
Packit 345191
    int result;
Packit 345191
    struct numanode_bandwidth_t *aa = (struct numanode_bandwidth_t *)(a);
Packit 345191
    struct numanode_bandwidth_t *bb = (struct numanode_bandwidth_t *)(b);
Packit 345191
    result = (aa->bandwidth > bb->bandwidth) - (aa->bandwidth < bb->bandwidth);
Packit 345191
    if (result == 0) {
Packit 345191
        result = (aa->numanode > bb->numanode) - (aa->numanode < bb->numanode);
Packit 345191
    }
Packit 345191
    return result;
Packit 345191
}
Packit 345191
Packit 345191
static int bandwidth_create_nodes(const int *bandwidth, int *num_unique,
Packit 345191
                                  struct bandwidth_nodes_t **bandwidth_nodes)
Packit 345191
{
Packit 345191
    /***************************************************************************
Packit 345191
    *   bandwidth (IN):                                                        *
Packit 345191
    *       A vector of length equal NUMA_NUM_NODES that gives bandwidth for   *
Packit 345191
    *       each numa node, zero if numa node has unknown bandwidth.           *
Packit 345191
    *   num_unique (OUT):                                                      *
Packit 345191
    *       number of unique non-zero bandwidth values in bandwidth            *
Packit 345191
    *       vector.                                                            *
Packit 345191
    *   bandwidth_nodes (OUT):                                                 *
Packit 345191
    *       A list of length num_unique sorted by bandwidth value where        *
Packit 345191
    *       each element gives a list of the numa nodes that have the          *
Packit 345191
    *       given bandwidth.                                                   *
Packit 345191
    *   RETURNS MEMKIND_SUCCESS on success, error code on failure              *
Packit 345191
    ***************************************************************************/
Packit 345191
    int err = MEMKIND_SUCCESS;
Packit 345191
    int i, last_bandwidth;
Packit 345191
    *bandwidth_nodes = NULL;
Packit 345191
    /* allocate space for sorting array */
Packit 345191
    int nodes_num = numa_num_configured_nodes();
Packit 345191
    struct numanode_bandwidth_t *numanode_bandwidth = malloc(sizeof(
Packit 345191
                                                                 struct numanode_bandwidth_t) * nodes_num);
Packit 345191
    if (!numanode_bandwidth) {
Packit 345191
        err = MEMKIND_ERROR_MALLOC;
Packit 345191
        log_err("malloc() failed.");
Packit 345191
    }
Packit 345191
    if (!err) {
Packit 345191
        /* set sorting array */
Packit 345191
        int j = 0;
Packit 345191
        for (i = 0; i < NUMA_NUM_NODES; ++i) {
Packit 345191
            if (bandwidth[i] != BANDWIDTH_NODE_NOT_PRESENT) {
Packit 345191
                numanode_bandwidth[j].numanode = i;
Packit 345191
                numanode_bandwidth[j].bandwidth = bandwidth[i];
Packit 345191
                ++j;
Packit 345191
            }
Packit 345191
        }
Packit 345191
Packit 345191
        if (j == 0) {
Packit 345191
            err = MEMKIND_ERROR_UNAVAILABLE;
Packit 345191
        }
Packit 345191
    }
Packit 345191
    if (!err) {
Packit 345191
        qsort(numanode_bandwidth, nodes_num, sizeof(struct numanode_bandwidth_t),
Packit 345191
              bandwidth_compare_numanode);
Packit 345191
        /* calculate the number of unique bandwidths */
Packit 345191
        *num_unique = 1;
Packit 345191
        last_bandwidth = numanode_bandwidth[0].bandwidth;
Packit 345191
        for (i = 1; i < nodes_num; ++i) {
Packit 345191
            if (numanode_bandwidth[i].bandwidth != last_bandwidth) {
Packit 345191
                last_bandwidth = numanode_bandwidth[i].bandwidth;
Packit 345191
                ++*num_unique;
Packit 345191
            }
Packit 345191
        }
Packit 345191
        /* allocate output array */
Packit 345191
        *bandwidth_nodes = (struct bandwidth_nodes_t *)malloc(sizeof(
Packit 345191
                                                                  struct bandwidth_nodes_t) * (*num_unique) + sizeof(int) * nodes_num);
Packit 345191
        if (!*bandwidth_nodes) {
Packit 345191
            err = MEMKIND_ERROR_MALLOC;
Packit 345191
            log_err("malloc() failed.");
Packit 345191
        }
Packit 345191
    }
Packit 345191
    if (!err) {
Packit 345191
        /* populate output */
Packit 345191
        (*bandwidth_nodes)[0].numanodes = (int *)(*bandwidth_nodes + *num_unique);
Packit 345191
        last_bandwidth = numanode_bandwidth[0].bandwidth;
Packit 345191
        int k = 0;
Packit 345191
        int l = 0;
Packit 345191
        for (i = 0; i < nodes_num; ++i, ++l) {
Packit 345191
            (*bandwidth_nodes)[0].numanodes[i] = numanode_bandwidth[i].numanode;
Packit 345191
            if (numanode_bandwidth[i].bandwidth != last_bandwidth) {
Packit 345191
                (*bandwidth_nodes)[k].num_numanodes = l;
Packit 345191
                (*bandwidth_nodes)[k].bandwidth = last_bandwidth;
Packit 345191
                l = 0;
Packit 345191
                ++k;
Packit 345191
                (*bandwidth_nodes)[k].numanodes = (*bandwidth_nodes)[0].numanodes + i;
Packit 345191
                last_bandwidth = numanode_bandwidth[i].bandwidth;
Packit 345191
            }
Packit 345191
        }
Packit 345191
        (*bandwidth_nodes)[k].num_numanodes = l;
Packit 345191
        (*bandwidth_nodes)[k].bandwidth = last_bandwidth;
Packit 345191
    }
Packit 345191
    if (numanode_bandwidth) {
Packit 345191
        free(numanode_bandwidth);
Packit 345191
    }
Packit 345191
    if (err) {
Packit 345191
        if (*bandwidth_nodes) {
Packit 345191
            free(*bandwidth_nodes);
Packit 345191
        }
Packit 345191
    }
Packit 345191
    return err;
Packit 345191
}
Packit 345191
Packit 345191
static int bandwidth_set_closest_numanode(int num_unique,
Packit 345191
                                          const struct bandwidth_nodes_t *bandwidth_nodes, bool is_single_node,
Packit 345191
                                          int num_cpunode, struct vec_cpu_node **closest_numanode)
Packit 345191
{
Packit 345191
    /***************************************************************************
Packit 345191
    *   num_unique (IN):                                                       *
Packit 345191
    *       Length of bandwidth_nodes vector.                                  *
Packit 345191
    *   bandwidth_nodes (IN):                                                  *
Packit 345191
    *       Output vector from bandwidth_create_nodes().                       *
Packit 345191
    *   is_single_node (IN):                                                   *
Packit 345191
    *       Flag used to mark is only single closest numanode                  *
Packit 345191
    *       is a valid configuration                                           *
Packit 345191
    *   num_cpunode (IN):                                                      *
Packit 345191
    *       Number of cpu's and length of closest_numanode.                    *
Packit 345191
    *   closest_numanode (OUT):                                                *
Packit 345191
    *       Vector that maps cpu index to closest numa node(s)                 *
Packit 345191
    *       of the specified bandwidth.                                        *
Packit 345191
    *   RETURNS zero on success, error code on failure                         *
Packit 345191
    ***************************************************************************/
Packit 345191
    int err = MEMKIND_SUCCESS;
Packit 345191
    int min_distance, distance, i, j, old_errno;
Packit 345191
    struct bandwidth_nodes_t match;
Packit 345191
    match.bandwidth = -1;
Packit 345191
    int target_bandwidth = bandwidth_nodes[num_unique-1].bandwidth;
Packit 345191
Packit 345191
    struct vec_cpu_node *node_arr = (struct vec_cpu_node *) calloc(num_cpunode,
Packit 345191
                                                                   sizeof(struct vec_cpu_node));
Packit 345191
Packit 345191
    if (!node_arr) {
Packit 345191
        log_err("calloc() failed.");
Packit 345191
        return MEMKIND_ERROR_MALLOC;
Packit 345191
    }
Packit 345191
Packit 345191
    for (i = 0; i < num_unique; ++i) {
Packit 345191
        if (bandwidth_nodes[i].bandwidth == target_bandwidth) {
Packit 345191
            match = bandwidth_nodes[i];
Packit 345191
            break;
Packit 345191
        }
Packit 345191
    }
Packit 345191
    if (match.bandwidth == -1) {
Packit 345191
        err = MEMKIND_ERROR_UNAVAILABLE;
Packit 345191
    } else {
Packit 345191
        for (i = 0; i < num_cpunode; ++i) {
Packit 345191
            min_distance = INT_MAX;
Packit 345191
            for (j = 0; j < match.num_numanodes; ++j) {
Packit 345191
                old_errno = errno;
Packit 345191
                distance = numa_distance(numa_node_of_cpu(i), match.numanodes[j]);
Packit 345191
                errno = old_errno;
Packit 345191
                if (distance < min_distance) {
Packit 345191
                    min_distance = distance;
Packit 345191
                    VEC_CLEAR(&node_arr[i]);
Packit 345191
                    VEC_PUSH_BACK(&node_arr[i], match.numanodes[j]);
Packit 345191
                } else if (distance == min_distance) {
Packit 345191
                    VEC_PUSH_BACK(&node_arr[i], match.numanodes[j]);
Packit 345191
                }
Packit 345191
            }
Packit 345191
            if (VEC_SIZE(&node_arr[i]) > 1 && is_single_node &&
Packit 345191
                numa_bitmask_isbitset(numa_all_cpus_ptr, i)) {
Packit 345191
                log_err("Invalid Numa Configuration for cpu %d", i);
Packit 345191
                int node = -1;
Packit 345191
                VEC_FOREACH(node, &node_arr[i]) {
Packit 345191
                    log_err("Node %d", node);
Packit 345191
                }
Packit 345191
                err = MEMKIND_ERROR_RUNTIME;
Packit 345191
            }
Packit 345191
        }
Packit 345191
    }
Packit 345191
Packit 345191
    if (err) {
Packit 345191
        for (i = 0; i < num_cpunode; ++i) {
Packit 345191
            VEC_DELETE(&node_arr[i]);
Packit 345191
        }
Packit 345191
        free(node_arr);
Packit 345191
        node_arr = NULL;
Packit 345191
    }
Packit 345191
Packit 345191
    *closest_numanode = node_arr;
Packit 345191
Packit 345191
    return err;
Packit 345191
}
Packit 345191
Packit 345191
int set_closest_numanode(fill_bandwidth_values fill_values, const char *env,
Packit 345191
                         struct vec_cpu_node **closest_numanode, int num_cpu, bool is_single_node)
Packit 345191
{
Packit 345191
    int status;
Packit 345191
    int num_unique = 0;
Packit 345191
    int i;
Packit 345191
    struct bandwidth_nodes_t *bandwidth_nodes = NULL;
Packit 345191
    int *bandwidth = (int *)calloc(NUMA_NUM_NODES, sizeof(int));
Packit 345191
Packit 345191
    if (!bandwidth) {
Packit 345191
        log_err("calloc() failed.");
Packit 345191
        return MEMKIND_ERROR_MALLOC;
Packit 345191
    }
Packit 345191
Packit 345191
    status = bandwidth_fill_nodes(bandwidth, fill_values, env);
Packit 345191
    if (status)
Packit 345191
        goto exit;
Packit 345191
Packit 345191
    status = bandwidth_create_nodes(bandwidth, &num_unique, &bandwidth_nodes);
Packit 345191
    if (status)
Packit 345191
        goto exit;
Packit 345191
Packit 345191
    status = bandwidth_set_closest_numanode(num_unique, bandwidth_nodes,
Packit 345191
                                            is_single_node, num_cpu, closest_numanode);
Packit 345191
Packit 345191
    for(i = 0; i < bandwidth_nodes[num_unique-1].num_numanodes; ++i) {
Packit 345191
        log_info("NUMA node %d is high-bandwidth/dax-kmem memory.",
Packit 345191
                 bandwidth_nodes[num_unique-1].numanodes[i]);
Packit 345191
    }
Packit 345191
Packit 345191
exit:
Packit 345191
Packit 345191
    free(bandwidth_nodes);
Packit 345191
    free(bandwidth);
Packit 345191
Packit 345191
    return status;
Packit 345191
}
Packit 345191
Packit 345191
void set_bitmask_for_all_closest_numanodes(unsigned long *nodemask,
Packit 345191
                                           unsigned long maxnode, const struct vec_cpu_node *closest_numanode, int num_cpu)
Packit 345191
{
Packit 345191
    if (MEMKIND_LIKELY(nodemask)) {
Packit 345191
        struct bitmask nodemask_bm = {maxnode, nodemask};
Packit 345191
        int cpu;
Packit 345191
        int node = -1;
Packit 345191
        numa_bitmask_clearall(&nodemask_bm);
Packit 345191
        for (cpu = 0; cpu < num_cpu; ++cpu) {
Packit 345191
            VEC_FOREACH(node, &closest_numanode[cpu]) {
Packit 345191
                numa_bitmask_setbit(&nodemask_bm, node);
Packit 345191
            }
Packit 345191
        }
Packit 345191
    }
Packit 345191
}
Packit 345191
Packit 345191
int set_bitmask_for_current_closest_numanode(unsigned long *nodemask,
Packit 345191
                                             unsigned long maxnode, const struct vec_cpu_node *closest_numanode, int num_cpu)
Packit 345191
{
Packit 345191
    if (MEMKIND_LIKELY(nodemask)) {
Packit 345191
        struct bitmask nodemask_bm = {maxnode, nodemask};
Packit 345191
        numa_bitmask_clearall(&nodemask_bm);
Packit 345191
        int cpu = sched_getcpu();
Packit 345191
        if (MEMKIND_LIKELY(cpu < num_cpu)) {
Packit 345191
            int node = -1;
Packit 345191
            VEC_FOREACH(node, &closest_numanode[cpu]) {
Packit 345191
                numa_bitmask_setbit(&nodemask_bm, node);
Packit 345191
            }
Packit 345191
        } else {
Packit 345191
            return MEMKIND_ERROR_RUNTIME;
Packit 345191
        }
Packit 345191
    }
Packit 345191
    return MEMKIND_SUCCESS;
Packit 345191
}