k****f 发帖数: 3794 | 1 1。for loop,测试0比测试n要快。
for(i=n-1;i>=0;i--) 替代 for(i=0;i
2。节省转跳分支
i+= !(!(j)); 替代 if( j!=0 ) i++;
现在的编译还需要这种古怪的写法么? |
y*******g 发帖数: 6599 | 2 有必要吗?
如果这段不是瓶颈的话
【在 k****f 的大作中提到】 : 1。for loop,测试0比测试n要快。 : for(i=n-1;i>=0;i--) 替代 for(i=0;i: 2。节省转跳分支 : i+= !(!(j)); 替代 if( j!=0 ) i++; : 现在的编译还需要这种古怪的写法么?
|
x******c 发帖数: 13 | 3 these really depends on the CPU it runs on...
anyway, for 1, it probably makes no difference
for 2, I think it makes a difference on performance critical code. branch
mis-predication usually has a pretty high cost |
k****f 发帖数: 3794 | 4 对应常见的intel/amd cpu呢?有没有什么定论呢?
【在 x******c 的大作中提到】 : these really depends on the CPU it runs on... : anyway, for 1, it probably makes no difference : for 2, I think it makes a difference on performance critical code. branch : mis-predication usually has a pretty high cost
|
x******c 发帖数: 13 | 5 what I said above is for modern intel/amd cpus.
No one can say for sure without profiling/benchmarking though.
As a general rule: don't write code like that.
If your code is not fast enough, use a profiler to identify the most
performance critical parts, then try these to see if it helps. |
r*********r 发帖数: 3195 | 6 第二个可能有用。因为跳转会清空流水线,现在的cpu都有几十级流水线,
清一次就慢很多。 |
B********e 发帖数: 1062 | 7 1 is used pretty often.
The accumulation for all the loops may have huge effects.
【在 k****f 的大作中提到】 : 1。for loop,测试0比测试n要快。 : for(i=n-1;i>=0;i--) 替代 for(i=0;i: 2。节省转跳分支 : i+= !(!(j)); 替代 if( j!=0 ) i++; : 现在的编译还需要这种古怪的写法么?
|
b***i 发帖数: 3043 | 8 2是怎么实现的?写成汇编语言试试
【在 k****f 的大作中提到】 : 1。for loop,测试0比测试n要快。 : for(i=n-1;i>=0;i--) 替代 for(i=0;i: 2。节省转跳分支 : i+= !(!(j)); 替代 if( j!=0 ) i++; : 现在的编译还需要这种古怪的写法么?
|
c**d 发帖数: 580 | 9 给2写一下汇编,肯定有不对的地方,太久远。。。
x86 assember:
mov EBX [addr of i]
mov ECX [addr of j]
neg ECX
neg ECX
add EBX ECX |
c**d 发帖数: 580 | 10 第一个因为有JZ,去检查EFLAGS,所以i-- 更快些。
不过现在的compiler应该对付这个不是问题,而且还有循环展开什么的。区别应该很小
了。 |
|
|
t****t 发帖数: 6806 | 11 你这个太不对了, 差十万八千里
neg对应C的操作符是~,不是!
剩下的自己想吧
【在 c**d 的大作中提到】 : 给2写一下汇编,肯定有不对的地方,太久远。。。 : x86 assember: : mov EBX [addr of i] : mov ECX [addr of j] : neg ECX : neg ECX : add EBX ECX
|
c**d 发帖数: 580 | 12 好像必须要CMP,看了一眼手册。
有人写不用CMP的么? |
t****t 发帖数: 6806 | 13 CMP不是关键问题, 关键是不要分支
一般在x86上用setcc来去掉分支
比如说
mov ebx, a
xor eax, eax
test ebx, ebx /* 一般测试0用这个 */
setnz al
/* eax=(a!=0) */
【在 c**d 的大作中提到】 : 好像必须要CMP,看了一眼手册。 : 有人写不用CMP的么?
|
T*****9 发帖数: 2484 | 14 问一个
我到现在还不是很了解x86怎么用xchg实现test_and_set的。。。
【在 t****t 的大作中提到】 : CMP不是关键问题, 关键是不要分支 : 一般在x86上用setcc来去掉分支 : 比如说 : mov ebx, a : xor eax, eax : test ebx, ebx /* 一般测试0用这个 */ : setnz al : /* eax=(a!=0) */
|
D*******a 发帖数: 3688 | 15 setcc是几86出来的指令?
另,也可以:
lahf
shr ax, 14 //把0-flag移到最低位
and ax, 1
【在 t****t 的大作中提到】 : CMP不是关键问题, 关键是不要分支 : 一般在x86上用setcc来去掉分支 : 比如说 : mov ebx, a : xor eax, eax : test ebx, ebx /* 一般测试0用这个 */ : setnz al : /* eax=(a!=0) */
|
c**d 发帖数: 580 | 16 setnz 是386以后的,估计real和protected模式都不干活说。 |
t****t 发帖数: 6806 | 17 setcc的确是386以上才有的.
不过现在还有386以下的机器吗, 现在的OS还有哪个能在286以下跑的?
什么叫real和protected模式都不干活? 你多半模式之间的区别都没搞明白.
【在 c**d 的大作中提到】 : setnz 是386以后的,估计real和protected模式都不干活说。
|
t****t 发帖数: 6806 | 18 没什么啊, 就是xchg自动lock, 所以它总是atomic的
比如说一直换一个0到lock
如果换出来一个1就拿到了lock, 如果换出来的还是0就是没拿到接着等
【在 T*****9 的大作中提到】 : 问一个 : 我到现在还不是很了解x86怎么用xchg实现test_and_set的。。。
|
g****g 发帖数: 310 | 19 绝对没必要,也不应该写这类代码。根本没有任何速度上的提升。(如果有,那么是在
你做梦的时候)
unsigned long avg1=0, avg2=0;
for (int n=0;n<1000000; n++)
{
int j = 0, i=0;
a = rdtsc();
i+= !(!(j));
b=rdtsc()-a;
avg1+=b;
j=0; i=1;
a = rdtsc();
if( j!=0 ) i++;
b=rdtsc()-a;
avg2+=b;
j++;i++;
}
std::cout << "Take:" << avg1/1000000 << std::endl;
std::cout << "Take:" << avg2/1000000 << std::endl;
两者的结果基本相同。 |
k****f 发帖数: 3794 | 20 你这个代码会被编译器优化掉的,j=0就被直接拿去优化i+=!(!j)
你应该产生n个随机数放到数组里面,是0和非0个数差不多的,这样子才能比较好。
【在 g****g 的大作中提到】 : 绝对没必要,也不应该写这类代码。根本没有任何速度上的提升。(如果有,那么是在 : 你做梦的时候) : unsigned long avg1=0, avg2=0; : for (int n=0;n<1000000; n++) : { : int j = 0, i=0; : a = rdtsc(); : i+= !(!(j)); : b=rdtsc()-a; : avg1+=b;
|
|
|
g****g 发帖数: 310 | |
g****g 发帖数: 310 | 22 一样的结果,整天讨论哪个快,却自己不去测试一下有意义么?
unsigned long avg1=0, avg2=0;
srand( (unsigned)time( NULL ) );
int j = 0, i=0;
for (int n=0;n<1000000; n++)
{
j = (rand() > RAND_MAX/2) ? 0 : 1;
a = rdtsc();
i+= !(!(j));
b=rdtsc()-a;
avg1+=b;
j=0; i=1;
a = rdtsc();
if( j!=0 ) i++;
b=rdtsc()-a;
avg2+=b;
}
std::cout << "Take:" << avg1/1000000 << std::endl;
std::cout << "Take:" << avg2/1000000 << std:
【在 k****f 的大作中提到】 : 你这个代码会被编译器优化掉的,j=0就被直接拿去优化i+=!(!j) : 你应该产生n个随机数放到数组里面,是0和非0个数差不多的,这样子才能比较好。
|
k****f 发帖数: 3794 | 23 你把j放到循环体了
j++有个鸟用
【在 g****g 的大作中提到】 : 楼上的你没看到每次循环后j++么?
|
g****g 发帖数: 310 | 24 对于1,可以肯定告诉你,不存在任何速度上的差别。
【在 k****f 的大作中提到】 : 1。for loop,测试0比测试n要快。 : for(i=n-1;i>=0;i--) 替代 for(i=0;i: 2。节省转跳分支 : i+= !(!(j)); 替代 if( j!=0 ) i++; : 现在的编译还需要这种古怪的写法么?
|
g****g 发帖数: 310 | 25 rand也测过了,根本没区别,你干吗不自己去试试?
【在 k****f 的大作中提到】 : 你把j放到循环体了 : j++有个鸟用
|
g****g 发帖数: 310 | 26 wrong, no difference at all, can you test before post?
【在 B********e 的大作中提到】 : 1 is used pretty often. : The accumulation for all the loops may have huge effects.
|
t****t 发帖数: 6806 | 27 2其实我知道是没什么区别的, 现在的编译器去分支还可以
不过你贴的例子确实是不对啊.
【在 g****g 的大作中提到】 : rand也测过了,根本没区别,你干吗不自己去试试?
|
k****f 发帖数: 3794 | 28 嗯,我看过GCC的汇编结果了
不加优化,确实是有jmp指令的
一加了优化选项,比如O3,jmp就没有了,被setne之类替换掉的
结果两个c代码编译出来就一样了
【在 t****t 的大作中提到】 : 2其实我知道是没什么区别的, 现在的编译器去分支还可以 : 不过你贴的例子确实是不对啊.
|
g****g 发帖数: 310 | 29 我的结论:
对于那个for循环,两者完全一样,
对于i+= !(!(j)); 替代 if( j!=0 ) i++;
i+= !(!(j))快,如果这段代码很critical,那么你可以这么改。 |
g****g 发帖数: 310 | 30 不加任何优化的代码
if( j!=0 ) i++;
0041DD87 837D B0 00 CMP DWORD PTR SS:[EBP-50],0
0041DD8B 74 09 JE SHORT test2.0041DD96
0041DD8D 8B45 A4 MOV EAX,DWORD PTR SS:[EBP-5C]
0041DD90 83C0 01 ADD EAX,1
0041DD93 8945 A4 MOV DWORD PTR SS:[EBP-5C],EAX
i+= !(!(j));
0041DD0D 33C0 XOR EAX,EAX
0041DD0F 837D B0 00 CMP DWORD PTR SS:[EBP-50],0
0041DD13 0F95C0 SETNE AL
0041DD16 0345 A4 ADD EAX,DWORD PTR SS:[EBP-5C]
0041DD19 |
|
|
g****g 发帖数: 310 | 31 我的结论:
对于那个for循环,两者完全一样,
对于i+= !(!(j)); 替代 if( j!=0 ) i++;
i+= !(!(j))快,如果这段代码很critical,那么你可以这么改。 |
t****t 发帖数: 6806 | 32 不加优化比较根本没意义
【在 g****g 的大作中提到】 : 不加任何优化的代码 : if( j!=0 ) i++; : 0041DD87 837D B0 00 CMP DWORD PTR SS:[EBP-50],0 : 0041DD8B 74 09 JE SHORT test2.0041DD96 : 0041DD8D 8B45 A4 MOV EAX,DWORD PTR SS:[EBP-5C] : 0041DD90 83C0 01 ADD EAX,1 : 0041DD93 8945 A4 MOV DWORD PTR SS:[EBP-5C],EAX : i+= !(!(j)); : 0041DD0D 33C0 XOR EAX,EAX : 0041DD0F 837D B0 00 CMP DWORD PTR SS:[EBP-50],0
|
T*****9 发帖数: 2484 | 33 xchg会自动lock?
我一直以为就是交换寄存器和mem的值
【在 t****t 的大作中提到】 : 没什么啊, 就是xchg自动lock, 所以它总是atomic的 : 比如说一直换一个0到lock : 如果换出来一个1就拿到了lock, 如果换出来的还是0就是没拿到接着等
|
N********n 发帖数: 8363 | 34 Don't write code that makes your co-worker cringe.
【在 k****f 的大作中提到】 : 1。for loop,测试0比测试n要快。 : for(i=n-1;i>=0;i--) 替代 for(i=0;i: 2。节省转跳分支 : i+= !(!(j)); 替代 if( j!=0 ) i++; : 现在的编译还需要这种古怪的写法么?
|