x86 强内存模型 (Strong Memory Model):
除了 StoreLoad 重排序外,处理器不会对内存访问进行重排序
写操作会立即对其他核心可见
ARM 弱内存模型 (Weak Memory Model):
允许更多类型的内存访问重排序
写操作可能不会立即对其他核心可见
需要显式使用内存屏障来保证顺序性
给予处理器更多优化空间,但增加了编程复杂度
Memory Model Performance TestClick to open code
这个测试程序通过以下方式展示了内存模型的差异:
测试原理:
创建两个并发线程,每个线程都写入一个变量并读取另一个变量
在弱内存模型中,由于内存访问重排序,可能会观察到更多的 r1=r2=0 的情况
在强内存模型中,这种情况会较少出现
#include <pthread.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
// 共享变量
volatile int x = 0;
volatile int y = 0;
volatile int r1 = 0;
volatile int r2 = 0;
// 计数器,记录不同执行序列的发生次数
uint64_t count_none = 0; // r1 = r2 = 0
uint64_t count_x = 0; // r1 = 1, r2 = 0
uint64_t count_y = 0; // r1 = 0, r2 = 1
uint64_t count_both = 0; // r1 = r2 = 1
// 线程函数
void* thread1(void* arg) {
x = 1;
#ifdef ARM
__asm__ volatile("dmb ish" ::: "memory"); // ARM内存屏障
#endif
r1 = y;
return NULL;
}
void* thread2(void* arg) {
y = 1;
#ifdef ARM
__asm__ volatile("dmb ish" ::: "memory"); // ARM内存屏障
#endif
r2 = x;
return NULL;
}
// 执行单次测试
void run_once() {
pthread_t t1, t2;
// 重置共享变量
x = y = r1 = r2 = 0;
// 创建线程
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
// 等待线程结束
pthread_join(t1, NULL);
pthread_join(t2, NULL);
// 统计结果
if (r1 == 0 && r2 == 0) count_none++;
else if (r1 == 1 && r2 == 0) count_x++;
else if (r1 == 0 && r2 == 1) count_y++;
else if (r1 == 1 && r2 == 1) count_both++;
}
int main() {
const int iterations = 1000000;
struct timespec start, end;
// 获取开始时间
clock_gettime(CLOCK_MONOTONIC, &start);
// 运行多次测试
for (int i = 0; i < iterations; i++) {
run_once();
}
// 获取结束时间
clock_gettime(CLOCK_MONOTONIC, &end);
// 计算运行时间(毫秒)
double time_ms = (end.tv_sec - start.tv_sec) * 1000.0 +
(end.tv_nsec - start.tv_nsec) / 1000000.0;
// 输出结果
printf("测试结果 (%d 次迭代):\n", iterations);
printf("r1=0, r2=0: %lu (%.2f%%)\n", count_none,
(double)count_none/iterations*100);
printf("r1=1, r2=0: %lu (%.2f%%)\n", count_x,
(double)count_x/iterations*100);
printf("r1=0, r2=1: %lu (%.2f%%)\n", count_y,
(double)count_y/iterations*100);
printf("r1=1, r2=1: %lu (%.2f%%)\n", count_both,
(double)count_both/iterations*100);
printf("总运行时间: %.2f ms\n", time_ms);
printf("平均每次迭代时间: %.3f us\n", time_ms*1000/iterations);
return 0;
}
测试结果intel 8352Y
测试结果(1000000次选代):
r1=0, r2=0: 0 (0.00%)
r1=1, r2=0: 336 (0.03%)
r1=0, r2=1: 999664 (99.97%)
r1=1, r2=1: 0 (0.00%)
总运行时间:26725.53ms
平均每次迭代时间:26.726 us
测试结果ampere altra max
测试结果(10000000次选代):
r1=0,r2=0:0(0.00%
r1=1,r2=0:67902 (6.79%)
r1=0,r2=1:932084
r1=1, r2=1: 14 (0.00%)
总运行时间:57942.97ms
(93.21%)
平均每次选代时间:57.943 us
可以看出这两者之间差距ARM在增加DSB指令后执行的时间更长了
本文由 妖言君 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Oct 28, 2024 at 04:34 pm