移除SSE intrinsic函数中的指令为何会导致性能下降?
移除SSE intrinsic函数中的指令为何会导致性能下降?
咱先把话说在前头:这个问题不是关于YUV422到RGB的转换本身哦!
先给你看看对应的SSE实现代码:
static void yuv422ToRGB(unsigned char* img, int width, int height, int widthStep, unsigned char* dst) { __m128i yMask1 = _mm_setr_epi8(0, -1, 0, -1, 0, -1, 4, -1, 4, -1, 4, -1, 8, -1, 8, -1); __m128i yMask2 = _mm_setr_epi8(8, -1, 12, -1, 12, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1); __m128i uvMask1 = _mm_setr_epi8(1, 3, 1, 3, 1, 3, 5, 7, 5, 7, 5, 7, 9, 11, 9, 11); __m128i uvMask2 = _mm_setr_epi8(9, 11, 13, 15, 13, 15, 13, 15, -1, -1, -1, -1, -1, -1, -1, -1); __m128i magicMask1 = _mm_setr_epi8(0, 102, 25, 52, -127, 0, 0, 102, 25, 52, -127, 0, 0, 102, 25, 52); __m128i magicMask2 = _mm_setr_epi8(-127, 0, 0, 102, 25, 52, -127, 0, 0, 0, 0, 0, 0, 0, 0, 0); __m128i const128 = _mm_set1_epi8(-127); __m128i const16 = _mm_set1_epi16(16); __m128i const32 = _mm_set1_epi16(32); __m128i const74 = _mm_set1_epi16(74); // 代码此处截断,不影响核心逻辑分析 }
为啥移除这些SSE指令会导致性能下降?咱掰碎了说:
- 首先,SSE就是吃并行饭的!这段代码里的每个
__m128i操作,都是一次干16个字节的活——原本要循环16次处理单字节的逻辑,现在一条指令就搞定了。要是你删了某条SSE指令,要么得退回到“一次处理1个/2个字节”的标量模式,循环次数直接翻好几倍,CPU的吞吐量瞬间就垮了。 - 其次,这套指令序列是流水线友好的:从掩码加载、数据提取到运算,是顺着CPU流水线走的,每一步都在给下一个任务铺路。你删中间指令,就等于把流水线拆了个口子,CPU得停下来等数据、重新调度,这中间的停顿(stall)可是很费时间的。
- 再者,代码里的这些掩码(比如
yMask1、uvMask1)是用来一次性打包提取Y/U/V分量的,删了相关指令,你就得手动拆分数据,额外加一堆内存访问和判断逻辑——内存访问的延迟可比SIMD运算高多了,这开销一下子就上去了。 - 举个具体的例子:要是你删了
yMask2的定义,原本一次能从128位寄存器里抠出后续的Y分量,现在就得手动加载、移位、拆分,多出来好几个标量操作,每轮循环的执行时间直接变长,整体性能自然就降了。
备注:内容来源于stack exchange,提问作者Crigges
相关产品推荐
相关产品推荐

