116 lines
3.1 KiB
C
116 lines
3.1 KiB
C
#include <pthread.h>
|
|
#include <sys/types.h>
|
|
#include <sys/cpuset.h>
|
|
#include <sys/domainset.h>
|
|
#include <sys/thr.h>
|
|
#include <sys/mman.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
|
|
#include "topo.h"
|
|
|
|
static pthread_mutex_t alloc_lock;
|
|
#define NM_MAX_OBJS_PER_LVL (256)
|
|
#define MEM_OBJ_SIZE (4096) // 4k
|
|
#define MEM_OBJ_NUM (1024 * 256) // 4k * 1024 * 256 = 1GB per region
|
|
#define MEM_REGION_NUM (4) // 4 x 1GB = 4GB total
|
|
static int nm_mem_idx[NM_MAX_OBJS_PER_LVL];
|
|
static int nm_mem_region_idx[NM_MAX_OBJS_PER_LVL];
|
|
static void* nm_mem_regions[NM_MAX_OBJS_PER_LVL][MEM_REGION_NUM];
|
|
|
|
struct topo_obj;
|
|
|
|
int
|
|
topo_alloc_init(int verbose, struct topo_obj * tobj)
|
|
{
|
|
long tid;
|
|
thr_self(&tid);
|
|
domainset_t orig_dom;
|
|
int orig_policy;
|
|
|
|
pthread_mutex_init(&alloc_lock, NULL);
|
|
|
|
DOMAINSET_ZERO(&orig_dom);
|
|
|
|
// save existing thread's allocation strategy
|
|
int ret = cpuset_getdomain(CPU_LEVEL_WHICH, CPU_WHICH_TID, tid, sizeof(orig_dom), &orig_dom, &orig_policy);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
|
|
domainset_t tmp_domain;
|
|
for (int i = 0; i < topo_num_numa(tobj); i++) {
|
|
DOMAINSET_ZERO(&tmp_domain);
|
|
DOMAINSET_SET(i, &tmp_domain);
|
|
|
|
ret = cpuset_setdomain(CPU_LEVEL_WHICH, CPU_WHICH_TID, tid, sizeof(tmp_domain), &tmp_domain, DOMAINSET_POLICY_PREFER);
|
|
if (ret != 0) {
|
|
if (verbose) {
|
|
fprintf(stderr, "libnm: cpuset_setdomain failed with %d\n", errno);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
for (unsigned int j = 0; j < MEM_REGION_NUM; j++) {
|
|
if ((nm_mem_regions[i][j] = mmap(NULL, MEM_OBJ_NUM * MEM_OBJ_SIZE, PROT_READ | PROT_WRITE,
|
|
MAP_ANON | MAP_ALIGNED_SUPER | MAP_NOCORE | MAP_PRIVATE | MAP_NOSYNC,
|
|
-1, 0)) == MAP_FAILED) {
|
|
if (verbose) {
|
|
fprintf(stderr, "libnm: mmap failed with %d\n", errno);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// touch the pages to prefault the pages
|
|
for (unsigned int k = 0; k < MEM_OBJ_NUM; k++) {
|
|
*(uint32_t*)((char*)nm_mem_regions[i][j] + k * MEM_OBJ_SIZE) = 0;
|
|
}
|
|
|
|
if (verbose) {
|
|
fprintf(stdout, "libnm: reserved %u bytes (%u MB) on node %d. vaddr: 0x%p\n", MEM_OBJ_NUM * MEM_OBJ_SIZE, MEM_OBJ_SIZE * MEM_OBJ_NUM / 1024 / 1024, i, nm_mem_regions[i][j]);
|
|
}
|
|
}
|
|
|
|
nm_mem_idx[i] = 0;
|
|
nm_mem_region_idx[i] = 0;
|
|
}
|
|
|
|
// restore existing thread's allocation strategy
|
|
ret = cpuset_setdomain(CPU_LEVEL_WHICH, CPU_WHICH_TID, tid, sizeof(orig_dom), &orig_dom, orig_policy);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void *
|
|
topo_malloc(unsigned int node, size_t size)
|
|
{
|
|
void * ret = NULL;
|
|
int num_objs = (size + MEM_OBJ_SIZE - 1) / MEM_OBJ_SIZE;
|
|
int retry = 0;
|
|
|
|
pthread_mutex_lock(&alloc_lock);
|
|
int cur_region = nm_mem_region_idx[node];
|
|
int cur_idx = nm_mem_idx[node];
|
|
|
|
retry:
|
|
if ((int)MEM_OBJ_NUM - cur_idx >= num_objs) {
|
|
ret = (char*)nm_mem_regions[node][cur_region] + MEM_OBJ_SIZE * cur_idx;
|
|
nm_mem_region_idx[node] = cur_region;
|
|
nm_mem_idx[node] = cur_idx + num_objs;
|
|
} else if (!retry && (cur_region < (int)MEM_REGION_NUM)) {
|
|
// check next region
|
|
cur_region++;
|
|
cur_idx = 0;
|
|
retry = 1;
|
|
goto retry;
|
|
}
|
|
pthread_mutex_unlock(&alloc_lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
topo_free(unsigned int node __attribute__((unused)), void * addr __attribute__((unused)))
|
|
{
|
|
// dummy function
|
|
} |