libnuma 及底层实现

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博客

你可能感兴趣的:(linux,kernel)