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

Reply via email to