在 Intel Xeon 上非临时负载的 MMIO 性能不佳

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

我看到

vmovntdqa
非临时负载的内存 (WC) 读取性能不佳 在 Intel Xeon E-2224 系统上的指令,但在 AMD 上表现出色 EPYC 3151 系统。为什么会有如此巨大的差异,我能做些什么吗? 关于它?似乎指令根本没有按预期工作 英特尔系统。

我在连接到 PCI Express 的 FPGA 板上有 DDR 内存。我在用

mmap()
从用户空间访问所述 DDR 内存映射到的 PCI BAR。 BAR 被标记为可预取,正如预期的那样,Linux 提供了
_wc
sysfs 下相应的资源文件。

这是我的基准测试结果:

System: Dell R240
CPU: Intel Xeon E-2224
Read speed (memcpy()): 13.7 MB/s
Read speed (streaming/NT load): 9.6 MB/s

System: Supermicro M11SDV-4C-LN4F
CPU: AMD EPYC 3151
Read speed (memcpy()): 6.8 MB/s
Read speed (streaming/NT load): 273.6 MB/s

Dell R250 (Intel Xeon E-2314) 和 SuperMicro X11SCA-F(英特尔至强 E-2224G)。

基准程序(C++、Linux)是:

/* iobench.cpp */

#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <chrono>
#include <cassert>
#include <cstring>
#include <iostream>

/* streaming-load-memcpy.cpp (adapted from Mesa, see below) */
void util_streaming_load_memcpy(void* __restrict__ dst,
                                void* __restrict__ src,
                                size_t len);

int main(int argc, char** argv) {
    const size_t sz = 4 * 1024 * 1024; /* 4 MB */
    assert(argc == 2);

    int sysfs_fd = open(argv[1], O_RDWR | O_CLOEXEC);
    if (sysfs_fd == -1) assert_perror(errno);

    void* src = mmap(nullptr, sz, PROT_READ | PROT_WRITE, MAP_SHARED, sysfs_fd, 0);

    if (src == (void*)-1) assert_perror(errno);
    if (close(sysfs_fd) == -1) assert_perror(errno);

    char* dst = static_cast<char*>(aligned_alloc(4096, sz));
    assert(dst != nullptr);

    std::chrono::steady_clock::time_point begin;
    std::chrono::steady_clock::time_point end;

    begin = std::chrono::steady_clock::now();
    util_streaming_load_memcpy(dst, src, sz);
    // Or: memcpy(dst, src, sz); */
    end = std::chrono::steady_clock::now();

    float duration_sec = std::chrono::duration<float>(end - begin).count();
    float speed = sz / duration_sec / 1024.0 / 1024.0;
    std::cout << speed << " MB/s\n";

    if (munmap(src, sz) == -1) assert_perror(errno);
}

util_streaming_load_memcpy()
改编自 Mesa 项目(需要做一些小的改动才能独立编译)。

  • 编译:
    g++ -mavx -O2 iobench.cpp streaming-load-memcpy.cpp -o iobench
  • 像这样跑步:
    ./iobench /sys/bus/pci/devices/0000\:13\:00.0/resource2_wc

util_streaming_load_memcpy()
的流加载循环编译为:

...
1540:       c4 e2 79 2a 1e          vmovntdqa (%rsi),%xmm3
1545:       c4 e2 79 2a 56 10       vmovntdqa 0x10(%rsi),%xmm2
154b:       48 83 c6 40             add    $0x40,%rsi
154f:       48 83 c0 40             add    $0x40,%rax
1553:       c4 e2 79 2a 4e e0       vmovntdqa -0x20(%rsi),%xmm1
1559:       c4 e2 79 2a 46 f0       vmovntdqa -0x10(%rsi),%xmm0
155f:       c5 f9 7f 58 c0          vmovdqa %xmm3,-0x40(%rax)
1564:       c5 f9 7f 50 d0          vmovdqa %xmm2,-0x30(%rax)
1569:       c5 f9 7f 48 e0          vmovdqa %xmm1,-0x20(%rax)
156e:       c5 f9 7f 40 f0          vmovdqa %xmm0,-0x10(%rax)
1573:       48 39 d6                cmp    %rdx,%rsi
1576:       75 c8                   jne    1540 <_Z26util_streaming_load_memcpyPvS_m+0x40>
...

我尝试了以下方法,但似乎没有任何有意义的区别:

  • 调整 UEFI BIOS 设置
  • 运行最近的稳定内核 (6.2.6)
  • 禁用推测执行缓解措施(内核命令行
    mitigations=off
  • 更新英特尔微码(使用微码 0xf0 完成的测试)
  • 使用 256 位 NT 加载(
    vmovntdqa
    ymm*
    寄存器)
  • 检查
    /sys/kernel/debug/x86/pat_memtype_list
    ;内存列为
    write-combining
  • 使用 Dell R240 板载 Matrox G200eW3 GPU 内存进行读取而不是 我们的 FPGA DDR

由于存在大量 CPU 漏洞,包括“MMIO Stale Data 漏洞”,我忍不住想,这是不是一些缓解措施的结果 CPU 微代码还是设计?微码不能轻易降级 低于固件加载的版本。

performance x86 avx pci memory-mapped-io
© www.soinside.com 2019 - 2024. All rights reserved.