Давно хотел посмотреть, как на деле обстоят дела с потоковой обработкой данных в .NET. И вот сегодня представился случай.
Код: недописанный класс, реализующий MD5. Использовался только один оператор для первого раунда (то, что в референсной реализации называется FF()
).
using System; using CryptoLib.Hashing; using Mono.Simd; namespace Test { internal class Program { private static void Main() { var md5 = new Md5(); const uint a = 1; const uint b = 2; const uint c = 3; const uint d = 4; var s = new Vector4ui(a, b, c, d); var x = new uint[16]; uint r1 = md5.Op1(x, a, b, c, d, 0, 12, 0); Vector4ui r2 = md5.Op1(x, s, 0, 12, 0); const uint cycles = 100000000; DateTime st = DateTime.Now; for (uint i = 0; i < cycles; i++) r1 = md5.Op1(x, r1, b, c, d, 0, 12, 0); DateTime e1 = DateTime.Now; for (uint i = 0; i < cycles; i++) r2 = md5.Op1(x, r2, 0, 12, 0); DateTime e2 = DateTime.Now; int bits = IntPtr.Size*8; int ms1 = (e1 - st).Milliseconds; int ms2 = (e2 - e1).Milliseconds; Console.WriteLine("Running {0}-bit code.", bits); Console.WriteLine("Normal: {0}ms", ms1); Console.WriteLine("SIMD: {0}ms", ms2); } } }
Реализация Md5.Op1()
вовсе не замысловата:
public uint Op1(uint[] x, uint a, uint b, uint c, uint d, byte k, byte s, byte i) { return b + (a + F(b, c, d) + x[k] + T[i]).Rol(s); } public Vector4ui Op1(uint[] x, Vector4ui state, byte k, byte s, byte i) { state.X = state.Y + (state.X + F(state.Y, state.Z, state.W) + x[k] + T[i]).Rol(s); return state; }
Среда выполнения:
- 64-битная Windows 7 RC (build 7100);
- Core2 Quad Q6600 (поддержка инструкций до SSSE3);
- .NET Framework CLR v2.0.50727;
- Mono 2.4 (под Windows есть только 32-битный CLR).
Результаты по трём запускам релизного кода:
Normal (ms) |
SIMD (ms) |
Runtime |
Bitness |
331,33 |
11,33 |
Mono+ |
32 |
320,33 |
131,33 |
Mono- |
32 |
857,33 |
768,67 |
MS .NET |
32 |
853,67 |
774,00 |
MS .NET |
64 |
- Mono+ – с включенной оптимизацией (
-O=simd
); - Mono- – с выключенной оптимизацией (
-O=-simd
).
Добавить комментарий