gpt4 book ai didi

C++ 将 5 字节结构与缓存行对齐

转载 作者:太空宇宙 更新时间:2023-11-04 12:39:43 26 4
gpt4 key购买 nike

我正在开发 CPU-FPGA 协处理框架,因此我需要完全控制数据的对齐方式。我有一个只需要 5 个字节的数据结构:

typedef struct __attribute__ ((packed))  {
uint32_t dst;
uint8_t weight;
} edg_t;

我的 FPGA 接口(interface)可以在每个周期(每秒 2 亿次读取)读取 1 个缓存行(64 字节)。将尽可能多的元素塞入一个缓存行对我的性能至关重要,因此填充结构是不可能的。

5 字节:12 个元素/读取
8 字节:8 个元素/读取(填充)
填充 -> 性能降低 1.5 倍

但是,我不能让结构跨越缓存行之间的边缘,这需要我在 FPGA 上构建逻辑以不断移动读取数据。

构建缓冲区时我当前的解决方案如下所示:

int num_elements = 1000;
int num_cachelines = num_elements / 12 + 1;

uint8_t* buffer = new uint8_t[num_cachelines * 64]
uint8_t* buf_ptr = buffer - 4;

for (int i = 0; i < num_elements; i++) {
if (i % 12 == 0) buf_ptr += 4; //skip the last 4 bytes of each cache-line

edg_t* edg_ptr = (edg_t*) buf_ptr;
edg_ptr->dst = i; //example, I have random generators here
edg_ptr->weight = i % 256;
buf_ptr++;

}

当 FPGA 自己完成所有工作时这很好,现在我希望 FPGA 和 CPU 合作。这意味着 CPU 现在也必须读取缓冲区。

我想知道是否有更好的方法让编译器自动处理填充,或者我是否必须每次都手动跳过字节,就像我在上面的缓冲区创建代码中所做的那样?

最佳答案

我假设您将创建此缓冲区结构一次,然后一遍又一遍地填充它以供 FPGA 读取(反之亦然)。如果是这样,这个布局应该可以工作:

constexpr size_t cacheline_size = 64;
constexpr size_t num_elements = 1000;

struct __attribute__ ((packed)) edg_t {
/*volatile*/ uint32_t dst; // volatile if the FPGA writes too
/*volatile*/ uint8_t weight;
};

constexpr size_t elements_per_cachline = cacheline_size/sizeof(edg_t);
constexpr size_t num_cachelines = num_elements / elements_per_cachline + 1;

struct alignas(cacheline_size) cacheline_t {
std::array<edg_t, elements_per_cachline> edg;
inline auto begin() { return edg.begin(); }
inline auto end() { return edg.end(); }
};

struct cacheline_collection_t {
std::array<cacheline_t, num_cachelines> cl;
inline void* address_for_fpga() { return this; }
inline auto begin() { return cl.begin(); }
inline auto end() { return cl.end(); }
};

int main() {
cacheline_collection_t clc;
std::cout << "edg_t : "
<< alignof(edg_t) << " " << sizeof(clc.cl[0].edg[0]) << "\n";
std::cout << "cacheline_t : "
<< alignof(cacheline_t) << " " << sizeof(clc.cl[0]) << "\n";
std::cout << "cacheline_collection_t: "
<< alignof(cacheline_collection_t) << " " << sizeof(clc) << "\n";

// access
for(auto& cl : clc) {
for(auto& edg : cl) {
std::cout << edg.dst << " " << (unsigned)edg.weight << "\n";
}
}
}

assembly @ godbolt看起来不错。内部循环已完全内联到 12 个代码块,其中每个 block 的 rax 偏移量增加 5。然后它在 3 个操作中(有条件地)转到下一个缓存行:

    add     rax, 64
cmp rax, rcx
jne .LBB0_1

关于C++ 将 5 字节结构与缓存行对齐,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54796514/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com