在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在核心和处理器之间保持同步的方式.
免责声明:单词无法描述我厌恶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,或两者兼而有之?
我正在构建一个微基准来测量性能变化,因为我在一些原始图像处理操作中尝试使用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) 我在网上采用了衡量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) 我需要做出uint64_t2个uint32_t交错的比特:如果A=a0a1a2...a31和B=b0b1...b31,我需要C = a0b0a1b1...a31b31.有没有办法有效地做到这一点?到目前为止,我只有一个for循环的32次迭代的天真方法,每次迭代都有C|=((A&(1<<i))<<i)|((B&(1<<i))<<(i+1)).
我想应该有一些数学技巧,例如将A和B乘以一些特殊数字,这导致在得到的64位数字中将它们的位与零交错,这样只剩下or这些产品.但我找不到这样的乘数.
另一种可能的方法是编译器内部或汇编指令,但我不知道.
我尝试用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) 我正在编写一个编译器(更多的是为了娱乐而不是其他任何东西),但我想尽量使它尽可能高效.例如,有人告诉我,在英特尔架构中,使用除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) 我在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) 我正在研究使用x86 CPU中的时间戳寄存器(TSR)来测量基准性能.它是一个有用的寄存器,因为它以单调时间单位测量,不受时钟速度变化的影响.很酷.
这是一份英特尔文档,显示了使用TSR进行可靠基准测试的asm片段,包括使用cpuid进行管道同步.见第16页:
要读取开始时间,它说(我注释了一下):
__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)
我不知道为什么暂存寄存器用来取的价值观edx
和eax.为什么不删除MOVS和读取TSR值右出的edx
和eax?像这样:
__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的结果).
谢谢
给定具有恒定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.
使用内核确定的校准时间的优点很多:
cpuid叶片0x15 宣传其TSC频率,因此不一定需要进行校准)时,您会自动在TSC校准中获取新技术.gettimeofday和clock_gettime1)使用的TSC频率在某种程度上"一致" .然而,使用Linux的TSC校准的一些缺点包括:
0例如:系统可能没有dmesg安装,您可能无法以普通用户身份运行它,累积的输出可能已经缠绕,因此线路不再存在,您可能会在grep上获得误报,内核消息是英文散文,可能会有变化,可能很难启动子流程等等.
1这是否有争议 - 但如果您将rdtsc调用与使用OS时间保持的代码混合,则可能会提高精度.