Как использовать Intel RDRAND, используя встроенную сборку с.Net

Я использую процессор Intel Ivy Bridge и хочу использовать код операции RDRAND ( https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide) в C#.

Как я могу вызвать эту инструкцию процессора через C#? Я видел пример выполнения ассемблера из C# здесь: x86 / x64 CPUID в C#

Но я не уверен, как использовать его для RDRAND. Код не должен проверять, поддерживает ли процессор, выполняющий код, инструкцию или нет.

У меня есть этот пример C++ выполнения байт кода ассемблера от drng_samples от Intel:

int rdrand32_step (uint32_t *rand)
{
    unsigned char ok;

    /* rdrand edx */
    asm volatile(".byte 0x0f,0xc7,0xf0; setc %1"
        : "=a" (*rand), "=qm" (ok)
        :
        : "edx"
    );

    return ok;
}

Как объединить пример выполнения ассемблерного кода в C# с кодом C++, взятым из примера кода Intel drng?

1 ответ

Решение

Есть ответы на SO, которые будут генерировать (неуправляемый) код сборки во время выполнения для обратного вызова управляемого кода. Это все очень интересно, но я предлагаю вам просто использовать C++/CLI для этой цели, поскольку он был разработан для упрощения сценариев взаимодействия. Создайте новую библиотеку классов Visual C++ CLR и дайте ей одну rdrandwrapper.cpp:

#include <immintrin.h>

using namespace System;

namespace RdRandWrapper {

#pragma managed(push, off)
  bool getRdRand(unsigned int* pv) {
    const int max_rdrand_tries = 10;
    for (int i = 0; i < max_rdrand_tries; ++i) {
      if (_rdrand32_step(pv)) return true;
    }
    return false;
  }
#pragma managed(pop)

  public ref class RandomGeneratorError : Exception
  {
  public:
    RandomGeneratorError() : Exception() {}
    RandomGeneratorError(String^ message) : Exception(message) {}
  };

  public ref class RdRandom
  {
  public:
    int Next() {
      unsigned int v;
      if (!getRdRand(&v)) {
        throw gcnew RandomGeneratorError("Failed to get hardware RNG number.");
      }
      return v & 0x7fffffff;
    }
  };
}

Это очень простая реализация, которая просто пытается имитировать Random.Next в получении одного неотрицательного случайного целого числа. На вопрос, он не пытается проверить, что RDRAND фактически доступен на CPU, но он обрабатывает случай, когда инструкция присутствует, но не работает. (Это не может произойти на текущем оборудовании, если оно не сломано, как подробно описано здесь.)

Результирующая сборка представляет собой смешанную сборку, которая может использоваться управляемым кодом C#. Обязательно скомпилируйте сборку как x86 или x64, так же как и ваш неуправляемый код (по умолчанию проекты настроены на компиляцию как "Любой ЦП", что не будет работать правильно, так как неуправляемый код имеет только одну конкретную битность).

using System;
using RdRandWrapper;

class Program {
  static void Main(string[] args) {
    var r = new RdRandom();
    for (int i = 0; i != 10; ++i) {
      Console.WriteLine(r.Next());
    }
  }
}

Я не предъявляю претензий к производительности, но, вероятно, она не очень хороша. Если вы хотите получить много случайных значений таким образом, вы, вероятно, захотите Next(int[] values) перегружать, чтобы получить много случайных значений за один вызов, чтобы уменьшить издержки взаимодействия.

Другие вопросы по тегам