|
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 <memkind.h>
|
|
Packit Service |
724aca |
#include <memkind/internal/memkind_default.h>
|
|
Packit Service |
724aca |
#include <memkind/internal/memkind_arena.h>
|
|
Packit Service |
724aca |
#include <memkind/internal/memkind_private.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 <limits.h>
|
|
Packit Service |
724aca |
#include <stdint.h>
|
|
Packit Service |
724aca |
#include <unistd.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 <jemalloc/jemalloc.h>
|
|
Packit Service |
724aca |
#include <utmpx.h>
|
|
Packit Service |
724aca |
#include <sched.h>
|
|
Packit Service |
724aca |
#include <limits.h>
|
|
Packit Service |
724aca |
#include <sys/mman.h>
|
|
Packit Service |
724aca |
#include <sys/param.h>
|
|
Packit Service |
724aca |
#include <assert.h>
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
#include "config.h"
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
#define HUGE_PAGE_SIZE (1ull << MEMKIND_MASK_PAGE_SIZE_2MB)
|
|
Packit Service |
724aca |
#define PAGE_2_BYTES(x) ((x) << 12)
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
static const char *const global_stats[MEMKIND_STAT_TYPE_MAX_VALUE] = {
|
|
Packit Service |
724aca |
"stats.resident",
|
|
Packit Service |
724aca |
"stats.active",
|
|
Packit Service |
724aca |
"stats.allocated"
|
|
Packit Service |
724aca |
};
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
#define ARENA_STAT_MAX 2
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
struct stats_arena {
|
|
Packit Service |
724aca |
const char *stats[ARENA_STAT_MAX];
|
|
Packit Service |
724aca |
unsigned stats_no;
|
|
Packit Service |
724aca |
};
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
static const struct stats_arena arena_stats [MEMKIND_STAT_TYPE_MAX_VALUE] = {
|
|
Packit Service |
724aca |
{ .stats = {"stats.arenas.%u.resident", NULL}, .stats_no = 1},
|
|
Packit Service |
724aca |
{ .stats = {"stats.arenas.%u.pactive", NULL}, .stats_no = 1},
|
|
Packit Service |
724aca |
{ .stats = {"stats.arenas.%u.small.allocated", "stats.arenas.%u.large.allocated"}, .stats_no = 2},
|
|
Packit Service |
724aca |
};
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
static void *jemk_mallocx_check(size_t size, int flags);
|
|
Packit Service |
724aca |
static void *jemk_rallocx_check(void *ptr, size_t size, int flags);
|
|
Packit Service |
724aca |
static void tcache_finalize(void *args);
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
static unsigned integer_log2(unsigned v)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
return (sizeof(unsigned) * 8) - (__builtin_clz(v) + 1);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
static unsigned round_pow2_up(unsigned v)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
unsigned v_log2 = integer_log2(v);
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
if (v != 1 << v_log2) {
|
|
Packit Service |
724aca |
v = 1 << (v_log2 + 1);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
return v;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
MEMKIND_EXPORT int memkind_set_arena_map_len(struct memkind *kind)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
if (kind->ops->get_arena == memkind_bijective_get_arena) {
|
|
Packit Service |
724aca |
kind->arena_map_len = 1;
|
|
Packit Service |
724aca |
} else if (kind->ops->get_arena == memkind_thread_get_arena) {
|
|
Packit Service |
724aca |
char *arena_num_env = secure_getenv("MEMKIND_ARENA_NUM_PER_KIND");
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
if (arena_num_env) {
|
|
Packit Service |
724aca |
unsigned long int arena_num_value = strtoul(arena_num_env, NULL, 10);
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
if ((arena_num_value == 0) || (arena_num_value > INT_MAX)) {
|
|
Packit Service |
724aca |
log_err("Wrong MEMKIND_ARENA_NUM_PER_KIND environment value: %lu.",
|
|
Packit Service |
724aca |
arena_num_value);
|
|
Packit Service |
724aca |
return MEMKIND_ERROR_ENVIRON;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
kind->arena_map_len = arena_num_value;
|
|
Packit Service |
724aca |
} else {
|
|
Packit Service |
724aca |
int calculated_arena_num = numa_num_configured_cpus() * 4;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
#if ARENA_LIMIT_PER_KIND != 0
|
|
Packit Service |
724aca |
calculated_arena_num = MIN((ARENA_LIMIT_PER_KIND), calculated_arena_num);
|
|
Packit Service |
724aca |
#endif
|
|
Packit Service |
724aca |
kind->arena_map_len = calculated_arena_num;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
kind->arena_map_len = round_pow2_up(kind->arena_map_len);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
kind->arena_map_mask = kind->arena_map_len - 1;
|
|
Packit Service |
724aca |
return 0;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
static pthread_once_t arena_config_once = PTHREAD_ONCE_INIT;
|
|
Packit Service |
724aca |
static int arena_init_status;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
static pthread_key_t tcache_key;
|
|
Packit Service |
724aca |
static bool memkind_hog_memory;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
static void arena_config_init()
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
const char *str = secure_getenv("MEMKIND_HOG_MEMORY");
|
|
Packit Service |
724aca |
memkind_hog_memory = str && str[0] == '1';
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
arena_init_status = pthread_key_create(&tcache_key, tcache_finalize);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
#define MALLOCX_ARENA_MAX 0xffe // copy-pasted from jemalloc/internal/jemalloc_internal.h
|
|
Packit Service |
724aca |
#define DIRTY_DECAY_MS_DEFAULT 10000 // copy-pasted from jemalloc/internal/arena_types.h DIRTY_DECAY_MS_DEFAULT
|
|
Packit Service |
724aca |
#define DIRTY_DECAY_MS_CONSERVATIVE 0
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
static struct memkind *arena_registry_g[MALLOCX_ARENA_MAX];
|
|
Packit Service |
724aca |
static pthread_mutex_t arena_registry_write_lock;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
struct memkind *get_kind_by_arena(unsigned arena_ind)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
// there is no way to obtain MALLOCX_ARENA_MAX from jemalloc
|
|
Packit Service |
724aca |
// so this checks if arena_ind does not exceed assumed range
|
|
Packit Service |
724aca |
assert(arena_ind < MALLOCX_ARENA_MAX);
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
return arena_registry_g[arena_ind];
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
// Allocates size bytes aligned to alignment. Returns NULL if allocation fails.
|
|
Packit Service |
724aca |
static void *alloc_aligned_slow(size_t size, size_t alignment,
|
|
Packit Service |
724aca |
struct memkind *kind)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
size_t extended_size = size + alignment;
|
|
Packit Service |
724aca |
void *ptr;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
ptr = kind_mmap(kind, NULL, extended_size);
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
if(ptr == MAP_FAILED) {
|
|
Packit Service |
724aca |
return NULL;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
uintptr_t addr = (uintptr_t)ptr;
|
|
Packit Service |
724aca |
uintptr_t aligned_addr = (addr + alignment) & ~(alignment - 1);
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
size_t head_len = aligned_addr - addr;
|
|
Packit Service |
724aca |
if (head_len > 0) {
|
|
Packit Service |
724aca |
munmap(ptr, head_len);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
uintptr_t tail = aligned_addr + size;
|
|
Packit Service |
724aca |
size_t tail_len = (addr + extended_size) - (aligned_addr + size);
|
|
Packit Service |
724aca |
if (tail_len > 0) {
|
|
Packit Service |
724aca |
munmap((void *)tail, tail_len);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
return (void *)aligned_addr;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void *arena_extent_alloc(extent_hooks_t *extent_hooks,
|
|
Packit Service |
724aca |
void *new_addr,
|
|
Packit Service |
724aca |
size_t size,
|
|
Packit Service |
724aca |
size_t alignment,
|
|
Packit Service |
724aca |
bool *zero,
|
|
Packit Service |
724aca |
bool *commit,
|
|
Packit Service |
724aca |
unsigned arena_ind)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
struct memkind *kind = get_kind_by_arena(arena_ind);
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
int err = memkind_check_available(kind);
|
|
Packit Service |
724aca |
if (err) {
|
|
Packit Service |
724aca |
return NULL;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void *addr = kind_mmap(kind, new_addr, size);
|
|
Packit Service |
724aca |
if (addr == MAP_FAILED) {
|
|
Packit Service |
724aca |
return NULL;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
if (new_addr != NULL && addr != new_addr) {
|
|
Packit Service |
724aca |
/* wrong place */
|
|
Packit Service |
724aca |
munmap(addr, size);
|
|
Packit Service |
724aca |
return NULL;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
if ((uintptr_t)addr & (alignment-1)) {
|
|
Packit Service |
724aca |
munmap(addr, size);
|
|
Packit Service |
724aca |
addr = alloc_aligned_slow(size, alignment, kind);
|
|
Packit Service |
724aca |
if(addr == NULL) {
|
|
Packit Service |
724aca |
return NULL;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
*zero = true;
|
|
Packit Service |
724aca |
*commit = true;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
return addr;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void *arena_extent_alloc_hugetlb(extent_hooks_t *extent_hooks,
|
|
Packit Service |
724aca |
void *new_addr,
|
|
Packit Service |
724aca |
size_t size,
|
|
Packit Service |
724aca |
size_t alignment,
|
|
Packit Service |
724aca |
bool *zero,
|
|
Packit Service |
724aca |
bool *commit,
|
|
Packit Service |
724aca |
unsigned arena_ind)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
//round up to huge page size
|
|
Packit Service |
724aca |
size = (size + (HUGE_PAGE_SIZE - 1)) & ~(HUGE_PAGE_SIZE - 1);
|
|
Packit Service |
724aca |
return arena_extent_alloc(extent_hooks, new_addr, size, alignment, zero, commit,
|
|
Packit Service |
724aca |
arena_ind);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
bool arena_extent_dalloc(extent_hooks_t *extent_hooks,
|
|
Packit Service |
724aca |
void *addr,
|
|
Packit Service |
724aca |
size_t size,
|
|
Packit Service |
724aca |
bool committed,
|
|
Packit Service |
724aca |
unsigned arena_ind)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
return true;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
bool arena_extent_commit(extent_hooks_t *extent_hooks,
|
|
Packit Service |
724aca |
void *addr,
|
|
Packit Service |
724aca |
size_t size,
|
|
Packit Service |
724aca |
size_t offset,
|
|
Packit Service |
724aca |
size_t length,
|
|
Packit Service |
724aca |
unsigned arena_ind)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
return false;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
bool arena_extent_decommit(extent_hooks_t *extent_hooks,
|
|
Packit Service |
724aca |
void *addr,
|
|
Packit Service |
724aca |
size_t size,
|
|
Packit Service |
724aca |
size_t offset,
|
|
Packit Service |
724aca |
size_t length,
|
|
Packit Service |
724aca |
unsigned arena_ind)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
return true;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
bool arena_extent_purge(extent_hooks_t *extent_hooks,
|
|
Packit Service |
724aca |
void *addr,
|
|
Packit Service |
724aca |
size_t size,
|
|
Packit Service |
724aca |
size_t offset,
|
|
Packit Service |
724aca |
size_t length,
|
|
Packit Service |
724aca |
unsigned arena_ind)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
if (memkind_hog_memory) {
|
|
Packit Service |
724aca |
return true;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
int err = madvise(addr + offset, length, MADV_DONTNEED);
|
|
Packit Service |
724aca |
return (err != 0);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
bool arena_extent_split(extent_hooks_t *extent_hooks,
|
|
Packit Service |
724aca |
void *addr,
|
|
Packit Service |
724aca |
size_t size,
|
|
Packit Service |
724aca |
size_t size_a,
|
|
Packit Service |
724aca |
size_t size_b,
|
|
Packit Service |
724aca |
bool committed,
|
|
Packit Service |
724aca |
unsigned arena_ind)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
return false;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
bool arena_extent_merge(extent_hooks_t *extent_hooks,
|
|
Packit Service |
724aca |
void *addr_a,
|
|
Packit Service |
724aca |
size_t size_a,
|
|
Packit Service |
724aca |
void *addr_b,
|
|
Packit Service |
724aca |
size_t size_b,
|
|
Packit Service |
724aca |
bool committed,
|
|
Packit Service |
724aca |
unsigned arena_ind)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
return false;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
extent_hooks_t arena_extent_hooks = {
|
|
Packit Service |
724aca |
.alloc = arena_extent_alloc,
|
|
Packit Service |
724aca |
.dalloc = arena_extent_dalloc,
|
|
Packit Service |
724aca |
.commit = arena_extent_commit,
|
|
Packit Service |
724aca |
.decommit = arena_extent_decommit,
|
|
Packit Service |
724aca |
.purge_lazy = arena_extent_purge,
|
|
Packit Service |
724aca |
.split = arena_extent_split,
|
|
Packit Service |
724aca |
.merge = arena_extent_merge
|
|
Packit Service |
724aca |
};
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
extent_hooks_t arena_extent_hooks_hugetlb = {
|
|
Packit Service |
724aca |
.alloc = arena_extent_alloc_hugetlb,
|
|
Packit Service |
724aca |
.dalloc = arena_extent_dalloc,
|
|
Packit Service |
724aca |
.commit = arena_extent_commit,
|
|
Packit Service |
724aca |
.decommit = arena_extent_decommit,
|
|
Packit Service |
724aca |
.purge_lazy = arena_extent_purge,
|
|
Packit Service |
724aca |
.split = arena_extent_split,
|
|
Packit Service |
724aca |
.merge = arena_extent_merge
|
|
Packit Service |
724aca |
};
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
extent_hooks_t *get_extent_hooks_by_kind(struct memkind *kind)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
if (kind == MEMKIND_HUGETLB
|
|
Packit Service |
724aca |
|| kind == MEMKIND_HBW_HUGETLB
|
|
Packit Service |
724aca |
|| kind == MEMKIND_HBW_ALL_HUGETLB
|
|
Packit Service |
724aca |
|| kind == MEMKIND_HBW_PREFERRED_HUGETLB) {
|
|
Packit Service |
724aca |
return &arena_extent_hooks_hugetlb;
|
|
Packit Service |
724aca |
} else {
|
|
Packit Service |
724aca |
return &arena_extent_hooks;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
MEMKIND_EXPORT int memkind_arena_create_map(struct memkind *kind,
|
|
Packit Service |
724aca |
extent_hooks_t *hooks)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
int err;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
pthread_once(&arena_config_once, arena_config_init);
|
|
Packit Service |
724aca |
if(arena_init_status) {
|
|
Packit Service |
724aca |
return arena_init_status;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
err = memkind_set_arena_map_len(kind);
|
|
Packit Service |
724aca |
if(err) {
|
|
Packit Service |
724aca |
return err;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
#ifdef MEMKIND_TLS
|
|
Packit Service |
724aca |
if (kind->ops->get_arena == memkind_thread_get_arena) {
|
|
Packit Service |
724aca |
pthread_key_create(&(kind->arena_key), free);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
#endif
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
if (pthread_mutex_lock(&arena_registry_write_lock) != 0)
|
|
Packit Service |
724aca |
assert(0 && "failed to acquire mutex");
|
|
Packit Service |
724aca |
unsigned i;
|
|
Packit Service |
724aca |
size_t unsigned_size = sizeof(unsigned int);
|
|
Packit Service |
724aca |
kind->arena_zero = UINT_MAX;
|
|
Packit Service |
724aca |
for(i = 0; i<kind->arena_map_len; i++) {
|
|
Packit Service |
724aca |
unsigned arena_index;
|
|
Packit Service |
724aca |
//create new arena with consecutive index
|
|
Packit Service |
724aca |
err = jemk_mallctl("arenas.create", (void *)&arena_index, &unsigned_size, NULL,
|
|
Packit Service |
724aca |
0);
|
|
Packit Service |
724aca |
if(err) {
|
|
Packit Service |
724aca |
log_err("Could not create arena.");
|
|
Packit Service |
724aca |
err = MEMKIND_ERROR_ARENAS_CREATE;
|
|
Packit Service |
724aca |
goto exit;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
//store arena with lowest index (arenas could be created in descending/ascending order)
|
|
Packit Service |
724aca |
if(kind->arena_zero > arena_index) {
|
|
Packit Service |
724aca |
kind->arena_zero = arena_index;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
//setup extent_hooks for newly created arena
|
|
Packit Service |
724aca |
char cmd[64];
|
|
Packit Service |
724aca |
snprintf(cmd, sizeof(cmd), "arena.%u.extent_hooks", arena_index);
|
|
Packit Service |
724aca |
err = jemk_mallctl(cmd, NULL, NULL, (void *)&hooks, sizeof(extent_hooks_t *));
|
|
Packit Service |
724aca |
if(err) {
|
|
Packit Service |
724aca |
goto exit;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
arena_registry_g[arena_index] = kind;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
exit:
|
|
Packit Service |
724aca |
if (pthread_mutex_unlock(&arena_registry_write_lock) != 0)
|
|
Packit Service |
724aca |
assert(0 && "failed to release mutex");
|
|
Packit Service |
724aca |
return err;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
MEMKIND_EXPORT int memkind_arena_create(struct memkind *kind,
|
|
Packit Service |
724aca |
struct memkind_ops *ops, const char *name)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
int err = memkind_default_create(kind, ops, name);
|
|
Packit Service |
724aca |
if (!err) {
|
|
Packit Service |
724aca |
err = memkind_arena_create_map(kind, get_extent_hooks_by_kind(kind));
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
return err;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
MEMKIND_EXPORT int memkind_arena_destroy(struct memkind *kind)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
if (kind->arena_map_len) {
|
|
Packit Service |
724aca |
char cmd[128];
|
|
Packit Service |
724aca |
unsigned i;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
if (pthread_mutex_lock(&arena_registry_write_lock) != 0)
|
|
Packit Service |
724aca |
assert(0 && "failed to acquire mutex");
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
for (i = 0; i < kind->arena_map_len; ++i) {
|
|
Packit Service |
724aca |
snprintf(cmd, 128, "arena.%u.destroy", kind->arena_zero + i);
|
|
Packit Service |
724aca |
jemk_mallctl(cmd, NULL, NULL, NULL, 0);
|
|
Packit Service |
724aca |
arena_registry_g[kind->arena_zero + i] = NULL;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
if (pthread_mutex_unlock(&arena_registry_write_lock) != 0)
|
|
Packit Service |
724aca |
assert(0 && "failed to release mutex");
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
#ifdef MEMKIND_TLS
|
|
Packit Service |
724aca |
if (kind->ops->get_arena == memkind_thread_get_arena) {
|
|
Packit Service |
724aca |
pthread_key_delete(kind->arena_key);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
#endif
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
memkind_default_destroy(kind);
|
|
Packit Service |
724aca |
return 0;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
int memkind_arena_finalize(struct memkind *kind)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
return memkind_arena_destroy(kind);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
// max allocation size to be cached by tcache mechanism
|
|
Packit Service |
724aca |
#define TCACHE_MAX (1<<(JEMALLOC_TCACHE_CLASS))
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
static void tcache_finalize(void *args)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
int i;
|
|
Packit Service |
724aca |
unsigned *tcache_map = args;
|
|
Packit Service |
724aca |
for(i = 0; i
|
|
Packit Service |
724aca |
if(tcache_map[i] != 0) {
|
|
Packit Service |
724aca |
jemk_mallctl("tcache.destroy", NULL, NULL, (void *)&tcache_map[i],
|
|
Packit Service |
724aca |
sizeof(unsigned));
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
static inline int memkind_lookup_arena(void *ptr, unsigned int *arena)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
size_t sz = sizeof(unsigned);
|
|
Packit Service |
724aca |
unsigned temp_arena;
|
|
Packit Service |
724aca |
int err = jemk_mallctl("arenas.lookup", &temp_arena, &sz, &ptr, sizeof(ptr));
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
if (err) {
|
|
Packit Service |
724aca |
log_err("Could not found arena, err=%d", err);
|
|
Packit Service |
724aca |
return 1;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
*arena = temp_arena;
|
|
Packit Service |
724aca |
return 0;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
MEMKIND_EXPORT struct memkind *memkind_arena_detect_kind(void *ptr)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
if (!ptr) {
|
|
Packit Service |
724aca |
return NULL;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
struct memkind *kind = NULL;
|
|
Packit Service |
724aca |
unsigned arena;
|
|
Packit Service |
724aca |
int err = memkind_lookup_arena(ptr, &arena);
|
|
Packit Service |
724aca |
if (MEMKIND_LIKELY(!err)) {
|
|
Packit Service |
724aca |
kind = get_kind_by_arena(arena);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
/* if no kind was associated with arena it means that allocation doesn't come from
|
|
Packit Service |
724aca |
jemk_*allocx API - it is jemk_*alloc API (MEMKIND_DEFAULT) */
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
return (kind) ? kind : MEMKIND_DEFAULT;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
static inline int get_tcache_flag(unsigned partition, size_t size)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
// do not cache allocation larger than tcache_max nor those coming from non-static kinds
|
|
Packit Service |
724aca |
if(size > TCACHE_MAX || partition >= MEMKIND_NUM_BASE_KIND) {
|
|
Packit Service |
724aca |
return MALLOCX_TCACHE_NONE;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
unsigned *tcache_map = pthread_getspecific(tcache_key);
|
|
Packit Service |
724aca |
if(tcache_map == NULL) {
|
|
Packit Service |
724aca |
tcache_map = calloc(MEMKIND_NUM_BASE_KIND, sizeof(unsigned));
|
|
Packit Service |
724aca |
if(tcache_map == NULL) {
|
|
Packit Service |
724aca |
return MALLOCX_TCACHE_NONE;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
pthread_setspecific(tcache_key, (void *)tcache_map);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
if(MEMKIND_UNLIKELY(tcache_map[partition] == 0)) {
|
|
Packit Service |
724aca |
size_t unsigned_size = sizeof(unsigned);
|
|
Packit Service |
724aca |
int err = jemk_mallctl("tcache.create", (void *)&tcache_map[partition],
|
|
Packit Service |
724aca |
&unsigned_size, NULL, 0);
|
|
Packit Service |
724aca |
if(err) {
|
|
Packit Service |
724aca |
log_err("Could not acquire tcache, err=%d", err);
|
|
Packit Service |
724aca |
return MALLOCX_TCACHE_NONE;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
return MALLOCX_TCACHE(tcache_map[partition]);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
MEMKIND_EXPORT void *memkind_arena_malloc(struct memkind *kind, size_t size)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
void *result = NULL;
|
|
Packit Service |
724aca |
unsigned arena;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
int err = kind->ops->get_arena(kind, &arena, size);
|
|
Packit Service |
724aca |
if (MEMKIND_LIKELY(!err)) {
|
|
Packit Service |
724aca |
result = jemk_mallocx_check(size,
|
|
Packit Service |
724aca |
MALLOCX_ARENA(arena) | get_tcache_flag(kind->partition, size));
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
return result;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
static void *memkind_arena_malloc_no_tcache(struct memkind *kind, size_t size)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
void *result = NULL;
|
|
Packit Service |
724aca |
if (kind == MEMKIND_DEFAULT) {
|
|
Packit Service |
724aca |
result = jemk_mallocx_check(size, MALLOCX_TCACHE_NONE);
|
|
Packit Service |
724aca |
} else {
|
|
Packit Service |
724aca |
unsigned arena;
|
|
Packit Service |
724aca |
int err = kind->ops->get_arena(kind, &arena, size);
|
|
Packit Service |
724aca |
if (MEMKIND_LIKELY(!err)) {
|
|
Packit Service |
724aca |
result = jemk_mallocx_check(size, MALLOCX_ARENA(arena) | MALLOCX_TCACHE_NONE);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
return result;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
MEMKIND_EXPORT void memkind_arena_free(struct memkind *kind, void *ptr)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
if (kind == MEMKIND_DEFAULT) {
|
|
Packit Service |
724aca |
jemk_free(ptr);
|
|
Packit Service |
724aca |
} else if (ptr != NULL) {
|
|
Packit Service |
724aca |
jemk_dallocx(ptr, get_tcache_flag(kind->partition, 0));
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
MEMKIND_EXPORT void memkind_arena_free_with_kind_detect(void *ptr)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
struct memkind *kind = memkind_arena_detect_kind(ptr);
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
memkind_arena_free(kind, ptr);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
MEMKIND_EXPORT size_t memkind_arena_malloc_usable_size(void *ptr)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
return memkind_default_malloc_usable_size(NULL, ptr);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
MEMKIND_EXPORT void *memkind_arena_realloc(struct memkind *kind, void *ptr,
|
|
Packit Service |
724aca |
size_t size)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
unsigned arena;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
if (size == 0 && ptr != NULL) {
|
|
Packit Service |
724aca |
memkind_arena_free(kind, ptr);
|
|
Packit Service |
724aca |
ptr = NULL;
|
|
Packit Service |
724aca |
} else {
|
|
Packit Service |
724aca |
int err = kind->ops->get_arena(kind, &arena, size);
|
|
Packit Service |
724aca |
if (MEMKIND_LIKELY(!err)) {
|
|
Packit Service |
724aca |
if (ptr == NULL) {
|
|
Packit Service |
724aca |
ptr = jemk_mallocx_check(size,
|
|
Packit Service |
724aca |
MALLOCX_ARENA(arena) | get_tcache_flag(kind->partition, size));
|
|
Packit Service |
724aca |
} else {
|
|
Packit Service |
724aca |
ptr = jemk_rallocx_check(ptr, size,
|
|
Packit Service |
724aca |
MALLOCX_ARENA(arena) | get_tcache_flag(kind->partition, size));
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
return ptr;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
int memkind_arena_update_cached_stats(void)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
uint64_t epoch = 1;
|
|
Packit Service |
724aca |
return jemk_mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch));
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
MEMKIND_EXPORT void *memkind_arena_realloc_with_kind_detect(void *ptr,
|
|
Packit Service |
724aca |
size_t size)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
if (!ptr) {
|
|
Packit Service |
724aca |
errno = EINVAL;
|
|
Packit Service |
724aca |
return NULL;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
struct memkind *kind = memkind_arena_detect_kind(ptr);
|
|
Packit Service |
724aca |
if (kind == MEMKIND_DEFAULT) {
|
|
Packit Service |
724aca |
return memkind_default_realloc(kind, ptr, size);
|
|
Packit Service |
724aca |
} else {
|
|
Packit Service |
724aca |
return memkind_arena_realloc(kind, ptr, size);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
MEMKIND_EXPORT int memkind_arena_update_memory_usage_policy(
|
|
Packit Service |
724aca |
struct memkind *kind, memkind_mem_usage_policy policy)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
int err = MEMKIND_SUCCESS;
|
|
Packit Service |
724aca |
unsigned i;
|
|
Packit Service |
724aca |
ssize_t dirty_decay_val = 0;
|
|
Packit Service |
724aca |
switch ( policy ) {
|
|
Packit Service |
724aca |
case MEMKIND_MEM_USAGE_POLICY_DEFAULT:
|
|
Packit Service |
724aca |
dirty_decay_val = DIRTY_DECAY_MS_DEFAULT;
|
|
Packit Service |
724aca |
break;
|
|
Packit Service |
724aca |
case MEMKIND_MEM_USAGE_POLICY_CONSERVATIVE:
|
|
Packit Service |
724aca |
dirty_decay_val = DIRTY_DECAY_MS_CONSERVATIVE;
|
|
Packit Service |
724aca |
break;
|
|
Packit Service |
724aca |
default:
|
|
Packit Service |
724aca |
log_err("Unrecognized memory policy %d", policy);
|
|
Packit Service |
724aca |
return MEMKIND_ERROR_INVALID;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
for (i = 0; i < kind->arena_map_len; ++i) {
|
|
Packit Service |
724aca |
char cmd[64];
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
snprintf(cmd, sizeof(cmd), "arena.%u.dirty_decay_ms", kind->arena_zero + i);
|
|
Packit Service |
724aca |
err = jemk_mallctl(cmd, NULL, NULL, (void *)&dirty_decay_val, sizeof(ssize_t));
|
|
Packit Service |
724aca |
if ( err ) {
|
|
Packit Service |
724aca |
log_err("Incorrect dirty_decay_ms value %zu", dirty_decay_val);
|
|
Packit Service |
724aca |
return MEMKIND_ERROR_INVALID;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
return err;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
MEMKIND_EXPORT void *memkind_arena_calloc(struct memkind *kind, size_t num,
|
|
Packit Service |
724aca |
size_t size)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
void *result = NULL;
|
|
Packit Service |
724aca |
unsigned arena;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
int err = kind->ops->get_arena(kind, &arena, size);
|
|
Packit Service |
724aca |
if (MEMKIND_LIKELY(!err)) {
|
|
Packit Service |
724aca |
result = jemk_mallocx_check(num * size,
|
|
Packit Service |
724aca |
MALLOCX_ARENA(arena) | MALLOCX_ZERO | get_tcache_flag(kind->partition, size));
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
return result;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
MEMKIND_EXPORT int memkind_arena_posix_memalign(struct memkind *kind,
|
|
Packit Service |
724aca |
void **memptr, size_t alignment,
|
|
Packit Service |
724aca |
size_t size)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
int err;
|
|
Packit Service |
724aca |
unsigned arena;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
*memptr = NULL;
|
|
Packit Service |
724aca |
err = kind->ops->get_arena(kind, &arena, size);
|
|
Packit Service |
724aca |
if (MEMKIND_LIKELY(!err)) {
|
|
Packit Service |
724aca |
err = memkind_posix_check_alignment(kind, alignment);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
if (MEMKIND_LIKELY(!err)) {
|
|
Packit Service |
724aca |
if (MEMKIND_UNLIKELY(size_out_of_bounds(size))) {
|
|
Packit Service |
724aca |
return 0;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
/* posix_memalign should not change errno.
|
|
Packit Service |
724aca |
Set it to its previous value after calling jemalloc */
|
|
Packit Service |
724aca |
int errno_before = errno;
|
|
Packit Service |
724aca |
*memptr = jemk_mallocx_check(size,
|
|
Packit Service |
724aca |
MALLOCX_ALIGN(alignment) | MALLOCX_ARENA(arena) | get_tcache_flag(
|
|
Packit Service |
724aca |
kind->partition, size));
|
|
Packit Service |
724aca |
errno = errno_before;
|
|
Packit Service |
724aca |
err = *memptr ? 0 : ENOMEM;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
return err;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
MEMKIND_EXPORT int memkind_bijective_get_arena(struct memkind *kind,
|
|
Packit Service |
724aca |
unsigned int *arena, size_t size)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
*arena = kind->arena_zero;
|
|
Packit Service |
724aca |
return 0;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
#ifdef MEMKIND_TLS
|
|
Packit Service |
724aca |
MEMKIND_EXPORT int memkind_thread_get_arena(struct memkind *kind,
|
|
Packit Service |
724aca |
unsigned int *arena, size_t size)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
int err = 0;
|
|
Packit Service |
724aca |
unsigned int *arena_tsd;
|
|
Packit Service |
724aca |
arena_tsd = pthread_getspecific(kind->arena_key);
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
if (MEMKIND_UNLIKELY(arena_tsd == NULL)) {
|
|
Packit Service |
724aca |
arena_tsd = malloc(sizeof(unsigned int));
|
|
Packit Service |
724aca |
if (arena_tsd == NULL) {
|
|
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 |
// On glibc pthread_self() is incremented by 0x801000 for every
|
|
Packit Service |
724aca |
// thread (no matter the arch's word width). This might change
|
|
Packit Service |
724aca |
// in the future, but even in the worst case the hash will
|
|
Packit Service |
724aca |
// degenerate to a single bucket with no loss of correctness.
|
|
Packit Service |
724aca |
*arena_tsd = ((uint64_t)pthread_self() >> 12) %
|
|
Packit Service |
724aca |
kind->arena_map_len;
|
|
Packit Service |
724aca |
err = pthread_setspecific(kind->arena_key, arena_tsd) ?
|
|
Packit Service |
724aca |
MEMKIND_ERROR_RUNTIME : 0;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
*arena = kind->arena_zero + *arena_tsd;
|
|
Packit Service |
724aca |
return err;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
#else
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
/*
|
|
Packit Service |
724aca |
*
|
|
Packit Service |
724aca |
* We use thread control block as unique thread identifier
|
|
Packit Service |
724aca |
* For more read: https://www.akkadia.org/drepper/tls.pdf
|
|
Packit Service |
724aca |
* We could consider using rdfsbase when it will arrive to linux kernel
|
|
Packit Service |
724aca |
*
|
|
Packit Service |
724aca |
* This approach works only on glibc (and possibly similar implementations)
|
|
Packit Service |
724aca |
* but that covers our current needs.
|
|
Packit Service |
724aca |
*
|
|
Packit Service |
724aca |
*/
|
|
Packit Service |
724aca |
static uintptr_t get_fs_base()
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
return (uintptr_t)pthread_self();
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
MEMKIND_EXPORT int memkind_thread_get_arena(struct memkind *kind,
|
|
Packit Service |
724aca |
unsigned int *arena, size_t size)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
unsigned int arena_idx;
|
|
Packit Service |
724aca |
// it's likely that each thread control block lies on different page
|
|
Packit Service |
724aca |
// so we extracting page number with >> 12 to improve hashing
|
|
Packit Service |
724aca |
arena_idx = (get_fs_base() >> 12) & kind->arena_map_mask;
|
|
Packit Service |
724aca |
*arena = kind->arena_zero + arena_idx;
|
|
Packit Service |
724aca |
return 0;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
#endif //MEMKIND_TLS
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
static void *jemk_mallocx_check(size_t size, int flags)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
/*
|
|
Packit Service |
724aca |
* Checking for out of range size due to unhandled error in
|
|
Packit Service |
724aca |
* jemk_mallocx(). Size invalid for the range
|
|
Packit Service |
724aca |
* LLONG_MAX <= size <= ULLONG_MAX
|
|
Packit Service |
724aca |
* which is the result of passing a negative signed number as size
|
|
Packit Service |
724aca |
*/
|
|
Packit Service |
724aca |
void *result = NULL;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
if (MEMKIND_UNLIKELY(size >= LLONG_MAX)) {
|
|
Packit Service |
724aca |
errno = ENOMEM;
|
|
Packit Service |
724aca |
} else if (size != 0) {
|
|
Packit Service |
724aca |
result = jemk_mallocx(size, flags);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
return result;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
static void *jemk_rallocx_check(void *ptr, size_t size, int flags)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
/*
|
|
Packit Service |
724aca |
* Checking for out of range size due to unhandled error in
|
|
Packit Service |
724aca |
* jemk_mallocx(). Size invalid for the range
|
|
Packit Service |
724aca |
* LLONG_MAX <= size <= ULLONG_MAX
|
|
Packit Service |
724aca |
* which is the result of passing a negative signed number as size
|
|
Packit Service |
724aca |
*/
|
|
Packit Service |
724aca |
void *result = NULL;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
if (MEMKIND_UNLIKELY(size >= LLONG_MAX)) {
|
|
Packit Service |
724aca |
errno = ENOMEM;
|
|
Packit Service |
724aca |
} else {
|
|
Packit Service |
724aca |
result = jemk_rallocx(ptr, size, flags);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
return result;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void memkind_arena_init(struct memkind *kind)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
if (kind != MEMKIND_DEFAULT) {
|
|
Packit Service |
724aca |
int err = memkind_arena_create_map(kind, get_extent_hooks_by_kind(kind));
|
|
Packit Service |
724aca |
if (err) {
|
|
Packit Service |
724aca |
log_fatal("[%s] Failed to create arena map (error code:%d).", kind->name, err);
|
|
Packit Service |
724aca |
abort();
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
static int memkind_arena_get_stat(struct memkind *kind, memkind_stat_type stat,
|
|
Packit Service |
724aca |
bool check_init, size_t *value)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
size_t sz = sizeof(size_t);
|
|
Packit Service |
724aca |
size_t temp_stat;
|
|
Packit Service |
724aca |
int err = MEMKIND_SUCCESS;
|
|
Packit Service |
724aca |
unsigned i, j;
|
|
Packit Service |
724aca |
char cmd[128];
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
*value = 0;
|
|
Packit Service |
724aca |
for (i = 0; i < kind->arena_map_len; ++i) {
|
|
Packit Service |
724aca |
if (check_init) {
|
|
Packit Service |
724aca |
bool is_init;
|
|
Packit Service |
724aca |
size_t sz_b_state = sizeof(is_init);
|
|
Packit Service |
724aca |
snprintf(cmd, 128, "arena.%u.initialized", kind->arena_zero + i);
|
|
Packit Service |
724aca |
err = jemk_mallctl(cmd, (void *)&is_init, &sz_b_state, NULL, 0);
|
|
Packit Service |
724aca |
if (err) {
|
|
Packit Service |
724aca |
log_err("Error on getting initialized state of arena.");
|
|
Packit Service |
724aca |
return MEMKIND_ERROR_INVALID;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
if (!is_init) {
|
|
Packit Service |
724aca |
continue;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
for (j = 0; j < arena_stats[stat].stats_no; ++j) {
|
|
Packit Service |
724aca |
snprintf(cmd, 128, arena_stats[stat].stats[j], kind->arena_zero + i);
|
|
Packit Service |
724aca |
err = jemk_mallctl(cmd, &temp_stat, &sz, NULL, 0);
|
|
Packit Service |
724aca |
if (err) {
|
|
Packit Service |
724aca |
log_err("Error on getting arena statistic.");
|
|
Packit Service |
724aca |
return MEMKIND_ERROR_INVALID;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
*value += temp_stat;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
return err;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
int memkind_arena_get_stat_with_check_init(struct memkind *kind,
|
|
Packit Service |
724aca |
memkind_stat_type stat, bool check_init, size_t *value)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
int status;
|
|
Packit Service |
724aca |
switch (stat) {
|
|
Packit Service |
724aca |
case MEMKIND_STAT_TYPE_RESIDENT:
|
|
Packit Service |
724aca |
case MEMKIND_STAT_TYPE_ALLOCATED:
|
|
Packit Service |
724aca |
status = memkind_arena_get_stat(kind, stat, check_init, value);
|
|
Packit Service |
724aca |
break;
|
|
Packit Service |
724aca |
case MEMKIND_STAT_TYPE_ACTIVE:
|
|
Packit Service |
724aca |
status = memkind_arena_get_stat(kind, stat, check_init, value);
|
|
Packit Service |
724aca |
*value = PAGE_2_BYTES(*value);
|
|
Packit Service |
724aca |
break;
|
|
Packit Service |
724aca |
default:
|
|
Packit Service |
724aca |
//not reached
|
|
Packit Service |
724aca |
return MEMKIND_ERROR_INVALID;
|
|
Packit Service |
724aca |
break;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
return status;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
int memkind_arena_get_kind_stat(struct memkind *kind, memkind_stat_type stat,
|
|
Packit Service |
724aca |
size_t *value)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
return memkind_arena_get_stat_with_check_init(kind, stat, false, value);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
int memkind_arena_get_global_stat(memkind_stat_type stat, size_t *value)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
size_t sz = sizeof(size_t);
|
|
Packit Service |
724aca |
int err = jemk_mallctl(global_stats[stat], value, &sz, NULL, 0);
|
|
Packit Service |
724aca |
if (err) {
|
|
Packit Service |
724aca |
log_err("Error on getting global statistic.");
|
|
Packit Service |
724aca |
return MEMKIND_ERROR_INVALID;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
return err;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
int memkind_arena_enable_background_threads(size_t threads_limit)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
bool background_thread_val = true;
|
|
Packit Service |
724aca |
int err;
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
if (threads_limit) {
|
|
Packit Service |
724aca |
err = jemk_mallctl("max_background_threads", NULL, NULL, &threads_limit,
|
|
Packit Service |
724aca |
sizeof(size_t));
|
|
Packit Service |
724aca |
if (err) {
|
|
Packit Service |
724aca |
log_err("Error on setting threads limit");
|
|
Packit Service |
724aca |
return MEMKIND_ERROR_INVALID;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
err = jemk_mallctl("background_thread", NULL, NULL, &background_thread_val,
|
|
Packit Service |
724aca |
sizeof(bool));
|
|
Packit Service |
724aca |
if (err) {
|
|
Packit Service |
724aca |
log_err("Error on activating background thread");
|
|
Packit Service |
724aca |
return MEMKIND_ERROR_INVALID;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
return err;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
#define DEST_SLAB_END(begin, size) ((uintptr_t)begin+ (uintptr_t)size)
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
struct mem_util_stats {
|
|
Packit Service |
724aca |
void *target_slab; // address of the slab of a potential realloaction would go to ( NULL in case of large/huge allocation)
|
|
Packit Service |
724aca |
size_t nfree; // number of free regions in the slab
|
|
Packit Service |
724aca |
size_t nregs; // number of regions in the slab
|
|
Packit Service |
724aca |
size_t slab_size; // size of the slab in bytes
|
|
Packit Service |
724aca |
size_t bin_nfree; // total number of free regions in the bin the slab belongs to
|
|
Packit Service |
724aca |
size_t bin_nregs; // total number of regions in the bin the slab belongs to
|
|
Packit Service |
724aca |
};
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void *memkind_arena_defrag_reallocate_with_kind_detect (void *ptr)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
return memkind_arena_defrag_reallocate(memkind_detect_kind(ptr), ptr);
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
void *memkind_arena_defrag_reallocate(struct memkind *kind, void *ptr)
|
|
Packit Service |
724aca |
{
|
|
Packit Service |
724aca |
if (!ptr) {
|
|
Packit Service |
724aca |
return NULL;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
size_t out_sz = sizeof(struct mem_util_stats);
|
|
Packit Service |
724aca |
struct mem_util_stats out;
|
|
Packit Service |
724aca |
int err = jemk_mallctl("experimental.utilization.query", &out, &out_sz, &ptr,
|
|
Packit Service |
724aca |
sizeof(ptr));
|
|
Packit Service |
724aca |
if (err) {
|
|
Packit Service |
724aca |
log_err("Error on get utilization query");
|
|
Packit Service |
724aca |
return NULL;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
|
|
Packit Service |
724aca |
// Check if input pointer resides outside of potential reallocation slab
|
|
Packit Service |
724aca |
// Check if occupied regions inside the slab are below average occupied regions inside bin
|
|
Packit Service |
724aca |
// Check if there are some free regions in the destination slab
|
|
Packit Service |
724aca |
if (out.target_slab &&
|
|
Packit Service |
724aca |
((ptr < out.target_slab) ||
|
|
Packit Service |
724aca |
(uintptr_t)ptr > DEST_SLAB_END(out.target_slab, out.slab_size)) &&
|
|
Packit Service |
724aca |
out.nfree * out.bin_nregs >= out.nregs * out.bin_nfree &&
|
|
Packit Service |
724aca |
out.nfree != 0) {
|
|
Packit Service |
724aca |
size_t size = memkind_malloc_usable_size(kind, ptr);
|
|
Packit Service |
724aca |
void *ptr_new = memkind_arena_malloc_no_tcache(kind, size);
|
|
Packit Service |
724aca |
if (MEMKIND_UNLIKELY(!ptr_new)) return NULL;
|
|
Packit Service |
724aca |
memcpy(ptr_new, ptr, size);
|
|
Packit Service |
724aca |
memkind_free(kind, ptr);
|
|
Packit Service |
724aca |
return ptr_new;
|
|
Packit Service |
724aca |
}
|
|
Packit Service |
724aca |
return NULL;
|
|
Packit Service |
724aca |
}
|