Инструкция rdseed с несколькими потоками

Я хотел бы сгенерировать семена для пользовательского PRNG, используя инструкцию rdseed с несколькими ядрами.

Вот что у меня есть до сих пор, используя OpenMP.

//gcc -Wall -O3 -fopenmp -mrdseed myrand.c
#include <x86intrin.h>
#include <stdio.h>
int main(void)  {  
    #pragma omp parallel
    {
        unsigned r;
        #pragma omp critical
        while(!_rdseed32_step(&r));
        //prng_init(r);
        printf("%d\n", r);
    }
}

Является ли это правильным/идеальным способом создания начального числа для каждого потока? Нужен ли мне критический раздел при вызове rdseed. Встроенная функция _rdseed32_step возвращает 1, если было сгенерировано случайное значение, и 0 в противном случае.

Руководство по Intel DRNP

4.3.1 Рекомендации по повторным попыткам

В отличие от инструкции RDRAND, начальные значения поступают непосредственно из кондиционера энтропии, и вызывающая сторона может вызывать RDSEED быстрее, чем эти значения генерируются. Это означает, что приложения должны быть разработаны надежно и быть готовыми к сбою вызовов RDSEED из-за отсутствия начальных значений (CF=0).

Если только один поток нечасто вызывает RDSEED, очень маловероятно, что случайное начальное число будет недоступно. Только в периоды повышенного спроса, например, когда один поток вызывает RDSEED в быстрой последовательности или несколько потоков одновременно вызывают RDSEED, возможно возникновение потери памяти. Однако, поскольку инструкция RDSEED не имеет встроенного механизма справедливости, нет никаких гарантий относительно того, как часто поток должен повторять выполнение инструкции или сколько повторных попыток может потребоваться для получения случайного начального числа. На практике это зависит от количества аппаратных потоков на ЦП и от того, насколько агрессивно они вызывают RDSEED.

Насколько я понимаю, на каждый процессор приходится только один генератор начальных чисел, поэтому начальные значения не могут генерироваться параллельно, и, поскольку для создания начального числа требуется время, мне кажется, что правильное решение состоит в том, чтобы каждое ядро/гиперпоток запрашивало потока по одному, и пусть поток, вызывающий rdseed, будет ждать, пока не получит начальное число.

Поскольку мне нужно только одно семя на поток, тогда

#pragma omp critical
while(!_rdseed32_step(&r));

мне кажется правильный подход.


person Z boson    schedule 17.02.2017    source источник
comment
Аппаратное обеспечение уже имеет буфер и механизм повторных попыток исчерпания; блокировка вашего собственного программного обеспечения только для того, чтобы свести к минимуму возможность повторной попытки, кажется бессмысленной дополнительной нагрузкой.   -  person Peter Cordes    schedule 12.05.2021


Ответы (1)


Это сработает. В очень маловероятном случае, если ГСЧ сломается в середине выполнения этого кода, он замкнется в жестком цикле, но в реальных сценариях он выдаст вам случайное число, и все будет в порядке.

_rdseed16_step(), _rdseed32_step() и _rdseed64_step() следуют семантике инструкции RdSeed, которая должна возвращать бит успеха в CF и случайное число в целевом регистре. Таким образом, его можно запустить в цикле, чтобы получить столько случайных битов, сколько требуется.

person David Johnston    schedule 12.05.2021