在我们的应用程序的Linux版本中,我需要一个用于嵌入式探查器的高分辨率计时器.我们的分析器测量的范围与单个功能一样小,因此它需要一个优于25纳秒的定时器精度.
以前我们的实现使用内联汇编和rdtsc操作直接从CPU查询高频定时器,但这是有问题的,需要经常重新校准.
所以我尝试使用该clock_gettime函数来查询CLOCK_PROCESS_CPUTIME_ID.文档声称这给了我纳秒时间,但我发现单次调用的开销clock_gettime()超过250ns.这使得不可能将事件计时100ns,并且在计时器功能上具有如此高的开销会严重降低应用程序性能,从而扭曲配置文件超出值.(我们每秒有数十万个分析节点.)
有没有办法调用clock_gettime()开销小于¼μs?或者是否有其他方法可以可靠地获得时间戳计数器,开销<25ns?还是我坚持使用rdtsc?
下面是我过去常用的代码clock_gettime().
// calls gettimeofday() to return wall-clock time in seconds:
extern double Get_FloatTime();
enum { TESTRUNS = 1024*1024*4 };
// time the high-frequency timer against the wall clock
{
double fa = Get_FloatTime();
timespec spec;
clock_getres( CLOCK_PROCESS_CPUTIME_ID, &spec );
printf("CLOCK_PROCESS_CPUTIME_ID resolution: %ld sec %ld nano\n",
spec.tv_sec, spec.tv_nsec );
for ( int i = 0 ; i < TESTRUNS ; ++ i …Run Code Online (Sandbox Code Playgroud) 我正在编写一个C代码,用于测量获取信号量所需的时钟周期数.我正在使用rdtsc,在对信号量进行测量之前,我连续两次调用rdtsc来测量开销.我在for循环中重复了这么多次,然后我将平均值用作rdtsc开销.
这是正确的,首先要使用平均值吗?
尽管如此,这里的一个大问题是,有时我会得到开销的负值(不一定是平均值,但至少是for循环中的部分值).
这也影响了连续计算sem_wait()操作所需的cpu周期数,有时也证明是负数.如果我写的不清楚,这里有一部分我正在编写的代码.
为什么我会得到这样的负值?
(编者注:请参阅获取CPU周期计数?以获得完整的64位时间戳的正确和可移植方式."=A"编译为x86-64时,asm约束只能得到低或高32位,具体取决于寄存器分配是否发生为uint64_t输出选择RAX或RDX .它不会选择edx:eax.)
(编辑的第二个注释:哎呀,这就是为什么我们得到负面结果的答案.仍然值得留下一个注释作为警告,不要复制这个rdtsc实现.)
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
static inline uint64_t get_cycles()
{
uint64_t t;
// editor's note: "=A" is unsafe for this in x86-64
__asm volatile ("rdtsc" : "=A"(t));
return t;
}
int num_measures = 10;
int main ()
{
int i, value, res1, res2;
uint64_t c1, c2;
int tsccost, tot, a;
tot=0;
for(i=0; i<num_measures; i++)
{ …Run Code Online (Sandbox Code Playgroud) 现代CPU的缓存访问速度是多少?Intel P4,Core2,Corei7,AMD每个处理器时钟周期内可以从内存中读取或写入多少字节?
请回答理论(ld/sd单位的宽度及其uOPs/tick的吞吐量)和实际数字(甚至是memcpy速度测试,或STREAM基准测试),如果有的话.
PS是问题,与汇编程序中的最大加载/存储指令率有关.可以有理论加载速率(所有每个Tick的指令都是最宽的负载),但是处理器只能给出部分这样的,一个实际的加载限制.
我从这个链接(https://gist.github.com/jiewmeng/3787223)获得了这个程序.我一直在网上搜索,以便更好地理解处理器缓存(L1和L2).我想成为能够编写一个程序,让我能够猜测我的新笔记本电脑上L1和L2缓存的大小.(仅用于学习目的.我知道我可以检查规格.)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define KB 1024
#define MB 1024 * 1024
int main() {
unsigned int steps = 256 * 1024 * 1024;
static int arr[4 * 1024 * 1024];
int lengthMod;
unsigned int i;
double timeTaken;
clock_t start;
int sizes[] = {
1 * KB, 4 * KB, 8 * KB, 16 * KB, 32 * KB, 64 * KB, 128 * KB, 256 * KB,
512 * KB, 1 * MB, 1.5 …Run Code Online (Sandbox Code Playgroud) 我对此有一个总体的想法。这就是我的想法:
首先,找出我将使用的 L1 缓存的大小。然后创建一个数组(字节数足够大以适合 L1 缓存),编写一个程序来访问数组的每个元素。然后在每几个循环中创建时间戳。
对于 L2 缓存中的延迟,我可以增大阵列以到达 L2 缓存。
但实际上我不知道如何开始。我不清楚每个缓存的数组应该有多大,以及如何用上面的想法编写这个 C 程序。
谁能帮我写一下这个C程序吗?任何帮助将不胜感激!
多谢!
在这篇文章的"示例"部分中,作者列出了所有内存组件寄存器/ L1/L2/RAM的延迟...我的问题是:如何测量(在线查找)任何给定芯片的实际延迟?让我们说吧
model name : Intel(R) Core(TM)2 Duo CPU E4600 @ 2.40GHz
stepping : 13
cpu MHz : 1200.000
Run Code Online (Sandbox Code Playgroud)
我也尝试过从英特尔手册中获取信息,但对于我的生活,这些事情是巨大的,我不知道在哪里寻找信息.
谢谢.
我在x86-64中查看下面的虚方法调用:
mov rcx, qword ptr [x]
mov rax, qword ptr [rcx]
call qword ptr [rax+8]
Run Code Online (Sandbox Code Playgroud)
以及Agner Fog的延迟表:
http://www.agner.org/optimize/instruction_tables.pdf
当我使用Ivy Bridge CPU时,我正在查看第175页.
我是否正确,前两个MOV指令都只占用2个(它们都是移动存储器来注册)CPU周期?我以为对虚拟方法的调用比这慢?
在178页的指令延迟表中,它表示此调用的延迟是2个CPU周期(我认为?).CALL与CALL'r'(寄存器)和CALL'm'(存储器)相比,'near'意味着什么?
所以根据Fog小册子,上面的ASM确实需要6个CPU周期,我没有误解过任何东西?
编辑:我将虚函数调用更改为vtable中的第二个.
我读了一篇文章(1.5岁http://www.drdobbs.com/parallel/cache-friendly-code-solving-manycores-ne/240012736),其中讨论了缓存性能和数据大小.他们展示了以下代码,他们说这些代码是在i7(沙桥)上运行的
static volatile int array[Size];
static void test_function(void)
{
for (int i = 0; i < Iterations; i++)
for (int x = 0; x < Size; x++)
array[x]++;
}
Run Code Online (Sandbox Code Playgroud)
他们声称如果他们保持Size*Iterations不变,增加Size,当数组内存中的大小增加超过L2缓存大小时,他们会观察到执行时间(10x)的巨大峰值.
作为我自己的练习,我想尝试一下,看看我是否可以为我的机器重现他们的结果.(i7 3770k,win7,visual c ++ 2012编译器,Win32调试模式,未启用优化).令我惊讶的是,我无法看到执行所花费的时间增加(甚至超过L3缓存大小),这让我觉得编译器在某种程度上优化了这段代码.但我也没有看到任何优化.我看到的唯一的速度变化是,在我的机器的字大小以下,它需要稍长.以下是我的时间,代码清单和相关的反汇编.
有谁知道原因:
1)为什么不管阵列的大小如何,所用的时间都不会增加?或者我怎么能找到?
2)为什么所花费的时间从高处开始然后减小直到达到缓存行大小,如果数据小于行大小,是否应该在没有从缓存读取的情况下处理更多迭代?
时序:
Size=1,Iterations=1073741824, Time=3829
Size=2,Iterations=536870912, Time=2625
Size=4,Iterations=268435456, Time=2563
Size=16,Iterations=67108864, Time=2906
Size=32,Iterations=33554432, Time=3469
Size=64,Iterations=16777216, Time=3250
Size=256,Iterations=4194304, Time=3140
Size=1024,Iterations=1048576, Time=3110
Size=2048,Iterations=524288, Time=3187
Size=4096,Iterations=262144, Time=3078
Size=8192,Iterations=131072, Time=3125
Size=16384,Iterations=65536, Time=3109
Size=32768,Iterations=32768, Time=3078
Size=65536,Iterations=16384, Time=3078
Size=262144,Iterations=4096, Time=3172
Size=524288,Iterations=2048, Time=3109
Size=1048576,Iterations=1024, Time=3094
Size=2097152,Iterations=512, Time=3313
Size=4194304,Iterations=256, Time=3391
Size=8388608,Iterations=128, …Run Code Online (Sandbox Code Playgroud) 为了测量程序中缓存未命中的影响,我想要计算缓存未命中对用于实际计算的周期造成的延迟。\n我用它来perf stat测量周期、L1 负载、L1 未命中、LLC 负载和 LLC - 我的程序中遗漏了。这是一个示例输出:
467\xe2\x80\xaf769,70 msec task-clock # 1,000 CPUs utilized \n 1\xe2\x80\xaf234\xe2\x80\xaf063\xe2\x80\xaf672\xe2\x80\xaf432 cycles # 2,638 GHz (62,50%)\n 572\xe2\x80\xaf761\xe2\x80\xaf379\xe2\x80\xaf098 instructions # 0,46 insn per cycle (75,00%)\n 129\xe2\x80\xaf143\xe2\x80\xaf035\xe2\x80\xaf219 branches # 276,083 M/sec (75,00%)\n 6\xe2\x80\xaf457\xe2\x80\xaf141\xe2\x80\xaf079 branch-misses # 5,00% of all branches (75,00%)\n 195\xe2\x80\xaf360\xe2\x80\xaf583\xe2\x80\xaf052 L1-dcache-loads # 417,643 M/sec (75,00%)\n 33\xe2\x80\xaf224\xe2\x80\xaf066\xe2\x80\xaf301 L1-dcache-load-misses # 17,01% of all L1-dcache hits (75,00%)\n 20\xe2\x80\xaf620\xe2\x80\xaf655\xe2\x80\xaf322 LLC-loads # 44,083 M/sec (50,00%)\n 6\xe2\x80\xaf030\xe2\x80\xaf530\xe2\x80\xaf728 LLC-load-misses # 29,25% of all LL-cache hits (50,00%)\nRun Code Online (Sandbox Code Playgroud)\n那么我的问题是:\n如何将缓存未命中数转换为“丢失”时钟周期数? …