Blame memkind-1.10.1/src/memkind_hugetlb.c

Packit Service 7f3b24
// SPDX-License-Identifier: BSD-2-Clause
Packit Service 7f3b24
/* Copyright (C) 2014 - 2020 Intel Corporation. */
Packit Service 7f3b24
Packit Service 7f3b24
#include <memkind/internal/memkind_hugetlb.h>
Packit Service 7f3b24
#include <memkind/internal/memkind_default.h>
Packit Service 7f3b24
#include <memkind/internal/memkind_arena.h>
Packit Service 7f3b24
#include <memkind/internal/memkind_private.h>
Packit Service 7f3b24
#include <memkind/internal/memkind_log.h>
Packit Service 7f3b24
Packit Service 7f3b24
#include <sys/mman.h>
Packit Service 7f3b24
#ifndef MAP_HUGETLB
Packit Service 7f3b24
#define MAP_HUGETLB 0x40000
Packit Service 7f3b24
#endif
Packit Service 7f3b24
#ifndef MAP_HUGE_2MB
Packit Service 7f3b24
#define MAP_HUGE_2MB (21 << 26)
Packit Service 7f3b24
#endif
Packit Service 7f3b24
Packit Service 7f3b24
#include <stdio.h>
Packit Service 7f3b24
#include <errno.h>
Packit Service 7f3b24
#include <numa.h>
Packit Service 7f3b24
#include <pthread.h>
Packit Service 7f3b24
#include <dirent.h>
Packit Service 7f3b24
Packit Service 7f3b24
MEMKIND_EXPORT struct memkind_ops MEMKIND_HUGETLB_OPS = {
Packit Service 7f3b24
    .create = memkind_arena_create,
Packit Service 7f3b24
    .destroy = memkind_default_destroy,
Packit Service 7f3b24
    .malloc = memkind_arena_malloc,
Packit Service 7f3b24
    .calloc = memkind_arena_calloc,
Packit Service 7f3b24
    .posix_memalign = memkind_arena_posix_memalign,
Packit Service 7f3b24
    .realloc = memkind_arena_realloc,
Packit Service 7f3b24
    .free = memkind_arena_free,
Packit Service 7f3b24
    .check_available = memkind_hugetlb_check_available_2mb,
Packit Service 7f3b24
    .get_mmap_flags = memkind_hugetlb_get_mmap_flags,
Packit Service 7f3b24
    .get_arena = memkind_thread_get_arena,
Packit Service 7f3b24
    .init_once = memkind_hugetlb_init_once,
Packit Service 7f3b24
    .malloc_usable_size = memkind_default_malloc_usable_size,
Packit Service 7f3b24
    .finalize = memkind_arena_finalize,
Packit Service 7f3b24
    .get_stat = memkind_arena_get_kind_stat,
Packit Service 7f3b24
    .defrag_reallocate = memkind_arena_defrag_reallocate
Packit Service 7f3b24
};
Packit Service 7f3b24
Packit Service 7f3b24
static int get_nr_overcommit_hugepages_cached(size_t pagesize, size_t *out);
Packit Service 7f3b24
static int get_nr_hugepages_cached(size_t pagesize, struct bitmask *nodemask,
Packit Service 7f3b24
                                   size_t *out);
Packit Service 7f3b24
Packit Service 7f3b24
static int memkind_hugetlb_check_available(struct memkind *kind,
Packit Service 7f3b24
                                           size_t huge_size);
Packit Service 7f3b24
Packit Service 7f3b24
MEMKIND_EXPORT int memkind_hugetlb_get_mmap_flags(struct memkind *kind,
Packit Service 7f3b24
                                                  int *flags)
Packit Service 7f3b24
{
Packit Service 7f3b24
    *flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_HUGE_2MB;
Packit Service 7f3b24
    return 0;
Packit Service 7f3b24
}
Packit Service 7f3b24
Packit Service 7f3b24
MEMKIND_EXPORT void memkind_hugetlb_init_once(void)
Packit Service 7f3b24
{
Packit Service 7f3b24
    memkind_init(MEMKIND_HUGETLB, true);
Packit Service 7f3b24
}
Packit Service 7f3b24
Packit Service 7f3b24
MEMKIND_EXPORT int memkind_hugetlb_check_available_2mb(struct memkind *kind)
Packit Service 7f3b24
{
Packit Service 7f3b24
    return memkind_hugetlb_check_available(kind, 2097152);
Packit Service 7f3b24
}
Packit Service 7f3b24
Packit Service 7f3b24
/* huge_size: the huge page size in bytes */
Packit Service 7f3b24
static int memkind_hugetlb_check_available(struct memkind *kind,
Packit Service 7f3b24
                                           size_t huge_size)
Packit Service 7f3b24
{
Packit Service 7f3b24
    int err = 0;
Packit Service 7f3b24
    nodemask_t nodemask;
Packit Service 7f3b24
    struct bitmask nodemask_bm = {NUMA_NUM_NODES, nodemask.n};
Packit Service 7f3b24
Packit Service 7f3b24
    /* on x86_64 default huge page size is 2MB */
Packit Service 7f3b24
    if (huge_size == 0) {
Packit Service 7f3b24
        huge_size = 2097152;
Packit Service 7f3b24
    }
Packit Service 7f3b24
Packit Service 7f3b24
    if (kind->ops->get_mbind_nodemask) {
Packit Service 7f3b24
        err = kind->ops->get_mbind_nodemask(kind, nodemask.n, NUMA_NUM_NODES);
Packit Service 7f3b24
    } else {
Packit Service 7f3b24
        numa_bitmask_setall(&nodemask_bm);
Packit Service 7f3b24
    }
Packit Service 7f3b24
Packit Service 7f3b24
    size_t nr_persistent_hugepages, nr_overcommit_hugepages;
Packit Service 7f3b24
Packit Service 7f3b24
    err = get_nr_hugepages_cached(huge_size, &nodemask_bm,
Packit Service 7f3b24
                                  &nr_persistent_hugepages);
Packit Service 7f3b24
    if(err) {
Packit Service 7f3b24
        return err;
Packit Service 7f3b24
    }
Packit Service 7f3b24
Packit Service 7f3b24
    err = get_nr_overcommit_hugepages_cached(huge_size, &nr_overcommit_hugepages);
Packit Service 7f3b24
    if(err) {
Packit Service 7f3b24
        return err;
Packit Service 7f3b24
    }
Packit Service 7f3b24
Packit Service 7f3b24
    if (!nr_overcommit_hugepages && !nr_persistent_hugepages) {
Packit Service 7f3b24
        log_err("Persistent hugepages and overcommit hugepages are not available.");
Packit Service 7f3b24
        return MEMKIND_ERROR_HUGETLB;
Packit Service 7f3b24
    }
Packit Service 7f3b24
Packit Service 7f3b24
    return err;
Packit Service 7f3b24
}
Packit Service 7f3b24
Packit Service 7f3b24
struct hugepage_size_info {
Packit Service 7f3b24
    size_t size;
Packit Service 7f3b24
    size_t *nr_hugepages_per_node_array;
Packit Service 7f3b24
    size_t  nr_overcommit;
Packit Service 7f3b24
};
Packit Service 7f3b24
Packit Service 7f3b24
struct memkind_hugepages_config_t {
Packit Service 7f3b24
    struct hugepage_size_info **hugepages_info_array;
Packit Service 7f3b24
    int hugepages_info_array_len;
Packit Service 7f3b24
    int err; // 0 if sysfs parsing successful, appropriate memkind_error otherwise
Packit Service 7f3b24
} memkind_hugepages_config;
Packit Service 7f3b24
Packit Service 7f3b24
static pthread_once_t memkind_hugepages_config_once_g = PTHREAD_ONCE_INIT;
Packit Service 7f3b24
Packit Service 7f3b24
static struct hugepage_size_info *allocate_hugepage_size_info()
Packit Service 7f3b24
{
Packit Service 7f3b24
    struct hugepage_size_info *newInfo = malloc(sizeof(struct hugepage_size_info));
Packit Service 7f3b24
    if(newInfo == NULL) {
Packit Service 7f3b24
        log_err("malloc() failed.");
Packit Service 7f3b24
        return NULL;
Packit Service 7f3b24
    }
Packit Service 7f3b24
Packit Service 7f3b24
    newInfo->nr_hugepages_per_node_array = calloc(NUMA_NUM_NODES, sizeof(size_t));
Packit Service 7f3b24
    if(newInfo->nr_hugepages_per_node_array == NULL) {
Packit Service 7f3b24
        free(newInfo);
Packit Service 7f3b24
        log_err("calloc() failed.");
Packit Service 7f3b24
        return NULL;
Packit Service 7f3b24
    }
Packit Service 7f3b24
Packit Service 7f3b24
    return newInfo;
Packit Service 7f3b24
}
Packit Service 7f3b24
Packit Service 7f3b24
static size_t get_sysfs_entry_value(const char *entry_path)
Packit Service 7f3b24
{
Packit Service 7f3b24
    int errno_before;
Packit Service 7f3b24
    FILE *fid;
Packit Service 7f3b24
    int num_read;
Packit Service 7f3b24
    size_t value_read, ret = 0;
Packit Service 7f3b24
Packit Service 7f3b24
    errno_before = errno;
Packit Service 7f3b24
    fid = fopen(entry_path, "r");
Packit Service 7f3b24
    if (fid) {
Packit Service 7f3b24
        num_read = fscanf(fid, "%zud", &value_read);
Packit Service 7f3b24
        if(num_read) {
Packit Service 7f3b24
            ret  = value_read;
Packit Service 7f3b24
        }
Packit Service 7f3b24
        fclose(fid);
Packit Service 7f3b24
    } else {
Packit Service 7f3b24
        errno = errno_before;
Packit Service 7f3b24
    }
Packit Service 7f3b24
    return ret;
Packit Service 7f3b24
}
Packit Service 7f3b24
Packit Service 7f3b24
// construct hugepage_size_info object and fill it with data for provided pagesize
Packit Service 7f3b24
static void init_hugepage_size_info(size_t pagesize,
Packit Service 7f3b24
                                    struct hugepage_size_info *newInfo)
Packit Service 7f3b24
{
Packit Service 7f3b24
    char formatted_path[128];
Packit Service 7f3b24
    const char *nr_path_fmt =
Packit Service 7f3b24
        "/sys/devices/system/node/node%u/hugepages/hugepages-%zukB/nr_hugepages";
Packit Service 7f3b24
    const char *nr_overcommit_path_fmt =
Packit Service 7f3b24
        "/sys/kernel/mm/hugepages/hugepages-%zukB/nr_overcommit_hugepages";
Packit Service 7f3b24
    int snprintf_ret = 0;
Packit Service 7f3b24
    size_t node;
Packit Service 7f3b24
Packit Service 7f3b24
    size_t pagesize_kb = pagesize >> 10;
Packit Service 7f3b24
Packit Service 7f3b24
    newInfo->size = pagesize;
Packit Service 7f3b24
Packit Service 7f3b24
    //read overcommit hugepages limit for this pagesize
Packit Service 7f3b24
    snprintf_ret = snprintf(formatted_path, sizeof(formatted_path),
Packit Service 7f3b24
                            nr_overcommit_path_fmt, pagesize_kb);
Packit Service 7f3b24
    if (snprintf_ret > 0 && snprintf_ret < sizeof(formatted_path)) {
Packit Service 7f3b24
        newInfo->nr_overcommit = get_sysfs_entry_value(formatted_path);
Packit Service 7f3b24
        log_info("Overcommit limit for %zu kB hugepages is %zu.", pagesize,
Packit Service 7f3b24
                 newInfo->nr_overcommit);
Packit Service 7f3b24
    }
Packit Service 7f3b24
Packit Service 7f3b24
    //read every node nr_hugepages for this pagesize
Packit Service 7f3b24
    for (node = 0; node < NUMA_NUM_NODES; ++node) {
Packit Service 7f3b24
        snprintf_ret = snprintf(formatted_path, sizeof(formatted_path), nr_path_fmt,
Packit Service 7f3b24
                                node, pagesize_kb);
Packit Service 7f3b24
        if(snprintf_ret > 0 && snprintf_ret < sizeof(formatted_path)) {
Packit Service 7f3b24
            newInfo->nr_hugepages_per_node_array[node] = get_sysfs_entry_value(
Packit Service 7f3b24
                                                             formatted_path);
Packit Service 7f3b24
            if(node < numa_num_configured_nodes()) {
Packit Service 7f3b24
                log_info("Number of %zu kB hugepages on node %zu equals %zu.", pagesize, node,
Packit Service 7f3b24
                         newInfo->nr_hugepages_per_node_array[node]);
Packit Service 7f3b24
            }
Packit Service 7f3b24
        }
Packit Service 7f3b24
    }
Packit Service 7f3b24
}
Packit Service 7f3b24
Packit Service 7f3b24
// get hugepage size in bytes out of sysfs dir name
Packit Service 7f3b24
static int parse_pagesize_from_sysfs_entry(const char *entry, size_t *out)
Packit Service 7f3b24
{
Packit Service 7f3b24
    size_t pagesize;
Packit Service 7f3b24
    int ret = sscanf(entry, "hugepages-%zukB", &pagesize);
Packit Service 7f3b24
Packit Service 7f3b24
    if(ret == 1) {
Packit Service 7f3b24
        *out = pagesize << 10; //we are using bytes but kernel is using kB
Packit Service 7f3b24
        return 0;
Packit Service 7f3b24
    }
Packit Service 7f3b24
Packit Service 7f3b24
    return -1;
Packit Service 7f3b24
}
Packit Service 7f3b24
Packit Service 7f3b24
Packit Service 7f3b24
static void hugepages_config_init_once()
Packit Service 7f3b24
{
Packit Service 7f3b24
    unsigned j, i = 0;
Packit Service 7f3b24
    size_t pagesize;
Packit Service 7f3b24
    struct hugepage_size_info **hugepages_info_array = NULL;
Packit Service 7f3b24
    struct dirent *dir;
Packit Service 7f3b24
    DIR *hugepages_sysfs = opendir("/sys/kernel/mm/hugepages");
Packit Service 7f3b24
    if(hugepages_sysfs == NULL) {
Packit Service 7f3b24
        memkind_hugepages_config.err = MEMKIND_ERROR_HUGETLB;
Packit Service 7f3b24
        log_err("/sys/kernel/mm/hugepages directory is not available.");
Packit Service 7f3b24
        return;
Packit Service 7f3b24
    }
Packit Service 7f3b24
Packit Service 7f3b24
    unsigned hugepages_info_array_len = 2; //initial size of array
Packit Service 7f3b24
    hugepages_info_array = malloc(hugepages_info_array_len * sizeof(
Packit Service 7f3b24
                                      struct hugepage_size_info *));
Packit Service 7f3b24
    if (hugepages_info_array == NULL) {
Packit Service 7f3b24
        memkind_hugepages_config.err = MEMKIND_ERROR_MALLOC;
Packit Service 7f3b24
        closedir(hugepages_sysfs);
Packit Service 7f3b24
        log_err("malloc() failed.");
Packit Service 7f3b24
        return;
Packit Service 7f3b24
    }
Packit Service 7f3b24
Packit Service 7f3b24
    while ((dir = readdir(hugepages_sysfs)) != NULL) {
Packit Service 7f3b24
        if(dir->d_type == DT_DIR &&
Packit Service 7f3b24
           parse_pagesize_from_sysfs_entry(dir->d_name, &pagesize) == 0) {
Packit Service 7f3b24
            struct hugepage_size_info *new_hugepage_info = allocate_hugepage_size_info();
Packit Service 7f3b24
            if(new_hugepage_info == NULL) {
Packit Service 7f3b24
                memkind_hugepages_config.err = MEMKIND_ERROR_MALLOC;
Packit Service 7f3b24
                break;
Packit Service 7f3b24
            }
Packit Service 7f3b24
Packit Service 7f3b24
            init_hugepage_size_info(pagesize, new_hugepage_info);
Packit Service 7f3b24
Packit Service 7f3b24
            //there is more hugepage sizes than expected, reallocation of array needed
Packit Service 7f3b24
            if(i == hugepages_info_array_len) {
Packit Service 7f3b24
                hugepages_info_array_len *= 2;
Packit Service 7f3b24
                struct hugepage_size_info **swap_tmp = realloc(hugepages_info_array,
Packit Service 7f3b24
                                                               hugepages_info_array_len * sizeof(struct hugepage_size_info *));
Packit Service 7f3b24
                if(swap_tmp == NULL) {
Packit Service 7f3b24
                    free(new_hugepage_info);
Packit Service 7f3b24
                    memkind_hugepages_config.err = MEMKIND_ERROR_MALLOC;
Packit Service 7f3b24
                    log_err("realloc() failed.");
Packit Service 7f3b24
                    break;
Packit Service 7f3b24
                }
Packit Service 7f3b24
                hugepages_info_array = swap_tmp;
Packit Service 7f3b24
Packit Service 7f3b24
            }
Packit Service 7f3b24
            hugepages_info_array[i] = new_hugepage_info;
Packit Service 7f3b24
            i++;
Packit Service 7f3b24
        }
Packit Service 7f3b24
    }
Packit Service 7f3b24
Packit Service 7f3b24
    closedir(hugepages_sysfs);
Packit Service 7f3b24
Packit Service 7f3b24
    if(memkind_hugepages_config.err == 0) {
Packit Service 7f3b24
        memkind_hugepages_config.hugepages_info_array = hugepages_info_array;
Packit Service 7f3b24
        memkind_hugepages_config.hugepages_info_array_len = i;
Packit Service 7f3b24
    } else {
Packit Service 7f3b24
        for(j=0; j
Packit Service 7f3b24
            free(hugepages_info_array[i]);
Packit Service 7f3b24
        }
Packit Service 7f3b24
        free(hugepages_info_array);
Packit Service 7f3b24
    }
Packit Service 7f3b24
Packit Service 7f3b24
    return;
Packit Service 7f3b24
}
Packit Service 7f3b24
Packit Service 7f3b24
#ifdef __GNUC__
Packit Service 7f3b24
__attribute__((destructor))
Packit Service 7f3b24
#endif
Packit Service 7f3b24
static void destroy_hugepages_per_node()
Packit Service 7f3b24
{
Packit Service 7f3b24
    int i;
Packit Service 7f3b24
    for(i=0; i
Packit Service 7f3b24
        free(memkind_hugepages_config.hugepages_info_array[i]);
Packit Service 7f3b24
    }
Packit Service 7f3b24
    free(memkind_hugepages_config.hugepages_info_array);
Packit Service 7f3b24
}
Packit Service 7f3b24
Packit Service 7f3b24
// helper function that find and return hugepage_size_info object for specified pagesize
Packit Service 7f3b24
static struct hugepage_size_info *get_hugepage_info_for_pagesize(
Packit Service 7f3b24
    size_t pagesize)
Packit Service 7f3b24
{
Packit Service 7f3b24
    int i;
Packit Service 7f3b24
Packit Service 7f3b24
    for(i=0; i
Packit Service 7f3b24
        if(memkind_hugepages_config.hugepages_info_array[i]->size == pagesize) {
Packit Service 7f3b24
            return memkind_hugepages_config.hugepages_info_array[i];
Packit Service 7f3b24
        }
Packit Service 7f3b24
    }
Packit Service 7f3b24
    return NULL;
Packit Service 7f3b24
}
Packit Service 7f3b24
Packit Service 7f3b24
// returns sum of pre-allocated hugepage for specified pagesize and set of nodes
Packit Service 7f3b24
static int get_nr_hugepages_cached(size_t pagesize, struct bitmask *nodemask,
Packit Service 7f3b24
                                   size_t *out)
Packit Service 7f3b24
{
Packit Service 7f3b24
    int i;
Packit Service 7f3b24
    size_t nr_hugepages = 0;
Packit Service 7f3b24
    int num_node = numa_num_configured_nodes();
Packit Service 7f3b24
    pthread_once(&memkind_hugepages_config_once_g,
Packit Service 7f3b24
                 hugepages_config_init_once);
Packit Service 7f3b24
Packit Service 7f3b24
Packit Service 7f3b24
    if(memkind_hugepages_config.err != 0) {
Packit Service 7f3b24
        return memkind_hugepages_config.err;
Packit Service 7f3b24
    }
Packit Service 7f3b24
Packit Service 7f3b24
    struct hugepage_size_info *info = get_hugepage_info_for_pagesize(pagesize);
Packit Service 7f3b24
    if(info == NULL) {
Packit Service 7f3b24
        log_err("Unable to allocate hugepages, because info about pre-allocated hugepages is not available.");
Packit Service 7f3b24
        return MEMKIND_ERROR_HUGETLB;
Packit Service 7f3b24
    }
Packit Service 7f3b24
Packit Service 7f3b24
    for(i=0; i
Packit Service 7f3b24
        if(numa_bitmask_isbitset(nodemask, i)) {
Packit Service 7f3b24
            nr_hugepages += info->nr_hugepages_per_node_array[i];
Packit Service 7f3b24
        }
Packit Service 7f3b24
    }
Packit Service 7f3b24
Packit Service 7f3b24
    *out = nr_hugepages;
Packit Service 7f3b24
    return 0;
Packit Service 7f3b24
}
Packit Service 7f3b24
Packit Service 7f3b24
// returns hugepages overcommit limit for specified pagesize
Packit Service 7f3b24
static int get_nr_overcommit_hugepages_cached(size_t pagesize, size_t *out)
Packit Service 7f3b24
{
Packit Service 7f3b24
    pthread_once(&memkind_hugepages_config_once_g,
Packit Service 7f3b24
                 hugepages_config_init_once);
Packit Service 7f3b24
Packit Service 7f3b24
    if(memkind_hugepages_config.err != 0) {
Packit Service 7f3b24
        return memkind_hugepages_config.err;
Packit Service 7f3b24
    }
Packit Service 7f3b24
Packit Service 7f3b24
    struct hugepage_size_info *info = get_hugepage_info_for_pagesize(pagesize);
Packit Service 7f3b24
    if(info == NULL) {
Packit Service 7f3b24
        log_err("Unable to allocate hugepages, because info about overcommit hugepages is not available.");
Packit Service 7f3b24
        return MEMKIND_ERROR_HUGETLB;
Packit Service 7f3b24
    }
Packit Service 7f3b24
Packit Service 7f3b24
    *out = info->nr_overcommit;
Packit Service 7f3b24
    return 0;
Packit Service 7f3b24
}
Packit Service 7f3b24