x**l 发帖数: 64 | 1 linux下的一段代码,single thread,可以独占一个cpu 100%的资源。最主要部分就是
这个loop
for (uint32_t i = 0; i < 10; i++)
{
working(pBuf, bufferNum);
gap(gapLoops);
}
working()会做一些有business 意义的操作,
gap()就是很简单的一个双循环去制造一些时延在两次working()之间。
如果gap()只运行很短的时间,例如34个cpu clock cycles,则working()在iteration
2~10次时用的时间很短,例如,1100个cycles
如果gap()只运行较长时间,两次working()之间的时延有1个second,则working()在
iteration 2~10次的运行时间会double甚至2.5倍,例如会达到2500个cycles
我已经用numactl和chrt让这个程序充分独占一个cpu core,而且用cpuset把其他
threads移开这个core上.
我的问题是:
是什么原因导致了这种差异?
有什么debug的手段/定量地检查这种原因造成的影响?
编辑:
我知道在某些real time kernel或者一些RTOS下,没有这种差异. 但对更大型的复杂程
序则仍然有这种差异. 由于不能理解其中的原因,所以无法调制. 所以我主要想理解为
什么,而不是怎样才能避免这个差异. | x****u 发帖数: 44466 | 2 这是操作系统原理的基本问题。。。
iteration
【在 x**l 的大作中提到】 : linux下的一段代码,single thread,可以独占一个cpu 100%的资源。最主要部分就是 : 这个loop : for (uint32_t i = 0; i < 10; i++) : { : working(pBuf, bufferNum); : gap(gapLoops); : } : working()会做一些有business 意义的操作, : gap()就是很简单的一个双循环去制造一些时延在两次working()之间。 : 如果gap()只运行很短的时间,例如34个cpu clock cycles,则working()在iteration
| x**l 发帖数: 64 | 3 sample code我放在这个link
https://onedrive.live.com/?cid=96AAD7C8AEF82405&id=96AAD7C8AEF82405!108
用这个命令可以在linux上用gcc 4.4或者更高版本build
g++ -O3 -std=c++0x -march=native -ftemplate-depth-1025 main_inline.cpp -o a_
inline_opt.out
参考启动命令分别是这样的
短时延
sudo numactl --physcpubind=3 --membind=0 ./a_inlin_opt.out 1 0
长时延
sudo numactl --physcpubind=3 --membind=0 ./a_inlin_opt.out 1 2999999999
启动后还需要用 "sudo -f -p [priority] 改变调度策略,然后按任意键继续.
谢谢大家了. | x**l 发帖数: 64 | 4 谢谢,没错,大方向容易理解,现在缺少的是具体的细节原因.
【在 x****u 的大作中提到】 : 这是操作系统原理的基本问题。。。 : : iteration
| x****u 发帖数: 44466 | 5 你这个有business意义的事情,应该不是单纯的CPU能罩得住的计算吧。
a_
【在 x**l 的大作中提到】 : sample code我放在这个link : https://onedrive.live.com/?cid=96AAD7C8AEF82405&id=96AAD7C8AEF82405!108 : 用这个命令可以在linux上用gcc 4.4或者更高版本build : g++ -O3 -std=c++0x -march=native -ftemplate-depth-1025 main_inline.cpp -o a_ : inline_opt.out : 参考启动命令分别是这样的 : 短时延 : sudo numactl --physcpubind=3 --membind=0 ./a_inlin_opt.out 1 0 : 长时延 : sudo numactl --physcpubind=3 --membind=0 ./a_inlin_opt.out 1 2999999999
| x**l 发帖数: 64 | 6 是很简单的运算, 一些 memory copy 加整数运算和branch 跳转. 没有任何system
call 和lib function.
sample 代码在那里,void translate().
你可以自己改成任何简单的代码逻辑, 不能是浮点运算或者其它任何涉及到进入kernel
mode的调用.
【在 x****u 的大作中提到】 : 你这个有business意义的事情,应该不是单纯的CPU能罩得住的计算吧。 : : a_
| x****u 发帖数: 44466 | 7 那把这段代码直接改为驱动不就完事了?
kernel
【在 x**l 的大作中提到】 : 是很简单的运算, 一些 memory copy 加整数运算和branch 跳转. 没有任何system : call 和lib function. : sample 代码在那里,void translate(). : 你可以自己改成任何简单的代码逻辑, 不能是浮点运算或者其它任何涉及到进入kernel : mode的调用.
| x**l 发帖数: 64 | 8 为什么改成driver就可以?
如果是driver,它的scheduling policy是由user space的caller process决定的.
如果是kernel process, no way we can control the core on which it is running.
by no means moving it to driver could solve it.
【在 x****u 的大作中提到】 : 那把这段代码直接改为驱动不就完事了? : : kernel
| x****u 发帖数: 44466 | 9 用户态下你可以控制policy,不过比policy级别高的东西多了。
内核态你可以独占CPU任意长时间,不过这都是有代价的。。。
running.
【在 x**l 的大作中提到】 : 为什么改成driver就可以? : 如果是driver,它的scheduling policy是由user space的caller process决定的. : 如果是kernel process, no way we can control the core on which it is running. : by no means moving it to driver could solve it.
| x**l 发帖数: 64 | 10 请问比user space 下的policy 级别高的有哪些? 能给个link吗?
【在 x****u 的大作中提到】 : 用户态下你可以控制policy,不过比policy级别高的东西多了。 : 内核态你可以独占CPU任意长时间,不过这都是有代价的。。。 : : running.
| | | x****u 发帖数: 44466 | 11 比如抢占啊,中断啊。
就算你设了CPU亲和度也不是绝对的。
【在 x**l 的大作中提到】 : 请问比user space 下的policy 级别高的有哪些? 能给个link吗?
| x**l 发帖数: 64 | 12 interrupt shield可以让interrup只route到特定的几个core上去.而避免使用另外一些
core.
抢占应该是严格按照schduling policy 来的.
【在 x****u 的大作中提到】 : 比如抢占啊,中断啊。 : 就算你设了CPU亲和度也不是绝对的。
| x****u 发帖数: 44466 | 13 你用的命令做不到啊。
【在 x**l 的大作中提到】 : interrupt shield可以让interrup只route到特定的几个core上去.而避免使用另外一些 : core. : 抢占应该是严格按照schduling policy 来的.
| x**l 发帖数: 64 | 14 即使enable interrupt shield也不能解决问题. interrupt sheild 可以通过
/proc/irq/default_smp_affinity修改.
而且就算是interrupt造成的影响, 但不能解释为什么会对working()有影响.
在1 sec 延迟情况下, interrupt99%会落在运行gap()时,而不是运行working()时.
就算interrupt落在working()运行时,也不能解释为什么8个working() call都会受完全
一致的影响.
【在 x****u 的大作中提到】 : 你用的命令做不到啊。
| x****u 发帖数: 44466 | 15 这些东西不是为了实时系统设计的,你不应该在普通Linux上做RTOS的事情啊。
【在 x**l 的大作中提到】 : 即使enable interrupt shield也不能解决问题. interrupt sheild 可以通过 : /proc/irq/default_smp_affinity修改. : 而且就算是interrupt造成的影响, 但不能解释为什么会对working()有影响. : 在1 sec 延迟情况下, interrupt99%会落在运行gap()时,而不是运行working()时. : 就算interrupt落在working()运行时,也不能解释为什么8个working() call都会受完全 : 一致的影响.
| x**l 发帖数: 64 | 16 我知道在某些real time kernel或者一些RTOS下,没有这种差异. 但对更大型的复杂程
序,在RT kernel下则仍然有这种差异. 由于不能理解其中的原因,所以无法调制. 所以
我主要想理解为什么,而不是怎样为这个小程序避免这个差异.
【在 x****u 的大作中提到】 : 这些东西不是为了实时系统设计的,你不应该在普通Linux上做RTOS的事情啊。
| x****u 发帖数: 44466 | 17 就是任务切换了啊。
【在 x**l 的大作中提到】 : 我知道在某些real time kernel或者一些RTOS下,没有这种差异. 但对更大型的复杂程 : 序,在RT kernel下则仍然有这种差异. 由于不能理解其中的原因,所以无法调制. 所以 : 我主要想理解为什么,而不是怎样为这个小程序避免这个差异.
| x****k 发帖数: 2932 | 18 没有任务切换,100%CPU独占,无浮点,无sys call,only one thread on the core.
interrupt shield,
【在 x****u 的大作中提到】 : 就是任务切换了啊。
| x****u 发帖数: 44466 | 19 没任务切换,跑完进程你的CPU就死掉了。
core.
【在 x****k 的大作中提到】 : 没有任务切换,100%CPU独占,无浮点,无sys call,only one thread on the core. : interrupt shield,
| x****k 发帖数: 2932 | 20 什么叫CPU死掉?至少我测试时系统没有freeze,任务切换只发生在其他thread上,不
会抢占这个ctritical的thread
【在 x****u 的大作中提到】 : 没任务切换,跑完进程你的CPU就死掉了。 : : core.
| | | x****u 发帖数: 44466 | 21 俗称跑飞了
【在 x****k 的大作中提到】 : 什么叫CPU死掉?至少我测试时系统没有freeze,任务切换只发生在其他thread上,不 : 会抢占这个ctritical的thread
| x****k 发帖数: 2932 | 22 我的情况不属于跑飞了
【在 x****u 的大作中提到】 : 俗称跑飞了
| S*A 发帖数: 7142 | 23 这个不属于跑飞了,跑飞了是指 PC (EIP) 指到代码段以外的地方去了。
你的程序我的 core 2 due 跑不了, illegal instruction。 应该就是
那个 rdtscp 的汇编指令。rdtscp 是 i7 才引入的。 | S*A 发帖数: 7142 | 24 我想我知道你描述的问题了。
rdtscp 不是 full serialize instruction.
你去读一下 Intel 手册, rdtscp 保证读 TSC 的时候前面
的全部 instruction 都运行完了。 但是不保证没有开始运行
后面的 instruction. 因为 Intel 的 CPU 是 out of order
execution。 你相当与把 rdtscp 后面的循环也算到 work()
里面了。
建议你读一下 Intel 的这个文档,特别是第 16 页关于 rdtscp
的误差。你应该用 CPUID 来 full serialize instruction。
http://www.intel.com/content/www/us/en/intelligent-systems/embe | x****u 发帖数: 44466 | 25 楼主说
“我知道在某些real time kernel或者一些RTOS下,没有这种差异. 但对更大型的复杂程
序,在RT kernel下则仍然有这种差异.”
【在 S*A 的大作中提到】 : 我想我知道你描述的问题了。 : rdtscp 不是 full serialize instruction. : 你去读一下 Intel 手册, rdtscp 保证读 TSC 的时候前面 : 的全部 instruction 都运行完了。 但是不保证没有开始运行 : 后面的 instruction. 因为 Intel 的 CPU 是 out of order : execution。 你相当与把 rdtscp 后面的循环也算到 work() : 里面了。 : 建议你读一下 Intel 的这个文档,特别是第 16 页关于 rdtscp : 的误差。你应该用 CPUID 来 full serialize instruction。 : http://www.intel.com/content/www/us/en/intelligent-systems/embe
| S*A 发帖数: 7142 | 26 这个程序测量 TSC 的方法就是错的,无论什么 OS 都需要改过来再说,
不然结果没有意义。如果 RTOS 频繁中断或者中断里面有 serialize
instruction 完全有可能使结果看上去更接近。
杂程
【在 x****u 的大作中提到】 : 楼主说 : “我知道在某些real time kernel或者一些RTOS下,没有这种差异. 但对更大型的复杂程 : 序,在RT kernel下则仍然有这种差异.”
| x**l 发帖数: 64 | 27 谢谢回复
测量方式是存在误差,绝对不会产生大于1000个clocks级别的误差,xeon上
instruction pipeline不会超过50级,instruction虽然execution out-of-order, 但
进pipeline(IF)和最后的WB肯定是按序的,所以不会超过50 clocks的误差
当然,为了让结果更准确,可以把rdtsc部分改成这样,这样你应该可以compile了。
asm volatile(
"cpuid;"
"rdtsc;"
"cpuid;"
: "=a" (a), "=d" (d));
即使把代码改成这样,最终结果应该不会有太大变化
而且即使考虑中断或者ISR中的serialize instruction.在两种运行情况下对working()
的影响应该是近似的,而不应该产生1100 vs 2500 clocks的差别。
【在 S*A 的大作中提到】 : 这个程序测量 TSC 的方法就是错的,无论什么 OS 都需要改过来再说, : 不然结果没有意义。如果 RTOS 频繁中断或者中断里面有 serialize : instruction 完全有可能使结果看上去更接近。 : : 杂程
| G********f 发帖数: 17 | 28 simple cache miss ? what's being used in working could be pushed out of
cache during gap.
iteration
【在 x**l 的大作中提到】 : linux下的一段代码,single thread,可以独占一个cpu 100%的资源。最主要部分就是 : 这个loop : for (uint32_t i = 0; i < 10; i++) : { : working(pBuf, bufferNum); : gap(gapLoops); : } : working()会做一些有business 意义的操作, : gap()就是很简单的一个双循环去制造一些时延在两次working()之间。 : 如果gap()只运行很短的时间,例如34个cpu clock cycles,则working()在iteration
| x**l 发帖数: 64 | 29 cache missing. tlb missing 都只是可能. 问题在于是什么造成cache或者tlb的内容
被evicted了.整个core只有一个thread, L1i/L1d和tlb都是per core独有的.
【在 G********f 的大作中提到】 : simple cache miss ? what's being used in working could be pushed out of : cache during gap. : : iteration
| G********f 发帖数: 17 | 30 what about L2 ?
【在 x**l 的大作中提到】 : cache missing. tlb missing 都只是可能. 问题在于是什么造成cache或者tlb的内容 : 被evicted了.整个core只有一个thread, L1i/L1d和tlb都是per core独有的.
| | | x**l 发帖数: 64 | 31 我专门把code和data size限制小于L1 size. 32K byte
【在 G********f 的大作中提到】 : what about L2 ?
| S*A 发帖数: 7142 | 32
你自己跑过你这样的测量程序吗,肯定没有吧。我随便看一眼你这段修改过
嵌入汇编就有至少2处影响结果的错误。要不你先改好了先测一下吧。
这个就留给你做功课了。
关于 out of order, 你知道 Intel 内部是翻译成完全不同的 micro code
执行的吧?连 register 都是 remap 过的。 所以你说绝对不会产生 1000
clocks 级别的误差从那里来的,有 Intel 官方的出处吗?
我只是很奇怪你为什么不先修正了你的程序再讨论。
[ssa]$ sudo ./a.out 1 0
allocate mem@0xbb6010
memory lock is enabled.
Please run "sudo chrt -f -p [priority] " to change scheduling policy,
then press any key to continue.
Num of buffers: 1, size of each buffer: 256*8=2048 bytes, repeat 1 times,
testing.....
working time: 36993 clock cycles, gap: 407 clock cycles, dummy:0.
working time: 1496 clock cycles, gap: 253 clock cycles, dummy:0.
working time: 1408 clock cycles, gap: 253 clock cycles, dummy:0.
working time: 1430 clock cycles, gap: 242 clock cycles, dummy:0.
working time: 23584 clock cycles, gap: 242 clock cycles, dummy:0.
working time: 3069 clock cycles, gap: 253 clock cycles, dummy:0.
working time: 1408 clock cycles, gap: 253 clock cycles, dummy:0.
working time: 1419 clock cycles, gap: 253 clock cycles, dummy:0.
working time: 1397 clock cycles, gap: 242 clock cycles, dummy:0.
working time: 1430 clock cycles, gap: 253 clock cycles, dummy:0.
[ssa] $ sudo ./a.out 1 299999
allocate mem@0xfdb010
memory lock is enabled.
Please run "sudo chrt -f -p [priority] " to change scheduling policy,
then press any key to continue.
Num of buffers: 1, size of each buffer: 256*8=2048 bytes, repeat 1 times,
testing.....
working time: 31284 clock cycles, gap: 352 clock cycles, dummy:0.
working time: 2101 clock cycles, gap: 374 clock cycles, dummy:0.
working time: 2002 clock cycles, gap: 341 clock cycles, dummy:0.
working time: 1958 clock cycles, gap: 363 clock cycles, dummy:0.
working time: 1947 clock cycles, gap: 341 clock cycles, dummy:0.
working time: 1947 clock cycles, gap: 605 clock cycles, dummy:0.
working time: 1958 clock cycles, gap: 341 clock cycles, dummy:0.
working time: 1958 clock cycles, gap: 594 clock cycles, dummy:0.
working time: 1947 clock cycles, gap: 341 clock cycles, dummy:0.
working time: 1947 clock cycles, gap: 605 clock cycles, dummy:0.
[ssa]$ sudo ./a.out 1 2999999999
allocate mem@0x2475010
memory lock is enabled.
Please run "sudo chrt -f -p [priority] " to change scheduling policy,
then press any key to continue.
Num of buffers: 1, size of each buffer: 256*8=2048 bytes, repeat 1 times,
testing.....
working time: 39468 clock cycles, gap: 473 clock cycles, dummy:0.
working time: 2827 clock cycles, gap: 462 clock cycles, dummy:0.
working time: 2574 clock cycles, gap: 462 clock cycles, dummy:0.
working time: 2563 clock cycles, gap: 462 clock cycles, dummy:0.
working time: 2563 clock cycles, gap: 462 clock cycles, dummy:0.
working time: 2563 clock cycles, gap: 462 clock cycles, dummy:0.
working time: 2563 clock cycles, gap: 451 clock cycles, dummy:0.
working time: 2563 clock cycles, gap: 473 clock cycles, dummy:0.
working time: 2574 clock cycles, gap: 462 clock cycles, dummy:0.
working time: 2574 clock cycles, gap: 451 clock cycles, dummy:0.
$ sudo ./a.out 1 0
allocate mem@0x1a8a010
memory lock is enabled.
Please run "sudo chrt -f -p [priority] " to change scheduling policy,
then press any key to continue.
Num of buffers: 1, size of each buffer: 256*8=2048 bytes, repeat 1 times,
testing.....
working time: 39017 clock cycles, gap: 748 clock cycles, dummy:0.
working time: 2926 clock cycles, gap: 451 clock cycles, dummy:0.
working time: 2596 clock cycles, gap: 737 clock cycles, dummy:0.
working time: 2607 clock cycles, gap: 451 clock cycles, dummy:0.
working time: 2596 clock cycles, gap: 792 clock cycles, dummy:0.
working time: 2596 clock cycles, gap: 462 clock cycles, dummy:0.
working time: 2629 clock cycles, gap: 726 clock cycles, dummy:0.
working time: 2596 clock cycles, gap: 462 clock cycles, dummy:0.
working time: 2596 clock cycles, gap: 737 clock cycles, dummy:0.
working time: 2607 clock cycles, gap: 451 clock cycles, dummy:0.
没有你说的差别那么大。 而且 run to run 的 variance 变化比较大,
后面一个 run 长循环和短循环是完全没有区别的。
【在 x**l 的大作中提到】 : 谢谢回复 : 测量方式是存在误差,绝对不会产生大于1000个clocks级别的误差,xeon上 : instruction pipeline不会超过50级,instruction虽然execution out-of-order, 但 : 进pipeline(IF)和最后的WB肯定是按序的,所以不会超过50 clocks的误差 : 当然,为了让结果更准确,可以把rdtsc部分改成这样,这样你应该可以compile了。 : asm volatile( : "cpuid;" : "rdtsc;" : "cpuid;" : : "=a" (a), "=d" (d));
| z*******n 发帖数: 1034 | 33 手机操作系统现在至少是soft real time的,你也可以去MobileDevelopment版交流讨论
到此一挖墙
iteration
【在 x**l 的大作中提到】 : linux下的一段代码,single thread,可以独占一个cpu 100%的资源。最主要部分就是 : 这个loop : for (uint32_t i = 0; i < 10; i++) : { : working(pBuf, bufferNum); : gap(gapLoops); : } : working()会做一些有business 意义的操作, : gap()就是很简单的一个双循环去制造一些时延在两次working()之间。 : 如果gap()只运行很短的时间,例如34个cpu clock cycles,则working()在iteration
| S*A 发帖数: 7142 | 34 这个程序有汇编,手机那个 rdtsp 的指令是跑不了的。
讨论
【在 z*******n 的大作中提到】 : 手机操作系统现在至少是soft real time的,你也可以去MobileDevelopment版交流讨论 : 到此一挖墙 : : iteration
| z*******n 发帖数: 1034 | 35 基本概念 代码无关
【在 S*A 的大作中提到】 : 这个程序有汇编,手机那个 rdtsp 的指令是跑不了的。 : : 讨论
| S*A 发帖数: 7142 | 36 没有代码你如何在你的手机上实验验证是不是个
问题?理论探讨一下手机上会有什么结果然后
理论上辩论一番?
LZ 碰到这个问题根本就是 tight 在 x86 平台上的。
而且这个问题很可能本来就不是个问题。
【在 z*******n 的大作中提到】 : 基本概念 代码无关
| z*******n 发帖数: 1034 | 37 看你回复了这么多,你讲讲interrupt吧
【在 S*A 的大作中提到】 : 没有代码你如何在你的手机上实验验证是不是个 : 问题?理论探讨一下手机上会有什么结果然后 : 理论上辩论一番? : LZ 碰到这个问题根本就是 tight 在 x86 平台上的。 : 而且这个问题很可能本来就不是个问题。
| x**l 发帖数: 64 | 38 谢谢你指出错误,匆忙之中修改的,没有测试.
如果你的CPU不支持 rdtscp,请使用这个function
typedef unsigned long long ticks;
static __inline__ ticks getticks(void)
{
unsigned a, d;
asm volatile(
"rdtsc;"
: "=a" (a), "=d" (d)
:
: "memory");
asm volatile("cpuid"
:
:
: "%eax", "%ebx", "%ecx", "%edx");
return ((ticks)a) | (((ticks)d) << 32);
}
你没有用numactl去调用,所以即使修改了代码,结果也不准确。
这是我的sample 输出
$ sudo numactl --physcpubind=3 --membind=0 ./a_inline_opt.out 1 0
allocate mem@0x606010
memory lock is enabled.
Please run "sudo chrt -f -p [priority] " to change scheduling policy,
then press any key to continue.
Num of buffers: 1, size of each buffer: 256*8=2048 bytes, repeat 1 times,
testing.....
working time: 40812 clock cycles, gap: 1224 clock cycles, dummy:0, isFound:0.
working time: 1972 clock cycles, gap: 340 clock cycles, dummy:0, isFound:0.
working time: 1408 clock cycles, gap: 332 clock cycles, dummy:0, isFound:0.
working time: 1404 clock cycles, gap: 340 clock cycles, dummy:0, isFound:0.
working time: 1408 clock cycles, gap: 344 clock cycles, dummy:0, isFound:0.
working time: 1420 clock cycles, gap: 344 clock cycles, dummy:0, isFound:0.
working time: 1416 clock cycles, gap: 336 clock cycles, dummy:0, isFound:0.
working time: 1412 clock cycles, gap: 336 clock cycles, dummy:0, isFound:0.
working time: 1404 clock cycles, gap: 340 clock cycles, dummy:0, isFound:0.
working time: 1412 clock cycles, gap: 344 clock cycles, dummy:0, isFound:0.
$ sudo numactl --physcpubind=3 --membind=0 ./a_inline_opt.out 1 999999999
allocate mem@0x606010
memory lock is enabled.
Please run "sudo chrt -f -p [priority] " to change scheduling policy,
then press any key to continue.
Num of buffers: 1, size of each buffer: 256*8=2048 bytes, repeat 1 times,
testing.....
working time: 35072 clock cycles, gap: 1001922056 clock cycles, dummy:
1937409509842606368, isFound:0.
working time: 3336 clock cycles, gap: 1001890144 clock cycles, dummy:
1937409509842606368, isFound:0.
working time: 2648 clock cycles, gap: 1001806484 clock cycles, dummy:
1937409509842606368, isFound:0.
working time: 2392 clock cycles, gap: 1001846708 clock cycles, dummy:
1937409509842606368, isFound:0.
working time: 2316 clock cycles, gap: 1001847392 clock cycles, dummy:
1937409509842606368, isFound:0.
working time: 2320 clock cycles, gap: 1001764560 clock cycles, dummy:
1937409509842606368, isFound:0.
working time: 2124 clock cycles, gap: 1001793148 clock cycles, dummy:
1937409509842606368, isFound:0.
working time: 2144 clock cycles, gap: 1001742628 clock cycles, dummy:
1937409509842606368, isFound:0.
working time: 2048 clock cycles, gap: 1001768928 clock cycles, dummy:
1937409509842606368, isFound:0.
working time: 2140 clock cycles, gap: 1001755064 clock cycles, dummy:
1937409509842606368, isFound:0.
用numctl启动命令后,需要用chrt改变scheduling
sudo chrt -f -p 10 $(ps -eF | grep "a_inline" | grep -vE "sudo|grep" | sed
-nr 's/root +([0-9]+).*/1/p')
当gap()的loop数为0时,如果还使用rdtsp来获得clk #,其所花的时间为40clocks,加
入用cpuid后,这个时间变为大约340clock
对于有较新intel cpu的同学,可以使用rdtsp来或者clock,因为working()和gap()
是在一个简单循环里执行的,所以就算rdtscp后边的指令调到它前面执行了,在计算
time difference是会被相减消除掉,下面是我使用rdtscp的sample output
$ sudo numactl --physcpubind=3 --membind=0 ./a_inline_opt.out 1 0
allocate mem@0x606010
memory lock is enabled.
Please run "sudo chrt -f -p [priority] " to change scheduling policy,
then press any key to continue.
Num of buffers: 1, size of each buffer: 256*8=2048 bytes, repeat 1 times,
testing.....
working time: 12288 clock cycles, gap: 100 clock cycles, dummy:0, isFound:0.
working time: 1400 clock cycles, gap: 40 clock cycles, dummy:0, isFound:0.
working time: 1164 clock cycles, gap: 40 clock cycles, dummy:0, isFound:0.
working time: 1160 clock cycles, gap: 44 clock cycles, dummy:0, isFound:0.
working time: 1132 clock cycles, gap: 40 clock cycles, dummy:0, isFound:0.
working time: 1136 clock cycles, gap: 40 clock cycles, dummy:0, isFound:0.
working time: 1144 clock cycles, gap: 40 clock cycles, dummy:0, isFound:0.
working time: 1136 clock cycles, gap: 40 clock cycles, dummy:0, isFound:0.
working time: 1136 clock cycles, gap: 44 clock cycles, dummy:0, isFound:0.
working time: 1136 clock cycles, gap: 40 clock cycles, dummy:0, isFound:0.
$ sudo numactl --physcpubind=3 --membind=0 ./a_inline_opt.out 1 999999999
allocate mem@0x606010
memory lock is enabled.
Please run "sudo chrt -f -p [priority] " to change scheduling policy,
then press any key to continue.
Num of buffers: 1, size of each buffer: 256*8=2048 bytes, repeat 1 times,
testing.....
working time: 11428 clock cycles, gap: 1001929868 clock cycles, dummy:
1937409509842606368, isFound:0.
working time: 3464 clock cycles, gap: 1001934524 clock cycles, dummy:
1937409509842606368, isFound:0.
working time: 2092 clock cycles, gap: 1001929608 clock cycles, dummy:
1937409509842606368, isFound:0.
working time: 2152 clock cycles, gap: 1001879780 clock cycles, dummy:
1937409509842606368, isFound:0.
working time: 1984 clock cycles, gap: 1001909656 clock cycles, dummy:
1937409509842606368, isFound:0.
working time: 1596 clock cycles, gap: 1001894788 clock cycles, dummy:
1937409509842606368, isFound:0.
working time: 1996 clock cycles, gap: 1001942808 clock cycles, dummy:
1937409509842606368, isFound:0.
working time: 1596 clock cycles, gap: 1001894892 clock cycles, dummy:
1937409509842606368, isFound:0.
working time: 1924 clock cycles, gap: 1001912108 clock cycles, dummy:
1937409509842606368, isFound:0.
working time: 1964 clock cycles, gap: 1001848472 clock cycles, dummy:
1937409509842606368, isFound:0.
【在 S*A 的大作中提到】 : 没有代码你如何在你的手机上实验验证是不是个 : 问题?理论探讨一下手机上会有什么结果然后 : 理论上辩论一番? : LZ 碰到这个问题根本就是 tight 在 x86 平台上的。 : 而且这个问题很可能本来就不是个问题。
| x**l 发帖数: 64 | 39 关于不超过1000 clock误差,主要是基于对架构的理解。
x86的instruction是非等长的cisc指令,在内部会翻译成等长指令执行。但不管怎样变
,内部始终是基于pipeline的,在没有pipeline stallment情况下,pipeline入口和出
口肯定是按序的,所以无论后面的instruction跳到前面执行,也限制在pipeline的长
度内。
我记得网上有review关于intel的sandy bridge,提到了pipeline的级数,不会超过50。
回到我的代码,就算rdtscp被后面的instruction 插了,在这个简单循环中,最后的
clock数是靠将两次rdtscp的结果相减获得的,所以误差会相互抵消. | k**********g 发帖数: 989 | 40 Sorry didn't read the whole thing. Too much details for me to understand at
7:15AM.
Some places to check.
(1) Did you disable the BIOS clock-frequency and time-sharing options?
Specifically:
--- Intel EIST, Enhanced SpeedStep
http://www.intel.com/cd/channel/reseller/asmo-na/eng/203838.htm
--- Intel Turbo Boost
http://www.intel.com/content/www/us/en/architecture-and-technol
--- Intel HyperThreading
http://www.intel.com/content/www/us/en/architecture-and-technol
These "trio" can affect CPU frequency and various performance measurement.
When doing measurements that need to be repeatable (reproducible), it is
recommended to disable all three, and re-enable when the test is done.
Second possibility:
The branch prediction table may be somehow "expired". It doesn't actually "
expire" based on time, but maybe some other threads (from other applications
) has populated the branch prediction table, thus evicting your program's
predictions from it.
Just my two guesses. | | | S*A 发帖数: 7142 | 41 FT,还是错的。请接着改。
请问你是在 Intel 工作吗?你能用 Intel 内部结构去
推断 CPU 的行为而忽视 Intel 手册。
如果你对 1000 cycle 的误差感兴趣,
为什么你不按照 Intel 建议的方式使用 rdtsc 和 rdtscp?
你前面根本没有给出如何用 numctl 所以没有人能重复你的实验。
再说了,你即使用了 process scheduling, 你还是不能避免
non maskable interrupt。所以用了也是白用,你在 user space
是不能保证独占 CPU 的。
用你自己的话说,即使有少量 Interrupt/scheduling, 如何
解释我的两个 run 分布那么均匀?特别是没有循环的那个
Interrupt/scheduling 应该完全没有 Hit 到。那有循环那个
结果一样,应该也是没有 hit 到。不然你如何解释我的实验
结果,即使不改 scheduler ?
【在 x**l 的大作中提到】 : 谢谢你指出错误,匆忙之中修改的,没有测试. : 如果你的CPU不支持 rdtscp,请使用这个function : typedef unsigned long long ticks; : static __inline__ ticks getticks(void) : { : unsigned a, d; : asm volatile( : "rdtsc;" : : "=a" (a), "=d" (d) : :
| S*A 发帖数: 7142 | 42 所以我很迷惑,你似乎知道很多内部细节,但是你又忽律
很多重要的技术细节。你不按照 Intel 建议的方式来测量,
然后抱怨有意想不到的结果。
你现在还是没有论据支持你的1000 cycle 的说法。我对 Intel
CPU 还算比较了解也不敢按照你那样乱推测。我感觉你的
测量就没有可靠性。
就算我退一步,按照你的思路,50个pipeline,先假设
Intel CPU 里面就是这样工作的。你的论据也不成立。
rdtsc 单单一个 instruction 就有 250-300 cycle。
你只要pipelien 里面有 4 个 rdtsc 那样的 instruction,
你的误差就有 1000 cycle 了。 50 个 pipeline 里面
出现 4 个 rdtscp 还是有可能的吧,特别是对空循环
的例子。
你不按照 Intel 建议的方式就没有什么信服力。
而且我的反例也有了。
50。
【在 x**l 的大作中提到】 : 关于不超过1000 clock误差,主要是基于对架构的理解。 : x86的instruction是非等长的cisc指令,在内部会翻译成等长指令执行。但不管怎样变 : ,内部始终是基于pipeline的,在没有pipeline stallment情况下,pipeline入口和出 : 口肯定是按序的,所以无论后面的instruction跳到前面执行,也限制在pipeline的长 : 度内。 : 我记得网上有review关于intel的sandy bridge,提到了pipeline的级数,不会超过50。 : 回到我的代码,就算rdtscp被后面的instruction 插了,在这个简单循环中,最后的 : clock数是靠将两次rdtscp的结果相减获得的,所以误差会相互抵消.
| z*******n 发帖数: 1034 | 43 nmi smi 是经常发生的?因噎废食?
【在 S*A 的大作中提到】 : FT,还是错的。请接着改。 : 请问你是在 Intel 工作吗?你能用 Intel 内部结构去 : 推断 CPU 的行为而忽视 Intel 手册。 : 如果你对 1000 cycle 的误差感兴趣, : 为什么你不按照 Intel 建议的方式使用 rdtsc 和 rdtscp? : 你前面根本没有给出如何用 numctl 所以没有人能重复你的实验。 : 再说了,你即使用了 process scheduling, 你还是不能避免 : non maskable interrupt。所以用了也是白用,你在 user space : 是不能保证独占 CPU 的。 : 用你自己的话说,即使有少量 Interrupt/scheduling, 如何
| S*A 发帖数: 7142 | 44 请问你去编译运行了 LZ 的程序了吗?
你知道他的嵌入汇编有什么错误吗? 包括 rdtscp 的版本,
现在还有。这个测量结果就不是那么信服。
又退一步来说,如果你认为 nmi 什么的可以忽律,
那同样道理 scheduling method 就可忽律。
那么我的更正的程序的结果就有说服力了。
我的程序修正了读 TSC 的 bug, 测量出没有这种差别。
至少差别是在 variance 里面的。
【在 z*******n 的大作中提到】 : nmi smi 是经常发生的?因噎废食?
| z*******n 发帖数: 1034 | 45 你不是爱读intel的文档吗
这有一个
http://www.intel.com/content/dam/www/public/us/en/documents/whi
【在 S*A 的大作中提到】 : 请问你去编译运行了 LZ 的程序了吗? : 你知道他的嵌入汇编有什么错误吗? 包括 rdtscp 的版本, : 现在还有。这个测量结果就不是那么信服。 : 又退一步来说,如果你认为 nmi 什么的可以忽律, : 那同样道理 scheduling method 就可忽律。 : 那么我的更正的程序的结果就有说服力了。 : 我的程序修正了读 TSC 的 bug, 测量出没有这种差别。 : 至少差别是在 variance 里面的。
| S*A 发帖数: 7142 | 46 这个文档我在 24 楼贴过啦, LZ 应该好好读一下。
【在 z*******n 的大作中提到】 : 你不是爱读intel的文档吗 : 这有一个 : http://www.intel.com/content/dam/www/public/us/en/documents/whi
| S*A 发帖数: 7142 | 47 BTW, 没有人喜欢读文档的。我也不例外。但是
如果要用起来那也没有办法。 | z*******n 发帖数: 1034 | 48 你读了吗,做测量首先考虑的就是context switching
【在 S*A 的大作中提到】 : BTW, 没有人喜欢读文档的。我也不例外。但是 : 如果要用起来那也没有办法。
| S*A 发帖数: 7142 | 49 废话,所以人家示范的那个程序是在 kernel mode 实现的。
那里是用 user space 实现的。1000 cycle 根本就不够 schedule
两次,所以那个调整 scheduler 就是 distraction。 LZ 应该
先把读 TSC 代码里的 bug 修理好,做好测量再讨论。
【在 z*******n 的大作中提到】 : 你读了吗,做测量首先考虑的就是context switching
| z*******n 发帖数: 1034 | 50 一个system call 就到kernel去了 spinlock是内核才可以用?
【在 S*A 的大作中提到】 : 废话,所以人家示范的那个程序是在 kernel mode 实现的。 : 那里是用 user space 实现的。1000 cycle 根本就不够 schedule : 两次,所以那个调整 scheduler 就是 distraction。 LZ 应该 : 先把读 TSC 代码里的 bug 修理好,做好测量再讨论。
| | | S*A 发帖数: 7142 | 51 不明白你问这个和原来的问题有什么关系。
楼太歪了。
【在 z*******n 的大作中提到】 : 一个system call 就到kernel去了 spinlock是内核才可以用?
| z*******n 发帖数: 1034 | 52 你基础知识太差 是cs专业的么
【在 S*A 的大作中提到】 : 不明白你问这个和原来的问题有什么关系。 : 楼太歪了。
| S*A 发帖数: 7142 | 53 是吗,你是刚学 system call 和 spinlock 一定什么
东西都要扯上吗?
我只是觉得这个 1000 cycle 的差别和 system call
和 spinlock 关系不大。
请你这个 CS 专业的来示范一下如何用 system call
和 spinlock 解释这个 1000 cycle 的差别,让我们
看看是不是很牵强。
【在 z*******n 的大作中提到】 : 你基础知识太差 是cs专业的么
| x**l 发帖数: 64 | 54
FT,还是错的。请接着改。
---我改为两个lfence夹一个rdtsc,如果你还觉得不正确,麻烦你明示你认为正确的办法.
+++++++++++++
请问你是在 Intel 工作吗?你能用 Intel 内部结构去
推断 CPU 的行为而忽视 Intel 手册。
如果你对 1000 cycle 的误差感兴趣,
为什么你不按照 Intel 建议的方式使用 rdtsc 和 rdtscp?
----我始终不认为这1000个cycle是由于rdtscp/rdtsc造成的,道理很简单,最终计算的
是两次clock值的difference,而不是绝对值,在一个working()和gap()交替执行的循环
中,不管out-of-order execution怎么跳,rdtsc测测了误差都不会造成一种是working()
的时间是
1100左右, 1100左右, 1100左右,1100左右,1100左右,...
另一种是
2500左右, 2500左右, 2500左右, 2500左右, 2500左右, ....
++++++++++++++++++++++++++++++++++++
你前面根本没有给出如何用 numctl 所以没有人能重复你的实验。
再说了,你即使用了 process scheduling, 你还是不能避免
non maskable interrupt。所以用了也是白用,你在 user space
是不能保证独占 CPU 的。
-----我的测试环境设置太多,我拣最重要的一些写的,在3楼我写了启动方式,我的实际
做法要做的话包括这些
1. 至少有2个core的cpu.假设core 0和1. 我的测试的环境远比这个好,但我觉得2个
core可以说明问题了
2. 主流的linux distro, 我是rhel 2.6.32-220.4.1, redhat应该把32后面的一些
patch和functionality也merge进来了,至少要支持cpuset.
3. 建立一个cpuset,假设path为/dev/cpuset/system/, 包含core 0.
将所有的threads全部移到这个cpuset下.
4. 建另外一个cpuset, 假设path为/dev/cpuset/test/, 包含core 1
5. 修改/proc/irq/* 下的设置, shield interrupt from core 1.
6. 将当前的console的thread从system移到 /dev/cpuset/test/, 使用numactl启动程
序.
sudo numactl --physcpubind=1 --membind=0 ./a_inlin_opt.out 1 0
sudo numactl --physcpubind=1 --membind=0 ./a_inlin_opt.out 1 2999999999
7. 启动后到第二个console,用chrt修改scheduling policy.例如这个命令
sudo chrt -f -p 10 $(ps -eF | grep "a_inline" | grep -vE "sudo|grep" | sed
-nr 's/root +([0-9]+).*/1/p')
8. 严格的话,还要将那个在test cpuset下的console的thread移回system cpuset.
9. 回到最初的console,敲任意键运行.
+++++++++++++++++++++++++++++
用你自己的话说,即使有少量 Interrupt/scheduling, 如何
解释我的两个 run 分布那么均匀?特别是没有循环的那个
Interrupt/scheduling 应该完全没有 Hit 到。那有循环那个
结果一样,应该也是没有 hit 到。不然你如何解释我的实验
结果,即使不改 scheduler ?
----------没在你的机器上调试, 我真没办法解释为什么为什么你的两次run的分布
那么均匀.你用的是virtual machine吗?
我不用numactl,不改schedule policy,也可以看到类似的效应(working()花了两倍甚至
2.5倍的时间),但volatility会大一些.在家没有机器可以跑,所以结果没办法paste结果
上来.
++++++++++++++++++++++++++++++++++
【在 S*A 的大作中提到】 : FT,还是错的。请接着改。 : 请问你是在 Intel 工作吗?你能用 Intel 内部结构去 : 推断 CPU 的行为而忽视 Intel 手册。 : 如果你对 1000 cycle 的误差感兴趣, : 为什么你不按照 Intel 建议的方式使用 rdtsc 和 rdtscp? : 你前面根本没有给出如何用 numctl 所以没有人能重复你的实验。 : 再说了,你即使用了 process scheduling, 你还是不能避免 : non maskable interrupt。所以用了也是白用,你在 user space : 是不能保证独占 CPU 的。 : 用你自己的话说,即使有少量 Interrupt/scheduling, 如何
| x**l 发帖数: 64 | 55
所以我很迷惑,你似乎知道很多内部细节,但是你又忽律
很多重要的技术细节。你不按照 Intel 建议的方式来测量,
然后抱怨有意想不到的结果。
你现在还是没有论据支持你的1000 cycle 的说法。我对 Intel
CPU 还算比较了解也不敢按照你那样乱推测。我感觉你的
测量就没有可靠性。
----关于测量问题我刚给你回了,请看一下,谢谢
+++++++++++
就算我退一步,按照你的思路,50个pipeline,先假设
Intel CPU 里面就是这样工作的。你的论据也不成立。
rdtsc 单单一个 instruction 就有 250-300 cycle。
你只要pipelien 里面有 4 个 rdtsc 那样的 instruction,
你的误差就有 1000 cycle 了。 50 个 pipeline 里面
出现 4 个 rdtscp 还是有可能的吧,特别是对空循环
的例子。
----不知道你的rdtsc需要250~300cycle是从哪里来的?有reference没有?还是自己测的?
如果我们定义x86指令在pipeline中要占多少级为指令所花的时间,可以重复调用(不是
循环调用,unroll loop)这个函数,把前后两次调用的返值的different算一下就可以了
typedef unsigned long long ticks;
static __inline__ ticks getticks(void)
{
unsigned a, d;
asm volatile(
"rdtscp;"
: "=a" (a), "=d" (d)
:
:);
return ((ticks)a) | (((ticks)d) << 32);
}
-O3的优化,但return value一定要存下来参与difference的计算.
我在一台xeon sandy bridge上的结果可以稳定在32个clock.偶尔有36个clock
objdump后的可以看到基本就是下面这段代码的重复(intel style)
rdtscp
shl rdx. 0x20
mov eax,eax
or rdx,rax
mov QWORD PTR[rsp+0x228],rdx
5条instruction也就是32个clock的差别,其中还包括一个mov 到memory
的操作.
+++++++++++
你不按照 Intel 建议的方式就没有什么信服力。
而且我的反例也有了。
【在 S*A 的大作中提到】 : 所以我很迷惑,你似乎知道很多内部细节,但是你又忽律 : 很多重要的技术细节。你不按照 Intel 建议的方式来测量, : 然后抱怨有意想不到的结果。 : 你现在还是没有论据支持你的1000 cycle 的说法。我对 Intel : CPU 还算比较了解也不敢按照你那样乱推测。我感觉你的 : 测量就没有可靠性。 : 就算我退一步,按照你的思路,50个pipeline,先假设 : Intel CPU 里面就是这样工作的。你的论据也不成立。 : rdtsc 单单一个 instruction 就有 250-300 cycle。 : 你只要pipelien 里面有 4 个 rdtsc 那样的 instruction,
| x**l 发帖数: 64 | 56 能把你修改后的getticks()贴一下吗?
【在 S*A 的大作中提到】 : 请问你去编译运行了 LZ 的程序了吗? : 你知道他的嵌入汇编有什么错误吗? 包括 rdtscp 的版本, : 现在还有。这个测量结果就不是那么信服。 : 又退一步来说,如果你认为 nmi 什么的可以忽律, : 那同样道理 scheduling method 就可忽律。 : 那么我的更正的程序的结果就有说服力了。 : 我的程序修正了读 TSC 的 bug, 测量出没有这种差别。 : 至少差别是在 variance 里面的。
| z*******n 发帖数: 1034 | 57 根本问题是 中断没有关,在任何情况下都可能会被切换出去做别的事情,
很难理解吗
【在 x**l 的大作中提到】 : 能把你修改后的getticks()贴一下吗?
| z*******n 发帖数: 1034 | 58 一知半解君发intel手册不看的,最大绝对误差176
如果你的两种情况的值是稳定的,因为有误差,所一绝对意义不大
可是当比较的时候,比较意义大,因为都带着误差
【在 x**l 的大作中提到】 : 能把你修改后的getticks()贴一下吗?
| z*******n 发帖数: 1034 | 59 根本问题是中断,这个帖子里有人说driver也在说中断,
你就抓些没有的
【在 S*A 的大作中提到】 : 是吗,你是刚学 system call 和 spinlock 一定什么 : 东西都要扯上吗? : 我只是觉得这个 1000 cycle 的差别和 system call : 和 spinlock 关系不大。 : 请你这个 CS 专业的来示范一下如何用 system call : 和 spinlock 解释这个 1000 cycle 的差别,让我们 : 看看是不是很牵强。
| S*A 发帖数: 7142 | 60 我就简短点说吧,
你的 rdtsc 第一个版本先是有后面的 cpuid 冲掉了前面的 rdtsc 的
EAX EDX 寄存器,
修改改后的第二个版本应该先做 CPUID 然后做 RDTSC。看
Intel 手册。
你的 rdtscp 的汇编版本放开 out of order 不说,rdtscp 会
clobber ECX 寄存器,在里面存 CPU ID。你的汇编没有告诉
gcc 你破坏了 ECX 寄存器。虽然你用了 volatile, 那个只是
告诉 gcc 你有其他的 memory side effect (其实你没有)。
你仍然需要告诉 gcc clobber ECX。
然后正确的读 RDTSC 和 RDTSCP 的嵌入汇编代码在 24 楼
的 Intel pdf 里面都有,我就不重复了。
我没有用虚拟机。
你那个 1000 cycle 的差别不可能是中间被 schedule 其他的
thread。 单单 schedule 一次 task 就要 1000 cycle 这个数
量极。你要换出去换回来是不可能的。而且也不能解释这个
刚刚好每个 work() 都被抢先 schedule 掉。我不理解你
为什么要在 user space 玩这些 schedule 的 game。 如果
你要比较确定的控制 CPU 行为,你应该用 kernel module,
例如 Intel pdf 里面做的那样,你就可以整个 disable preempt。
我还是不能信服你的测量结果,因为你没有排除 out of order。
如果你能够收集一个排除 out of order 的结果,多做几次这个
会比较有意义。大家在这里瞎猜 out of order 到底有多少影响
是在浪费时间。
我想到一个假设的理论可能解释这个现象。你在 GAP()里面
花比较长时间的循环以后,CPU expire 了 work() 那些代码的
instruction cache。导致进入 work()的时候需要从新 decode
instruction, 然后就多了一些时间。或者你很长时间没有访问
data memory,导致其中一些 work() 用到的 data cache
被 expired 了。或者是 work() 循环里的 branch predict
被仍掉了。你想想,如果是 1 秒钟以后才用到,这样的
频率也太低了,被仍掉是完全有可能的。至于 Intel 的 cache
expire 用什么具体的算法就是完全超出我知道的范围了。
所以这些也只能推测。 |
|