Re: [心得] 内存效能瓶颈

楼主: fo40225   2016-01-02 15:06:59
※ 引述《erspicu (.)》之铭言:
: 全code....
: http://paste.ofcode.org/3bw8ufpUwuPqT4xNfwUScZH
: 你觉得在你默认的猜测中
: a.
: color = (uint)((0xff << 24) | ((rgb555 & 0x1f) << 19) | ((rgb555 & 0x3e0)
: << 6) | ((rgb555 & 0x7c00) >> 7));
: b.
: color = rgb555_Table[rgb555 ];
: 你会觉得哪个速度比较快????
: 一个是好几次的bitwise计算算出结果..
: 一个是用index捞取array一个步骤
: 答案是 a 比较快... 不管是debug模式下或是一般模式
: (现在一般电脑的情况...cpu效能超高,一般内存没追上cpu速度)
: 只是一般模式a快得更多
: 而pointer的写法 debug模式下,快一般array的操作方式一点,一般模式,
: 用指标跟ARRAY速度差不多(应该是一样)....
: pointer在c#好像不只一种方式操作
测试环境为 VS2015 .net 4.6.1 Release build 64位元执行模式
直接观察反组译码
在原测试code中第51行
color = (uint)((0xff << 24) | ((rgb555 & 0x1f) << 19) | ((rgb555 & 0x3e0)
<< 6) | ((rgb555 & 0x7c00) >> 7));
这句只会执行一次(最后一次) 而不是10000*65535次
(反而第50行 rgb555 = (ushort)(i & 0xffff);
老老实实的执行了10000*65535次 优化的逻辑真奇怪)
而array只会检查i有没有超过阵列界限65535次 不会取值
pointer 则是CLR的bug
https://github.com/dotnet/coreclr/issues/2480
每次存取fixed的pointer时 都重新从local variables加载到CPU register
(暂时的解法是把pointer复制出来一份)
所以结果为 37X 19X 55X ms
====
测试code
http://paste.ofcode.org/d8tZ28wfK3iA5Mi3kLuvAR
不确定在原测试code 63行有没有写错
color = rgb555_Table_pointer[i];
测试code通通改成用
color = rgb555_Table_pointer[rgb555];
注: GC.KeepAlive() 是拿来模拟一个method call 避免取值赋值被优化掉
其方法内容是空白 如果不呼叫GC.KeepAlive() 而自己写空方法的话 一样会被优化掉
http://referencesource.microsoft.com/#mscorlib/system/gc.cs,18b31b2edcc0f711
在加上GC.KeepAlive(color); 的状况下
Array 32XX ms
bitwise 34XX ms
pointer 30XX ms
而这个测试也顺便测试JIT warm up 的影响
以及传说 "int的操作有特别优化" 这两件事
看起来是没什么影响
====
: 参考
: http://nbsoftsolutions.com/blog/high-performance-unsafe-c-code-is-a-lie
这篇文章刚好挑到一个在.net中极度优化的类别 string
所以会得到使用指标没有什么加速效果的结论
: stringBuilder.Append((char)currentByte);
内部为char array pointer操作
http://referencesource.microsoft.com/#mscorlib/system/text/
stringbuilder.cs.html,a2e7c78d85807da5
: stringBuilder.ToString()
内部为pointer操作
http://referencesource.microsoft.com/#mscorlib/system/text/
stringbuilder.cs,5a97da49a158a3c9
: charBuffer[index++] = (char)currentByte;
: new string(charBuffer, 0, index);
: *bytePtr++ = currentByte;
: new string((sbyte*)byteArray);
: charPtr++ = (char)currentByte;
: new string(charPtr);
string的建构子内部均为为C++实作
以String(char [] value)为例
http://referencesource.microsoft.com/#mscorlib/system/
string.cs,ec408439366007e6
https://github.com/dotnet/coreclr/blob/master/src/vm/ecalllist.h#L220
https://github.com/dotnet/coreclr/blob/master/src/
classlibnative/bcltype/stringnative.cpp#L99
https://github.com/dotnet/coreclr/blob/master/src/vm/object.cpp#L2086
测试出来的结果相当是正常的 如果有比较慢 有可能是做了多余的转型导致
网络上也有使用unsafe大幅加速的例子 可参考
http://blog.darkthread.net/post-2010-06-19-use-unsafe.aspx
作者: Litfal (Litfal)   2016-01-02 15:28:00
64位元环境的确会有这个短循环只跑一次的问题,我也不知道是神优化还是BUG,用32BIT或把color提到class field才能
楼主: fo40225   2016-01-02 15:38:00
刚测试 32位元一样只跑一次 class field就不会只有一次了
作者: erspicu (.)   2016-01-02 18:24:00
一直觉得优化原则.JIT 若没摸都反组译那层 被包著没办法深入看进去的话 一切都很谜样... 可能真的要来学了

Links booklink

Contact Us: admin [ a t ] ucptt.com