相关疑难解决方法(0)

CPU TSC获取操作,尤其是在多核多处理器环境中

在Linux世界中,要获得纳秒精度定时器/时钟提示,可以使用:

#include <sys/time.h>

int foo()
{
   timespec ts;

   clock_gettime(CLOCK_REALTIME, &ts); 
   //--snip--      
}
Run Code Online (Sandbox Code Playgroud)

这个答案提出了asm一种用RDTSC指令直接查询cpu时钟的方法.

在多核,多处理器架构中,这个时钟滴答/定时器值如何在多个内核/处理器之间同步?我的理解是,在固有的围栏中完成了.这种理解是否正确?

你能否提出一些可以详细解释这个问题的文件?我对Intel Nehalem和Sandy Bridge微体系结构感兴趣.

编辑

将进程限制为单个核心或cpu不是一种选择,因为该进程非常庞大(就消耗的资源而言)并且希望最佳地利用包含所有核心和处理器的机器中的所有资源.

编辑

感谢您确认TSC在核心和处理器之间同步.但我最初的问题是这种同步是如何完成的?它是否带有某种围栏?你知道任何公共文件吗?

结论

感谢所有输入:以下是此讨论的结论:TSC在初始化时使用在多处理器/多核系统中的核心和处理器之间发生的RESET进行同步.之后,每个Core都是独立的.TSC与锁相环保持不变,这将使频率变化正常化,从而使给定Core内的时钟变化正常化,这就是TSC在核心和处理器之间保持同步的方式.

c assembly multicore cpu-registers microprocessors

14
推荐指数
4
解决办法
7895
查看次数

哪个内联汇编代码对于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
查看次数

RDTSC开销的差异

我正在构建一个微基准来测量性能变化,因为我在一些原始图像处理操作中尝试使用SIMD指令内在函数.但是,编写有用的微基准测试很困难,因此我想首先了解(如果可能的话)消除尽可能多的变异和误差源.

我必须考虑的一个因素是测量代码本身的开销.我正在使用RDTSC进行测量,我正在使用以下代码来查找测量开销:

extern inline unsigned long long __attribute__((always_inline)) rdtsc64() {
    unsigned int hi, lo;
        __asm__ __volatile__(
            "xorl %%eax, %%eax\n\t"
            "cpuid\n\t"
            "rdtsc"
        : "=a"(lo), "=d"(hi)
        : /* no inputs */
        : "rbx", "rcx");
    return ((unsigned long long)hi << 32ull) | (unsigned long long)lo;
}

unsigned int find_rdtsc_overhead() {
    const int trials = 1000000;

    std::vector<unsigned long long> times;
    times.resize(trials, 0.0);

    for (int i = 0; i < trials; ++i) {
        unsigned long long t_begin = rdtsc64();
        unsigned long long t_end = rdtsc64(); …
Run Code Online (Sandbox Code Playgroud)

c++ performance assembly intel rdtsc

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

这个时钟是否适用于Intel i3?

我在网上采用了衡量SSE绩效的方法.

#ifndef __TIMER_H__
#define __TIMER_H__

#pragma warning (push)
#pragma warning (disable : 4035)    // disable no return value warning

__forceinline  unsigned int GetPentiumTimer()
{
    __asm
    {
        xor   eax,eax             // VC won't realize that eax is modified w/out this
                                  //   instruction to modify the val.
                                  //   Problem shows up in release mode builds
        _emit 0x0F                // Pentium high-freq counter to edx;eax
        _emit 0x31                // only care about low 32 bits in eax

        xor   edx,edx             // so VC gets that edx is …
Run Code Online (Sandbox Code Playgroud)

c++ performance intel performancecounter

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

有效地交织比特

我需要做出uint64_t2个uint32_t交错的比特:如果A=a0a1a2...a31B=b0b1...b31,我需要C = a0b0a1b1...a31b31.有没有办法有效地做到这一点?到目前为止,我只有一个for循环的32次迭代的天真方法,每次迭代都有C|=((A&(1<<i))<<i)|((B&(1<<i))<<(i+1)).

我想应该有一些数学技巧,例如将A和B乘以一些特殊数字,这导致在得到的64位数字中将它们的位与零交错,这样只剩下or这些产品.但我找不到这样的乘数.

另一种可能的方法是编译器内部或汇编指令,但我不知道.

c++ algorithm math assembly bit-manipulation

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

为什么使用std :: multiset作为优先级队列比使用std :: priority_queue更快?

我尝试用std :: priority_queue替换std :: multiset。但是我对速度结果感到失望。该算法的运行时间增加了50%...

以下是相应的命令:

top() = begin();
pop() = erase(knn.begin());
push() = insert();
Run Code Online (Sandbox Code Playgroud)

我对priority_queue实现的速度感到惊讶,我预期会有不同的结果(对于PQ更好)...从概念上讲,多集被用作优先级队列。为什么优先级队列和多重集即使在情况下也具有如此不同的性能-O2

十个结果的平均值,MSVS 2010,Win XP,32位,方法findAllKNN2()(请参见下面的内容)

MS
N           time [s]
100 000     0.5
1 000 000   8

PQ
N           time [s]
100 000     0.8
1 000 000   12
Run Code Online (Sandbox Code Playgroud)

什么会导致这些结果?尚未对源代码进行其他更改...感谢您的帮助...

MS实施:

template <typename Point>
struct TKDNodePriority
{
    KDNode <Point> *node;
    typename Point::Type priority;

    TKDNodePriority() : node ( NULL ), priority ( 0 ) {}
    TKDNodePriority ( KDNode <Point> *node_, typename Point::Type priority_ ) : node ( …
Run Code Online (Sandbox Code Playgroud)

c++ performance priority-queue multimap multiset

9
推荐指数
3
解决办法
3609
查看次数

装配性能调整

我正在编写一个编译器(更多的是为了娱乐而不是其他任何东西),但我想尽量使它尽可能高效.例如,有人告诉我,在英特尔架构中,使用除EAX执行数学之外的任何寄存器都会产生成本(大概是因为它转换成EAX实际的数学运算).这里至少有一个说明可能性的来源(http://www.swansontec.com/sregisters.html).

我想验证和衡量这些性能特征的差异.因此,我用C++编写了这个程序:

#include "stdafx.h"
#include <intrin.h>
#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    __int64 startval;
    __int64 stopval;
    unsigned int value; // Keep the value to keep from it being optomized out

    startval = __rdtsc(); // Get the CPU Tick Counter using assembly RDTSC opcode

    // Simple Math: a = (a << 3) + 0x0054E9
    _asm {
        mov ebx, 0x1E532 // Seed
        shl ebx, 3
        add ebx, 0x0054E9
        mov value, ebx
    }

    stopval …
Run Code Online (Sandbox Code Playgroud)

c++ compiler-construction assembly compiler-theory

9
推荐指数
4
解决办法
587
查看次数

在一个带有constant_tsc和nonstop_tsc的cpu上,为什么我的时间会漂移?

我在constant_tsc和cpu上运行这个测试nonstop_tsc

$ grep -m 1 ^flags /proc/cpuinfo | sed 's/ /\n/g' | egrep "constant_tsc|nonstop_tsc"
constant_tsc
nonstop_tsc
Run Code Online (Sandbox Code Playgroud)

第1步:计算tsc的滴答率:

我计算_ticks_per_ns了许多观测值的中位数.我用它rdtscp来确保按顺序执行.

static const int trials = 13;
std::array<double, trials> rates;

for (int i = 0; i < trials; ++i)
{
    timespec beg_ts, end_ts;
    uint64_t beg_tsc, end_tsc;

    clock_gettime(CLOCK_MONOTONIC, &beg_ts);
    beg_tsc = rdtscp();

    uint64_t elapsed_ns;
    do
    {
        clock_gettime(CLOCK_MONOTONIC, &end_ts);
        end_tsc = rdtscp();

        elapsed_ns = to_ns(end_ts - beg_ts); // calculates ns between two timespecs
    }
    while (elapsed_ns < …
Run Code Online (Sandbox Code Playgroud)

c++ linux rdtsc

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

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

确定Linux上的TSC频率

给定具有恒定TSC的x86 ,这对于测量实时非常有用,如何在启动时使用Linux计算的TSC校准因子在TSC参考周期的"单位"和正常人类实时单位(如纳秒)之间进行转换

也就是说,当然可以通过CLOCK_MONOTONIC在某个时间间隔的两端进行TSC和时钟测量(例如,用)来计算用户区中的TSC频率,以确定TSC频率,但Linux已经在启动时进行了此计算,因为它内部使用TSC帮助进行计时.

例如,您可以通过以下方式查看内核的结果dmesg | grep tsc:

[    0.000000] tsc: PIT calibration matches HPET. 2 loops
[    0.000000] tsc: Detected 3191.922 MHz processor
[    1.733060] tsc: Refined TSC clocksource calibration: 3192.007 MHz
Run Code Online (Sandbox Code Playgroud)

在更糟糕的情况下,我猜你可以尝试dmesg在运行时grep结果,但坦率地看起来很可怕,脆弱和各种各样的坏0.

使用内核确定的校准时间的优点很多:

  1. 您不必自己编写TSC校准例程,并且您可以非常确定Linux版本是最佳的.
  2. 当你使用现有的二进制文件(例如,最近芯片开始使用cpuid叶片0x15 宣传其TSC频率,因此不一定需要进行校准)时,您会自动在TSC校准中获取新技术.
  3. 您不会通过TSC校准减慢启动速度.
  4. 您在每次运行过程中使用相同的TSC值(至少在重新启动之前).
  5. 您的TSC频率与OS时间保持功能(如1gettimeofdayclock_gettime1)使用的TSC频率在某种程度上"一致" .
  6. 内核能够在引导时,在内核模式下很早地进行TSC校准,没有中断的祸害,其他进程,并且能够访问底层硬件定时器方向作为其校准源.

然而,使用Linux的TSC校准的一些缺点包括:

  1. 它不适用于每个Linux安装(例如,可能不使用tsc clocksource的安装)或其他操作系统上的安装,因此您可能仍然无法编写后备校准方法.
  2. 有理由相信"最近"校准可能比旧校准更准确,特别是在开机后立即进行校准:晶体行为可能会发生变化,特别是在温度变化时,因此通过这样做可以获得更准确的频率手动接近您将使用它的点.

0例如:系统可能没有dmesg安装,您可能无法以普通用户身份运行它,累积的输出可能已经缠绕,因此线路不再存在,您可能会在grep上获得误报,内核消息是英文散文,可能会有变化,可能很难启动子流程等等.

1这是否有争议 - 但如果您将rdtsc调用与使用OS时间保持的代码混合,则可能会提高精度.

linux performance x86 rdtsc

8
推荐指数
0
解决办法
961
查看次数