在答案中,我已经声明未对齐访问的速度与对齐访问的速度几乎相同(在x86/x86_64上).我没有任何数字来支持这个陈述,所以我已经为它创建了一个基准.
你看到这个基准测试有什么缺陷吗?你可以改进它(我的意思是,增加GB /秒,所以它更好地反映了真相)?
#include <sys/time.h>
#include <stdio.h>
template <int N>
__attribute__((noinline))
void loop32(const char *v) {
for (int i=0; i<N; i+=160) {
__asm__ ("mov (%0), %%eax" : : "r"(v) :"eax");
__asm__ ("mov 0x04(%0), %%eax" : : "r"(v) :"eax");
__asm__ ("mov 0x08(%0), %%eax" : : "r"(v) :"eax");
__asm__ ("mov 0x0c(%0), %%eax" : : "r"(v) :"eax");
__asm__ ("mov 0x10(%0), %%eax" : : "r"(v) :"eax");
__asm__ ("mov 0x14(%0), %%eax" : : "r"(v) :"eax");
__asm__ ("mov 0x18(%0), %%eax" : : "r"(v) :"eax"); …Run Code Online (Sandbox Code Playgroud) 我试图确定读取元素所需的时间,以确保它是缓存命中或缓存未命中.为了阅读顺序我使用_mm_lfence()函数.我得到了意想不到的结果,经过检查后,我看到lfence函数的开销不确定.所以我正在执行程序,在例如100 000次迭代的循环中测量这种开销.我得到一次迭代的超过1000个时钟周期的结果,下次是200.这可能是lfence函数开销之间存在这种差异的原因,如果它是如此不可靠,我怎样才能正确判断缓存命中和缓存未命中的延迟?我试图使用与此帖相同的方法:使用时间戳计数器进行内存延迟测量
给出不可靠结果的代码是这样的:
for(int i=0; i < arr_size; i++){
_mm_mfence();
_mm_lfence();
t1 = __rdtsc();
_mm_lfence();
_mm_lfence();
t2 = __rdtsc();
_mm_lfence();
arr[i] = t2-t1;
}
Run Code Online (Sandbox Code Playgroud)
arr中的值在不同的范围内变化,arr_size为100 000.
有人可以帮我理解https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html中给出的汇编程序
它是这样的:
uint64_t msr;
asm volatile ( "rdtsc\n\t" // Returns the time in EDX:EAX.
"shl $32, %%rdx\n\t" // Shift the upper bits left.
"or %%rdx, %0" // 'Or' in the lower bits.
: "=a" (msr)
:
: "rdx");
Run Code Online (Sandbox Code Playgroud)
它与以下内容有何不同:
uint64_t msr;
asm volatile ( "rdtsc\n\t"
: "=a" (msr));
Run Code Online (Sandbox Code Playgroud)
为什么我们需要转移和/或操作以及rdx到底有什么作用?
编辑:添加了原始问题尚不清楚的内容.
回顾一下.第一行加载寄存器eax和edx中的时间戳.第二行将eax中的值移位并存储在rdx中.第三行将edx中的值与rdx中的值一起使用,并将其保存在rdx中.第四行将rdx中的值赋给我的变量.最后一行将rdx设置为0.
再次感谢!:)
EDIT2:回答了我的一些问题......
我读过 RDTSC 可以给出错误的读数,不应依赖。
这是真的吗?如果是这样,可以做些什么?
假设我的CPU中的所有内核具有相同的频率,从技术上讲,我可以每毫秒左右为每个内核同步系统时间和时间戳计数器对.然后根据我正在运行的当前核心,我可以获取当前rdtsc值并使用tick delta除以核心频率,我能够估计自上次同步系统时间和时间戳计数器对后经过的时间.推断当前系统时间而没有来自当前线程的系统调用开销(假设不需要锁来检索上述数据).这在理论上很有效,但在实践中我发现有时我会得到更多的滴答,然后我会期望,也就是说,如果我的核心频率为1GHz并且我花了1毫秒的系统时间和时间戳计数器对,我希望看到一个delta在大约10 ^ 6个刻度的刻度线中,但实际上我发现它可以在10 ^ 6到10 ^ 7之间的任何位置.我不确定有什么问题,有人可以分享他对如何计算系统时间的看法rdtsc吗?我的主要目标是避免每次我想知道系统时间时执行系统调用的需要,并且能够在用户空间中执行计算,这将给我一个很好的估计(目前我定义了一个很好的估计结果)与实际系统时间间隔为10微秒.
我使用 C++ 对多个 NOP 指令和单个 NOP 指令进行计时rdtsc。但是,我没有发现执行 NOP 所需的周期数与执行的 NOP 数成正比。我很困惑为什么会出现这种情况。我的 CPU 是 Intel Core i7-5600U @ 2.60Ghz。
这是代码:
#include <stdio.h>
int main() {
unsigned long long t;
t = __rdtsc();
asm volatile("nop");
t = __rdtsc() - t;
printf("rdtsc for one NOP: %llu\n", t);
t = __rdtsc();
asm volatile("nop; nop; nop; nop; nop; nop; nop;");
t = __rdtsc() - t;
printf("rdtsc for seven NOPs: %llu\n", t);
}
Run Code Online (Sandbox Code Playgroud)
我得到的值如下:
rdtsc for one NOP: 78
rdtsc for seven NOPs: 91 …Run Code Online (Sandbox Code Playgroud) 是否可以使用 C++ 在运行时确定 AVX-512 FMA 单元的数量?
我已经有代码来确定 CPU 是否支持 AVX-512,但我无法确定 FMA 单元的数量。
我试图将别人的项目从32位转换为64位.除了一个函数外,一切似乎都没问题,它使用了构建x64时Visual Studio不支持的汇编表达式:
// Returns the Read Time Stamp Counter of the CPU
// The instruction returns in registers EDX:EAX the count of ticks from processor reset.
// Added in Pentium. Opcode: 0F 31.
int64_t CDiffieHellman::GetRTSC( void )
{
int tmp1 = 0;
int tmp2 = 0;
#if defined(WIN32)
__asm
{
RDTSC; // Clock cycles since CPU started
mov tmp1, eax;
mov tmp2, edx;
}
#else
asm( "RDTSC;\n\t"
"movl %%eax, %0;\n\t"
"movl %%edx, %1;"
:"=r"(tmp1),"=r"(tmp2)
:
:
);
#endif
return ((int64_t)tmp1 …Run Code Online (Sandbox Code Playgroud) 我是C ++和基准测试的新手
我不明白这段代码的作用是什么?因此,我找到了一些有关edx,eax寄存器的信息,但是我不完全了解它如何在代码中发挥作用。所以我理解这段代码本质上返回了cpu周期的当前滴答声。因此,它是否将当前的滴答存储在寄存器中,一部分存储在hi中,另一部分存储在lo中。并且,“ = a”和“ = d”是否指定将其存储在哪个寄存器中。
将其分为两个部分的意义何在?
"rdtsc" : "=a" (lo), "=d" (hi)
Run Code Online (Sandbox Code Playgroud)
上下文中的代码:
int64_t rdtsc(){
unsigned int lo,hi;
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
return ((uint64_t)hi << 32) | lo;
}
Run Code Online (Sandbox Code Playgroud)