From 339c2b886a6fe5741774a506c258a8c4adf90f1c Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Fri, 27 Dec 2024 12:07:04 +0800 Subject: [PATCH] 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`. --- Source/CTest/cmCTestMultiProcessHandler.cxx | 2 +- Source/cmCoreTryCompile.cxx | 2 +- Source/cmGeneratedFileStream.cxx | 2 +- Source/cmSystemTools.cxx | 25 +++++++++++++++++++++ Source/cmSystemTools.h | 3 ++- Source/cmake.cxx | 2 +- 6 files changed, 31 insertions(+), 5 deletions(-) diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 4ef47e7314..f771a1568e 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/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); diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 9674bf2bbe..a8fd0e0929 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -359,7 +359,7 @@ cm::optional 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; } diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx index 37a2be4a75..30f8a30296 100644 --- a/Source/cmGeneratedFileStream.cxx +++ b/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; } diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index cac7605b2a..6bc04f6b91 100644 --- a/Source/cmSystemTools.cxx +++ b/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 @@ -79,10 +87,15 @@ #include #include #include +#include #include #include #include +#ifndef CM_HAVE_THREAD_LOCAL +# include +#endif + #include #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 gen_mutex_lock(gen_mutex); +#else + thread_local +#endif + static std::mt19937 gen{ cmSystemTools::RandomSeed() }; + return static_cast(gen()); +} + namespace { std::string InitLogicalWorkingDirectory() { diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index dd6170b4bd..13f2572e5d 100644 --- a/Source/cmSystemTools.h +++ b/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); diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 5b4d58f72c..a41b53874a 100644 --- a/Source/cmake.cxx +++ b/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