libnuma是一个用于Linux系统的NUMA(非一致性内存访问)API。
libnuma提供了一组函数和工具,用于管理和优化NUMA系统中的内存分配和访问。
NUMA是一种计算机体系结构,其中多个处理器和内存模块通过高速互联网络连接在一起。在NUMA系统中,每个处理器都有自己的本地内存,但也可以访问其他处理器的内存。
libnuma的主要功能包括以下几个方面:
1. 内存分配:libnuma提供了一些函数,如numa_alloc_onnode和numa_alloc_local,用于在指定的NUMA节点上分配内存。这些函数可以确保内存分配在本地节点上,从而减少远程访问的开销。例如,以下代码将在NUMA节点0上分配1MB的内存:
void* mem = numa_alloc_onnode(1024*1024, 0);
2. 内存绑定:libnuma还提供了一些函数,如numa_bind和numa_set_bind_policy,用于将线程或进程绑定到指定的NUMA节点上。通过绑定,可以确保线程或进程只在指定的节点上执行,从而减少远程访问的开销。例如,以下代码将当前线程绑定到NUMA节点1上:
numa_bind(numa_parse_nodestring("1"));
3. 内存迁移:libnuma提供了一些函数,如numa_migrate_pages和numa_migrate_hint,用于在NUMA节点之间迁移内存页面。通过迁移,可以将访问频率较高的页面移动到本地节点上,从而提高内存访问的效率。例如,以下代码将页面从NUMA节点0迁移到NUMA节点1:
unsigned long nodemask = 1UL << 1;
numa_migrate_pages(0, nodemask);
4. NUMA信息查询:libnuma提供了一些函数,如numa_num_configured_nodes和numa_node_size,用于查询系统中的NUMA节点数量和每个节点的内存大小。这些信息可以帮助开发人员了解系统的NUMA配置,并根据需要进行优化。例如,以下代码将打印系统中的NUMA节点数量和每个节点的内存大小:
int num_nodes = numa_num_configured_nodes();
for (int i = 0; i < num_nodes; i++) {
long size = numa_node_size(i, NULL);
printf("Node %d: %ld bytes\n", i, size);
}
通过上述功能,libnuma可以帮助开发人员更好地管理和优化NUMA系统中的内存分配和访问。下面举几个例子来说明其使用方法和效果。
例子1:内存分配和绑定
假设我们有一个NUMA系统,其中有两个节点,每个节点有4个处理器核心和8GB的内存。我们希望在节点0上分配1GB的内存,并将线程绑定到节点1上。可以使用以下代码实现:
void* mem = numa_alloc_onnode(1024*1024*1024, 0);
numa_bind(numa_parse_nodestring("1"));
这样,我们就在节点0上分配了1GB的内存,并将当前线程绑定到节点1上。
例子2:内存迁移
假设我们有一个NUMA系统,其中有两个节点,每个节点有4个处理器核心和8GB的内存。我们发现某个页面在节点0上的访问频率很高,希望将其迁移到节点1上以提高访问效率。可以使用以下代码实现:
unsigned long nodemask = 1UL << 1;
numa_migrate_pages(0, nodemask);
这样,我们就将页面从节点0迁移到节点1。
例子3:NUMA信息查询
假设我们想了解系统中的NUMA节点数量和每个节点的内存大小。可以使用以下代码实现:
int num_nodes = numa_num_configured_nodes();
for (int i = 0; i < num_nodes; i++) {
long size = numa_node_size(i, NULL);
printf("Node %d: %ld bytes\n", i, size);
}
这样,就可以打印出系统中的NUMA节点数量和每个节点的内存大小。
通过以上例子,可以更好地理解libnuma的使用方法和效果。libnuma提供了一组函数和工具,用于管理和优化NUMA系统中的内存分配和访问,可以帮助开发人员充分利用NUMA系统的性能优势。
#include
cc ... -lnuma
int numa_available(void);
int numa_max_possible_node(void);
int numa_num_possible_nodes();
int numa_max_node(void);
int numa_num_configured_nodes();
struct bitmask *numa_get_mems_allowed(void);
int numa_num_configured_cpus(void);
struct bitmask *numa_all_nodes_ptr;
struct bitmask *numa_no_nodes_ptr;
struct bitmask *numa_all_cpus_ptr;
int numa_num_task_cpus();
int numa_num_task_nodes();
int numa_parse_bitmap(char *line , struct bitmask *mask);
struct bitmask *numa_parse_nodestring(const char *string);
struct bitmask *numa_parse_nodestring_all(const char *string);
struct bitmask *numa_parse_cpustring(const char *string);
struct bitmask *numa_parse_cpustring_all(const char *string);
long numa_node_size(int node, long *freep);
long long numa_node_size64(int node, long long *freep);
int numa_preferred(void);
void numa_set_preferred(int node);
int numa_get_interleave_node(void);
struct bitmask *numa_get_interleave_mask(void);
void numa_set_interleave_mask(struct bitmask *nodemask);
void numa_interleave_memory(void *start, size_t size, struct
bitmask *nodemask);
void numa_bind(struct bitmask *nodemask);
void numa_set_localalloc(void);
void numa_set_membind(struct bitmask *nodemask);
void numa_set_membind_balancing(struct bitmask *nodemask);
struct bitmask *numa_get_membind(void);
void *numa_alloc_onnode(size_t size, int node);
void *numa_alloc_local(size_t size);
void *numa_alloc_interleaved(size_t size);
void *numa_alloc_interleaved_subset(size_t size, struct bitmask
*nodemask); void *numa_alloc(size_t size);
void *numa_realloc(void *old_addr, size_t old_size, size_t
new_size);
void numa_free(void *start, size_t size);
int numa_run_on_node(int node);
int numa_run_on_node_mask(struct bitmask *nodemask);
int numa_run_on_node_mask_all(struct bitmask *nodemask);
struct bitmask *numa_get_run_node_mask(void);
void numa_tonode_memory(void *start, size_t size, int node);
void numa_tonodemask_memory(void *start, size_t size, struct
bitmask *nodemask);
void numa_setlocal_memory(void *start, size_t size);
void numa_police_memory(void *start, size_t size);
void numa_set_bind_policy(int strict);
void numa_set_strict(int strict);
int numa_distance(int node1, int node2);
int numa_sched_getaffinity(pid_t pid, struct bitmask *mask);
int numa_sched_setaffinity(pid_t pid, struct bitmask *mask);
int numa_node_to_cpus(int node, struct bitmask *mask);
void numa_node_to_cpu_update();
int numa_node_of_cpu(int cpu);
struct bitmask *numa_allocate_cpumask();
void numa_free_cpumask();
struct bitmask *numa_allocate_nodemask();
void numa_free_nodemask();
struct bitmask *numa_bitmask_alloc(unsigned int n);
struct bitmask *numa_bitmask_clearall(struct bitmask *bmp);
struct bitmask *numa_bitmask_clearbit(struct bitmask *bmp,
unsigned int n);
int numa_bitmask_equal(const struct bitmask *bmp1, const struct
bitmask *bmp2);
void numa_bitmask_free(struct bitmask *bmp);
int numa_bitmask_isbitset(const struct bitmask *bmp, unsigned int
n);
unsigned int numa_bitmask_nbytes(struct bitmask *bmp);
struct bitmask *numa_bitmask_setall(struct bitmask *bmp);
struct bitmask *numa_bitmask_setbit(struct bitmask *bmp, unsigned
int n);
void copy_bitmask_to_nodemask(struct bitmask *bmp, nodemask_t
*nodemask)
void copy_nodemask_to_bitmask(nodemask_t *nodemask, struct
bitmask *bmp)
void copy_bitmask_to_bitmask(struct bitmask *bmpfrom, struct
bitmask *bmpto)
unsigned int numa_bitmask_weight(const struct bitmask *bmp )
int numa_move_pages(int pid, unsigned long count, void **pages,
const int *nodes, int *status, int flags);
int numa_migrate_pages(int pid, struct bitmask *fromnodes, struct
bitmask *tonodes);
void numa_error(char *where);
extern int numa_exit_on_error;
extern int numa_exit_on_warn;
void numa_warn(int number, char *where, ...);
numa_migrate_pages系统调用,内核中是kernel_migrate_pages服务函数,以X86体系结构作为说明
kernel_migrate_pages[mm/mempolicy.c]
do_migrate_pages.part.31()
migrate_to_node
queue_pages_range
walk_page_range
migrate_pages[mm/migrate.c]
PageHuge
unmap_and_move_huge_page/ unmap_and_move
__unmap_and_move
lock_page(page); //获得页面锁
get_new_page
try_to_unmap[mm/rmap.c]
rmap_walk
rmap_walk_anon/ rmap_walk_ksm/ rmap_walk_file
try_to_unmap_one (rwc->rmap_one)
flush_cache_page //flush cache
ptep_clear_flush
flush_tlb_mm_range//flush TLB(包括remote核)
flush_tlb_func_local
flush_tlb_func_common flush_tlb_others(=native_flush_tlb_others)
flush_tlb_func_remote
page_mapped
move_to_new_page //真正的页面移动(拷贝)
……
remove_migration_ptes
……
参考文献:
Flush-Cache/Page-Lock/Flush-TLB说明 - CodeAntenna
Flush-Cache/Page-Lock/Flush-TLB说明_flush cache-CSDN博客