mbind 函数详解 链接到标题

1. 函数介绍 链接到标题

mbind 是 Linux 系统中用于设置内存区域 NUMA(Non-Uniform Memory Access)策略的系统调用。可以把 mbind 想象成"内存分配的导航系统"——它告诉操作系统应该将特定的内存区域分配到哪个 NUMA 节点上,就像导航系统告诉你应该走哪条路到达目的地一样。

在现代多核系统中,特别是 NUMA 架构中,不同的 CPU 核心访问不同内存节点的速度是不一样的。mbind 允许你为特定的内存区域指定分配策略,从而优化程序性能。

2. 函数原型 链接到标题

#include <numaif.h>

long mbind(void *addr, unsigned long len, int mode,
           const unsigned long *nodemask, unsigned long maxnode, unsigned flags);

3. 功能 链接到标题

mbind 函数用于为指定的内存区域设置 NUMA 内存分配策略。它可以控制从该内存区域分配的页面应该从哪个 NUMA 节点分配。

4. 参数 链接到标题

  • addr: 内存区域的起始地址
  • len: 内存区域的长度(以字节为单位)
  • mode: 内存分配策略模式
  • nodemask: 指向节点掩码数组的指针,指定可用的 NUMA 节点
  • maxnode: nodemask 数组的最大节点数
  • flags: 控制操作行为的标志位

5. 策略模式(mode 参数) 链接到标题

模式 说明
MPOL_DEFAULT 0 默认策略,遵循系统默认行为
MPOL_PREFERRED 1 优先分配到指定节点
MPOL_BIND 2 严格绑定到指定节点集合
MPOL_INTERLEAVE 3 在指定节点间交错分配
MPOL_LOCAL 4 分配到本地节点(进程运行的节点)

6. 标志位(flags 参数) 链接到标题

标志 说明
0 默认行为
MPOL_MF_STRICT 严格模式,如果策略不能满足则失败
MPOL_MF_MOVE 尝试移动已存在的页面
MPOL_MF_MOVE_ALL 移动所有页面(需要特权)

7. 返回值 链接到标题

  • 成功: 返回 0
  • 失败: 返回 -1,并设置相应的 errno 错误码

常见错误码:

  • EFAULT: 地址参数无效
  • EINVAL: 参数无效
  • ENOMEM: 内存不足
  • EPERM: 权限不足

8. 相似函数或关联函数 链接到标题

  • set_mempolicy: 设置进程默认内存策略
  • get_mempolicy: 获取内存策略
  • migrate_pages: 迁移进程页面到指定节点
  • move_pages: 移动指定页面到指定节点
  • numa_ functions*: libnuma 库提供的 NUMA 操作函数

9. 示例代码 链接到标题

示例1:基础用法 - 设置内存区域策略 链接到标题

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <numaif.h>
#include <numa.h>
#include <string.h>
#include <errno.h>

// 设置节点掩码
void set_nodemask(unsigned long *nodemask, unsigned long maxnode, int node) {
    memset(nodemask, 0, (maxnode + 7) / 8);  // 清零
    if (node >= 0 && node < maxnode) {
        nodemask[node / (sizeof(unsigned long) * 8)] |= 
            (1UL << (node % (sizeof(unsigned long) * 8)));
    }
}

// 显示 NUMA 信息
void show_numa_info() {
    printf("=== NUMA 系统信息 ===\n");
    
    if (numa_available() == -1) {
        printf("系统不支持 NUMA\n");
        return;
    }
    
    int max_node = numa_max_node();
    printf("最大 NUMA 节点: %d\n", max_node);
    
    printf("在线节点: ");
    for (int i = 0; i <= max_node; i++) {
        if (numa_bitmask_isbitset(numa_get_mems_allowed(), i)) {
            printf("%d ", i);
        }
    }
    printf("\n");
    
    printf("当前 CPU 所在节点: %d\n", numa_node_of_cpu(sched_getcpu()));
    printf("\n");
}

int main() {
    const size_t memory_size = 1024 * 1024;  // 1MB
    void *memory_block;
    unsigned long nodemask[16];
    unsigned long maxnode = sizeof(nodemask) * 8;
    
    printf("=== mbind 基础示例 ===\n\n");
    
    // 显示 NUMA 信息
    show_numa_info();
    
    // 检查 NUMA 支持
    if (numa_available() == -1) {
        printf("警告: 系统不支持 NUMA,使用普通内存分配\n");
        memory_block = malloc(memory_size);
        if (!memory_block) {
            perror("malloc");
            return 1;
        }
    } else {
        // 使用 mmap 分配内存以便使用 mbind
        memory_block = mmap(NULL, memory_size, PROT_READ | PROT_WRITE,
                           MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        if (memory_block == MAP_FAILED) {
            perror("mmap");
            return 1;
        }
        
        printf("分配内存块: %p - %p (大小: %zu 字节)\n", 
               memory_block, (char*)memory_block + memory_size - 1, memory_size);
        
        // 设置节点掩码(绑定到节点 0)
        set_nodemask(nodemask, maxnode, 0);
        
        printf("设置内存策略: 绑定到节点 0\n");
        
        // 使用 mbind 设置内存策略
        if (mbind(memory_block, memory_size, MPOL_BIND, 
                  nodemask, maxnode, MPOL_MF_MOVE) == -1) {
            printf("mbind 失败: %s\n", strerror(errno));
            printf("这在某些系统配置下是正常的\n");
        } else {
            printf("✓ 成功设置内存策略\n");
        }
    }
    
    // 使用内存
    memset(memory_block, 0xAA, memory_size);
    printf("已使用内存块\n");
    
    // 清理资源
    if (numa_available() != -1) {
        munmap(memory_block, memory_size);
    } else {
        free(memory_block);
    }
    
    return 0;
}

示例2:不同策略模式的使用 链接到标题

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <numaif.h>
#include <numa.h>
#include <string.h>
#include <errno.h>
#include <time.h>

// 设置多节点掩码
void set_multi_nodemask(unsigned long *nodemask, unsigned long maxnode, 
                       int *nodes, int node_count) {
    memset(nodemask, 0, (maxnode + 7) / 8);
    
    for (int i = 0; i < node_count; i++) {
        int node = nodes[i];
        if (node >= 0 && node < maxnode) {
            nodemask[node / (sizeof(unsigned long) * 8)] |= 
                (1UL << (node % (sizeof(unsigned long) * 8)));
        }
    }
}

// 显示节点掩码
void show_nodemask(const unsigned long *nodemask, unsigned long maxnode) {
    printf("节点掩码: ");
    int count = 0;
    for (unsigned long i = 0; i < maxnode; i++) {
        if (nodemask[i / (sizeof(unsigned long) * 8)] & 
            (1UL << (i % (sizeof(unsigned long) * 8)))) {
            if (count > 0) printf(",");
            printf("%lu", i);
            count++;
        }
    }
    if (count == 0) {
        printf("(无节点)");
    }
    printf("\n");
}

// 获取策略模式名称
const char* get_policy_name(int mode) {
    switch (mode) {
        case MPOL_DEFAULT: return "MPOL_DEFAULT (默认)";
        case MPOL_PREFERRED: return "MPOL_PREFERRED (优先)";
        case MPOL_BIND: return "MPOL_BIND (绑定)";
        case MPOL_INTERLEAVE: return "MPOL_INTERLEAVE (交错)";
        case MPOL_LOCAL: return "MPOL_LOCAL (本地)";
        default: return "未知策略";
    }
}

// 测试内存访问性能
double test_memory_performance(void *memory, size_t size) {
    char *ptr = (char*)memory;
    const size_t step = 4096;  // 页面大小
    const int iterations = 100;
    
    struct timespec start, end;
    clock_gettime(CLOCK_MONOTONIC, &start);
    
    // 访问内存
    for (int iter = 0; iter < iterations; iter++) {
        for (size_t i = 0; i < size; i += step) {
            ptr[i] = (char)(i ^ iter);
        }
    }
    
    clock_gettime(CLOCK_MONOTONIC, &end);
    
    double time_taken = (end.tv_sec - start.tv_sec) + 
                       (end.tv_nsec - start.tv_nsec) / 1e9;
    return time_taken;
}

void demonstrate_policies() {
    const size_t memory_size = 4 * 1024 * 1024;  // 4MB
    void *memory_block;
    unsigned long nodemask[16];
    unsigned long maxnode = sizeof(nodemask) * 8;
    
    printf("=== 不同策略模式演示 ===\n\n");
    
    if (numa_available() == -1) {
        printf("系统不支持 NUMA,跳过演示\n");
        return;
    }
    
    int max_node = numa_max_node();
    printf("系统最大 NUMA 节点: %d\n\n", max_node);
    
    if (max_node < 1) {
        printf("系统只有一个 NUMA 节点,策略差异不明显\n");
        return;
    }
    
    // 分配内存
    memory_block = mmap(NULL, memory_size, PROT_READ | PROT_WRITE,
                       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (memory_block == MAP_FAILED) {
        perror("mmap");
        return;
    }
    
    printf("分配测试内存: %zu MB\n", memory_size / (1024 * 1024));
    
    // 1. 默认策略
    printf("1. 默认策略 (MPOL_DEFAULT):\n");
    if (mbind(memory_block, memory_size, MPOL_DEFAULT, 
              NULL, maxnode, 0) == 0) {
        double time1 = test_memory_performance(memory_block, memory_size);
        printf("   访问时间: %.6f 秒\n", time1);
    } else {
        printf("   设置失败: %s\n", strerror(errno));
    }
    
    // 2. 绑定到节点 0
    printf("\n2. 绑定策略 (MPOL_BIND) - 节点 0:\n");
    set_nodemask(nodemask, maxnode, 0);
    show_nodemask(nodemask, maxnode);
    
    if (mbind(memory_block, memory_size, MPOL_BIND, 
              nodemask, maxnode, MPOL_MF_MOVE) == 0) {
        double time2 = test_memory_performance(memory_block, memory_size);
        printf("   访问时间: %.6f 秒\n", time2);
    } else {
        printf("   设置失败: %s\n", strerror(errno));
    }
    
    // 3. 交错分配到多个节点
    printf("\n3. 交错策略 (MPOL_INTERLEAVE) - 节点 0,1:\n");
    int nodes[] = {0, 1};
    set_multi_nodemask(nodemask, maxnode, nodes, 2);
    show_nodemask(nodemask, maxnode);
    
    if (mbind(memory_block, memory_size, MPOL_INTERLEAVE, 
              nodemask, maxnode, MPOL_MF_MOVE) == 0) {
        double time3 = test_memory_performance(memory_block, memory_size);
        printf("   访问时间: %.6f 秒\n", time3);
    } else {
        printf("   设置失败: %s\n", strerror(errno));
    }
    
    // 4. 优先分配到节点 1
    printf("\n4. 优先策略 (MPOL_PREFERRED) - 节点 1:\n");
    set_nodemask(nodemask, maxnode, 1);
    show_nodemask(nodemask, maxnode);
    
    if (mbind(memory_block, memory_size, MPOL_PREFERRED, 
              nodemask, maxnode, MPOL_MF_MOVE) == 0) {
        double time4 = test_memory_performance(memory_block, memory_size);
        printf("   访问时间: %.6f 秒\n", time4);
    } else {
        printf("   设置失败: %s\n", strerror(errno));
    }
    
    // 清理
    munmap(memory_block, memory_size);
}

int main() {
    printf("=== mbind 策略模式演示 ===\n\n");
    
    // 显示系统信息
    if (numa_available() != -1) {
        printf("NUMA 系统信息:\n");
        printf("  最大节点: %d\n", numa_max_node());
        printf("  在线节点: ");
        struct bitmask *mask = numa_get_mems_allowed();
        for (int i = 0; i <= numa_max_node(); i++) {
            if (numa_bitmask_isbitset(mask, i)) {
                printf("%d ", i);
            }
        }
        printf("\n");
        printf("  当前 CPU 节点: %d\n\n", numa_node_of_cpu(sched_getcpu()));
    } else {
        printf("系统不支持 NUMA\n\n");
    }
    
    // 演示不同策略
    demonstrate_policies();
    
    printf("\n=== 策略说明 ===\n");
    printf("MPOL_DEFAULT:   使用系统默认策略\n");
    printf("MPOL_PREFERRED: 优先分配到指定节点,失败时分配到其他节点\n");
    printf("MPOL_BIND:      严格绑定到指定节点集合\n");
    printf("MPOL_INTERLEAVE:在多个节点间交错分配\n");
    printf("MPOL_LOCAL:     分配到当前 CPU 所在节点\n");
    
    return 0;
}

示例3:完整的 NUMA 内存管理工具 链接到标题

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <numaif.h>
#include <numa.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <time.h>

// 全局配置
struct numa_config {
    size_t memory_size;
    int policy_mode;
    int *target_nodes;
    int node_count;
    int flags;
    int verbose;
};

// 设置节点掩码
int set_nodemask_from_config(unsigned long *nodemask, unsigned long maxnode, 
                            const struct numa_config *config) {
    memset(nodemask, 0, (maxnode + 7) / 8);
    
    if (config->node_count == 0) {
        return 0;  // 无节点指定
    }
    
    for (int i = 0; i < config->node_count; i++) {
        int node = config->target_nodes[i];
        if (node >= 0 && node < maxnode) {
            nodemask[node / (sizeof(unsigned long) * 8)] |= 
                (1UL << (node % (sizeof(unsigned long) * 8)));
        } else {
            fprintf(stderr, "警告: 节点 %d 超出范围 [0-%lu]\n", node, maxnode - 1);
        }
    }
    
    return 0;
}

// 显示配置信息
void show_config(const struct numa_config *config) {
    printf("内存大小: %zu MB (%zu 字节)\n", 
           config->memory_size / (1024 * 1024), config->memory_size);
    
    printf("策略模式: ");
    switch (config->policy_mode) {
        case MPOL_DEFAULT: printf("默认\n"); break;
        case MPOL_PREFERRED: printf("优先\n"); break;
        case MPOL_BIND: printf("绑定\n"); break;
        case MPOL_INTERLEAVE: printf("交错\n"); break;
        case MPOL_LOCAL: printf("本地\n"); break;
        default: printf("未知 (%d)\n", config->policy_mode); break;
    }
    
    printf("目标节点: ");
    if (config->node_count == 0) {
        printf("无指定\n");
    } else {
        for (int i = 0; i < config->node_count; i++) {
            printf("%d ", config->target_nodes[i]);
        }
        printf("\n");
    }
    
    printf("标志位: ");
    if (config->flags == 0) {
        printf("无\n");
    } else {
        if (config->flags & MPOL_MF_STRICT) printf("STRICT ");
        if (config->flags & MPOL_MF_MOVE) printf("MOVE ");
        if (config->flags & MPOL_MF_MOVE_ALL) printf("MOVE_ALL ");
        printf("\n");
    }
}

// 显示 NUMA 系统信息
void show_numa_system_info() {
    printf("=== NUMA 系统信息 ===\n");
    
    if (numa_available() == -1) {
        printf("系统不支持 NUMA\n");
        return;
    }
    
    int max_node = numa_max_node();
    printf("最大 NUMA 节点: %d\n", max_node);
    
    printf("在线节点: ");
    struct bitmask *online_mask = numa_get_mems_allowed();
    for (int i = 0; i <= max_node; i++) {
        if (numa_bitmask_isbitset(online_mask, i)) {
            printf("%d ", i);
        }
    }
    printf("\n");
    
    printf("当前 CPU 所在节点: %d\n", numa_node_of_cpu(sched_getcpu()));
    
    // 显示各节点内存信息
    printf("节点内存信息:\n");
    for (int i = 0; i <= max_node; i++) {
        if (numa_bitmask_isbitset(online_mask, i)) {
            long long free_mem = numa_node_size64(i, NULL);
            if (free_mem >= 0) {
                printf("  节点 %d: 可用内存 %.2f GB\n", 
                       i, (double)free_mem / (1024 * 1024 * 1024));
            }
        }
    }
    printf("\n");
}

// 应用 NUMA 策略
int apply_numa_policy(void *memory, size_t size, const struct numa_config *config) {
    if (numa_available() == -1) {
        printf("系统不支持 NUMA,跳过策略设置\n");
        return 0;
    }
    
    unsigned long nodemask[64];  // 支持最多 64 * sizeof(long) * 8 个节点
    unsigned long maxnode = sizeof(nodemask) * 8;
    
    // 设置节点掩码
    if (set_nodemask_from_config(nodemask, maxnode, config) != 0) {
        return -1;
    }
    
    // 应用策略
    if (config->verbose) {
        printf("应用策略到内存区域 %p - %p\n", memory, (char*)memory + size - 1);
        printf("策略模式: %d\n", config->policy_mode);
        printf("节点掩码: ");
        int count = 0;
        for (unsigned long i = 0; i < maxnode; i++) {
            if (nodemask[i / (sizeof(unsigned long) * 8)] & 
                (1UL << (i % (sizeof(unsigned long) * 8)))) {
                if (count > 0) printf(",");
                printf("%lu", i);
                count++;
            }
        }
        if (count == 0) printf("(无)");
        printf("\n");
    }
    
    int result = mbind(memory, size, config->policy_mode, 
                      nodemask, maxnode, config->flags);
    
    if (result == -1) {
        fprintf(stderr, "mbind 失败: %s\n", strerror(errno));
        return -1;
    }
    
    if (config->verbose) {
        printf("✓ 策略应用成功\n");
    }
    
    return 0;
}

// 显示帮助信息
void show_help(const char *program_name) {
    printf("用法: %s [选项]\n", program_name);
    printf("\n选项:\n");
    printf("  -s, --size=SIZE        内存大小 (默认 100MB)\n");
    printf("  -p, --policy=MODE      策略模式\n");
    printf("                         default, preferred, bind, interleave, local\n");
    printf("  -n, --nodes=LIST       目标节点列表 (逗号分隔)\n");
    printf("  -f, --flags=FLAGS      标志位 (strict, move, move_all)\n");
    printf("  -v, --verbose          显示详细信息\n");
    printf("  -i, --info             显示 NUMA 系统信息\n");
    printf("  -h, --help             显示此帮助信息\n");
    printf("\n示例:\n");
    printf("  %s -s 500M -p bind -n 0,1     # 绑定到节点 0,1\n");
    printf("  %s -p preferred -n 1 -f move  # 优先节点 1,移动页面\n");
    printf("  %s -p interleave -n 0,1,2,3   # 交错分配到 4 个节点\n");
    printf("  %s -i                         # 显示系统 NUMA 信息\n");
}

int main(int argc, char *argv[]) {
    struct numa_config config = {
        .memory_size = 100 * 1024 * 1024,  // 100MB
        .policy_mode = MPOL_DEFAULT,
        .target_nodes = NULL,
        .node_count = 0,
        .flags = 0,
        .verbose = 0
    };
    
    int show_info = 0;
    int *temp_nodes = NULL;
    int temp_node_count = 0;
    
    printf("=== NUMA 内存策略管理工具 ===\n\n");
    
    // 解析命令行参数
    static struct option long_options[] = {
        {"size",    required_argument, 0, 's'},
        {"policy",  required_argument, 0, 'p'},
        {"nodes",   required_argument, 0, 'n'},
        {"flags",   required_argument, 0, 'f'},
        {"verbose", no_argument,       0, 'v'},
        {"info",    no_argument,       0, 'i'},
        {"help",    no_argument,       0, 'h'},
        {0, 0, 0, 0}
    };
    
    int opt;
    while ((opt = getopt_long(argc, argv, "s:p:n:f:ivh", long_options, NULL)) != -1) {
        switch (opt) {
            case 's': {
                char *endptr;
                config.memory_size = strtoul(optarg, &endptr, 10);
                if (*endptr == 'G' || *endptr == 'g') {
                    config.memory_size *= 1024 * 1024 * 1024;
                } else if (*endptr == 'M' || *endptr == 'm') {
                    config.memory_size *= 1024 * 1024;
                } else if (*endptr == 'K' || *endptr == 'k') {
                    config.memory_size *= 1024;
                }
                break;
            }
            case 'p':
                if (strcmp(optarg, "default") == 0) {
                    config.policy_mode = MPOL_DEFAULT;
                } else if (strcmp(optarg, "preferred") == 0) {
                    config.policy_mode = MPOL_PREFERRED;
                } else if (strcmp(optarg, "bind") == 0) {
                    config.policy_mode = MPOL_BIND;
                } else if (strcmp(optarg, "interleave") == 0) {
                    config.policy_mode = MPOL_INTERLEAVE;
                } else if (strcmp(optarg, "local") == 0) {
                    config.policy_mode = MPOL_LOCAL;
                } else {
                    fprintf(stderr, "错误: 未知策略模式 '%s'\n", optarg);
                    return 1;
                }
                break;
            case 'n': {
                // 解析节点列表
                char *node_str = strtok(optarg, ",");
                while (node_str && temp_node_count < 64) {
                    temp_nodes = realloc(temp_nodes, (temp_node_count + 1) * sizeof(int));
                    temp_nodes[temp_node_count] = atoi(node_str);
                    temp_node_count++;
                    node_str = strtok(NULL, ",");
                }
                config.target_nodes = temp_nodes;
                config.node_count = temp_node_count;
                break;
            }
            case 'f':
                if (strstr(optarg, "strict")) config.flags |= MPOL_MF_STRICT;
                if (strstr(optarg, "move_all")) config.flags |= MPOL_MF_MOVE_ALL;
                else if (strstr(optarg, "move")) config.flags |= MPOL_MF_MOVE;
                break;
            case 'v':
                config.verbose = 1;
                break;
            case 'i':
                show_info = 1;
                break;
            case 'h':
                show_help(argv[0]);
                free(temp_nodes);
                return 0;
            default:
                fprintf(stderr, "使用 '%s --help' 查看帮助信息\n", argv[0]);
                free(temp_nodes);
                return 1;
        }
    }
    
    // 显示系统信息
    if (show_info) {
        show_numa_system_info();
    }
    
    // 检查是否需要分配内存
    if (optind >= argc && !show_info) {
        if (config.verbose) {
            printf("配置信息:\n");
            show_config(&config);
            printf("\n");
        }
        
        // 检查 NUMA 支持
        if (numa_available() == -1) {
            printf("警告: 系统不支持 NUMA\n");
            if (config.policy_mode != MPOL_DEFAULT) {
                printf("注意: NUMA 策略设置将被忽略\n");
            }
        } else {
            printf("NUMA 系统: 支持\n");
        }
        
        // 分配内存
        void *memory_block;
        if (numa_available() != -1) {
            memory_block = mmap(NULL, config.memory_size, PROT_READ | PROT_WRITE,
                               MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
            if (memory_block == MAP_FAILED) {
                perror("mmap");
                free(temp_nodes);
                return 1;
            }
        } else {
            memory_block = malloc(config.memory_size);
            if (!memory_block) {
                perror("malloc");
                free(temp_nodes);
                return 1;
            }
        }
        
        printf("分配内存: %p - %p (大小: %zu MB)\n", 
               memory_block, (char*)memory_block + config.memory_size - 1,
               config.memory_size / (1024 * 1024));
        
        // 应用 NUMA 策略
        if (apply_numa_policy(memory_block, config.memory_size, &config) == 0) {
            printf("✓ NUMA 策略应用成功\n");
        } else {
            printf("✗ NUMA 策略应用失败\n");
        }
        
        // 使用内存
        printf("使用内存...\n");
        memset(memory_block, 0xAA, config.memory_size);
        printf("✓ 内存使用完成\n");
        
        // 清理资源
        if (numa_available() != -1) {
            munmap(memory_block, config.memory_size);
        } else {
            free(memory_block);
        }
    }
    
    free(temp_nodes);
    
    printf("\n=== 使用建议 ===\n");
    printf("1. MPOL_BIND: 用于关键应用,确保内存分配在指定节点\n");
    printf("2. MPOL_PREFERRED: 用于一般应用,优先但不强制\n");
    printf("3. MPOL_INTERLEAVE: 用于大数据应用,均匀分布内存\n");
    printf("4. MPOL_LOCAL: 用于延迟敏感应用,就近分配\n");
    printf("\n");
    printf("注意事项:\n");
    printf("1. 需要 NUMA 支持的硬件和内核\n");
    printf("2. 某些策略需要 root 权限\n");
    printf("3. 大内存区域的策略设置可能耗时较长\n");
    
    return 0;
}

编译和运行说明 链接到标题

# 编译示例程序(需要 libnuma)
gcc -o mbind_example1 example1.c -lnuma
gcc -o mbind_example2 example2.c -lnuma
gcc -o mbind_example3 example3.c -lnuma

# 如果系统没有 libnuma,可以尝试:
gcc -o mbind_example1 example1.c
gcc -o mbind_example2 example2.c

# 运行示例
./mbind_example1
./mbind_example2
./mbind_example3 --help
./mbind_example3 -i
./mbind_example3 -s 100M -p bind -n 0,1

安装 libnuma(如果需要) 链接到标题

# Ubuntu/Debian
sudo apt-get install libnuma-dev

# CentOS/RHEL
sudo yum install numactl-devel

# Fedora
sudo dnf install numactl-devel

系统要求检查 链接到标题

# 检查 NUMA 支持
lscpu | grep -i numa

# 查看 NUMA 拓扑
numactl --hardware

# 检查内核支持
grep -i numa /boot/config-$(uname -r)

# 查看当前 NUMA 状态
cat /proc/cpuinfo | grep -i numa

重要注意事项 链接到标题

  1. 系统要求: 需要 NUMA 支持的硬件和内核
  2. 库依赖: 通常需要链接 libnuma 库
  3. 权限要求: 某些操作可能需要 root 权限
  4. 内存分配: 建议使用 mmap 而不是 malloc
  5. 错误处理: 始终检查返回值和 errno

实际应用场景 链接到标题

  1. 高性能计算: 优化大规模数值计算的内存访问
  2. 数据库系统: 将数据分配到合适的 NUMA 节点
  3. Web 服务器: 优化多线程应用的内存局部性
  4. 科学计算: 大型矩阵运算的内存布局优化
  5. 虚拟化环境: 为虚拟机合理分配物理内存节点

策略模式详细说明 链接到标题

// 策略模式使用示例
void explain_policies() {
    printf("NUMA 策略模式详解:\n");
    printf("1. MPOL_DEFAULT:\n");
    printf("   - 使用系统默认内存分配策略\n");
    printf("   - 适用于一般应用\n\n");
    
    printf("2. MPOL_PREFERRED:\n");
    printf("   - 优先在指定节点分配内存\n");
    printf("   - 如果指定节点不可用,则在其他节点分配\n");
    printf("   - 适用于希望优先使用特定节点但能容忍其他节点的应用\n\n");
    
    printf("3. MPOL_BIND:\n");
    printf("   - 严格限制只能在指定节点集合中分配内存\n");
    printf("   - 如果指定节点都不可用,则分配失败\n");
    printf("   - 适用于对内存位置有严格要求的应用\n\n");
    
    printf("4. MPOL_INTERLEAVE:\n");
    printf("   - 在多个节点间交错分配内存\n");
    printf("   - 适用于大内存应用,可以平衡各节点负载\n\n");
    
    printf("5. MPOL_LOCAL:\n");
    printf("   - 总是在进程运行的本地节点分配内存\n");
    printf("   - 适用于延迟敏感的应用\n");
}

最佳实践 链接到标题

// 安全的 NUMA 策略设置
int safe_mbind(void *addr, size_t len, int mode,
               const unsigned long *nodemask, unsigned long maxnode, unsigned flags) {
    // 检查 NUMA 支持
    if (numa_available() == -1) {
        errno = ENOSYS;
        return -1;
    }
    
    // 验证参数
    if (!addr || len == 0) {
        errno = EINVAL;
        return -1;
    }
    
    // 检查内存区域是否有效
    if (access((char*)addr, R_OK) == -1) {
        return -1;
    }
    
    // 应用策略
    int result = mbind(addr, len, mode, nodemask, maxnode, flags);
    
    // 处理常见错误
    if (result == -1) {
        switch (errno) {
            case EPERM:
                printf("警告: 权限不足,可能需要 root 权限\n");
                break;
            case ENOMEM:
                printf("警告: 内存不足\n");
                break;
        }
    }
    
    return result;
}

// 获取当前内存策略
int get_current_policy(void *addr, size_t len, int *mode, 
                      unsigned long *nodemask, unsigned long maxnode) {
    return get_mempolicy(mode, nodemask, maxnode, addr, MPOL_F_ADDR);
}

这些示例展示了 mbind 函数的各种使用方法,从基础的策略设置到完整的 NUMA 内存管理工具,帮助你全面掌握 Linux NUMA 内存管理机制。