Mono.SIMD на практике

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