Blame src/memkind_bandwidth.c

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