Преглед на файлове

cmSystemTools: Add RandomNumber method that avoid re-seeding from OS

When profiling Qt builds on macos, about 2.2% of a `cmake` invocation
was spent reading from `/dev/urandom`.  Use a (thread)local rng to
mitigate this cost, particularly in `cmGeneratedFileStreamBase::Open`.
Tim Blechmann преди 10 месеца
родител
ревизия
339c2b886a
променени са 6 файла, в които са добавени 31 реда и са изтрити 5 реда
  1. 1 1
      Source/CTest/cmCTestMultiProcessHandler.cxx
  2. 1 1
      Source/cmCoreTryCompile.cxx
  3. 1 1
      Source/cmGeneratedFileStream.cxx
  4. 25 0
      Source/cmSystemTools.cxx
  5. 2 1
      Source/cmSystemTools.h
  6. 1 1
      Source/cmake.cxx

+ 1 - 1
Source/CTest/cmCTestMultiProcessHandler.cxx

@@ -723,7 +723,7 @@ void cmCTestMultiProcessHandler::StartNextTestsOnTimer()
   // Wait between 1 and 5 seconds before trying again.
   unsigned int const milliseconds = this->FakeLoadForTesting
     ? 10
-    : (cmSystemTools::RandomSeed() % 5 + 1) * 1000;
+    : (cmSystemTools::RandomNumber() % 5 + 1) * 1000;
   this->StartNextTestsOnTimer_.start(
     [](uv_timer_t* timer) {
       uv_timer_stop(timer);

+ 1 - 1
Source/cmCoreTryCompile.cxx

@@ -359,7 +359,7 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode(
        of the same executable name (some filesystems fail on that).  */
     char targetNameBuf[64];
     snprintf(targetNameBuf, sizeof(targetNameBuf), "cmTC_%05x",
-             cmSystemTools::RandomSeed() & 0xFFFFF);
+             cmSystemTools::RandomNumber() & 0xFFFFF);
     targetName = targetNameBuf;
   }
 

+ 1 - 1
Source/cmGeneratedFileStream.cxx

@@ -139,7 +139,7 @@ void cmGeneratedFileStreamBase::Open(std::string const& name)
   } else {
     char buf[64];
     snprintf(buf, sizeof(buf), "tmp%05x",
-             cmSystemTools::RandomSeed() & 0xFFFFF);
+             cmSystemTools::RandomNumber() & 0xFFFFF);
     this->TempName += buf;
   }
 

+ 25 - 0
Source/cmSystemTools.cxx

@@ -18,6 +18,14 @@
 #  define _DARWIN_C_SOURCE
 #endif
 
+#ifndef __has_feature
+#  define __has_feature(x) 0
+#endif
+
+#if !defined(__clang__) || __has_feature(cxx_thread_local)
+#  define CM_HAVE_THREAD_LOCAL
+#endif
+
 #include "cmSystemTools.h"
 
 #include <iterator>
@@ -79,10 +87,15 @@
 #include <functional>
 #include <iostream>
 #include <memory>
+#include <random>
 #include <sstream>
 #include <utility>
 #include <vector>
 
+#ifndef CM_HAVE_THREAD_LOCAL
+#  include <mutex>
+#endif
+
 #include <fcntl.h>
 
 #include "cmsys/Directory.hxx"
@@ -2810,6 +2823,18 @@ unsigned int cmSystemTools::RandomSeed()
 #endif
 }
 
+unsigned int cmSystemTools::RandomNumber()
+{
+#ifndef CM_HAVE_THREAD_LOCAL
+  static std::mutex gen_mutex;
+  std::lock_guard<std::mutex> gen_mutex_lock(gen_mutex);
+#else
+  thread_local
+#endif
+  static std::mt19937 gen{ cmSystemTools::RandomSeed() };
+  return static_cast<unsigned int>(gen());
+}
+
 namespace {
 std::string InitLogicalWorkingDirectory()
 {

+ 2 - 1
Source/cmSystemTools.h

@@ -540,8 +540,9 @@ public:
 
   static void EnsureStdPipes();
 
-  /** Random seed generation.  */
+  /** Random number generation.  */
   static unsigned int RandomSeed();
+  static unsigned int RandomNumber();
 
   /** Find the directory containing CMake executables.  */
   static void FindCMakeResources(const char* argv0);

+ 1 - 1
Source/cmake.cxx

@@ -211,7 +211,7 @@ bool cmakeCheckStampFile(const std::string& stampName)
   // The build system is up to date.  The stamp file has been removed
   // by the VS IDE due to a "rebuild" request.  Restore it atomically.
   std::ostringstream stampTempStream;
-  stampTempStream << stampName << ".tmp" << cmSystemTools::RandomSeed();
+  stampTempStream << stampName << ".tmp" << cmSystemTools::RandomNumber();
   std::string stampTemp = stampTempStream.str();
   {
     // TODO: Teach cmGeneratedFileStream to use a random temp file (with