This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake".
The branch, master has been updated via 29b41babdb78b5e305ed9fc6b84dd69c1795dc69 (commit) via ae4205d219c6c9c6cc3d6b7ac959f9e68a2942cd (commit) via a6f1eabee0f6c7572f1fd3cfa8ec973deb21897e (commit) via 4f29bf56724aa8a71ce85b540f6b620454692ade (commit) via 8070abf784e0b12fdc5dfbafecdbe604f96c44a9 (commit) via 50b7be6d1f2022483cb75a5347a1e1a70a2994e0 (commit) via 566f8fa2f3bee5bf24902bcc125535435e6a9599 (commit) via eb1a9be4b63a807759ba81e4057219e1d6960eac (commit) via 6be53c6695e8d82d3633681f893b79db1de466f0 (commit) via c5428d8db2aebb215b418d72eae99f4a106a82b0 (commit) via 24de561a1a7529b919215edb0322279449c5e6c0 (commit) via 43d6e5a71f7cb68578c72ece1cb5046b929ebdc0 (commit) from 086f84aa20ac975ddf85ddf74434c13e00e9c9e6 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=29b41babdb78b5e305ed9fc6b84dd69c1795dc69 commit 29b41babdb78b5e305ed9fc6b84dd69c1795dc69 Merge: ae4205d 6be53c6 Author: Brad King <brad.k...@kitware.com> AuthorDate: Wed Mar 7 12:14:24 2018 +0000 Commit: Kitware Robot <kwro...@kitware.com> CommitDate: Wed Mar 7 07:14:35 2018 -0500 Merge topic 'ctest-affinity' 6be53c6695 CTest: Add options to control test process affinity to CPUs c5428d8db2 libuv: disable process affinity during CMake bootstrap 24de561a1a libuv: unix,win: add uv_spawn option to set child CPU affinity mask 43d6e5a71f libuv: misc: add function to get CPU affinity mask size Acked-by: Kitware Robot <kwro...@kitware.com> Merge-request: !1814 https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ae4205d219c6c9c6cc3d6b7ac959f9e68a2942cd commit ae4205d219c6c9c6cc3d6b7ac959f9e68a2942cd Merge: a6f1eab 8070abf Author: Brad King <brad.k...@kitware.com> AuthorDate: Wed Mar 7 07:13:09 2018 -0500 Commit: Brad King <brad.k...@kitware.com> CommitDate: Wed Mar 7 07:13:09 2018 -0500 Merge branch 'release-3.11' https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a6f1eabee0f6c7572f1fd3cfa8ec973deb21897e commit a6f1eabee0f6c7572f1fd3cfa8ec973deb21897e Merge: 4f29bf5 50b7be6 Author: Brad King <brad.k...@kitware.com> AuthorDate: Wed Mar 7 12:12:31 2018 +0000 Commit: Kitware Robot <kwro...@kitware.com> CommitDate: Wed Mar 7 07:12:50 2018 -0500 Merge topic 'autogen-empty-source-file-fix' 50b7be6d1f Autogen: Check if a file is empty before reading it Acked-by: Kitware Robot <kwro...@kitware.com> Merge-request: !1825 https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4f29bf56724aa8a71ce85b540f6b620454692ade commit 4f29bf56724aa8a71ce85b540f6b620454692ade Merge: 086f84a eb1a9be Author: Brad King <brad.k...@kitware.com> AuthorDate: Wed Mar 7 12:11:57 2018 +0000 Commit: Kitware Robot <kwro...@kitware.com> CommitDate: Wed Mar 7 07:12:02 2018 -0500 Merge topic 'xl-new-compiler-macros' eb1a9be4b6 XL: Recognize compilers identified by __ibmxl__ Acked-by: Kitware Robot <kwro...@kitware.com> Acked-by: Chuck Atkins <chuck.atk...@kitware.com> Merge-request: !1820 https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6be53c6695e8d82d3633681f893b79db1de466f0 commit 6be53c6695e8d82d3633681f893b79db1de466f0 Author: Brad King <brad.k...@kitware.com> AuthorDate: Thu Mar 1 10:38:15 2018 -0500 Commit: Brad King <brad.k...@kitware.com> CommitDate: Mon Mar 5 09:21:32 2018 -0500 CTest: Add options to control test process affinity to CPUs In commit v2.8.0~170 (ENH: Added ctest test options PROCESSORS and RUN_SERIAL, 2009-09-07) CTest learned to track the number of processors allocated to running tests in order to balance it against the desired level of parallelism. Extend this idea by introducing a new `PROCESSOR_AFFINITY` test property to ask that CTest run a test with the CPU affinity mask set. This will allow a set of tests that are running concurrently to use disjoint CPU resources. diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index d3e58d0..9d4a7e8 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -348,6 +348,7 @@ Properties on Tests /prop_test/LABELS /prop_test/MEASUREMENT /prop_test/PASS_REGULAR_EXPRESSION + /prop_test/PROCESSOR_AFFINITY /prop_test/PROCESSORS /prop_test/REQUIRED_FILES /prop_test/RESOURCE_LOCK diff --git a/Help/prop_test/PROCESSORS.rst b/Help/prop_test/PROCESSORS.rst index a1211fb..a927c10 100644 --- a/Help/prop_test/PROCESSORS.rst +++ b/Help/prop_test/PROCESSORS.rst @@ -2,6 +2,7 @@ PROCESSORS ---------- Set to specify how many process slots this test requires. +If not set, the default is ``1`` processor. Denotes the number of processors that this test will require. This is typically used for MPI tests, and should be used in conjunction with @@ -11,3 +12,5 @@ This will also be used to display a weighted test timing result in label and subproject summaries in the command line output of :manual:`ctest(1)`. The wall clock time for the test run will be multiplied by this property to give a better idea of how much cpu resource CTest allocated for the test. + +See also the :prop_test:`PROCESSOR_AFFINITY` test property. diff --git a/Help/prop_test/PROCESSOR_AFFINITY.rst b/Help/prop_test/PROCESSOR_AFFINITY.rst new file mode 100644 index 0000000..38ec179 --- /dev/null +++ b/Help/prop_test/PROCESSOR_AFFINITY.rst @@ -0,0 +1,11 @@ +PROCESSOR_AFFINITY +------------------ + +Set to a true value to ask CTest to launch the test process with CPU affinity +for a fixed set of processors. If enabled and supported for the current +platform, CTest will choose a set of processors to place in the CPU affinity +mask when launching the test process. The number of processors in the set is +determined by the :prop_test:`PROCESSORS` test property or the number of +processors available to CTest, whichever is smaller. The set of processors +chosen will be disjoint from the processors assigned to other concurrently +running tests that also have the ``PROCESSOR_AFFINITY`` property enabled. diff --git a/Help/release/dev/ctest-affinity.rst b/Help/release/dev/ctest-affinity.rst new file mode 100644 index 0000000..f4f72a5 --- /dev/null +++ b/Help/release/dev/ctest-affinity.rst @@ -0,0 +1,6 @@ +ctest-affinity +-------------- + +* A :prop_test:`PROCESSOR_AFFINITY` test property was added to request + that CTest run a test with CPU affinity for a set of processors + disjoint from other concurrently running tests with the property set. diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index a0010a2..e547356 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -131,6 +131,8 @@ set(SRCS LexerParser/cmListFileLexer.c LexerParser/cmListFileLexer.in.l + cmAffinity.cxx + cmAffinity.h cmArchiveWrite.cxx cmBase32.cxx cmCacheManager.cxx diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 50c2d86..99cf551 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCTestMultiProcessHandler.h" +#include "cmAffinity.h" #include "cmCTest.h" #include "cmCTestRunTest.h" #include "cmCTestScriptHandler.h" @@ -53,6 +54,8 @@ cmCTestMultiProcessHandler::cmCTestMultiProcessHandler() this->TestLoad = 0; this->Completed = 0; this->RunningCount = 0; + this->ProcessorsAvailable = cmAffinity::GetProcessorsAvailable(); + this->HaveAffinity = this->ProcessorsAvailable.size(); this->StopTimePassed = false; this->HasCycles = false; this->SerialTestRunning = false; @@ -127,6 +130,21 @@ bool cmCTestMultiProcessHandler::StartTestProcess(int test) return false; } + if (this->HaveAffinity && this->Properties[test]->WantAffinity) { + size_t needProcessors = this->GetProcessorsUsed(test); + if (needProcessors > this->ProcessorsAvailable.size()) { + return false; + } + std::vector<size_t> affinity; + affinity.reserve(needProcessors); + for (size_t i = 0; i < needProcessors; ++i) { + auto p = this->ProcessorsAvailable.begin(); + affinity.push_back(*p); + this->ProcessorsAvailable.erase(p); + } + this->Properties[test]->Affinity = std::move(affinity); + } + cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "test " << test << "\n", this->Quiet); this->TestRunningMap[test] = true; // mark the test as running @@ -200,6 +218,11 @@ inline size_t cmCTestMultiProcessHandler::GetProcessorsUsed(int test) if (processors > this->ParallelLevel) { processors = this->ParallelLevel; } + // Cap tests that want affinity to the maximum affinity available. + if (this->HaveAffinity && processors > this->HaveAffinity && + this->Properties[test]->WantAffinity) { + processors = this->HaveAffinity; + } return processors; } @@ -398,6 +421,11 @@ void cmCTestMultiProcessHandler::FinishTestProcess(cmCTestRunTest* runner, this->UnlockResources(test); this->RunningCount -= GetProcessorsUsed(test); + for (auto p : properties->Affinity) { + this->ProcessorsAvailable.insert(p); + } + properties->Affinity.clear(); + delete runner; if (started) { this->StartNextTests(); diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h index 7837ff9..19e1a35 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.h +++ b/Source/CTest/cmCTestMultiProcessHandler.h @@ -119,6 +119,8 @@ protected: // Number of tests that are complete size_t Completed; size_t RunningCount; + std::set<size_t> ProcessorsAvailable; + size_t HaveAffinity; bool StopTimePassed; // list of test properties (indices concurrent to the test map) PropertiesMap Properties; diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 30ad38c..1ae36f7 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -515,7 +515,8 @@ bool cmCTestRunTest::StartTest(size_t total) } return this->ForkProcess(timeout, this->TestProperties->ExplicitTimeout, - &this->TestProperties->Environment); + &this->TestProperties->Environment, + &this->TestProperties->Affinity); } void cmCTestRunTest::ComputeArguments() @@ -591,7 +592,8 @@ void cmCTestRunTest::DartProcessing() } bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout, - std::vector<std::string>* environment) + std::vector<std::string>* environment, + std::vector<size_t>* affinity) { this->TestProcess = cm::make_unique<cmProcess>(*this); this->TestProcess->SetId(this->Index); @@ -637,7 +639,8 @@ bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout, cmSystemTools::AppendEnv(*environment); } - return this->TestProcess->StartProcess(this->MultiTestHandler.Loop); + return this->TestProcess->StartProcess(this->MultiTestHandler.Loop, + affinity); } void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total) diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h index 4d57357..073af11 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -83,7 +83,8 @@ private: void DartProcessing(); void ExeNotFound(std::string exe); bool ForkProcess(cmDuration testTimeOut, bool explicitTimeout, - std::vector<std::string>* environment); + std::vector<std::string>* environment, + std::vector<size_t>* affinity); void WriteLogOutputTop(size_t completed, size_t total); // Run post processing of the process output for MemCheck void MemCheckPostProcess(); diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 84d8926..d1affd4 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -2165,6 +2165,9 @@ bool cmCTestTestHandler::SetTestsProperties( rt.Processors = 1; } } + if (key == "PROCESSOR_AFFINITY") { + rt.WantAffinity = cmSystemTools::IsOn(val.c_str()); + } if (key == "SKIP_RETURN_CODE") { rt.SkipReturnCode = atoi(val.c_str()); if (rt.SkipReturnCode < 0 || rt.SkipReturnCode > 255) { @@ -2336,6 +2339,7 @@ bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args) test.ExplicitTimeout = false; test.Cost = 0; test.Processors = 1; + test.WantAffinity = false; test.SkipReturnCode = -1; test.PreviousRuns = 0; if (this->UseIncludeRegExpFlag && diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index f4978b6..d2694a1 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -130,6 +130,8 @@ public: int Index; // Requested number of process slots int Processors; + bool WantAffinity; + std::vector<size_t> Affinity; // return code of test which will mark test as "not run" int SkipReturnCode; std::vector<std::string> Environment; diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index 09ed0a9..5c9b169 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -83,7 +83,7 @@ void cmProcess::SetCommandArguments(std::vector<std::string> const& args) this->Arguments = args; } -bool cmProcess::StartProcess(uv_loop_t& loop) +bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity) { this->ProcessState = cmProcess::State::Error; if (this->Command.empty()) { @@ -138,6 +138,22 @@ bool cmProcess::StartProcess(uv_loop_t& loop) options.stdio_count = 3; // in, out and err options.exit_cb = &cmProcess::OnExitCB; options.stdio = stdio; +#if !defined(CMAKE_USE_SYSTEM_LIBUV) + std::vector<char> cpumask; + if (affinity && !affinity->empty()) { + cpumask.resize(static_cast<size_t>(uv_cpumask_size()), 0); + for (auto p : *affinity) { + cpumask[p] = 1; + } + options.cpumask = cpumask.data(); + options.cpumask_size = cpumask.size(); + } else { + options.cpumask = nullptr; + options.cpumask_size = 0; + } +#else + static_cast<void>(affinity); +#endif status = uv_read_start(pipe_reader, &cmProcess::OnAllocateCB, &cmProcess::OnReadCB); diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h index 20e24b9..b2d87fa 100644 --- a/Source/CTest/cmProcess.h +++ b/Source/CTest/cmProcess.h @@ -36,7 +36,7 @@ public: void ChangeTimeout(cmDuration t); void ResetStartTime(); // Return true if the process starts - bool StartProcess(uv_loop_t& loop); + bool StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity); enum class State { diff --git a/Source/cmAffinity.cxx b/Source/cmAffinity.cxx new file mode 100644 index 0000000..bdf1f42 --- /dev/null +++ b/Source/cmAffinity.cxx @@ -0,0 +1,62 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmAffinity.h" + +#include "cm_uv.h" + +#ifndef CMAKE_USE_SYSTEM_LIBUV +#ifdef _WIN32 +#define CM_HAVE_CPU_AFFINITY +#include <windows.h> +#elif defined(__linux__) || defined(__FreeBSD__) +#define CM_HAVE_CPU_AFFINITY +#include <pthread.h> +#include <sched.h> +#if defined(__FreeBSD__) +#include <pthread_np.h> +#include <sys/cpuset.h> +#include <sys/param.h> +#endif +#if defined(__linux__) +typedef cpu_set_t cm_cpuset_t; +#else +typedef cpuset_t cm_cpuset_t; +#endif +#endif +#endif + +namespace cmAffinity { + +std::set<size_t> GetProcessorsAvailable() +{ + std::set<size_t> processorsAvailable; +#ifdef CM_HAVE_CPU_AFFINITY + int cpumask_size = uv_cpumask_size(); + if (cpumask_size > 0) { +#ifdef _WIN32 + DWORD_PTR procmask; + DWORD_PTR sysmask; + if (GetProcessAffinityMask(GetCurrentProcess(), &procmask, &sysmask) != + 0) { + for (int i = 0; i < cpumask_size; ++i) { + if (procmask & (((DWORD_PTR)1) << i)) { + processorsAvailable.insert(i); + } + } + } +#else + cm_cpuset_t cpuset; + CPU_ZERO(&cpuset); // NOLINT(clang-tidy) + if (pthread_getaffinity_np(pthread_self(), sizeof(cpuset), &cpuset) == 0) { + for (int i = 0; i < cpumask_size; ++i) { + if (CPU_ISSET(i, &cpuset)) { + processorsAvailable.insert(i); + } + } + } +#endif + } +#endif + return processorsAvailable; +} +} diff --git a/Source/cmAffinity.h b/Source/cmAffinity.h new file mode 100644 index 0000000..3775bae --- /dev/null +++ b/Source/cmAffinity.h @@ -0,0 +1,12 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once +#include "cmConfigure.h" // IWYU pragma: keep + +#include <cstddef> +#include <set> + +namespace cmAffinity { + +std::set<size_t> GetProcessorsAvailable(); +} diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt index 06df53f..126076d 100644 --- a/Tests/CMakeLib/CMakeLists.txt +++ b/Tests/CMakeLib/CMakeLists.txt @@ -49,3 +49,6 @@ if(TEST_CompileCommandOutput) endif() add_subdirectory(PseudoMemcheck) + +add_executable(testAffinity testAffinity.cxx) +target_link_libraries(testAffinity CMakeLib) diff --git a/Tests/CMakeLib/testAffinity.cxx b/Tests/CMakeLib/testAffinity.cxx new file mode 100644 index 0000000..4b82280 --- /dev/null +++ b/Tests/CMakeLib/testAffinity.cxx @@ -0,0 +1,18 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmAffinity.h" + +#include <cstddef> +#include <iostream> +#include <set> + +int main() +{ + std::set<size_t> cpus = cmAffinity::GetProcessorsAvailable(); + if (!cpus.empty()) { + std::cout << "CPU affinity mask count is '" << cpus.size() << "'.\n"; + } else { + std::cout << "CPU affinity not supported on this platform.\n"; + } + return 0; +} diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 31069fa..beadb1d 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -339,6 +339,9 @@ add_RunCMake_test(CPackConfig) add_RunCMake_test(CPackInstallProperties) add_RunCMake_test(ExternalProject) add_RunCMake_test(FetchContent) +if(NOT CMake_TEST_EXTERNAL_CMAKE) + set(CTestCommandLine_ARGS -DTEST_AFFINITY=$<TARGET_FILE:testAffinity>) +endif() add_RunCMake_test(CTestCommandLine) add_RunCMake_test(CacheNewline) # Only run this test on unix platforms that support diff --git a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake index 0fafea5..3033c9c 100644 --- a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake @@ -141,3 +141,23 @@ function(run_TestOutputSize) ) endfunction() run_TestOutputSize() + +function(run_TestAffinity) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/TestAffinity) + set(RunCMake_TEST_NO_CLEAN 1) + file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + # Create a test with affinity enabled. The default PROCESSORS + # value is 1, so our expected output checks that this is the + # number of processors in the mask. + file(WRITE "${RunCMake_TEST_BINARY_DIR}/CTestTestfile.cmake" " + add_test(Affinity \"${TEST_AFFINITY}\") + set_tests_properties(Affinity PROPERTIES PROCESSOR_AFFINITY ON) +") + # Run ctest with a large parallel level so that the value is + # not responsible for capping the number of processors available. + run_cmake_command(TestAffinity ${CMAKE_CTEST_COMMAND} -V -j 64) +endfunction() +if(TEST_AFFINITY) + run_TestAffinity() +endif() diff --git a/Tests/RunCMake/CTestCommandLine/TestAffinity-stdout.txt b/Tests/RunCMake/CTestCommandLine/TestAffinity-stdout.txt new file mode 100644 index 0000000..e23d30b --- /dev/null +++ b/Tests/RunCMake/CTestCommandLine/TestAffinity-stdout.txt @@ -0,0 +1 @@ +1: CPU affinity (mask count is '1'|not supported on this platform)\. https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c5428d8db2aebb215b418d72eae99f4a106a82b0 commit c5428d8db2aebb215b418d72eae99f4a106a82b0 Author: Brad King <brad.k...@kitware.com> AuthorDate: Mon Mar 5 09:18:53 2018 -0500 Commit: Brad King <brad.k...@kitware.com> CommitDate: Mon Mar 5 09:21:31 2018 -0500 libuv: disable process affinity during CMake bootstrap Avoid depending on platform-specific pthread features during bootstrap. diff --git a/Utilities/cmlibuv/src/unix/process.c b/Utilities/cmlibuv/src/unix/process.c index d7b6ad3..47ab1dc 100644 --- a/Utilities/cmlibuv/src/unix/process.c +++ b/Utilities/cmlibuv/src/unix/process.c @@ -45,6 +45,7 @@ extern char **environ; # include <grp.h> #endif +#ifndef CMAKE_BOOTSTRAP #if defined(__linux__) # define uv__cpu_set_t cpu_set_t #elif defined(__FreeBSD__) @@ -53,6 +54,7 @@ extern char **environ; # include <pthread_np.h> # define uv__cpu_set_t cpuset_t #endif +#endif static void uv__chld(uv_signal_t* handle, int signum) { uv_process_t* process; @@ -294,12 +296,14 @@ static void uv__process_child_init(const uv_process_options_t* options, int err; int fd; int n; +#ifndef CMAKE_BOOTSTRAP #if defined(__linux__) || defined(__FreeBSD__) int r; int i; int cpumask_size; uv__cpu_set_t cpuset; #endif +#endif if (options->flags & UV_PROCESS_DETACHED) setsid(); @@ -390,6 +394,7 @@ static void uv__process_child_init(const uv_process_options_t* options, _exit(127); } +#ifndef CMAKE_BOOTSTRAP #if defined(__linux__) || defined(__FreeBSD__) if (options->cpumask != NULL) { cpumask_size = uv_cpumask_size(); @@ -409,6 +414,7 @@ static void uv__process_child_init(const uv_process_options_t* options, } } #endif +#endif if (options->env != NULL) { environ = options->env; @@ -465,6 +471,7 @@ int uv_spawn(uv_loop_t* loop, int status; if (options->cpumask != NULL) { +#ifndef CMAKE_BOOTSTRAP #if defined(__linux__) || defined(__FreeBSD__) if (options->cpumask_size < (size_t)uv_cpumask_size()) { return UV_EINVAL; @@ -472,6 +479,9 @@ int uv_spawn(uv_loop_t* loop, #else return UV_ENOTSUP; #endif +#else + return UV_ENOTSUP; +#endif } assert(options->file != NULL); https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=24de561a1a7529b919215edb0322279449c5e6c0 commit 24de561a1a7529b919215edb0322279449c5e6c0 Author: Brad King <brad.k...@kitware.com> AuthorDate: Wed Sep 6 15:01:50 2017 -0400 Commit: Brad King <brad.k...@kitware.com> CommitDate: Mon Mar 5 09:21:31 2018 -0500 libuv: unix,win: add uv_spawn option to set child CPU affinity mask Implement it on Linux, FreeBSD, and Windows for now, and fail with UV_ENOTSUP on other platforms. Backported from upstream libuv PR 1527, scheduled for inclusion in libuv 2.0. diff --git a/Utilities/cmlibuv/include/uv.h b/Utilities/cmlibuv/include/uv.h index a2ba487..875e30a 100644 --- a/Utilities/cmlibuv/include/uv.h +++ b/Utilities/cmlibuv/include/uv.h @@ -925,6 +925,19 @@ typedef struct uv_process_options_s { */ uv_uid_t uid; uv_gid_t gid; + /* + Libuv can set the child process' CPU affinity mask. This happens when + `cpumask` is non-NULL. It must point to an array of char values + of length `cpumask_size`, whose value must be at least that returned by + uv_cpumask_size(). Each byte in the mask can be either zero (false) + or non-zero (true) to indicate whether the corresponding processor at + that index is included. + + If enabled on an unsupported platform, uv_spawn() will fail with + UV_ENOTSUP. + */ + char* cpumask; + size_t cpumask_size; } uv_process_options_t; /* diff --git a/Utilities/cmlibuv/src/unix/process.c b/Utilities/cmlibuv/src/unix/process.c index 9842710..d7b6ad3 100644 --- a/Utilities/cmlibuv/src/unix/process.c +++ b/Utilities/cmlibuv/src/unix/process.c @@ -32,6 +32,7 @@ #include <unistd.h> #include <fcntl.h> #include <poll.h> +#include <sched.h> #if defined(__APPLE__) && !TARGET_OS_IPHONE # include <crt_externs.h> @@ -44,6 +45,14 @@ extern char **environ; # include <grp.h> #endif +#if defined(__linux__) +# define uv__cpu_set_t cpu_set_t +#elif defined(__FreeBSD__) +# include <sys/param.h> +# include <sys/cpuset.h> +# include <pthread_np.h> +# define uv__cpu_set_t cpuset_t +#endif static void uv__chld(uv_signal_t* handle, int signum) { uv_process_t* process; @@ -285,6 +294,12 @@ static void uv__process_child_init(const uv_process_options_t* options, int err; int fd; int n; +#if defined(__linux__) || defined(__FreeBSD__) + int r; + int i; + int cpumask_size; + uv__cpu_set_t cpuset; +#endif if (options->flags & UV_PROCESS_DETACHED) setsid(); @@ -375,6 +390,26 @@ static void uv__process_child_init(const uv_process_options_t* options, _exit(127); } +#if defined(__linux__) || defined(__FreeBSD__) + if (options->cpumask != NULL) { + cpumask_size = uv_cpumask_size(); + assert(options->cpumask_size >= (size_t)cpumask_size); + + CPU_ZERO(&cpuset); + for (i = 0; i < cpumask_size; ++i) { + if (options->cpumask[i]) { + CPU_SET(i, &cpuset); + } + } + + r = -pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset); + if (r != 0) { + uv__write_int(error_fd, r); + _exit(127); + } + } +#endif + if (options->env != NULL) { environ = options->env; } @@ -429,6 +464,16 @@ int uv_spawn(uv_loop_t* loop, int i; int status; + if (options->cpumask != NULL) { +#if defined(__linux__) || defined(__FreeBSD__) + if (options->cpumask_size < (size_t)uv_cpumask_size()) { + return UV_EINVAL; + } +#else + return UV_ENOTSUP; +#endif + } + assert(options->file != NULL); assert(!(options->flags & ~(UV_PROCESS_DETACHED | UV_PROCESS_SETGID | diff --git a/Utilities/cmlibuv/src/win/process.c b/Utilities/cmlibuv/src/win/process.c index cc06d9e..f5f05af 100644 --- a/Utilities/cmlibuv/src/win/process.c +++ b/Utilities/cmlibuv/src/win/process.c @@ -954,6 +954,12 @@ int uv_spawn(uv_loop_t* loop, return UV_EINVAL; } + if (options->cpumask != NULL) { + if (options->cpumask_size < (size_t)uv_cpumask_size()) { + return UV_EINVAL; + } + } + assert(options->file != NULL); assert(!(options->flags & ~(UV_PROCESS_DETACHED | UV_PROCESS_SETGID | @@ -1084,6 +1090,12 @@ int uv_spawn(uv_loop_t* loop, process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP; } + if (options->cpumask != NULL) { + /* Create the child in a suspended state so we have a chance to set + its process affinity before it runs. */ + process_flags |= CREATE_SUSPENDED; + } + if (!CreateProcessW(application_path, arguments, NULL, @@ -1099,6 +1111,50 @@ int uv_spawn(uv_loop_t* loop, goto done; } + if (options->cpumask != NULL) { + /* The child is currently suspended. Set its process affinity + or terminate it if we can't. */ + int i; + int cpumasksize; + DWORD_PTR sysmask; + DWORD_PTR oldmask; + DWORD_PTR newmask; + + cpumasksize = uv_cpumask_size(); + + if (!GetProcessAffinityMask(info.hProcess, &oldmask, &sysmask)) { + err = GetLastError(); + TerminateProcess(info.hProcess, 1); + goto done; + } + + newmask = 0; + for (i = 0; i < cpumasksize; i++) { + if (options->cpumask[i]) { + if (oldmask & (((DWORD_PTR)1) << i)) { + newmask |= ((DWORD_PTR)1) << i; + } else { + err = UV_EINVAL; + TerminateProcess(info.hProcess, 1); + goto done; + } + } + } + + if (!SetProcessAffinityMask(info.hProcess, newmask)) { + err = GetLastError(); + TerminateProcess(info.hProcess, 1); + goto done; + } + + /* The process affinity of the child is set. Let it run. */ + if (ResumeThread(info.hThread) == ((DWORD)-1)) { + err = GetLastError(); + TerminateProcess(info.hProcess, 1); + goto done; + } + } + /* Spawn succeeded */ /* Beyond this point, failure is reported asynchronously. */ https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=43d6e5a71f7cb68578c72ece1cb5046b929ebdc0 commit 43d6e5a71f7cb68578c72ece1cb5046b929ebdc0 Author: Brad King <brad.k...@kitware.com> AuthorDate: Wed Sep 6 15:01:17 2017 -0400 Commit: Brad King <brad.k...@kitware.com> CommitDate: Mon Mar 5 09:21:31 2018 -0500 libuv: misc: add function to get CPU affinity mask size Implement it on Linux, FreeBSD, and Windows for now, and return UV_ENOTSUP on other platforms. Backported from upstream libuv PR 1527, scheduled for inclusion in libuv 2.0. diff --git a/Utilities/cmlibuv/include/uv.h b/Utilities/cmlibuv/include/uv.h index 328ce9e..a2ba487 100644 --- a/Utilities/cmlibuv/include/uv.h +++ b/Utilities/cmlibuv/include/uv.h @@ -1094,6 +1094,7 @@ UV_EXTERN uv_pid_t uv_os_getppid(void); UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count); UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count); +UV_EXTERN int uv_cpumask_size(void); UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses, int* count); diff --git a/Utilities/cmlibuv/src/unix/core.c b/Utilities/cmlibuv/src/unix/core.c index c7e431e..faaf697 100644 --- a/Utilities/cmlibuv/src/unix/core.c +++ b/Utilities/cmlibuv/src/unix/core.c @@ -40,6 +40,7 @@ #include <sys/uio.h> /* writev */ #include <sys/resource.h> /* getrusage */ #include <pwd.h> +#include <sched.h> #ifdef __sun # include <netdb.h> /* MAXHOSTNAMELEN on Solaris */ @@ -63,6 +64,8 @@ # include <sys/sysctl.h> # include <sys/filio.h> # include <sys/wait.h> +# include <sys/param.h> +# include <sys/cpuset.h> # define UV__O_CLOEXEC O_CLOEXEC # if defined(__FreeBSD__) && __FreeBSD__ >= 10 # define uv__accept4 accept4 @@ -1340,6 +1343,15 @@ int uv_os_gethostname(char* buffer, size_t* size) { } +int uv_cpumask_size(void) { +#if defined(__linux__) || defined(__FreeBSD__) + return CPU_SETSIZE; +#else + return UV_ENOTSUP; +#endif +} + + uv_os_fd_t uv_get_osfhandle(int fd) { return fd; } diff --git a/Utilities/cmlibuv/src/win/core.c b/Utilities/cmlibuv/src/win/core.c index 9ed4e82..8d121b3 100644 --- a/Utilities/cmlibuv/src/win/core.c +++ b/Utilities/cmlibuv/src/win/core.c @@ -603,3 +603,7 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) { return 0; } + +int uv_cpumask_size(void) { + return (int)(sizeof(DWORD_PTR) * 8); +} ----------------------------------------------------------------------- Summary of changes: Help/manual/cmake-properties.7.rst | 1 + Help/prop_test/PROCESSORS.rst | 3 + Help/prop_test/PROCESSOR_AFFINITY.rst | 11 ++++ Help/release/dev/ctest-affinity.rst | 6 ++ .../IBMCPP-C-DetermineVersionInternal.cmake | 16 +++-- .../IBMCPP-CXX-DetermineVersionInternal.cmake | 16 +++-- Modules/Compiler/XL-C-DetermineCompiler.cmake | 2 +- Modules/Compiler/XL-CXX-DetermineCompiler.cmake | 2 +- Source/CMakeLists.txt | 2 + Source/CTest/cmCTestMultiProcessHandler.cxx | 28 +++++++++ Source/CTest/cmCTestMultiProcessHandler.h | 2 + Source/CTest/cmCTestRunTest.cxx | 9 ++- Source/CTest/cmCTestRunTest.h | 3 +- Source/CTest/cmCTestTestHandler.cxx | 4 ++ Source/CTest/cmCTestTestHandler.h | 2 + Source/CTest/cmProcess.cxx | 18 +++++- Source/CTest/cmProcess.h | 2 +- Source/cmAffinity.cxx | 62 ++++++++++++++++++++ Source/cmAffinity.h | 12 ++++ Source/cmQtAutoGenerator.cxx | 29 +++++---- Tests/CMakeLib/CMakeLists.txt | 3 + Tests/CMakeLib/testAffinity.cxx | 18 ++++++ Tests/RunCMake/CMakeLists.txt | 3 + Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake | 20 +++++++ .../CTestCommandLine/TestAffinity-stdout.txt | 1 + Utilities/cmlibuv/include/uv.h | 14 +++++ Utilities/cmlibuv/src/unix/core.c | 12 ++++ Utilities/cmlibuv/src/unix/process.c | 55 +++++++++++++++++ Utilities/cmlibuv/src/win/core.c | 4 ++ Utilities/cmlibuv/src/win/process.c | 56 ++++++++++++++++++ 30 files changed, 389 insertions(+), 27 deletions(-) create mode 100644 Help/prop_test/PROCESSOR_AFFINITY.rst create mode 100644 Help/release/dev/ctest-affinity.rst create mode 100644 Source/cmAffinity.cxx create mode 100644 Source/cmAffinity.h create mode 100644 Tests/CMakeLib/testAffinity.cxx create mode 100644 Tests/RunCMake/CTestCommandLine/TestAffinity-stdout.txt hooks/post-receive -- CMake _______________________________________________ Cmake-commits mailing list Cmake-commits@cmake.org https://cmake.org/mailman/listinfo/cmake-commits