[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 Jonathan Wakely changed: What|Removed |Added Resolution|--- |FIXED Status|ASSIGNED|RESOLVED --- Comment #27 from Jonathan Wakely --- Fixed for 10.2 now.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #26 from CVS Commits --- The releases/gcc-10 branch has been updated by Jonathan Wakely : https://gcc.gnu.org/g:bbf9d358ae2104a09fc1b61e2b818928b6591831 commit r10-8448-gbbf9d358ae2104a09fc1b61e2b818928b6591831 Author: Jonathan Wakely Date: Tue May 19 16:49:21 2020 +0100 libstdc++: Use RDRAND as fallback if RDSEED keeps failing (PR 94087) It's not difficult for multiple threads to drain the entropy available to the RDSEED instruction, at which point we throw an exception. This change will try to use RDRAND after RDSEED fails repeatedly, and only throw if RDRAND also fails repeatedly. This doesn't guarantee a random value can always be read, but reduces the likelihood of failure when using the RDSEED instruction. PR libstdc++/94087 * src/c++11/random.cc (__x86_rdseed): Allow fallback function to be passed in. (__x86_rdseed_rdrand): New function that uses rdseed with rdrand fallback. (random_device::_M_init): Use __x86_rdseed_rdrand when both instructions are available. * testsuite/26_numerics/random/random_device/94087.cc: New test. (cherry picked from commit a2d196e75cef95c2b70734ad02e94f9da0e769fe)
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #25 from Avi Kivity --- Requesting a backport to gcc 10. We're hitting this even when not called in a loop.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 Jonathan Wakely changed: What|Removed |Added Status|NEW |ASSIGNED Assignee|unassigned at gcc dot gnu.org |redi at gcc dot gnu.org
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #24 from CVS Commits --- The master branch has been updated by Jonathan Wakely : https://gcc.gnu.org/g:a2d196e75cef95c2b70734ad02e94f9da0e769fe commit r11-506-ga2d196e75cef95c2b70734ad02e94f9da0e769fe Author: Jonathan Wakely Date: Tue May 19 16:49:21 2020 +0100 libstdc++: Use RDRAND as fallback if RDSEED keeps failing (PR 94087) It's not difficult for multiple threads to drain the entropy available to the RDSEED instruction, at which point we throw an exception. This change will try to use RDRAND after RDSEED fails repeatedly, and only throw if RDRAND also fails repeatedly. This doesn't guarantee a random value can always be read, but reduces the likelihood of failure when using the RDSEED instruction. PR libstdc++/94087 * src/c++11/random.cc (__x86_rdseed): Allow fallback function to be passed in. (__x86_rdseed_rdrand): New function that uses rdseed with rdrand fallback. (random_device::_M_init): Use __x86_rdseed_rdrand when both instructions are available. * testsuite/26_numerics/random/random_device/94087.cc: New test.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 Jonathan Wakely changed: What|Removed |Added Version|9.2.1 |10.1.0 Target Milestone|--- |10.2 --- Comment #23 from Jonathan Wakely --- (In reply to Jonathan Wakely from comment #22) > We could fit a linear_congruential_engine in the unused space of the union. But we'd still need to seed it on construction, even if we never use it. Changing version to 10 since there's no bug in gcc 9 (comment 16 explains why it was seen there).
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #22 from Jonathan Wakely --- (In reply to rguent...@suse.de from comment #20) > Doh. OK, guess I'd set up the twister in all cases and make it > programatically skip itself when rdrand/rdseed is available so we > could easily fall back to it. Not sure what extra state there is > that warrants the union, but well ... I suppose simply calling > random() from the C library isn't an option ;) Mersenne twister is just a bad choice, period. We could fit a linear_congruential_engine in the unused space of the union.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #21 from Jonathan Wakely --- (In reply to rguent...@suse.de from comment #18) > Note in virtualized environments support for RDRAND might be disabled > while RDSEED is enabled(?) even if no such hardware configuration > exists [by now]. If I were a chip manufacturer (hello VIA?) that > at the moment neither implements RDRAND nor RDSEED a good option > would be to only go for the stronger RDSEED and leave RDRAND > unimplemented. So we'd want something like this to check if RDRAND is usable: --- a/libstdc++-v3/src/c++11/random.cc +++ b/libstdc++-v3/src/c++11/random.cc @@ -97,7 +97,7 @@ namespace std _GLIBCXX_VISIBILITY(default) #if USE_RDSEED unsigned int __attribute__ ((target("rdseed"))) -__x86_rdseed(void*) +__x86_rdseed(void* fallback) { unsigned int retries = 100; unsigned int val; @@ -105,12 +105,25 @@ namespace std _GLIBCXX_VISIBILITY(default) while (__builtin_ia32_rdseed_si_step(&val) == 0) { if (--retries == 0) - std::__throw_runtime_error(__N("random_device: rdseed failed")); + { + if (auto f = reinterpret_cast(fallback)) + return f(nullptr); + std::__throw_runtime_error(__N("random_device: rdseed failed")); + } __builtin_ia32_pause(); } return val; } + +#if USE_RDRAND +unsigned int +__attribute__ ((target("rdseed,rdrnd"))) +__x86_rdseed_rdrand(void*) +{ + return __x86_rdseed(reinterpret_cast(&__x86_rdrand)); +} +#endif #endif #ifdef _GLIBCXX_USE_CRT_RAND_S @@ -205,6 +218,15 @@ namespace std _GLIBCXX_VISIBILITY(default) __cpuid_count(7, 0, eax, ebx, ecx, edx); if (ebx & bit_RDSEED) { +#ifdef USE_RDRAND + // CPUID.01H:ECX.RDRAND[bit 30] + __cpuid(1, eax, ebx, ecx, edx); + if (ecx & bit_RDRND) + { + _M_func = &__x86_rdseed_rdrand; + return; + } +#endif _M_func = &__x86_rdseed; return; }
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #20 from rguenther at suse dot de --- On Thu, 14 May 2020, redi at gcc dot gnu.org wrote: > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 > > --- Comment #19 from Jonathan Wakely --- > If you mean the mersenne twister in the std::random_device object, that's a > union member and doesn't exist when a proper source (/dev/random, rdrand, > rdseed etc) is available. So we'd need to add *another* mersenne twister > object > (which would double the size of std::random_device, changing ABI, or have to > be > global and protected by a mutex, or thread-local) and we'd have to seed it so > it's not 100% deterministic, and MT has a state size of 19968 bits which needs > a lot of seeding. It's not a good choice for many reasons. Doh. OK, guess I'd set up the twister in all cases and make it programatically skip itself when rdrand/rdseed is available so we could easily fall back to it. Not sure what extra state there is that warrants the union, but well ... I suppose simply calling random() from the C library isn't an option ;)
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #19 from Jonathan Wakely --- If you mean the mersenne twister in the std::random_device object, that's a union member and doesn't exist when a proper source (/dev/random, rdrand, rdseed etc) is available. So we'd need to add *another* mersenne twister object (which would double the size of std::random_device, changing ABI, or have to be global and protected by a mutex, or thread-local) and we'd have to seed it so it's not 100% deterministic, and MT has a state size of 19968 bits which needs a lot of seeding. It's not a good choice for many reasons.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #18 from rguenther at suse dot de --- On Thu, 14 May 2020, hjl.tools at gmail dot com wrote: > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 > > --- Comment #15 from H.J. Lu --- > (In reply to Jonathan Wakely from comment #13) > > We could do this easily enough (which could be simplified if RDRAND is > > guaranteed to be available when RDSEED is available): > > > > All Intel processors with RDSEED supports RDRAND which requires checking > of the CF bit in EFLAGS. Note in virtualized environments support for RDRAND might be disabled while RDSEED is enabled(?) even if no such hardware configuration exists [by now]. If I were a chip manufacturer (hello VIA?) that at the moment neither implements RDRAND nor RDSEED a good option would be to only go for the stronger RDSEED and leave RDRAND unimplemented.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #17 from rguenther at suse dot de --- On Thu, 14 May 2020, redi at gcc dot gnu.org wrote: > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 > > --- Comment #14 from Jonathan Wakely --- > (In reply to Jonathan Wakely from comment #13) > > I'd rather not have to do everything shown at > > https://software.intel.com/content/www/us/en/develop/articles/intel-digital- > > random-number-generator-drng-software-implementation-guide.html to produce a > > That was meant to link to section 5.2.6 "Generating Seeds from RDRAND" > https://software.intel.com/content/www/us/en/develop/articles/intel-digital-random-number-generator-drng-software-implementation-guide.html#inpage-nav-5-7 > > > stronger seed from RDRAND. > > Given that RDRAND is already an acceptable implementation for > std::random_device, and the standard makes no guarantees about the > cryptographic strength of values returned from std::random_device, using > RDRAND > directly is a reasonable alternative. How about falling back to the mersenne twister? Or does that invoke too much overhead in the fallback case? At least it is reliably there and cannot fail.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #16 from rguenther at suse dot de --- On Thu, 14 May 2020, redi at gcc dot gnu.org wrote: > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 > > --- Comment #12 from Jonathan Wakely --- > (In reply to wnereiz from comment #9) > > This issue seems not limit to a certain GCC version. I tried the code with > > gcc7, gcc9 and gcc10 on openSUSE Tumbleweed. All failed. > > As Richard said, the code to use rdseed was added for GCC 10, so there is no > way you're seeing the same problem on earlier releases. We only ship a single C++ runtime which is usually from the latest compiler thus a GCC 7 compiled binary run on openSUSE Tumbleweed picks up libstdc++.so.6 built from GCC 10 sources.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #15 from H.J. Lu --- (In reply to Jonathan Wakely from comment #13) > We could do this easily enough (which could be simplified if RDRAND is > guaranteed to be available when RDSEED is available): > All Intel processors with RDSEED supports RDRAND which requires checking of the CF bit in EFLAGS.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #14 from Jonathan Wakely --- (In reply to Jonathan Wakely from comment #13) > I'd rather not have to do everything shown at > https://software.intel.com/content/www/us/en/develop/articles/intel-digital- > random-number-generator-drng-software-implementation-guide.html to produce a That was meant to link to section 5.2.6 "Generating Seeds from RDRAND" https://software.intel.com/content/www/us/en/develop/articles/intel-digital-random-number-generator-drng-software-implementation-guide.html#inpage-nav-5-7 > stronger seed from RDRAND. Given that RDRAND is already an acceptable implementation for std::random_device, and the standard makes no guarantees about the cryptographic strength of values returned from std::random_device, using RDRAND directly is a reasonable alternative.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #13 from Jonathan Wakely --- We could do this easily enough (which could be simplified if RDRAND is guaranteed to be available when RDSEED is available): --- a/libstdc++-v3/src/c++11/random.cc +++ b/libstdc++-v3/src/c++11/random.cc @@ -105,7 +105,13 @@ namespace std _GLIBCXX_VISIBILITY(default) while (__builtin_ia32_rdseed_si_step(&val) == 0) { if (--retries == 0) - std::__throw_runtime_error(__N("random_device: rdseed failed")); + { +#if USE_RDRAND + return __x86_rdrand(nullptr); +#else + std::__throw_runtime_error(__N("random_device: rdseed failed")); +#endif + } __builtin_ia32_pause(); } I'd rather not have to do everything shown at https://software.intel.com/content/www/us/en/develop/articles/intel-digital-random-number-generator-drng-software-implementation-guide.html to produce a stronger seed from RDRAND.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #12 from Jonathan Wakely --- (In reply to wnereiz from comment #9) > This issue seems not limit to a certain GCC version. I tried the code with > gcc7, gcc9 and gcc10 on openSUSE Tumbleweed. All failed. As Richard said, the code to use rdseed was added for GCC 10, so there is no way you're seeing the same problem on earlier releases.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 Richard Biener changed: What|Removed |Added CC||hjl.tools at gmail dot com, ||redi at gcc dot gnu.org --- Comment #11 from Richard Biener --- HJ, is what libstdc++ does "unreasonable" (it uses rdseed by default if available) and could it do better? Can you reproduce the issue? The docs quoted by Andrew suggest that libstdc++ should, when retries are not enough, fall back to another method.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 Richard Biener changed: What|Removed |Added Ever confirmed|0 |1 Status|UNCONFIRMED |NEW Last reconfirmed||2020-05-14 --- Comment #10 from Richard Biener --- So it looks like the rdseed usage is new in GCC 10 libstdc++ and it prevails over the previous rdrand support if supported on your CPU. I can reproduce this on a CPU with rdseed support and libstdc++ from GCC 10. The code invoked looks correct to me: 20: 83 e8 01sub$0x1,%eax 23: 74 12 je 37 <_ZNSt12_GLOBAL__N_112__x86_rdseedEPv+ 0x37> 25: f3 90 pause 27: 0f c7 fardseed %edx 2a: 89 11 mov%edx,(%rcx) 2c: 73 f2 jae20 <_ZNSt12_GLOBAL__N_112__x86_rdseedEPv+ 0x20> the number of tries libstdc++ does is 100. Note rdrand doesn't exhibit this issue. So it might very well be a hardware limitation. Btw, the reproducer can be "enhanced" by providing the method of operation: std::random_device rd("rdseed"); that makes sure it will fail in a different way on a not capable CPU (Intel Broadwell or later or AMD Zen).
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 wnereiz at kawashiro dot org changed: What|Removed |Added CC||wnereiz at kawashiro dot org --- Comment #9 from wnereiz at kawashiro dot org --- This issue seems not limit to a certain GCC version. I tried the code with gcc7, gcc9 and gcc10 on openSUSE Tumbleweed. All failed. This problem affect at least one of the packages I built, which makes it crashes randomly when running.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #8 from Jonathan Wakely --- Sorry, I read "Creating and using **a** `std::random_device` object fails when used from multiple threads" to mean creating one object, and then apparently didn't read the code properly to dispel my misunderstanding.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 Carlos O'Ryan changed: What|Removed |Added Resolution|INVALID |--- Status|RESOLVED|UNCONFIRMED --- Comment #7 from Carlos O'Ryan --- (In reply to Jonathan Wakely from comment #6) > (In reply to Carlos O'Ryan from comment #0) > > Creating and using a `std::random_device` object fails when used from > > multiple threads. > > That's undefined behaviour. Calling non-const member functions on a single > object from multiple threads is always undefined unless specified otherwise. Each thread is creating its own `std::random_device` so I do not believe this is applicable.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 Jonathan Wakely changed: What|Removed |Added Resolution|--- |INVALID Status|UNCONFIRMED |RESOLVED --- Comment #6 from Jonathan Wakely --- (In reply to Carlos O'Ryan from comment #0) > Creating and using a `std::random_device` object fails when used from > multiple threads. That's undefined behaviour. Calling non-const member functions on a single object from multiple threads is always undefined unless specified otherwise. It might work "by accident", if GCC detects that your CPU supports the RDRAND instruction and that can be used (because doing so is stateless) but it will fail if it has to read from the /dev/random or /dev/urandom devices.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #4 from Carlos O'Ryan --- (In reply to Andrew Pinski from comment #1) > >The bug is *not* present on on Fedora:31 where the compiler reports: > > I doubt it is version based but rather based on what the CPU you are running > on. I should have mentioned that I used the same hardware to test with Fedora:31 and openSUSE/Tumbleweed (using Docker in case that matters), so I do not believe we can attribute the behavior difference to the CPU.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #5 from Carlos O'Ryan --- (In reply to Andrew Pinski from comment #2) > (In reply to Andrew Pinski from comment #1) > > >The bug is *not* present on on Fedora:31 where the compiler reports: > > > > I doubt it is version based but rather based on what the CPU you are running > > on. > > I Mean what type of CPU you are running on. Oh, I missed that question, from /proc/cpuinfo (on Linux): processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 94 model name : Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz stepping : 3 microcode : 0xd6 cpu MHz : 871.966 cache size : 8192 KB physical id : 0 siblings : 8 core id : 0 cpu cores : 4 apicid : 0 initial apicid : 0 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs taa itlb_multihit bogomips : 5424.00 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management:
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #3 from Andrew Pinski --- https://software.intel.com/sites/default/files/managed/98/4a/DRNG_Software_Implementation_Guide_2.1.pdf 5.3.1 Retry Recommendations ... If only one thread is calling RDSEED infrequently, it is very unlikely that a random seed will not be available. Only during periods of heavy demand, such as when one thread is calling RDSEED in rapid succession or multiple threads are calling RDSEED simultaneously, are underflows likely to occur. ... 5.3.1.2 Asynchronous applications The application should be prepared to give up on RDSEED after a small number of retries, where "small" is somewhere between 1 and 100, depending on the application's sensitivity to delays. As with synchronous applications, it is recommended that a PAUSE instruction be inserted into the retry loop. Applications needing a more aggressive approach can alternate between RDSEED and RDRAND, pulling seeds from RDSEED as they are available and filling a RDRAND buffer for future 512:1 reduction when they are not. CUT ---
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #1 from Andrew Pinski --- >The bug is *not* present on on Fedora:31 where the compiler reports: I doubt it is version based but rather based on what the CPU you are running on.
[Bug target/94087] std::random_device often fails when used from multiple threads
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 --- Comment #2 from Andrew Pinski --- (In reply to Andrew Pinski from comment #1) > >The bug is *not* present on on Fedora:31 where the compiler reports: > > I doubt it is version based but rather based on what the CPU you are running > on. I Mean what type of CPU you are running on.