Blame src/hbwmalloc.c

Packit Service 724aca
/*
Packit Service 724aca
 * Copyright (C) 2014 - 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 <hbwmalloc.h>
Packit Service 724aca
#include <memkind.h>
Packit Service 724aca
#include <memkind/internal/memkind_private.h>
Packit Service 724aca
#include <memkind/internal/memkind_hbw.h>
Packit Service 724aca
#include <memkind/internal/memkind_log.h>
Packit Service 724aca
Packit Service 724aca
#include <stdlib.h>
Packit Service 724aca
#include <stdio.h>
Packit Service 724aca
#include <pthread.h>
Packit Service 724aca
#include <errno.h>
Packit Service 724aca
#include <numa.h>
Packit Service 724aca
#include <numaif.h>
Packit Service 724aca
#include <unistd.h>
Packit Service 724aca
#include <stdint.h>
Packit Service 724aca
Packit Service 724aca
static hbw_policy_t hbw_policy_g = HBW_POLICY_PREFERRED;
Packit Service 724aca
static pthread_once_t hbw_policy_once_g = PTHREAD_ONCE_INIT;
Packit Service 724aca
Packit Service 724aca
static void hbw_policy_bind_init(void)
Packit Service 724aca
{
Packit Service 724aca
    hbw_policy_g = HBW_POLICY_BIND;
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
static void hbw_policy_bind_all_init(void)
Packit Service 724aca
{
Packit Service 724aca
    hbw_policy_g = HBW_POLICY_BIND_ALL;
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
static void hbw_policy_preferred_init(void)
Packit Service 724aca
{
Packit Service 724aca
    hbw_policy_g = HBW_POLICY_PREFERRED;
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
static void hbw_policy_interleave_init(void)
Packit Service 724aca
{
Packit Service 724aca
    hbw_policy_g = HBW_POLICY_INTERLEAVE;
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
// This function is intended to be called once per pagesize
Packit Service 724aca
// Getting kind should be done using hbw_get_kind() defined below
Packit Service 724aca
static memkind_t hbw_choose_kind(hbw_pagesize_t pagesize)
Packit Service 724aca
{
Packit Service 724aca
    memkind_t result = NULL;
Packit Service 724aca
Packit Service 724aca
    hbw_set_policy(hbw_policy_g);
Packit Service 724aca
Packit Service 724aca
    int policy = hbw_get_policy();
Packit Service 724aca
Packit Service 724aca
    // PREFERRED policy have separate handling cause it can fallback
Packit Service 724aca
    // to non-HBW kinds in case of HBW absence
Packit Service 724aca
    if (policy != HBW_POLICY_PREFERRED ) {
Packit Service 724aca
        switch (pagesize) {
Packit Service 724aca
            case HBW_PAGESIZE_2MB:
Packit Service 724aca
                if(policy == HBW_POLICY_BIND_ALL) {
Packit Service 724aca
                    result = MEMKIND_HBW_ALL_HUGETLB;
Packit Service 724aca
                } else {
Packit Service 724aca
                    result = MEMKIND_HBW_HUGETLB;
Packit Service 724aca
                }
Packit Service 724aca
                break;
Packit Service 724aca
            case HBW_PAGESIZE_1GB:
Packit Service 724aca
            case HBW_PAGESIZE_1GB_STRICT:
Packit Service 724aca
                result = MEMKIND_HBW_GBTLB;
Packit Service 724aca
                break;
Packit Service 724aca
            default:
Packit Service 724aca
                if (policy == HBW_POLICY_BIND) {
Packit Service 724aca
                    result = MEMKIND_HBW;
Packit Service 724aca
                } else if (policy == HBW_POLICY_BIND_ALL) {
Packit Service 724aca
                    result = MEMKIND_HBW_ALL;
Packit Service 724aca
                } else {
Packit Service 724aca
                    result = MEMKIND_HBW_INTERLEAVE;
Packit Service 724aca
                }
Packit Service 724aca
                break;
Packit Service 724aca
        }
Packit Service 724aca
    } else if (memkind_check_available(MEMKIND_HBW) == 0) {
Packit Service 724aca
        switch (pagesize) {
Packit Service 724aca
            case HBW_PAGESIZE_2MB:
Packit Service 724aca
                result = MEMKIND_HBW_PREFERRED_HUGETLB;
Packit Service 724aca
                break;
Packit Service 724aca
            case HBW_PAGESIZE_1GB:
Packit Service 724aca
            case HBW_PAGESIZE_1GB_STRICT:
Packit Service 724aca
                result = MEMKIND_HBW_PREFERRED_GBTLB;
Packit Service 724aca
                break;
Packit Service 724aca
            default:
Packit Service 724aca
                result = MEMKIND_HBW_PREFERRED;
Packit Service 724aca
                break;
Packit Service 724aca
        }
Packit Service 724aca
    } else {
Packit Service 724aca
        switch (pagesize) {
Packit Service 724aca
            case HBW_PAGESIZE_2MB:
Packit Service 724aca
                result = MEMKIND_HUGETLB;
Packit Service 724aca
                break;
Packit Service 724aca
            case HBW_PAGESIZE_1GB:
Packit Service 724aca
            case HBW_PAGESIZE_1GB_STRICT:
Packit Service 724aca
                result = MEMKIND_GBTLB;
Packit Service 724aca
                break;
Packit Service 724aca
            default:
Packit Service 724aca
                result = MEMKIND_DEFAULT;
Packit Service 724aca
                break;
Packit Service 724aca
        }
Packit Service 724aca
    }
Packit Service 724aca
    return result;
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
static memkind_t pagesize_kind[HBW_PAGESIZE_MAX_VALUE];
Packit Service 724aca
static inline memkind_t hbw_get_kind(hbw_pagesize_t pagesize)
Packit Service 724aca
{
Packit Service 724aca
    if(pagesize_kind[pagesize] == NULL) {
Packit Service 724aca
        pagesize_kind[pagesize] = hbw_choose_kind(pagesize);
Packit Service 724aca
    }
Packit Service 724aca
    return pagesize_kind[pagesize];
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
Packit Service 724aca
MEMKIND_EXPORT hbw_policy_t hbw_get_policy(void)
Packit Service 724aca
{
Packit Service 724aca
    return hbw_policy_g;
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
MEMKIND_EXPORT int hbw_set_policy(hbw_policy_t mode)
Packit Service 724aca
{
Packit Service 724aca
    switch(mode) {
Packit Service 724aca
        case HBW_POLICY_PREFERRED:
Packit Service 724aca
            pthread_once(&hbw_policy_once_g, hbw_policy_preferred_init);
Packit Service 724aca
            break;
Packit Service 724aca
        case HBW_POLICY_BIND:
Packit Service 724aca
            pthread_once(&hbw_policy_once_g, hbw_policy_bind_init);
Packit Service 724aca
            break;
Packit Service 724aca
        case HBW_POLICY_BIND_ALL:
Packit Service 724aca
            pthread_once(&hbw_policy_once_g, hbw_policy_bind_all_init);
Packit Service 724aca
            break;
Packit Service 724aca
        case HBW_POLICY_INTERLEAVE:
Packit Service 724aca
            pthread_once(&hbw_policy_once_g, hbw_policy_interleave_init);
Packit Service 724aca
            break;
Packit Service 724aca
        default:
Packit Service 724aca
            return EINVAL;
Packit Service 724aca
    }
Packit Service 724aca
Packit Service 724aca
    if (mode != hbw_policy_g) {
Packit Service 724aca
        return EPERM;
Packit Service 724aca
    }
Packit Service 724aca
Packit Service 724aca
    return 0;
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
MEMKIND_EXPORT int hbw_check_available(void)
Packit Service 724aca
{
Packit Service 724aca
    return  (memkind_check_available(MEMKIND_HBW) == 0) ? 0 : ENODEV;
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
static inline void hbw_touch_page(void *addr)
Packit Service 724aca
{
Packit Service 724aca
    volatile char *temp_ptr = (volatile char *) addr;
Packit Service 724aca
    char value = temp_ptr[0];
Packit Service 724aca
    temp_ptr[0] = value;
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
MEMKIND_EXPORT int hbw_verify_memory_region(void *addr, size_t size, int flags)
Packit Service 724aca
{
Packit Service 724aca
    /*
Packit Service 724aca
     * if size is invalid, flags have unsupported bit set or if addr is NULL.
Packit Service 724aca
     */
Packit Service 724aca
    if (addr == NULL || size == 0 || flags & ~HBW_TOUCH_PAGES) {
Packit Service 724aca
        return EINVAL;
Packit Service 724aca
    }
Packit Service 724aca
Packit Service 724aca
    /*
Packit Service 724aca
     * 4KB is the smallest pagesize. When pagesize is bigger, pages are verified more than once
Packit Service 724aca
     */
Packit Service 724aca
    const size_t page_size = sysconf(_SC_PAGESIZE);
Packit Service 724aca
    const size_t page_mask = ~(page_size-1);
Packit Service 724aca
Packit Service 724aca
    /*
Packit Service 724aca
     * block size should be power of two to enable compiler optimizations
Packit Service 724aca
     */
Packit Service 724aca
    const unsigned block_size = 64;
Packit Service 724aca
Packit Service 724aca
    char *end = addr + size;
Packit Service 724aca
    char *aligned_beg = (char *)((uintptr_t)addr & page_mask);
Packit Service 724aca
    nodemask_t nodemask;
Packit Service 724aca
    struct bitmask expected_nodemask = {NUMA_NUM_NODES, nodemask.n};
Packit Service 724aca
Packit Service 724aca
    memkind_hbw_all_get_mbind_nodemask(NULL, expected_nodemask.maskp,
Packit Service 724aca
                                       expected_nodemask.size);
Packit Service 724aca
Packit Service 724aca
    while(aligned_beg < end) {
Packit Service 724aca
        int nodes[block_size];
Packit Service 724aca
        void *pages[block_size];
Packit Service 724aca
        int i = 0, page_count = 0;
Packit Service 724aca
        char *iter_end = aligned_beg + block_size*page_size;
Packit Service 724aca
Packit Service 724aca
        if (iter_end > end) {
Packit Service 724aca
            iter_end = end;
Packit Service 724aca
        }
Packit Service 724aca
Packit Service 724aca
        while (aligned_beg < iter_end) {
Packit Service 724aca
            if (flags & HBW_TOUCH_PAGES) {
Packit Service 724aca
                hbw_touch_page(aligned_beg);
Packit Service 724aca
            }
Packit Service 724aca
            pages[page_count++] = aligned_beg;
Packit Service 724aca
            aligned_beg += page_size;
Packit Service 724aca
        }
Packit Service 724aca
Packit Service 724aca
        if (move_pages(0, page_count, pages, NULL, nodes, MPOL_MF_MOVE)) {
Packit Service 724aca
            return EFAULT;
Packit Service 724aca
        }
Packit Service 724aca
Packit Service 724aca
        for (i = 0; i < page_count; i++) {
Packit Service 724aca
            /*
Packit Service 724aca
             * negative value of nodes[i] indicates that move_pages could not establish
Packit Service 724aca
             * page location, e.g. addr is not pointing to valid virtual mapping
Packit Service 724aca
             */
Packit Service 724aca
            if(nodes[i] < 0) {
Packit Service 724aca
                return -1;
Packit Service 724aca
            }
Packit Service 724aca
            /*
Packit Service 724aca
             * if nodes[i] is not present in expected_nodemask then
Packit Service 724aca
             * physical memory backing page is not hbw
Packit Service 724aca
             */
Packit Service 724aca
            if (!numa_bitmask_isbitset(&expected_nodemask, nodes[i])) {
Packit Service 724aca
                return -1;
Packit Service 724aca
            }
Packit Service 724aca
        }
Packit Service 724aca
    }
Packit Service 724aca
Packit Service 724aca
    return 0;
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
MEMKIND_EXPORT void *hbw_malloc(size_t size)
Packit Service 724aca
{
Packit Service 724aca
    return memkind_malloc(hbw_get_kind(HBW_PAGESIZE_4KB), size);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
MEMKIND_EXPORT void *hbw_calloc(size_t num, size_t size)
Packit Service 724aca
{
Packit Service 724aca
    return memkind_calloc(hbw_get_kind(HBW_PAGESIZE_4KB), num, size);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
MEMKIND_EXPORT int hbw_posix_memalign(void **memptr, size_t alignment,
Packit Service 724aca
                                      size_t size)
Packit Service 724aca
{
Packit Service 724aca
    return memkind_posix_memalign(hbw_get_kind(HBW_PAGESIZE_4KB), memptr, alignment,
Packit Service 724aca
                                  size);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
MEMKIND_EXPORT int hbw_posix_memalign_psize(void **memptr, size_t alignment,
Packit Service 724aca
                                            size_t size,
Packit Service 724aca
                                            hbw_pagesize_t pagesize)
Packit Service 724aca
{
Packit Service 724aca
    if (pagesize == HBW_PAGESIZE_1GB_STRICT && size % (1 << 30)) {
Packit Service 724aca
        return EINVAL;
Packit Service 724aca
    }
Packit Service 724aca
Packit Service 724aca
    if((pagesize == HBW_PAGESIZE_2MB ||
Packit Service 724aca
        pagesize == HBW_PAGESIZE_1GB_STRICT ||
Packit Service 724aca
        pagesize == HBW_PAGESIZE_1GB) &&
Packit Service 724aca
       hbw_get_policy() == HBW_POLICY_INTERLEAVE) {
Packit Service 724aca
Packit Service 724aca
        log_err("HBW_POLICY_INTERLEAVE is unsupported with used page size!");
Packit Service 724aca
        return EINVAL;
Packit Service 724aca
    }
Packit Service 724aca
Packit Service 724aca
    return memkind_posix_memalign(hbw_get_kind(pagesize), memptr, alignment, size);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
MEMKIND_EXPORT void *hbw_realloc(void *ptr, size_t size)
Packit Service 724aca
{
Packit Service 724aca
    return memkind_realloc(hbw_get_kind(HBW_PAGESIZE_4KB), ptr, size);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
MEMKIND_EXPORT void hbw_free(void *ptr)
Packit Service 724aca
{
Packit Service 724aca
    memkind_free(0, ptr);
Packit Service 724aca
}
Packit Service 724aca
Packit Service 724aca
MEMKIND_EXPORT size_t hbw_malloc_usable_size(void *ptr)
Packit Service 724aca
{
Packit Service 724aca
    return memkind_malloc_usable_size(0, ptr);
Packit Service 724aca
}