【发布时间】:2018-10-07 12:14:05
【问题描述】:
这是我的简单 blitting 函数:
static void blit8(unsigned char* dest, unsigned char* src)
{
byte i;
for (i = 0; i < 8; ++i) {
if (*src != 0) {
*dest = *src;
}
++dest;
++src;
}
}
我已经在-O3,并且blit8 正在内联。 restrict (gcc) 在这里不起作用。也没有以任何不同的方式增加指针,或者使用另一个数字作为透明度,或者 i 的另一种类型......我什至尝试传递一个 1 字节的位掩码并检查它而不是取消引用 src。将i 的限制增加到 16 似乎可以提供 very 次要的加速(~4-6%),但我使用的是 8 字节,而不是 16 字节的块。
我的瓶颈?实际上没有线索,我不认为这是缓存线,因为我的未命中率很低(?)并且64(我的缓存线大小)在改变事物时没有特别的意义。但我也不认为它是内存速度(因为memcpy 更快,稍后再说)。
cg_annotate 说这个关于blit8(没有内联):
Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw file:function
3,747,585,536 62 1 1,252,173,824 2,097,653 0 674,067,968 0 0 ppu.c:blit8.constprop.0
常规cachegrind 输出(带内联):
I refs: 6,446,979,546
I1 misses: 184,752
LLi misses: 22,549
I1 miss rate: 0.00%
LLi miss rate: 0.00%
D refs: 2,150,502,425 (1,497,875,135 rd + 652,627,290 wr)
D1 misses: 17,121,968 ( 2,761,307 rd + 14,360,661 wr)
LLd misses: 253,685 ( 70,802 rd + 182,883 wr)
D1 miss rate: 0.8% ( 0.2% + 2.2% )
LLd miss rate: 0.0% ( 0.0% + 0.0% )
LL refs: 17,306,720 ( 2,946,059 rd + 14,360,661 wr)
LL misses: 276,234 ( 93,351 rd + 182,883 wr)
LL miss rate: 0.0% ( 0.0% + 0.0% )
0.8% D1 未命中率?对我来说听起来很低。
但对我来说最有趣的是,删除 0-check(在功能上与 memcpy 相同)提供了
memcpy 快了约 25%。我希望尽可能接近原始memcpy 的速度,同时保持颜色0 透明。
问题是,据我所知,没有向量指令支持条件,但我需要保留dest,其中src 是0。有没有什么 [fast] 可以像 OR 一样但在字节级别上运行?
我之前读过有一个扩展或其他东西告诉 CPU 不要缓存一些数据,但我再也找不到它了。我的想法是不直接从src 读取,只从它写入dest,并确保它没有被缓存。然后只需从位掩码中读取以检查透明度。 我只是不知道如何真正做到这一点。这甚至可能吗?更不用说快速了?我也不知道,所以我问这个问题。
我更喜欢仅使用 C 来提高速度的技巧,也许是一些 gcc 扩展,但如果 x86 汇编是唯一的方法,那就这样吧。帮助我了解我的实际瓶颈(因为我对我的结果感到困惑)也会有所帮助。
【问题讨论】:
-
为什么不使用 memcpy?它是超级优化的,如果在您的架构上可用,它会被一些低级组装操作所取代。
-
@sturcotte06 此代码不会用零覆盖,因此与 memcpy 不同。
-
@sturcotte06 OP 已经提到了
memcpy。 -
那么我不认为你可以匹配 memcpy 的性能,因为你不能利用 x86 指令。
-
与遮罩非常兼容。例如,请参阅似乎适合此处的
pblendvb指令。
标签: c performance optimization memcpy blit