导致该程序存储延迟的原因是什么?

问题描述 投票:0回答:1

给出以下 C 程序(MSVC 不会为我优化“工作”,对于其他编译器,您可能需要添加

asm
语句):

#include <inttypes.h>
#include <stdlib.h>

#define SIZE 10000

typedef struct {
    int32_t a, b, c;
} Struct;

void do_work(Struct* data) {
    int32_t* a = malloc(sizeof(int32_t) * SIZE),
        * b = malloc(sizeof(int32_t) * SIZE),
        * c = malloc(sizeof(int32_t) * SIZE);

    int32_t* a_ptr = a, * b_ptr = b, * c_ptr = c;
    for (size_t i = 0; i < SIZE; i++, a_ptr++, b_ptr++, c_ptr++, data++) {
        *a_ptr = data->a;
        *b_ptr = data->b;
        *c_ptr = data->c;
    }

    free(a);
    free(b);
    free(c);
}

int main() {
    Struct* data = malloc(sizeof(Struct) * SIZE);
    for (size_t i = 0; i < SIZE; i++) {
        data[i].a = i;
        data[i].b = i;
        data[i].c = i;
    }

    for (int i = 0; i < 500000; i++) {
        do_work(data);
    }

    free(data);
}

(我在 Rust 中有一个类似的程序,具有相同的结论)。

Intel VTune 报告称,该程序有 63.1% 的内存限制和 52.4% 的存储限制,存储延迟为 26%。它建议搜索虚假共享,但我不明白这里怎么可能有虚假共享。没有并发性,所有数据都由一个核心拥有,访问模式应该很容易预测和预取。我不明白为什么 CPU 需要在这里的商店中停顿。

我认为也许三个分配的地址的低位和高位是相同的,这导致它们被映射到相同的缓存线,但我记得读到现代CPU不只是删除一些位来分配一个缓存行但可以进行更复杂的计算。

另一种想法是,也许在分配被释放后,CPU 仍然忙于刷新存储,并且在下一次运行中,分配器为它们分配了相同的地址(或接近的地址),这给 CPU 带来了问题,因为它已经在存储新数据之前等待。所以我尝试不释放分配,但这导致代码速度慢得多。

我使用的是 Windows 11、笔记本电脑 Intel Core i9-13900HX、32 个逻辑核心、8 个性能核心和 16 个高效核心。

c x86-64 cpu-architecture micro-optimization micro-architecture
1个回答
0
投票

最有可能是

int32_t * SIZE
调用中的
malloc
。如果您使用像
SIZE << 2
这样的位移位,您的代码应该更快、更高效。

© www.soinside.com 2019 - 2024. All rights reserved.