相关疑难解决方法(0)

在C++中强制执行语句顺序

假设我有一些我想以固定顺序执行的语句.我想使用优化级别为2的g ++,因此可以重新排序某些语句.有什么工具可以强制执行某些语句排序?

请考虑以下示例.

using Clock = std::chrono::high_resolution_clock;

auto t1 = Clock::now(); // Statement 1
foo();                  // Statement 2
auto t2 = Clock::now(); // Statement 3

auto elapsedTime = t2 - t1;
Run Code Online (Sandbox Code Playgroud)

在这个例子中,重要的是语句1-3以给定的顺序执行.但是,编译器不能认为语句2独立于1和3并执行如下代码?

using Clock=std::chrono::high_resolution_clock;

foo();                  // Statement 2
auto t1 = Clock::now(); // Statement 1
auto t2 = Clock::now(); // Statement 3

auto elapsedTime = t2 - t1;
Run Code Online (Sandbox Code Playgroud)

c++ operator-precedence c++11

103
推荐指数
4
解决办法
1万
查看次数

在x86/x86_64处理器上使用LFENCE指令是否有意义?

通常在互联网上我发现LFENCE在处理器x86中没有任何意义,即它什么都不做,所以相反MFENCE我们可以绝对无痛地使用SFENCE,因为MFENCE= SFENCE+ LFENCE= SFENCE+ NOP= SFENCE.

但是如果LFENCE没有意义,那么为什么我们有四种方法在x86/x86_64中建立顺序一致性:

  1. LOAD(没有围栏)和STORE+MFENCE
  2. LOAD (没有围栏)和 LOCK XCHG
  3. MFENCE+ LOADSTORE(没有围栏)
  4. LOCK XADD(0)和STORE(没有围栏)

取自这里:http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html

以及Herb Sutter在第34页底部的表演:https://skydrive.live.com/view.aspx?status = 4E86B0CF20EF15AD!24884&app = WordPdf&wdo = 2&authkey =!AMtj_EflYn2507c

如果LFENCE没有做任何事情,那么方法(3)将具有以下含义:SFENCE + LOAD and STORE (without fence)但是SFENCE之前没有任何意义LOAD.即如果LFENCE什么都不做,方法(3)没有意义.

LFENCE在处理器x86/x86_64中是否有任何意义上的指令?

回答:

1. …

x86 assembly x86-64 atomic memory-barriers

40
推荐指数
2
解决办法
1万
查看次数

RDTSCP与RDTSC + CPUID

我正在做一些Linux内核时序,特别是在中断处理路径中.我一直在使用RDTSC进行计时,但是我最近了解到它并不一定准确,因为指令可能无序发生.

然后我尝试了:

  1. RDTSC + CPUID(在这里以相反的顺序)刷新管道,由于超级调用和诸如此类的原因,在虚拟机(我的工作环境)上产生高达60倍的开销(!).无论是否启用了HW Virtualization,都可以使用此功能.

  2. 最近我遇到了RDTSCP*指令,它看起来像RDTSC + CPUID那样做,但更高效,因为它是一个较新的指令 - 相对而言只有1.5x-2x的开销.

我的问题:RDTSCP作为一个测量点是否真的准确,它是做出时机的"正确"方法吗?

另外要明确一点,我的时间基本上就是这样,内部:

  • 保存当前循环计数器值
  • 执行一种类型的基准测试(即:磁盘,网络)
  • 将当前和上一个周期计数器的增量添加到累加器值,并按单个中断递增计数器
  • 最后,将delta/accumulator除以中断次数,得到每次中断的平均周期成本.

*http://www.intel.de/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf第27页

c x86 assembly linux-kernel

15
推荐指数
3
解决办法
8033
查看次数

哪个内联汇编代码对于rdtscp是正确的?

免责声明:单词无法描述我厌恶AT&T风格的语法

我有一个问题,我希望是由寄存器clobbering引起的.如果没有,我有一个更大的问题.

我使用的第一个版本是

static unsigned long long rdtscp(void)
{
    unsigned int hi, lo;
    __asm__ __volatile__("rdtscp" : "=a"(lo), "=d"(hi));
    return (unsigned long long)lo | ((unsigned long long)hi << 32);
}
Run Code Online (Sandbox Code Playgroud)

我注意到这个版本中没有'破坏'的东西.这是否是一个我不知道的问题...我想这取决于编译器是否内联函数.使用此版本会导致我无法始终重现的问题.

我发现的下一个版本是

static unsigned long long rdtscp(void)
{
    unsigned long long tsc;
    __asm__ __volatile__(
        "rdtscp;"
        "shl $32, %%rdx;"
        "or %%rdx, %%rax"
        : "=a"(tsc)
        :
        : "%rcx", "%rdx");

    return tsc;
}
Run Code Online (Sandbox Code Playgroud)

这是令人安心的不可读和官方的看,但就像我说我的问题并不总是可重复的所以我只是试图排除我的问题的一个可能的原因.

认为第一个版本存在问题的原因是它覆盖了以前持有函数参数的寄存器.

什么是正确的...版本1,或版本2,或两者兼而有之?

assembly gcc x86-64 inline-assembly

14
推荐指数
1
解决办法
8350
查看次数

英特尔的时间戳读取asm代码示例是否使用了两个以上的寄存器?

我正在研究使用x86 CPU中的时间戳寄存器(TSR)来测量基准性能.它是一个有用的寄存器,因为它以单调时间单位测量,不受时钟速度变化的影响.很酷.

这是一份英特尔文档,显示了使用TSR进行可靠基准测试的asm片段,包括使用cpuid进行管道同步.见第16页:

http://www.intel.com/content/www/us/en/embedded/training/ia-32-ia-64-benchmark-code-execution-paper.html

要读取开始时间,它说(我注释了一下):

__asm volatile (
    "cpuid\n\t"             // writes e[abcd]x
    "rdtsc\n\t"             // writes edx, eax
    "mov %%edx, %0\n\t" 
    "mov %%eax, %1\n\t"
    //
    :"=r" (cycles_high), "=r" (cycles_low)  // outputs
    :                                       // inputs
    :"%rax", "%rbx", "%rcx", "%rdx");       // clobber
Run Code Online (Sandbox Code Playgroud)

我不知道为什么暂存寄存器用来取的价值观edxeax.为什么不删除MOVS和读取TSR值右出的edxeax?像这样:

__asm volatile(                                                             
    "cpuid\n\t"
    "rdtsc\n\t"
    //
    : "=d" (cycles_high), "=a" (cycles_low) // outputs
    :                                       // inputs
    : "%rbx", "%rcx");                      // clobber     
Run Code Online (Sandbox Code Playgroud)

通过这样做,您可以保存两个寄存器,从而降低C编译器需要溢出的可能性.

我对吗?或者那些MOV在某种程度上是战略性的?

(我同意你确实需要临时寄存器来读取停止时间,因为在那种情况下指令的顺序是相反的:你有rdtscp,...,cpuid.cpuid指令破坏了rdtscp的结果).

谢谢

c benchmarking assembly inline-assembly rdtsc

8
推荐指数
1
解决办法
803
查看次数

(非)确定性 CPU 行为以及(物理)执行持续时间的推理

过去我曾处理过时间紧迫的软件开发。这些应用程序的开发基本上是这样进行的:“让我们编写代码,测试延迟和抖动,并对两者进行优化,直到它们处于可接受的范围内。” 我觉得这非常令人沮丧;这不是我所说的正确的工程,我想做得更好。

所以我研究了这个问题:为什么我们会有抖动?答案当然是:

  • 缓存:从主内存获取一段代码或数据比从 L1 缓存获取相同数据要多花费 2 个数量级的时间。所以物理执行时间取决于缓存中的内容。这又取决于几个因素:
    • 应用程序的代码和数据布局:我们都知道可怕的行主与列主矩阵遍历示例
    • CPU 的缓存策略,包括缓存行的推测性预取
    • 同一核心上的其他进程正在做事情
  • 分支预测:CPU 尝试猜测条件跳转的哪个分支将被执行。即使相同的条件跳转执行两次,预测也可能不同,因此一次可能会形成“管道泡沫”,而另一次则不会。
  • 中断:异步行为显然会导致抖动
  • 频率缩放:幸好在实时系统中被禁用

有很多事情会干扰一段代码的行为。尽管如此:如果我有两条指令,位于同一缓存行,不依赖于任何数据,也不包含(条件)跳转。然后,应该消除缓存和分支预测带来的抖动,并且只有中断才能发挥作用。正确的?好吧,我编写了一个小程序,获取时间戳计数器 (tsc) 两次,并将差异写入标准输出。我在一个打了 rt 补丁的 Linux 内核上执行了它,并且禁用了频率缩放。

该代码具有基于 glibc 的初始化和清理,并调用 printf,我认为它有时在缓存中,有时不在缓存中。但是在调用“rdtsc”(将 tsc 写入 edx:eax)之间,二进制文件的每次执行都应该是确定性的。为了确定起见,我反汇编了 elf 文件,这里是两个 rdtsc 调用的部分:

00000000000006b0 <main>:
 6b0:   0f 31                   rdtsc  
 6b2:   48 c1 e2 20             shl    $0x20,%rdx
 6b6:   48 09 d0                or     %rdx,%rax
 6b9:   48 89 c6                mov    %rax,%rsi
 6bc:   0f 31                   rdtsc  
 6be:   48 c1 e2 20             shl    $0x20,%rdx
 6c2:   48 09 d0                or     %rdx,%rax
 6c5:   48 29 c6 …
Run Code Online (Sandbox Code Playgroud)

cpu time caching deterministic

7
推荐指数
1
解决办法
1344
查看次数

加载和存储是否只有重新排序的指令?

我已经阅读了很多关于内存排序的文章,并且所有这些文章都只说CPU重新加载和存储.

CPU(我对x86 CPU特别感兴趣)是否仅重新排序加载和存储,并且不重新排序它具有的其余指令?

x86 cpu-architecture memory-barriers

6
推荐指数
2
解决办法
915
查看次数

LFENCE是否在AMD处理器上进行序列化?

在最近的英特尔ISA文档中,该lfence指令被定义为序列化指令流(防止指令流无序执行).特别是,该指令的描述包括以下行:

具体来说,LFENCE不会执行,直到所有先前的指令在本地完成,并且在LFENCE完成之前没有后续指令开始执行.

请注意,这适用于所有的指令,不只是内存加载指令,使得lfence 更多的不仅仅是一个存储排序防护.

虽然这现在出现在ISA文档中,但不清楚它是否是"架构",即所有x86实现都遵守,或者它是否特定于Intel.特别是AMD处理器是否也将lfence序列化为指令流?

x86 amd intel cpu-architecture memory-barriers

5
推荐指数
2
解决办法
723
查看次数

为什么 CPUID + RDTSC 不可靠?

我正在尝试在 x86-64 处理器上分析执行时间的代码。我指的是这篇英特尔白皮书,并且还浏览了其他 SO 线程,讨论了在此处此处使用 RDTSCP 与 CPUID+RDTSC 的主题。

在上面提到的白皮书中,使用 CPUID+RDTSC 的方法被称为不可靠,并且也使用统计数据进行了证明。

CPUID+RDTSC 不可靠的原因可能是什么?

此外,同一白皮书中的图 1(最小值行为图)和图 2(方差行为图)中的图具有“方波”模式。什么解释了这种模式?

x86 intel microbenchmark rdtsc cpuid

5
推荐指数
1
解决办法
531
查看次数

rdtsc乱序执行的解决方案?

我正在尝试将clock_gettime(CLOCK_REALTIME, &ts) 替换为rdtsc,以CPU 周期而不是服务器时间来衡量代码执行时间。基准测试代码的执行时间对于软件至关重要。我尝试在独立核心上的 x86_64 3.20GHz ubuntu 机器上运行代码并得到以下数字:

情况 1:时钟获取时间: 24 纳秒

void gettime(Timespec &ts) {
        clock_gettime(CLOCK_REALTIME, &ts);
}
Run Code Online (Sandbox Code Playgroud)

情况 2:rdtsc(没有 mfence 和编译器屏障): 10 ns

void rdtsc(uint64_t& tsc) {
        unsigned int lo,hi;
        __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
        tsc = ((uint64_t)hi << 32) | lo;
}
Run Code Online (Sandbox Code Playgroud)

情况 3:rdtsc(带有 mfence 和编译器屏障): 30 ns

void rdtsc(uint64_t& tsc) {
        unsigned int lo,hi;
        __asm__ __volatile__ ("mfence;rdtsc" : "=a" (lo), "=d" (hi) :: "memory");
        tsc = ((uint64_t)hi << 32) | lo;
}
Run Code Online (Sandbox Code Playgroud)

这里的问题是我知道 …

c++ gcc cpu-architecture memory-barriers rdtsc

2
推荐指数
1
解决办法
1298
查看次数

如何在没有函数调用的情况下在 Linux 中检索处理器时间?

我需要计算一部分(C++)代码的运行时间,并希望通过查找代码执行过程中经过的时钟滴答数来实现这一点。

我想找到代码开头的处理器时间和结尾处的处理器时间,然后减去它们以找到经过的滴答数。

这可以通过时钟功能来完成。然而,我测量的时间需要非常精确,并且使用函数调用被证明是非常具有侵入性的,因为调用者保存的寄存器分配器在每次调用时都会溢出许多变量。

因此,我不能使用任何函数调用,需要自己检索处理器时间。汇编代码没问题。

我正在使用 Debian 和 i7 Intel 处理器。我不能使用分析器,因为它太具有侵入性。

c c++ unix linux assembly

-2
推荐指数
1
解决办法
264
查看次数