相关疑难解决方法(0)

获取CPU周期数?

我在SO上看到这篇文章,其中包含C代码以获取最新的CPU周期数:

基于CPU周期计算的C/C++ Linux x86_64中的分析

有没有办法在C++中使用这个代码(欢迎使用windows和linux解决方案)?虽然用C语言编写(而C是C++的一个子集)但我不太确定这段代码是否适用于C++项目,如果没有,如何翻译呢?

我使用的是x86-64

EDIT2:

找到此功能但无法让VS2010识别汇编程序.我需要包含任何内容吗?(我相信我必须换uint64_tlong long窗户......?)

static inline uint64_t get_cycles()
{
  uint64_t t;
  __asm volatile ("rdtsc" : "=A"(t));
  return t;
}
Run Code Online (Sandbox Code Playgroud)

EDIT3:

从上面的代码我得到错误:

"错误C2400:'操作码'中的内联汇编语法错误;找到'数据类型'"

有人可以帮忙吗?

c c++ performance x86 rdtsc

26
推荐指数
5
解决办法
4万
查看次数

如何在GCC x86中使用RDTSC计算时钟周期?

使用Visual Studio,我可以从处理器读取时钟周期计数,如下所示.我如何与GCC做同样的事情?

#ifdef _MSC_VER             // Compiler: Microsoft Visual Studio

    #ifdef _M_IX86                      // Processor: x86

        inline uint64_t clockCycleCount()
        {
            uint64_t c;
            __asm {
                cpuid       // serialize processor
                rdtsc       // read time stamp counter
                mov dword ptr [c + 0], eax
                mov dword ptr [c + 4], edx
            }
            return c;
        }

    #elif defined(_M_X64)               // Processor: x64

        extern "C" unsigned __int64 __rdtsc();
        #pragma intrinsic(__rdtsc)
        inline uint64_t clockCycleCount()
        {
            return __rdtsc();
        }

    #endif

#endif
Run Code Online (Sandbox Code Playgroud)

c c++ x86 gcc rdtsc

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

有没有办法检查最近是否已刷新处理器缓存?

在i386 linux上.如果可能的话,最好在c /(c/posix std libs)/ proc中.如果没有,是否有任何组装或第三方库可以做到这一点?

编辑:我正在尝试开发测试内核模块是否清除缓存行或整个proccesor(使用wbinvd()).程序以root身份运行,但如果可能的话,我宁愿留在用户空间.

linux cpu flush hardware-interface cpu-cache

10
推荐指数
1
解决办法
2884
查看次数

英特尔的时间戳读取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
查看次数

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

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

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

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

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

x86 amd intel cpu-architecture memory-barriers

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

_mm_clflush 真的会刷新缓存吗?

我试图通过编写和运行测试程序来了解硬件缓存的工作原理:

#include <stdio.h>
#include <stdint.h>
#include <x86intrin.h>

#define LINE_SIZE   64

#define L1_WAYS     8
#define L1_SETS     64
#define L1_LINES    512

// 32K memory for filling in L1 cache
uint8_t data[L1_LINES*LINE_SIZE];

int main()
{
    volatile uint8_t *addr;
    register uint64_t i;
    int junk = 0;
    register uint64_t t1, t2;

    printf("data: %p\n", data);

    //_mm_clflush(data);
    printf("accessing 16 bytes in a cache line:\n");
    for (i = 0; i < 16; i++) {
        t1 = __rdtscp(&junk);
        addr = &data[i];
        junk = *addr;
        t2 = __rdtscp(&junk) - t1; …
Run Code Online (Sandbox Code Playgroud)

linux x86-64 cpu-architecture cpu-cache cache-locality

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

有没有办法刷新与程序相关的整个CPU缓存?

x86-64平台上,CLFLUSH汇编指令允许刷新对应于给定地址的缓存行.相反,冲洗与特定地址的缓存,会有一种通过使其充满了虚拟的内容,以刷新整个高速缓存(或者相关程序的缓存中执行,或整个高速缓存),例如(或任何我不会意识到的其他方法):

  • 仅使用标准C++ 17?
  • 如有必要,使用标准C++ 17和编译器内在函数?

以下函数的内容是什么:(无论编译器优化如何,该函数都应该工作)?

void flush_cache() 
{
    // Contents
}
Run Code Online (Sandbox Code Playgroud)

c++ memory optimization assembly cpu-cache

3
推荐指数
1
解决办法
4042
查看次数

NASM中的RDTSCP始终返回相同的值

我正在NASM中使用RDTSC和RDTSCP测量各种汇编语言指令的机器周期,以帮助优化。

我读了Intel的Gabriele Paoloni撰写的“如何在Intel IA-32和IA-64指令集体系结构上对代码执行时间进行基准测试”(2010年9月)和其他Web资源(其中大多数是C语言中的示例)。

使用下面的代码(从C转换),我测试了各种指令,但RDTSCP在RDX中始终返回零,在RAX中始终返回7。我首先认为7是周期数,但显然并非所有指令都需要7个周期。

rdtsc
cpuid
addsd xmm14,xmm1 ; Instruction to time
rdtscp
cpuid
Run Code Online (Sandbox Code Playgroud)

返回7,这并不奇怪,因为在某些体系结构上,添加了7个周期(包括延迟)。前两个指令(根据某些情况)可以颠倒,先是cpuid,然后是rdtsc,但这在这里没有什么区别。

当我将指令更改为2周期指令时:

rdtsc
cpuid
add rcx,rdx ; Instruction to time
rdtscp
cpuid
Run Code Online (Sandbox Code Playgroud)

这还会在rax中返回7,在rdx中返回零。

所以我的问题是:

  1. 如何访问和解释RDX:RAX中返回的值?

  2. 为什么RDX总是返回零,应该返回什么?

更新:

如果我将代码更改为此:

cpuid
rdtsc
mov [start_time],rax
addsd xmm14,xmm1 ; INSTRUCTION
rdtscp
mov [end_time],rax
cpuid
mov rax,[end_time]
mov rdx,[start_time]
sub rax,rdx
Run Code Online (Sandbox Code Playgroud)

我的rax达到了64,但这听起来像是周期太多。

optimization x86-64 nasm rdtsc windows64

3
推荐指数
1
解决办法
186
查看次数

Is there any difference in between (rdtsc + lfence + rdtsc) and (rdtsc + rdtscp) in measuring execution time?

As far as I know, the main difference in runtime ordering in a processor with respect to rdtsc and rdtscp instruction is that whether the execution waits until all previous instructions are executed locally.

In other words, it means lfence + rdtsc = rdtscp because lfence preceding the rdtsc instruction makes the following rdtsc to be executed after all previous instruction finish locally.

However, I've seen some example code that uses rdtsc at the start of measurement and rdtscp at …

x86 assembly cpu-architecture microbenchmark rdtsc

3
推荐指数
1
解决办法
475
查看次数

是否有比cpuid更便宜的序列化指令?

我已经看到了相关的问题,包括这里这里,但似乎有关序列化的唯一指令rdtsccpuid.

不幸的是,cpuid我的系统需要大约1000个周期,所以我想知道是否有人知道更便宜(更少的周期和没有读或写内存)序列化指令?

我看着iret,但这似乎改变了控制流程,这也是不可取的.

我实际上看过亚历克斯的答案中关联的白纸rstscp,但它说:

在读取计数器之前,RDTSCP指令等待直到执行了所有先前的指令.然而,后续指令可以在执行读取操作之前开始执行.

第二点似乎是让它不理想.

intel rdtsc cpu-cache

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

在x86_64平台上是否需要rdtsc的mfence?

unsigned int lo = 0;
unsigned int hi = 0;
__asm__ __volatile__ (
    "mfence;rdtsc" : "=a"(lo), "=d"(hi) : : "memory"
);
Run Code Online (Sandbox Code Playgroud)

mfence 在上面的代码中,是否有必要?

根据我的测试,找不到cpu重新排序.

测试代码片段包含在下面.

inline uint64_t clock_cycles() {
    unsigned int lo = 0;
    unsigned int hi = 0;
    __asm__ __volatile__ (
        "rdtsc" : "=a"(lo), "=d"(hi)
    );
    return ((uint64_t)hi << 32) | lo;
}

unsigned t1 = clock_cycles();
unsigned t2 = clock_cycles();
assert(t2 > t1);
Run Code Online (Sandbox Code Playgroud)

c++ linux timestamp x86-64

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

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
查看次数

使用rdtsc对intel进行汇编器基准测试给出了奇怪的答案,为什么?

前一段时间,我问了一个关于堆栈溢出的问题,并展示了如何在C++中执行rdtsc操作码.我最近使用rdtsc创建了一个基准函数,如下所示:

inline unsigned long long rdtsc() {
  unsigned int lo, hi;
  asm volatile (
     "cpuid \n"
     "rdtsc" 
   : "=a"(lo), "=d"(hi) /* outputs */
   : "a"(0)             /* inputs */
   : "%ebx", "%ecx");     /* clobbers*/
  return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
}

typedef uint64_t (*FuncOneInt)(uint32_t n);
/**
     time a function that takes an integer parameter and returns a 64 bit number
     Since this is capable of timing in clock cycles, we won't have to do it a
     huge …
Run Code Online (Sandbox Code Playgroud)

x86 assembly intel microbenchmark rdtsc

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