优化 SIMD 直方图计算
Optimizing SIMD histogram calculation
我编写了一个代码,该代码在给定 opencv struct IplImage * 和直方图缓冲区 unsigned int * 的情况下实现直方图计算。我对 SIMD 还是个新手,所以我可能没有充分利用指令集提供的全部潜力。
histogramASM:
xor rdx, rdx
xor rax, rax
mov eax, dword [imgPtr + imgWidthOffset]
mov edx, dword [imgPtr + imgHeightOffset]
mul rdx
mov rdx, rax ; rdx = Image Size
mov r10, qword [imgPtr + imgDataOffset] ; r10 = ImgData
NextPacket:
mov rax, rdx
movdqu xmm0, [r10 + rax - 16]
mov rcx,16 ; 16 pixels/paq
PacketLoop:
pextrb rbx, xmm0, 0 ; saving the pixel value on rbx
shl rbx,2
inc dword [rbx + Hist]
psrldq xmm0,1
loop PacketLoop
sub rdx,16
cmp rdx,0
jnz NextPacket
ret
在C上,我会运行这些代码获得相同的结果。
imgSize = (img->width)*(img->height);
pixelData = (unsigned char *) img->imageData;
for(i = 0; i < imgSize; i++)
{
pixel = *pixelData;
hist[pixel]++;
pixelData++;
}
但是,在我的计算机中使用 rdtsc() 测量的两者所花费的时间仅比 SIMD 的汇编程序好 1.5 倍。有没有办法优化上面的代码,快速用SIMD填充直方图向量?
提前致谢
与 Jester 一样,我很惊讶您的 SIMD 代码有任何重大改进。您是否在启用优化的情况下编译了 C 代码?
我可以提出的另一个建议是展开您的 Packetloop
循环。这是一个相当简单的优化,并将每个 "iteration" 的指令数减少到两个:
pextrb ebx, xmm0, 0
inc dword [ebx * 4 + Hist]
pextrb ebx, xmm0, 1
inc dword [ebx * 4 + Hist]
pextrb ebx, xmm0, 2
inc dword [ebx * 4 + Hist]
...
pextrb ebx, xmm0, 15
inc dword [ebx * 4 + Hist]
如果您正在使用 NASM,您可以使用 %rep 指令来节省一些输入:
%assign pixel 0
%rep 16
pextrb rbx, xmm0, pixel
inc dword [rbx * 4 + Hist]
%assign pixel pixel + 1
%endrep
我编写了一个代码,该代码在给定 opencv struct IplImage * 和直方图缓冲区 unsigned int * 的情况下实现直方图计算。我对 SIMD 还是个新手,所以我可能没有充分利用指令集提供的全部潜力。
histogramASM:
xor rdx, rdx
xor rax, rax
mov eax, dword [imgPtr + imgWidthOffset]
mov edx, dword [imgPtr + imgHeightOffset]
mul rdx
mov rdx, rax ; rdx = Image Size
mov r10, qword [imgPtr + imgDataOffset] ; r10 = ImgData
NextPacket:
mov rax, rdx
movdqu xmm0, [r10 + rax - 16]
mov rcx,16 ; 16 pixels/paq
PacketLoop:
pextrb rbx, xmm0, 0 ; saving the pixel value on rbx
shl rbx,2
inc dword [rbx + Hist]
psrldq xmm0,1
loop PacketLoop
sub rdx,16
cmp rdx,0
jnz NextPacket
ret
在C上,我会运行这些代码获得相同的结果。
imgSize = (img->width)*(img->height);
pixelData = (unsigned char *) img->imageData;
for(i = 0; i < imgSize; i++)
{
pixel = *pixelData;
hist[pixel]++;
pixelData++;
}
但是,在我的计算机中使用 rdtsc() 测量的两者所花费的时间仅比 SIMD 的汇编程序好 1.5 倍。有没有办法优化上面的代码,快速用SIMD填充直方图向量? 提前致谢
与 Jester 一样,我很惊讶您的 SIMD 代码有任何重大改进。您是否在启用优化的情况下编译了 C 代码?
我可以提出的另一个建议是展开您的 Packetloop
循环。这是一个相当简单的优化,并将每个 "iteration" 的指令数减少到两个:
pextrb ebx, xmm0, 0
inc dword [ebx * 4 + Hist]
pextrb ebx, xmm0, 1
inc dword [ebx * 4 + Hist]
pextrb ebx, xmm0, 2
inc dword [ebx * 4 + Hist]
...
pextrb ebx, xmm0, 15
inc dword [ebx * 4 + Hist]
如果您正在使用 NASM,您可以使用 %rep 指令来节省一些输入:
%assign pixel 0
%rep 16
pextrb rbx, xmm0, pixel
inc dword [rbx * 4 + Hist]
%assign pixel pixel + 1
%endrep