Давно хотел посмотреть, как на деле обстоят дела с потоковой обработкой данных в .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).

Leave a Reply