如何优化MATLAB按位运算

时间:2012-07-14 09:15:41

标签: performance matlab integer bit-manipulation

我在MATLAB中编写了自己的SHA1实现,它提供了正确的哈希值。但是,它非常慢(我的Core i7-2760QM上的字符串1000 a需要9.9秒),我认为缓慢是MATLAB实现按位逻辑运算(bitand的结果, bitorbitxorbitcmp)以及整数的按位移位(bitshiftbitrolbitror)。

特别是我想知道需要使用bitrol命令为bitrorfi构建定点数字对象,因为无论如何在Intel x86程序集中rol和{{ 1}}用于所有大小的寄存器和存储器地址。但是,ror非常快(它不需要任何定点数字结构,常规bitshift变量工作正常),这使得情况更加奇怪:为什么在MATLAB uint64bitrol需要使用bitror构建的定点数字对象,而fi则不需要,当在汇编级别时,它们都归结为bitshiftshl,{ {1}}和shr

因此,在将此函数作为.mex文件在C / C ++中编写之前,我很高兴知道是否有任何方法可以提高此函数的性能。我知道SHA1有一些特定的优化,但如果按位旋转的基本实现非常慢,那不是问题。

使用rolror进行一点测试,显然导致速度变慢的是使用tictoc的循环。有两个这样的循环:

bitrol

使用fi%# Define some variables. FFFFFFFF = uint64(hex2dec('FFFFFFFF')); %# constants: K(1), K(2), K(3), K(4). K(1) = uint64(hex2dec('5A827999')); K(2) = uint64(hex2dec('6ED9EBA1')); K(3) = uint64(hex2dec('8F1BBCDC')); K(4) = uint64(hex2dec('CA62C1D6')); W = uint64(zeros(1, 80)); ... some other code here ... %# First slow loop begins here. for index = 17:80 W(index) = uint64(bitrol(fi(bitxor(bitxor(bitxor(W(index-3), W(index-8)), W(index-14)), W(index-16)), 0, 32, 0), 1)); end %# First slow loop ends here. H = sha1_handle_block_struct.H; A = H(1); B = H(2); C = H(3); D = H(4); E = H(5); %# Second slow loop begins here. for index = 1:80 rotatedA = uint64(bitrol(fi(A, 0, 32, 0), 5)); if (index <= 20) % alternative #1. xorPart = bitxor(D, (bitand(B, (bitxor(C, D))))); xorPart = bitand(xorPart, FFFFFFFF); temp = rotatedA + xorPart + E + W(index) + K(1); elseif ((index >= 21) && (index <= 40)) % FIPS. xorPart = bitxor(bitxor(B, C), D); xorPart = bitand(xorPart, FFFFFFFF); temp = rotatedA + xorPart + E + W(index) + K(2); elseif ((index >= 41) && (index <= 60)) % alternative #2. xorPart = bitor(bitand(B, C), bitand(D, bitxor(B, C))); xorPart = bitand(xorPart, FFFFFFFF); temp = rotatedA + xorPart + E + W(index) + K(3); elseif ((index >= 61) && (index <= 80)) % FIPS. xorPart = bitxor(bitxor(B, C), D); xorPart = bitand(xorPart, FFFFFFFF); temp = rotatedA + xorPart + E + W(index) + K(4); else error('error in the code of sha1_handle_block.m!'); end temp = bitand(temp, FFFFFFFF); E = D; D = C; C = uint64(bitrol(fi(B, 0, 32, 0), 30)); B = A; A = temp; end %# Second slow loop ends here. 进行测量,消息tic的SHA1哈希的整个计算在我的笔记本电脑上大约0.63秒,其中在第一个慢循环中传递大约0.23秒在第二个慢循环中大约0.38秒。那么有没有办法在编写.mex文件之前在MATLAB中优化这些循环?

3 个答案:

答案 0 :(得分:4)

来自MATLAB文件交换的这个DataHash可以快速计算出SHA-1哈希值 我运行了以下代码:

x = 'The quick brown fox jumped over the lazy dog';  %# Just a short sentence
y = repmat('a', [1, 1e6]);                           %# A million a's
opt = struct('Method', 'SHA-1', 'Format', 'HEX', 'Input', 'bin');
tic, x_hashed = DataHash(uint8(x), opt), toc
tic, y_hashed = DataHash(uint8(y), opt), toc

并得到以下结果:

  

x_hashed = F6513640F3045E9768B239785625CAA6A2588842
  Elapsed time is 0.029250 seconds.

     

y_hashed = 34AA973CD4C4DAA4F61EEB2BDBAD27316534016F
  Elapsed time is 0.020595 seconds.

我用random online SHA-1 tool验证了结果,计算结果确实正确。此外,10 6 a的散列速度比第一句快1.5倍。

那么DataHash怎么这么快呢???使用java.security.MessageDigest库,不能少! 如果您对快速使用MATLAB的SHA-1函数感兴趣,那就可以了。

但是,如果这只是实现快速位级操作的练习,那么MATLAB并不能真正有效地处理它们,并且在大多数情况下,您将不得不求助于MEX。

答案 1 :(得分:3)

  

为什么在MATLAB中bitrol和bitror需要用fi构造的定点数字对象,而bitshift不会

bitrol和bitror不是适用于uints的按位逻辑函数集的一部分。它们是定点工具箱的一部分,它还包含适用于定点输入的bitand,bitshift等变体。

如果你想尝试只使用uint函数,一个bitrol可以表示为两个位移,一个bitand和一个bitor。那可能会更慢。

答案 2 :(得分:3)

与大多数MATLAB函数一样,bitandbitorbitxor是矢量化的。因此,如果您提供这些函数向量输入而不是在每个元素的循环中调用它们,您会得到更快的速度

示例:

%# create two sets of 10k random numbers
num = 10000;
hex = '0123456789ABCDEF';
A = uint64(hex2dec( hex(randi(16, [num 16])) ));
B = uint64(hex2dec( hex(randi(16, [num 16])) ));

%# compare loop vs. vectorized call
tic
C1 = zeros(size(A), class(A));
for i=1:numel(A)
    C1(i) = bitxor(A(i),B(i));
end
toc

tic
C2 = bitxor(A,B);
toc

assert(isequal(C1,C2))

时机是:

Elapsed time is 0.139034 seconds.
Elapsed time is 0.000960 seconds.

这快了一个数量级!

问题是,据我所知,SHA-1计算无法很好地向量化。所以你可能无法利用这种矢量化。

作为一项实验,我实现了一个纯MATLAB函数来计算这样的位操作:

function num = my_bitops(op,A,B)
    %# operation to perform: not, and, or, xor
    if ischar(op)
        op = str2func(op);
    end

    %# integer class: uint8, uint16, uint32, uint64
    clss = class(A);
    depth = str2double(clss(5:end));

    %# bit exponents
    e = 2.^(depth-1:-1:0);

    %# convert to binary
    b1 = logical(dec2bin(A,depth)-'0');
    if nargin == 3
        b2 = logical(dec2bin(B,depth)-'0');
    end

    %# perform binary operation
    if nargin < 3
        num = op(b1);
    else
        num = op(b1,b2);
    end

    %# convert back to integer
    num = sum(bsxfun(@times, cast(num,clss), cast(e,clss)), 2, 'native');
end

不幸的是,这在性能方面更糟糕:

tic, C1 = bitxor(A,B); toc
tic, C2 = my_bitops('xor',A,B); toc
assert(isequal(C1,C2))

时机是:

Elapsed time is 0.000984 seconds.
Elapsed time is 0.485692 seconds.

结论:编写MEX函数或搜索文件交换以查看某人是否已经执行过操作:)