2017-08-02 1 views
1

Ich benutze eine Intel Ivy Bridge CPU und möchte den RDRAND Opcode (https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide) in C# verwenden.Wie verwende ich Intels RDRAND mit Inline-Assemblierung mit. NET

Wie kann ich diese CPU-Anweisung über C# aufrufen? Ich habe ein Beispiel der Ausführung von Assembler-Code von C# hier gesehen: x86/x64 CPUID in C#

Aber ich bin mir nicht sicher, wie man es für RDRAND verwendet. Der Code muss nicht überprüfen, ob die CPU, die den Code ausführt, den Befehl unterstützt oder nicht.

Ich habe dieses C++ Beispiel aus drng_samples von Intel kommen Montage Bytecode ausführt:

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; 
} 

Wie kann das Beispiel der Assembler-Code in C# Ausführung mit dem C++ Code aus der Probe DRNG Intel kommen werden kombiniert Code?

+0

Verwenden Sie einfach ['RNGCryptoServiceProvider'] (https://msdn.microsoft.com/library/system.security.cryptography.rngcrptoserviceprovider), was für die meisten Zwecke, die besser als Pseudozufallszahlen benötigen, gut genug sein sollte. –

+0

@JeroenMostert Vielen Dank für Ihren Kommentar. Aber ich brauche es wirklich zufällig, um den Zweck wissenschaftlich genauer Softwareexperimente zu erfüllen. Ich habe TrueRNGV3 bestellt, aber es könnte zu lange dauern, bis ich eintrifft und ich habe in der Zwischenzeit nach Alternativen gesucht und RDRAND scheint vielversprechend. –

+1

Sie können keine prozessorspezifische Assembly in C# ausführen. Sie können einen Teil von C++ - Code dafür schreiben und diesen mit C++/CLI oder P/Invoke umhüllen, wie hier beschrieben (https://stackoverflow.com/questions/13436130/). –

Antwort

4

Es gibt Antworten auf SO, die während der Laufzeit (nicht verwalteten) Assembly-Code erzeugen, den verwalteter Code zurückrufen kann. Das ist alles sehr interessant, aber ich schlage vor, dass Sie einfach C++/CLI für diesen Zweck verwenden, weil es entworfen wurde, um Interop-Szenarien zu vereinfachen. Erstellen Sie eine neue Visual C++ CLR Klassenbibliothek und gibt ihm eine einziges 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; 
    } 
    }; 
} 

Dies ist eine sehr nackte Knochen-Implementierung, die nur Random.Next in immer eine einzige nicht-negative Zufallszahl zu imitieren versucht. Pro Frage, es versucht nicht zu überprüfen, dass RDRAND tatsächlich auf der CPU verfügbar ist, aber es behandelt den Fall, in dem der Befehl vorhanden ist aber nicht funktioniert. (Dies kann auf der aktuellen Hardware nicht passieren, es sei denn, es ist defekt, wie detailliert here.)

Die resultierende Assembly ist eine gemischte Assembly, die von verwaltetem C# -Code verbraucht werden kann. Stellen Sie sicher, dass Sie Ihre Assembly als x86 oder x64 kompilieren, genau wie Ihr nicht verwalteter Code (standardmäßig werden Projekte als "Any CPU" kompiliert, was nicht korrekt funktioniert, da der nicht verwaltete Code nur eine bestimmte Bitness aufweist).

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()); 
    } 
    } 
} 

Ich mache keine Ansprüche hinsichtlich Leistung, aber es ist wahrscheinlich nicht so toll. Wenn Sie viele zufällige Werte auf diese Weise erhalten möchten, möchten Sie wahrscheinlich eine Next(int[] values) Überladung, um viele zufällige Werte in einem Aufruf zu erhalten, um den Overhead von Interop zu reduzieren.

+0

Ich werde zuerst C++ - Entwicklungskette für Visual Studio dann installieren müssen :) Große Antwort. Ich werde es versuchen. –

+0

Arbeiten und vollständige Antwort! Vielen Dank für die Hilfe! –

+0

In Bezug auf die Leistung, bekomme ich ~ 366mbit/Sekunde zufällige Daten beim Anfordern von Int64 pro Anruf. Und jeder Anruf führte zu einem anderen Wert als der vorherige Anruf. Das wird ausreichen :) –

Verwandte Themen