set_mempolicy系统调用及示例

set_mempolicy系统调用及示例

set_mempolicy 是Linux系统调用,用于设置进程或内存区域的内存分配策略。它是NUMA(Non-Uniform Memory Access)系统中重要的内存管理工具,允许应用程序指定内存分配的节点偏好,优化内存访问性能。通过合理的内存策略设置,可以显著提高NUMA系统的性能。

  1. 函数介绍

set_mempolicy 是Linux系统调用,用于设置进程或内存区域的内存分配策略。它是NUMA(Non-Uniform Memory Access)系统中重要的内存管理工具,允许应用程序指定内存分配的节点偏好,优化内存访问性能。通过合理的内存策略设置,可以显著提高NUMA系统的性能。

data-ad-format="fluid" data-ad-layout-key="-7k+ex-4a-9w+4a">

https://www.calcguide.tech/2025/08/23/set-mempolicy系统调用及示例/

set_mempolicy系统调用及示例-CSDN博客

  1. 函数原型
1
2
3
4
#include <numaif.h>
long set_mempolicy(int mode, const unsigned long *nodemask,
unsigned long maxnode);

  1. 功能

set_mempolicy 设置当前进程的默认内存分配策略,影响后续的内存分配操作。它支持多种内存分配模式,允许指定特定的NUMA节点,帮助应用程序优化内存访问模式,减少跨节点内存访问的开销。

  1. 参数
  • int mode: 内存分配模式

  • *const unsigned long nodemask: NUMA节点掩码(可为NULL)

  • unsigned long maxnode: 节点掩码中的最大节点数

  1. 返回值
  • 成功: 返回0

  • 失败: 返回-1,并设置errno

  1. 相似函数,或关联函数
  • get_mempolicy: 获取当前内存策略

  • mbind: 为特定内存区域设置策略

  • migrate_pages: 迁移进程页面到指定节点

  • numa_*: NUMA库函数

  1. 示例代码

示例1:基础set_mempolicy使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <numaif.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

/**
* 检查系统NUMA支持
*/
int check_numa_support() {
long max_nodes = sysconf(_SC_NPROCESSORS_ONLN);
printf("=== NUMA支持检查 ===\n");
printf("在线CPU数: %ld\n", max_nodes);

// 检查是否支持NUMA
int ret = get_mempolicy(NULL, NULL, 0, 0, 0);
if (ret == -1 && errno == ENOSYS) {
printf("系统不支持NUMA内存策略\n");
return -1;
}

printf("系统支持NUMA内存策略\n");
return 0;
}

/**
* 演示基础set_mempolicy使用方法
*/
int demo_set_mempolicy_basic() {
int mode;
unsigned long nodemask;
int ret;

printf("=== 基础set_mempolicy使用示例 ===\n");

// 检查NUMA支持
if (check_numa_support() != 0) {
return 0; // 不支持NUMA时正常退出
}

// 获取当前内存策略
ret = get_mempolicy(&mode, &nodemask, sizeof(nodemask) * 8, 0, 0);
if (ret == 0) {
printf("当前内存策略模式: %d\n", mode);
printf("当前节点掩码: 0x%lx\n", nodemask);
}

// 设置默认内存策略为MPOL_PREFERRED(首选节点)
printf("\n1. 设置首选节点策略:\n");
unsigned long preferred_node = 0; // 首选节点0
ret = set_mempolicy(MPOL_PREFERRED, &preferred_node, sizeof(preferred_node) * 8);
if (ret == 0) {
printf(" 成功设置首选节点策略,首选节点: %lu\n", preferred_node);
} else {
printf(" 设置首选节点策略失败: %s\n", strerror(errno));
if (errno == EINVAL) {
printf(" 可能的原因:系统不支持指定的策略或节点\n");
}
}

// 设置策略为MPOL_BIND(绑定节点)
printf("\n2. 设置绑定节点策略:\n");
unsigned long bind_nodes = 0x3; // 绑定到节点0和1
ret = set_mempolicy(MPOL_BIND, &bind_nodes, sizeof(bind_nodes) * 8);
if (ret == 0) {
printf(" 成功设置绑定节点策略,绑定节点: 0x%lx\n", bind_nodes);
} else {
printf(" 设置绑定节点策略失败: %s\n", strerror(errno));
}

// 设置策略为MPOL_INTERLEAVE(交错分配)
printf("\n3. 设置交错分配策略:\n");
unsigned long interleave_nodes = 0xF; // 交错分配到节点0-3
ret = set_mempolicy(MPOL_INTERLEAVE, &interleave_nodes, sizeof(interleave_nodes) * 8);
if (ret == 0) {
printf(" 成功设置交错分配策略,节点: 0x%lx\n", interleave_nodes);
} else {
printf(" 设置交错分配策略失败: %s\n", strerror(errno));
}

// 恢复默认策略
printf("\n4. 恢复默认策略:\n");
ret = set_mempolicy(MPOL_DEFAULT, NULL, 0);
if (ret == 0) {
printf(" 成功恢复默认内存策略\n");
} else {
printf(" 恢复默认策略失败: %s\n", strerror(errno));
}

return 0;
}

int main() {
return demo_set_mempolicy_basic();
}

示例2:不同内存策略演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include <numaif.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <malloc.h>

/**
* 显示当前内存策略
*/
void show_current_policy() {
int mode;
unsigned long nodemask = 0;
long maxnode = sizeof(nodemask) * 8;

if (get_mempolicy(&mode, &nodemask, maxnode, 0, 0) == 0) {
printf("当前策略: ");
switch (mode) {
case MPOL_DEFAULT:
printf("MPOL_DEFAULT (默认策略)\n");
break;
case MPOL_PREFERRED:
printf("MPOL_PREFERRED (首选节点)\n");
break;
case MPOL_BIND:
printf("MPOL_BIND (绑定节点)\n");
break;
case MPOL_INTERLEAVE:
printf("MPOL_INTERLEAVE (交错分配)\n");
break;
default:
printf("未知模式 (%d)\n", mode);
break;
}
if (nodemask != 0) {
printf("节点掩码: 0x%lx\n", nodemask);
}
}
}

/**
* 分配内存并检查分配位置
*/
void* allocate_and_check_memory(size_t size) {
void *ptr = malloc(size);
if (!ptr) {
printf("内存分配失败\n");
return NULL;
}

// 检查内存分配的节点位置(需要NUMA库支持)
printf(" 分配 %zu 字节内存\n", size);

return ptr;
}

/**
* 演示不同内存策略
*/
int demo_memory_policies() {
void *memory_blocks&#91;5];

printf("=== 不同内存策略演示 ===\n");

// 检查NUMA支持
if (get_mempolicy(NULL, NULL, 0, 0, 0) == -1 && errno == ENOSYS) {
printf("系统不支持NUMA,跳过演示\n");
return 0;
}

printf("系统支持NUMA内存策略\n\n");

// 1. 默认策略
printf("1. 默认策略 (MPOL_DEFAULT):\n");
show_current_policy();
memory_blocks&#91;0] = allocate_and_check_memory(1024 * 1024); // 1MB

// 2. 首选节点策略
printf("\n2. 首选节点策略 (MPOL_PREFERRED):\n");
unsigned long preferred_node = 0;
if (set_mempolicy(MPOL_PREFERRED, &preferred_node, sizeof(preferred_node) * 8) == 0) {
show_current_policy();
memory_blocks&#91;1] = allocate_and_check_memory(1024 * 1024);
} else {
printf(" 设置首选节点策略失败: %s\n", strerror(errno));
}

// 3. 绑定节点策略
printf("\n3. 绑定节点策略 (MPOL_BIND):\n");
unsigned long bind_nodes = 0x3; // 节点0和1
if (set_mempolicy(MPOL_BIND, &bind_nodes, sizeof(bind_nodes) * 8) == 0) {
show_current_policy();
memory_blocks&#91;2] = allocate_and_check_memory(1024 * 1024);
} else {
printf(" 设置绑定节点策略失败: %s\n", strerror(errno));
}

// 4. 交错分配策略
printf("\n4. 交错分配策略 (MPOL_INTERLEAVE):\n");
unsigned long interleave_nodes = 0xF; // 节点0-3
if (set_mempolicy(MPOL_INTERLEAVE, &interleave_nodes, sizeof(interleave_nodes) * 8) == 0) {
show_current_policy();
memory_blocks&#91;3] = allocate_and_check_memory(4 * 1024 * 1024); // 4MB
} else {
printf(" 设置交错分配策略失败: %s\n", strerror(errno));
}

// 5. 恢复默认策略
printf("\n5. 恢复默认策略:\n");
if (set_mempolicy(MPOL_DEFAULT, NULL, 0) == 0) {
show_current_policy();
memory_blocks&#91;4] = allocate_and_check_memory(1024 * 1024);
} else {
printf(" 恢复默认策略失败: %s\n", strerror(errno));
}

// 释放内存
for (int i = 0; i < 5; i++) {
if (memory_blocks&#91;i]) {
free(memory_blocks&#91;i]);
}
}

return 0;
}

int main() {
return demo_memory_policies();
}

示例3:NUMA感知内存分配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include <numaif.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sched.h>

/**
* 获取系统NUMA信息
*/
void get_numa_info() {
printf("=== 系统NUMA信息 ===\n");

// 获取CPU数量
long nprocs = sysconf(_SC_NPROCESSORS_ONLN);
printf("在线CPU数: %ld\n", nprocs);

// 获取页面大小
long page_size = sysconf(_SC_PAGESIZE);
printf("页面大小: %ld 字节\n", page_size);

// 显示当前CPU亲和性
cpu_set_t cpuset;
if (sched_getaffinity(0, sizeof(cpuset), &cpuset) == 0) {
printf("当前CPU亲和性: ");
for (int i = 0; i < CPU_SETSIZE && i < 64; i++) {
if (CPU_ISSET(i, &cpuset)) {
printf("%d ", i);
}
}
printf("\n");
}
}

/**
* NUMA感知的大内存分配
*/
int demo_numa_aware_allocation() {
const size_t large_size = 100 * 1024 * 1024; // 100MB
char *large_buffer;
int ret;

printf("=== NUMA感知内存分配演示 ===\n");

// 检查NUMA支持
if (get_mempolicy(NULL, NULL, 0, 0, 0) == -1 && errno == ENOSYS) {
printf("系统不支持NUMA,使用默认分配\n");
large_buffer = malloc(large_size);
if (large_buffer) {
printf("成功分配 %zu MB 内存\n", large_size / (1024 * 1024));
free(large_buffer);
}
return 0;
}

get_numa_info();

printf("\n1. 使用默认策略分配大内存:\n");
show_current_policy();
large_buffer = malloc(large_size);
if (large_buffer) {
printf(" 成功分配 %zu MB 内存\n", large_size / (1024 * 1024));
// 初始化内存以确保实际分配
memset(large_buffer, 0, 1024);
free(large_buffer);
}

printf("\n2. 设置首选节点策略后分配:\n");
unsigned long preferred_node = 0;
ret = set_mempolicy(MPOL_PREFERRED, &preferred_node, sizeof(preferred_node) * 8);
if (ret == 0) {
show_current_policy();
large_buffer = malloc(large_size);
if (large_buffer) {
printf(" 成功分配 %zu MB 内存(倾向节点 %lu)\n",
large_size / (1024 * 1024), preferred_node);
memset(large_buffer, 0, 1024);
free(large_buffer);
}
}

printf("\n3. 设置绑定策略后分配:\n");
unsigned long bind_nodes = 0x1; // 仅绑定到节点0
ret = set_mempolicy(MPOL_BIND, &bind_nodes, sizeof(bind_nodes) * 8);
if (ret == 0) {
show_current_policy();
large_buffer = malloc(large_size);
if (large_buffer) {
printf(" 成功分配 %zu MB 内存(绑定到节点 0x%lx)\n",
large_size / (1024 * 1024), bind_nodes);
memset(large_buffer, 0, 1024);
free(large_buffer);
}
}

printf("\n4. 设置交错策略后分配:\n");
unsigned long interleave_nodes = 0x3; // 交错到节点0和1
ret = set_mempolicy(MPOL_INTERLEAVE, &interleave_nodes, sizeof(interleave_nodes) * 8);
if (ret == 0) {
show_current_policy();
large_buffer = malloc(large_size);
if (large_buffer) {
printf(" 成功分配 %zu MB 内存(交错到节点 0x%lx)\n",
large_size / (1024 * 1024), interleave_nodes);
memset(large_buffer, 0, 1024);
free(large_buffer);
}
}

// 恢复默认策略
set_mempolicy(MPOL_DEFAULT, NULL, 0);

return 0;
}

int main() {
return demo_numa_aware_allocation();
}

示例4:多线程NUMA策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <numaif.h>
#include <pthread.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sched.h>

/**
* 线程数据结构
*/
typedef struct {
int thread_id;
int preferred_node;
size_t alloc_size;
void *memory;
int result;
} thread_data_t;

/**
* 线程函数:设置NUMA策略并分配内存
*/
void* thread_function(void *arg) {
thread_data_t *data = (thread_data_t*)arg;

printf("线程 %d 启动,设置首选节点 %d\n", data->thread_id, data->preferred_node);

// 设置线程的NUMA策略
unsigned long preferred_node = data->preferred_node;
if (set_mempolicy(MPOL_PREFERRED, &preferred_node, sizeof(preferred_node) * 8) != 0) {
printf("线程 %d: 设置策略失败: %s\n", data->thread_id, strerror(errno));
data->result = -1;
return NULL;
}

// 分配内存
data->memory = malloc(data->alloc_size);
if (data->memory) {
printf("线程 %d: 成功分配 %zu KB 内存\n",
data->thread_id, data->alloc_size / 1024);

// 初始化内存
memset(data->memory, data->thread_id, 1024);
data->result = 0;
} else {
printf("线程 %d: 内存分配失败\n", data->thread_id);
data->result = -1;
}

return NULL;
}

/**
* 演示多线程NUMA策略
*/
int demo_multithread_numa() {
const int num_threads = 4;
pthread_t threads&#91;num_threads];
thread_data_t thread_data&#91;num_threads];

printf("=== 多线程NUMA策略演示 ===\n");

// 检查NUMA支持
if (get_mempolicy(NULL, NULL, 0, 0, 0) == -1 && errno == ENOSYS) {
printf("系统不支持NUMA,跳过多线程演示\n");
return 0;
}

// 初始化线程数据
for (int i = 0; i < num_threads; i++) {
thread_data&#91;i].thread_id = i;
thread_data&#91;i].preferred_node = i % 2; // 交替使用节点0和1
thread_data&#91;i].alloc_size = (1024 + i * 512) * 1024; // 1-3MB
thread_data&#91;i].memory = NULL;
thread_data&#91;i].result = 0;
}

// 创建线程
printf("创建 %d 个线程,每个线程使用不同的NUMA节点策略\n", num_threads);

for (int i = 0; i < num_threads; i++) {
if (pthread_create(&threads&#91;i], NULL, thread_function, &thread_data&#91;i]) != 0) {
printf("创建线程 %d 失败\n", i);
return -1;
}
}

// 等待所有线程完成
for (int i = 0; i < num_threads; i++) {
pthread_join(threads&#91;i], NULL);
printf("线程 %d 完成,结果: %s\n",
i, thread_data&#91;i].result == 0 ? "成功" : "失败");
}

// 释放内存
for (int i = 0; i < num_threads; i++) {
if (thread_data&#91;i].memory) {
free(thread_data&#91;i].memory);
}
}

// 显示最终策略
printf("\n主线程最终策略:\n");
show_current_policy();

return 0;
}

// 辅助函数声明
void show_current_policy();

int main() {
return demo_multithread_numa();
}

void show_current_policy() {
int mode;
unsigned long nodemask = 0;
long maxnode = sizeof(nodemask) * 8;

if (get_mempolicy(&mode, &nodemask, maxnode, 0, 0) == 0) {
printf("当前策略模式: %d", mode);
switch (mode) {
case MPOL_DEFAULT: printf(" (默认)"); break;
case MPOL_PREFERRED: printf(" (首选)"); break;
case MPOL_BIND: printf(" (绑定)"); break;
case MPOL_INTERLEAVE: printf(" (交错)"); break;
}
printf(", 节点掩码: 0x%lx\n", nodemask);
}
}

示例5:性能优化示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#include <numaif.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

/**
* 性能测试结构
*/
typedef struct {
const char *name;
int mode;
unsigned long nodemask;
double time_taken;
size_t memory_accessed;
} perf_test_t;

/**
* 内存访问性能测试
*/
double test_memory_access_performance(size_t size, int iterations) {
char *buffer;
struct timeval start, end;

// 分配测试内存
buffer = malloc(size);
if (!buffer) {
printf("内存分配失败\n");
return -1;
}

// 初始化内存
memset(buffer, 0, size);

// 开始性能测试
gettimeofday(&start, NULL);

// 执行内存访问测试
for (int i = 0; i < iterations; i++) {
// 顺序访问内存
for (size_t j = 0; j < size; j += 64) { // 64字节步长
buffer&#91;j] = (buffer&#91;j] + 1) % 256;
}
}

gettimeofday(&end, NULL);

// 计算耗时
double elapsed = (end.tv_sec - start.tv_sec) +
(end.tv_usec - start.tv_usec) / 1000000.0;

free(buffer);
return elapsed;
}

/**
* 演示不同策略的性能影响
*/
int demo_performance_impact() {
const size_t test_size = 50 * 1024 * 1024; // 50MB
const int iterations = 10;
perf_test_t tests&#91;4];

printf("=== NUMA策略性能影响演示 ===\n");
printf("测试内存大小: %zu MB\n", test_size / (1024 * 1024));
printf("测试迭代次数: %d\n", iterations);

// 检查NUMA支持
if (get_mempolicy(NULL, NULL, 0, 0, 0) == -1 && errno == ENOSYS) {
printf("系统不支持NUMA,跳过性能测试\n");
return 0;
}

// 初始化测试配置
tests&#91;0].name = "默认策略";
tests&#91;0].mode = MPOL_DEFAULT;
tests&#91;0].nodemask = 0;

tests&#91;1].name = "首选节点0";
tests&#91;1].mode = MPOL_PREFERRED;
tests&#91;1].nodemask = 0x1;

tests&#91;2].name = "绑定节点0";
tests&#91;2].mode = MPOL_BIND;
tests&#91;2].nodemask = 0x1;

tests&#91;3].name = "交错节点0-1";
tests&#91;3].mode = MPOL_INTERLEAVE;
tests&#91;3].nodemask = 0x3;

// 执行性能测试
for (int i = 0; i < 4; i++) {
printf("\n测试 %d: %s\n", i + 1, tests&#91;i].name);

// 设置内存策略
if (tests&#91;i].mode == MPOL_DEFAULT) {
if (set_mempolicy(MPOL_DEFAULT, NULL, 0) != 0) {
printf(" 设置策略失败: %s\n", strerror(errno));
continue;
}
} else {
if (set_mempolicy(tests&#91;i].mode, &tests&#91;i].nodemask,
sizeof(tests&#91;i].nodemask) * 8) != 0) {
printf(" 设置策略失败: %s\n", strerror(errno));
continue;
}
}

// 显示当前策略
show_current_policy();

// 执行性能测试
tests&#91;i].time_taken = test_memory_access_performance(test_size, iterations);
tests&#91;i].memory_accessed = test_size * iterations;

if (tests&#91;i].time_taken > 0) {
double bandwidth = (tests&#91;i].memory_accessed / (1024.0 * 1024.0)) /
tests&#91;i].time_taken;
printf(" 测试完成: %.3f 秒, 带宽: %.2f MB/s\n",
tests&#91;i].time_taken, bandwidth);
} else {
printf(" 测试失败\n");
}
}

// 显示性能对比结果
printf("\n=== 性能对比结果 ===\n");
double baseline_time = tests&#91;0].time_taken;

for (int i = 0; i < 4; i++) {
if (tests&#91;i].time_taken > 0) {
printf("%-15s: %.3f 秒", tests&#91;i].name, tests&#91;i].time_taken);
if (i > 0 && baseline_time > 0) {
double improvement = (baseline_time - tests&#91;i].time_taken) /
baseline_time * 100;
printf(" (%+.1f%%)", improvement);
}
printf("\n");
}
}

// 恢复默认策略
set_mempolicy(MPOL_DEFAULT, NULL, 0);

return 0;
}

void show_current_policy() {
int mode;
unsigned long nodemask = 0;
long maxnode = sizeof(nodemask) * 8;

if (get_mempolicy(&mode, &nodemask, maxnode, 0, 0) == 0) {
printf(" 当前策略: ");
switch (mode) {
case MPOL_DEFAULT: printf("默认"); break;
case MPOL_PREFERRED: printf("首选节点"); break;
case MPOL_BIND: printf("绑定节点"); break;
case MPOL_INTERLEAVE: printf("交错分配"); break;
default: printf("未知(%d)", mode); break;
}
if (nodemask != 0) {
printf(" (节点掩码: 0x%lx)", nodemask);
}
printf("\n");
}
}

int main() {
return demo_performance_impact();
}

set_mempolicy 使用注意事项

系统要求:

内核版本: 需要支持NUMA的Linux内核(2.6.7+)

硬件支持: 需要NUMA架构的硬件平台

编译选项: 需要链接NUMA库(-lnuma)

策略模式详解:

MPOL_DEFAULT: 使用系统默认策略

MPOL_PREFERRED: 首选指定节点,失败时使用其他节点

MPOL_BIND: 严格绑定到指定节点

MPOL_INTERLEAVE: 在指定节点间交错分配

参数验证:

mode有效性: 确保mode参数是有效的策略模式

nodemask合法性: 确保节点掩码指定的节点存在

maxnode范围: 确保不超过系统支持的最大节点数

错误处理:

ENOSYS: 系统不支持NUMA策略

EINVAL: 参数无效(模式或节点掩码)

ENOMEM: 内存不足

EPERM: 权限不足

性能考虑:

策略选择: 根据应用访问模式选择合适策略

节点亲和: 考虑CPU和内存节点的拓扑关系

内存局部性: 优化数据访问的局部性

最佳实践:

测试验证: 在实际硬件上测试策略效果

渐进应用: 从简单策略开始逐步优化

监控调优: 监控性能指标并调整策略

兼容处理: 处理不支持NUMA的系统环境

NUMA策略模式详解

MPOL_DEFAULT(默认模式):

  • 行为: 使用系统默认的内存分配策略

  • 特点: 不指定特定节点偏好

  • 适用: 一般应用或不确定优化方向时

MPOL_PREFERRED(首选模式):

  • 行为: 优先在指定节点分配内存

  • 特点: 分配失败时会使用其他可用节点

  • 适用: 希望优先使用特定节点但允许fallback的场景

MPOL_BIND(绑定模式):

  • 行为: 严格限制在指定节点分配内存

  • 特点: 分配失败时直接返回错误

  • 适用: 严格要求内存位置的应用

MPOL_INTERLEAVE(交错模式):

  • 行为: 在多个节点间轮询分配内存

  • 特点: 均匀分布内存负载

  • 适用: 大内存应用或需要负载均衡的场景

节点掩码操作

节点掩码设置示例:

1
2
3
4
5
6
7
8
9
// 单节点
unsigned long nodemask = 1UL << 0; // 节点0

// 多节点
unsigned long nodemask = (1UL << 0) | (1UL << 1); // 节点0和1

// 连续节点
unsigned long nodemask = (1UL << 4) - 1; // 节点0-3

节点掩码操作函数:

1
2
3
4
5
6
7
8
9
// 设置节点位
#define NODE_SET(node, mask) ((mask) |= (1UL << (node)))

// 清除节点位
#define NODE_CLR(node, mask) ((mask) &= ~(1UL << (node)))

// 检查节点位
#define NODE_ISSET(node, mask) ((mask) & (1UL << (node)))

常见使用场景

1. 数据库应用:

1
2
3
4
// 为不同数据缓冲区设置不同的节点策略
set_mempolicy(MPOL_PREFERRED, &node_0, sizeof(node_0) * 8); // 索引数据
set_mempolicy(MPOL_PREFERRED, &node_1, sizeof(node_1) * 8); // 用户数据

2. 高性能计算:

1
2
3
// 为计算密集型任务绑定到本地内存节点
set_mempolicy(MPOL_BIND, &local_node, sizeof(local_node) * 8);

3. Web服务器:

1
2
3
// 交错分配大缓存以平衡内存负载
set_mempolicy(MPOL_INTERLEAVE, &all_nodes, sizeof(all_nodes) * 8);

总结

set_mempolicy 是NUMA系统中重要的内存管理工具,提供了:

灵活的策略控制: 支持多种内存分配策略

性能优化能力: 通过节点亲和优化内存访问

应用适应性: 适用于各种NUMA应用场景

系统兼容性: 在不支持NUMA的系统上安全降级

通过合理使用 set_mempolicy,可以显著提升NUMA系统的内存访问性能,特别是在内存密集型应用中效果明显。在实际应用中,需要根据具体的工作负载特征和系统拓扑结构来选择合适的内存策略。

data-ad-format="auto" data-full-width-responsive="true">