AMD CPU 中的无开销监控代码显着增加了总同步持续时间

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

我正在进行一个测试来测量CPU不同核心之间的消息同步延迟。具体来说,我正在测量 CPU2 需要多少个时钟周期来检测 CPU1 共享数据的变化。 CPU1和CPU2都使用

rdtsc
指令来记录时序。我观察到 Intel 和 AMD CPU 平台之间的行为不一致。欢迎您对此问题有任何想法或建议。

代码如下。该程序包含两个线程“ping”和“pong”,分别在CPU1 和CPU2 上运行。正如他们的名字所暗示的,他们轮流增加自己的共享数据(

shd_data
)来实现乒乓循环,并最终测量总运行时间(
ts_end-ts_start
tb_end-tb_start
中的最小值)。为了也测量“ping”操作的平均时间,我添加了
rdtsc(tsc_start[loop]);
rdtsc(tsc_end[loop])
;在 while 循环内。然而,这两行监控代码显着影响了总运行时间,将平均乒乓循环时间从大约 180 个周期增加到 290 个周期。对此我找不到合理的解释。

#define MAX_LOOPS  10
#define BIDX 0
#define SIDX 15

static volatile int start_flag = 0;
static int shd_data[16];
unsigned long tb_start , tb_end, ts_start, ts_end;
unsigned long gap[12];
unsigned long tsc_start[MAX_LOOPS];
unsigned long tsc_end[MAX_LOOPS];

void* ping(void *args)
{
    int loop=0;
    int old = 0;
    int cur = 0;

    memset(tsc_start, 0, MAX_LOOPS*sizeof(unsigned long));
    memset(shd_data, 0, 64);    // preheat
    while (start_flag == 0) ;   // sync. start

    rdtsc(tb_start);
    while (++loop < MAX_LOOPS) {
        rdtsc(tsc_start[loop]);
        WRITE_ONCE(shd_data[BIDX], shd_data[BIDX]+1);
        do {
            cur = READ_ONCE(shd_data[SIDX]);
        } while (cur <= old);
        old = cur;
    }
    WRITE_ONCE(shd_data[BIDX], shd_data[BIDX]+1);
    rdtsc(tb_end);

    return NULL;
}


void* pong(void *args)
{
    int loop=0;
    int old = 0;
    int cur = 0;
    
    memset(tsc_end, 0, MAX_LOOPS*sizeof(unsigned long));
    memset(shd_data, 0, 64);    //preheat
    while (start_flag == 0) ;   // sync. start

    rdtsc(ts_start);
    while (++loop < MAX_LOOPS) {
        do {
            cur = READ_ONCE(shd_data[BIDX]);
            rdtsc(tsc_end[loop]);
        } while (cur <= old);
        old = cur;
        WRITE_ONCE(shd_data[SIDX], shd_data[SIDX]+1);
    }
    WRITE_ONCE(shd_data[SIDX], shd_data[SIDX]+1);
    rdtsc(ts_end);

    return NULL;
}

实验机是AMD 3910X,带有gcc-9.4.0。我还在 Intel i9-9900 CPU 上运行了相同的代码。有趣的是,使用 rdtsc 代码监控“ping”操作并没有影响整体乒乓时间,仍保持在 400 个周期左右。我不确定这种现象是否可以在其他 AMD 或 Intel CPU 上复制,因为我目前只能访问这两台机器。

更新:

通过调整CPU频率缩放,我的两台机器的CPU频率固定在3.6GHz的基础频率。

您可以从下面的链接找到完整的可运行代码:

https://onlinegdb.com/HoCs3AChhp

performance x86 cpu-architecture cpu-cache rdtsc
1个回答
0
投票

简要回答:缓存行争用

添加的监控代码,比如问题中提到的

rdtsc()
的使用,会导致数据段中变量布局的改变,导致运行时缓存行争用。修改“MAX_LOOPS”定义的值也会有同样的效果。应该注意的是,缓存争用也可能是由推测执行引起的。

如何修复

__attribute__((aligned(64)))
添加到
shd_data[32]
的定义中可确保其在缓存行上对齐。

限制

上述情况特定于AMD 3970X CPU,也可能适用于Zen2架构或其他AMD CPU。

我也在Intel i9-9900K上进行了这个实验,两个程序的数据段布局是相同的。但是,我还没有在 Intel CPU 上观察到缓存抖动,这是我还没有完全理解的事情。

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