CTest: Rename PROCESSES test property to RESOURCE_GROUPS
The `PROCESSES` test property name added for CMake 3.16 is too close to the existing `PROCESSORS` test property. Furthermore, the property in principle specifies groups of resources organized in a way that is meaningful to a particular test. The groups may often correspond to processes but they could have other meanings. Since the property name `PROCESSES` has not been in a final 3.16 release yet, simply rename it to `RESOURCE_GROUPS`. Fixes: #19914
This commit is contained in:
parent
c1d5d5eb11
commit
af9ed543b0
@ -414,10 +414,10 @@ Properties on Tests
|
||||
/prop_test/LABELS
|
||||
/prop_test/MEASUREMENT
|
||||
/prop_test/PASS_REGULAR_EXPRESSION
|
||||
/prop_test/PROCESSES
|
||||
/prop_test/PROCESSOR_AFFINITY
|
||||
/prop_test/PROCESSORS
|
||||
/prop_test/REQUIRED_FILES
|
||||
/prop_test/RESOURCE_GROUPS
|
||||
/prop_test/RESOURCE_LOCK
|
||||
/prop_test/RUN_SERIAL
|
||||
/prop_test/SKIP_REGULAR_EXPRESSION
|
||||
|
@ -1317,8 +1317,8 @@ The CTest hardware allocation feature consists of two inputs:
|
||||
* The :ref:`hardware specification file <ctest-hardware-specification-file>`,
|
||||
described below, which describes the hardware resources available on the
|
||||
system, and
|
||||
* The :prop_test:`PROCESSES` property of tests, which describes the resources
|
||||
required by the test
|
||||
* The :prop_test:`RESOURCE_GROUPS` property of tests, which describes the
|
||||
resources required by the test
|
||||
|
||||
When CTest runs a test, the hardware allocated to that test is passed in the
|
||||
form of a set of
|
||||
@ -1326,11 +1326,11 @@ form of a set of
|
||||
described below. Using this information to decide which resource to connect to
|
||||
is left to the test writer.
|
||||
|
||||
Please note that these processes are not spawned by CTest. The ``PROCESSES``
|
||||
property merely tells CTest what processes the test expects to launch. It is up
|
||||
to the test itself to do this process spawning, and read the :ref:`environment
|
||||
variables <ctest-hardware-environment-variables>` to determine which resources
|
||||
each process has been allocated.
|
||||
The ``RESOURCE_GROUPS`` property tells CTest what resources a test expects
|
||||
to use grouped in a way meaningful to the test. The test itself must read
|
||||
the :ref:`environment variables <ctest-hardware-environment-variables>` to
|
||||
determine which resources have been allocated to each group. For example,
|
||||
each group may correspond to a process the test will spawn when executed.
|
||||
|
||||
.. _`ctest-hardware-specification-file`:
|
||||
|
||||
@ -1423,10 +1423,10 @@ In the example file above, there are four GPUs with ID's 0 through 3. GPU 0 has
|
||||
2 slots, GPU 1 has 4, GPU 2 has 2, and GPU 3 has a default of 1 slot. There is
|
||||
also one cryptography chip with 4 slots.
|
||||
|
||||
``PROCESSES`` Property
|
||||
----------------------
|
||||
``RESOURCE_GROUPS`` Property
|
||||
----------------------------
|
||||
|
||||
See :prop_test:`PROCESSES` for a description of this property.
|
||||
See :prop_test:`RESOURCE_GROUPS` for a description of this property.
|
||||
|
||||
.. _`ctest-hardware-environment-variables`:
|
||||
|
||||
@ -1436,65 +1436,67 @@ Environment Variables
|
||||
Once CTest has decided which resources to allocate to a test, it passes this
|
||||
information to the test executable as a series of environment variables. For
|
||||
each example below, we will assume that the test in question has a
|
||||
:prop_test:`PROCESSES` property of ``2,gpus:2;gpus:4,gpus:1,crypto_chips:2``.
|
||||
:prop_test:`RESOURCE_GROUPS` property of
|
||||
``2,gpus:2;gpus:4,gpus:1,crypto_chips:2``.
|
||||
|
||||
The following variables are passed to the test process:
|
||||
|
||||
.. envvar:: CTEST_PROCESS_COUNT
|
||||
.. envvar:: CTEST_RESOURCE_GROUP_COUNT
|
||||
|
||||
The total number of processes specified by the :prop_test:`PROCESSES`
|
||||
The total number of groups specified by the :prop_test:`RESOURCE_GROUPS`
|
||||
property. For example:
|
||||
|
||||
* ``CTEST_PROCESS_COUNT=3``
|
||||
* ``CTEST_RESOURCE_GROUP_COUNT=3``
|
||||
|
||||
This variable will only be defined if :manual:`ctest(1)` has been given a
|
||||
``--hardware-spec-file``, or if :command:`ctest_test` has been given a
|
||||
``HARDWARE_SPEC_FILE``. If no hardware specification file has been given,
|
||||
this variable will not be defined.
|
||||
|
||||
.. envvar:: CTEST_PROCESS_<num>
|
||||
.. envvar:: CTEST_RESOURCE_GROUP_<num>
|
||||
|
||||
The list of resource types allocated to each process, with each item
|
||||
The list of resource types allocated to each group, with each item
|
||||
separated by a comma. ``<num>`` is a number from zero to
|
||||
``CTEST_PROCESS_COUNT`` minus one. ``CTEST_PROCESS_<num>`` is defined for
|
||||
each ``<num>`` in this range. For example:
|
||||
``CTEST_RESOURCE_GROUP_COUNT`` minus one. ``CTEST_RESOURCE_GROUP_<num>``
|
||||
is defined for each ``<num>`` in this range. For example:
|
||||
|
||||
* ``CTEST_PROCESS_0=gpus``
|
||||
* ``CTEST_PROCESS_1=gpus``
|
||||
* ``CTEST_PROCESS_2=crypto_chips,gpus``
|
||||
* ``CTEST_RESOURCE_GROUP_0=gpus``
|
||||
* ``CTEST_RESOURCE_GROUP_1=gpus``
|
||||
* ``CTEST_RESOURCE_GROUP_2=crypto_chips,gpus``
|
||||
|
||||
.. envvar:: CTEST_PROCESS_<num>_<resource-type>
|
||||
.. envvar:: CTEST_RESOURCE_GROUP_<num>_<resource-type>
|
||||
|
||||
The list of resource IDs and number of slots from each ID allocated to each
|
||||
process for a given resource type. This variable consists of a series of
|
||||
group for a given resource type. This variable consists of a series of
|
||||
pairs, each pair separated by a semicolon, and with the two items in the pair
|
||||
separated by a comma. The first item in each pair is ``id:`` followed by the
|
||||
ID of a resource of type ``<resource-type>``, and the second item is
|
||||
``slots:`` followed by the number of slots from that resource allocated to
|
||||
the given process. For example:
|
||||
the given group. For example:
|
||||
|
||||
* ``CTEST_PROCESS_0_GPUS=id:0,slots:2``
|
||||
* ``CTEST_PROCESS_1_GPUS=id:2,slots:2``
|
||||
* ``CTEST_PROCESS_2_GPUS=id:1,slots:4;id:3,slots:1``
|
||||
* ``CTEST_PROCESS_2_CRYPTO_CHIPS=id:card0,slots:2``
|
||||
* ``CTEST_RESOURCE_GROUP_0_GPUS=id:0,slots:2``
|
||||
* ``CTEST_RESOURCE_GROUP_1_GPUS=id:2,slots:2``
|
||||
* ``CTEST_RESOURCE_GROUP_2_GPUS=id:1,slots:4;id:3,slots:1``
|
||||
* ``CTEST_RESOURCE_GROUP_2_CRYPTO_CHIPS=id:card0,slots:2``
|
||||
|
||||
In this example, process 0 gets 2 slots from GPU ``0``, process 1 gets 2 slots
|
||||
from GPU ``2``, and process 2 gets 4 slots from GPU ``1`` and 2 slots from
|
||||
In this example, group 0 gets 2 slots from GPU ``0``, group 1 gets 2 slots
|
||||
from GPU ``2``, and group 2 gets 4 slots from GPU ``1`` and 2 slots from
|
||||
cryptography chip ``card0``.
|
||||
|
||||
``<num>`` is a number from zero to ``CTEST_PROCESS_COUNT`` minus one.
|
||||
``<num>`` is a number from zero to ``CTEST_RESOURCE_GROUP_COUNT`` minus one.
|
||||
``<resource-type>`` is the name of a resource type, converted to uppercase.
|
||||
``CTEST_PROCESS_<num>_<resource-type>`` is defined for the product of each
|
||||
``<num>`` in the range listed above and each resource type listed in
|
||||
``CTEST_PROCESS_<num>``.
|
||||
``CTEST_RESOURCE_GROUP_<num>_<resource-type>`` is defined for the product
|
||||
of each ``<num>`` in the range listed above and each resource type listed in
|
||||
``CTEST_RESOURCE_GROUP_<num>``.
|
||||
|
||||
Because some platforms have case-insensitive names for environment variables,
|
||||
the names of resource types may not clash in a case-insensitive environment.
|
||||
Because of this, for the sake of simplicity, all resource types must be
|
||||
listed in all lowercase in the
|
||||
:ref:`hardware specification file <ctest-hardware-specification-file>` and in
|
||||
the :prop_test:`PROCESSES` property, and they are converted to all uppercase
|
||||
in the ``CTEST_PROCESS_<num>_<resource-type>`` environment variable.
|
||||
:ref:`hardware specification file <ctest-hardware-specification-file>` and
|
||||
in the :prop_test:`RESOURCE_GROUPS` property, and they are converted to all
|
||||
uppercase in the ``CTEST_RESOURCE_GROUP_<num>_<resource-type>`` environment
|
||||
variable.
|
||||
|
||||
See Also
|
||||
========
|
||||
|
@ -1,54 +0,0 @@
|
||||
PROCESSES
|
||||
----------
|
||||
|
||||
Set to specify the number of processes spawned by a test, and the resources
|
||||
that they require. See :ref:`hardware allocation <ctest-hardware-allocation>`
|
||||
for more information on how this property integrates into the CTest hardware
|
||||
allocation feature.
|
||||
|
||||
The ``PROCESSES`` property is a :ref:`semicolon-separated list <CMake Language
|
||||
Lists>` of process descriptions. Each process description consists of an
|
||||
optional number of processes for the description followed by a series of
|
||||
resource requirements for those processes. These requirements (and the number
|
||||
of processes) are separated by commas. The resource requirements consist of the
|
||||
name of a resource type, followed by a colon, followed by an unsigned integer
|
||||
specifying the number of slots required on one resource of the given type.
|
||||
|
||||
Please note that these processes are not spawned by CTest. The ``PROCESSES``
|
||||
property merely tells CTest what processes the test expects to launch. It is up
|
||||
to the test itself to do this process spawning, and read the :ref:`environment
|
||||
variables <ctest-hardware-environment-variables>` to determine which resources
|
||||
each process has been allocated.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
add_test(NAME MyTest COMMAND MyExe)
|
||||
set_property(TEST MyTest PROPERTY PROCESSES
|
||||
"2,gpus:2"
|
||||
"gpus:4,crypto_chips:2")
|
||||
|
||||
In this example, there are two process descriptions (implicitly separated by a
|
||||
semicolon.) The content of the first description is ``2,gpus:2``. This
|
||||
description spawns 2 processes, each of which requires 2 slots from a single
|
||||
GPU. The content of the second description is ``gpus:4,crypto_chips:2``. This
|
||||
description does not specify a process count, so a default of 1 is assumed.
|
||||
This single process requires 4 slots from a single GPU and 2 slots from a
|
||||
single cryptography chip. In total, 3 processes are spawned from this test,
|
||||
each with their own unique requirements.
|
||||
|
||||
When CTest sets the :ref:`environment variables
|
||||
<ctest-hardware-environment-variables>` for a test, it assigns a process number
|
||||
based on the process description, starting at 0 on the left and the number of
|
||||
processes minus 1 on the right. For example, in the example above, the two
|
||||
processes in the first description would have IDs of 0 and 1, and the single
|
||||
process in the second description would have an ID of 2.
|
||||
|
||||
Both the ``PROCESSES`` and :prop_test:`RESOURCE_LOCK` properties serve similar
|
||||
purposes, but they are distinct and orthogonal. Resources specified by
|
||||
``PROCESSES`` do not affect :prop_test:`RESOURCE_LOCK`, and vice versa. Whereas
|
||||
:prop_test:`RESOURCE_LOCK` is a simpler property that is used for locking one
|
||||
global resource, ``PROCESSES`` is a more advanced property that allows multiple
|
||||
tests to simultaneously use multiple resources of the same type, specifying
|
||||
their requirements in a fine-grained manner.
|
54
Help/prop_test/RESOURCE_GROUPS.rst
Normal file
54
Help/prop_test/RESOURCE_GROUPS.rst
Normal file
@ -0,0 +1,54 @@
|
||||
RESOURCE_GROUPS
|
||||
---------------
|
||||
|
||||
Specify resources required by a test, grouped in a way that is meaningful to
|
||||
the test. See :ref:`hardware allocation <ctest-hardware-allocation>`
|
||||
for more information on how this property integrates into the CTest hardware
|
||||
allocation feature.
|
||||
|
||||
The ``RESOURCE_GROUPS`` property is a :ref:`semicolon-separated list <CMake
|
||||
Language Lists>` of group descriptions. Each entry consists of an optional
|
||||
number of groups using the description followed by a series of resource
|
||||
requirements for those groups. These requirements (and the number of groups)
|
||||
are separated by commas. The resource requirements consist of the name of a
|
||||
resource type, followed by a colon, followed by an unsigned integer
|
||||
specifying the number of slots required on one resource of the given type.
|
||||
|
||||
The ``RESOURCE_GROUPS`` property tells CTest what resources a test expects
|
||||
to use grouped in a way meaningful to the test. The test itself must read
|
||||
the :ref:`environment variables <ctest-hardware-environment-variables>` to
|
||||
determine which resources have been allocated to each group. For example,
|
||||
each group may correspond to a process the test will spawn when executed.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
add_test(NAME MyTest COMMAND MyExe)
|
||||
set_property(TEST MyTest PROPERTY RESOURCE_GROUPS
|
||||
"2,gpus:2"
|
||||
"gpus:4,crypto_chips:2")
|
||||
|
||||
In this example, there are two group descriptions (implicitly separated by a
|
||||
semicolon.) The content of the first description is ``2,gpus:2``. This
|
||||
description specifies 2 groups, each of which requires 2 slots from a single
|
||||
GPU. The content of the second description is ``gpus:4,crypto_chips:2``. This
|
||||
description does not specify a group count, so a default of 1 is assumed.
|
||||
This single group requires 4 slots from a single GPU and 2 slots from a
|
||||
single cryptography chip. In total, 3 resource groups are specified for this
|
||||
test, each with its own unique requirements.
|
||||
|
||||
When CTest sets the :ref:`environment variables
|
||||
<ctest-hardware-environment-variables>` for a test, it assigns a group number
|
||||
based on the group description, starting at 0 on the left and the number of
|
||||
groups minus 1 on the right. For example, in the example above, the two
|
||||
groups in the first description would have IDs of 0 and 1, and the single
|
||||
group in the second description would have an ID of 2.
|
||||
|
||||
Both the ``RESOURCE_GROUPS`` and :prop_test:`RESOURCE_LOCK` properties serve
|
||||
similar purposes, but they are distinct and orthogonal. Resources specified by
|
||||
``RESOURCE_GROUPS`` do not affect :prop_test:`RESOURCE_LOCK`, and vice versa.
|
||||
Whereas :prop_test:`RESOURCE_LOCK` is a simpler property that is used for
|
||||
locking one global resource, ``RESOURCE_GROUPS`` is a more advanced property
|
||||
that allows multiple tests to simultaneously use multiple resources of the
|
||||
same type, specifying their requirements in a fine-grained manner.
|
@ -9,10 +9,10 @@ not to run concurrently.
|
||||
See also :prop_test:`FIXTURES_REQUIRED` if the resource requires any setup or
|
||||
cleanup steps.
|
||||
|
||||
Both the :prop_test:`PROCESSES` and ``RESOURCE_LOCK`` properties serve similar
|
||||
purposes, but they are distinct and orthogonal. Resources specified by
|
||||
:prop_test:`PROCESSES` do not affect ``RESOURCE_LOCK``, and vice versa. Whereas
|
||||
``RESOURCE_LOCK`` is a simpler property that is used for locking one global
|
||||
resource, :prop_test:`PROCESSES` is a more advanced property that allows
|
||||
multiple tests to simultaneously use multiple resources of the same type,
|
||||
specifying their requirements in a fine-grained manner.
|
||||
Both the :prop_test:`RESOURCE_GROUPS` and ``RESOURCE_LOCK`` properties serve
|
||||
similar purposes, but they are distinct and orthogonal. Resources specified by
|
||||
:prop_test:`RESOURCE_GROUPS` do not affect ``RESOURCE_LOCK``, and vice versa.
|
||||
Whereas ``RESOURCE_LOCK`` is a simpler property that is used for locking one
|
||||
global resource, :prop_test:`RESOURCE_GROUPS` is a more advanced property
|
||||
that allows multiple tests to simultaneously use multiple resources of the
|
||||
same type, specifying their requirements in a fine-grained manner.
|
||||
|
@ -230,7 +230,7 @@ bool cmCTestMultiProcessHandler::AllocateHardware(int index)
|
||||
}
|
||||
|
||||
auto& allocatedHardware = this->AllocatedHardware[index];
|
||||
allocatedHardware.resize(this->Properties[index]->Processes.size());
|
||||
allocatedHardware.resize(this->Properties[index]->ResourceGroups.size());
|
||||
for (auto const& it : allocations) {
|
||||
for (auto const& alloc : it.second) {
|
||||
bool result = this->HardwareAllocator.AllocateResource(
|
||||
@ -252,7 +252,7 @@ bool cmCTestMultiProcessHandler::TryAllocateHardware(
|
||||
allocations.clear();
|
||||
|
||||
std::size_t processIndex = 0;
|
||||
for (auto const& process : this->Properties[index]->Processes) {
|
||||
for (auto const& process : this->Properties[index]->ResourceGroups) {
|
||||
for (auto const& requirement : process) {
|
||||
for (int i = 0; i < requirement.UnitsNeeded; ++i) {
|
||||
allocations[requirement.ResourceType].push_back(
|
||||
@ -912,14 +912,14 @@ static Json::Value DumpTimeoutAfterMatch(
|
||||
return timeoutAfterMatch;
|
||||
}
|
||||
|
||||
static Json::Value DumpProcessesToJsonArray(
|
||||
static Json::Value DumpResourceGroupsToJsonArray(
|
||||
const std::vector<
|
||||
std::vector<cmCTestTestHandler::cmCTestTestResourceRequirement>>&
|
||||
processes)
|
||||
resourceGroups)
|
||||
{
|
||||
Json::Value jsonProcesses = Json::arrayValue;
|
||||
for (auto const& it : processes) {
|
||||
Json::Value jsonProcess = Json::objectValue;
|
||||
Json::Value jsonResourceGroups = Json::arrayValue;
|
||||
for (auto const& it : resourceGroups) {
|
||||
Json::Value jsonResourceGroup = Json::objectValue;
|
||||
Json::Value requirements = Json::arrayValue;
|
||||
for (auto const& it2 : it) {
|
||||
Json::Value res = Json::objectValue;
|
||||
@ -928,10 +928,10 @@ static Json::Value DumpProcessesToJsonArray(
|
||||
res["slots"] = it2.SlotsNeeded;
|
||||
requirements.append(res);
|
||||
}
|
||||
jsonProcess["requirements"] = requirements;
|
||||
jsonProcesses.append(jsonProcess);
|
||||
jsonResourceGroup["requirements"] = requirements;
|
||||
jsonResourceGroups.append(jsonResourceGroup);
|
||||
}
|
||||
return jsonProcesses;
|
||||
return jsonResourceGroups;
|
||||
}
|
||||
|
||||
static Json::Value DumpCTestProperty(std::string const& name,
|
||||
@ -1005,9 +1005,10 @@ static Json::Value DumpCTestProperties(
|
||||
"PASS_REGULAR_EXPRESSION",
|
||||
DumpRegExToJsonArray(testProperties.RequiredRegularExpressions)));
|
||||
}
|
||||
if (!testProperties.Processes.empty()) {
|
||||
if (!testProperties.ResourceGroups.empty()) {
|
||||
properties.append(DumpCTestProperty(
|
||||
"PROCESSES", DumpProcessesToJsonArray(testProperties.Processes)));
|
||||
"RESOURCE_GROUPS",
|
||||
DumpResourceGroupsToJsonArray(testProperties.ResourceGroups)));
|
||||
}
|
||||
if (testProperties.WantAffinity) {
|
||||
properties.append(
|
||||
|
@ -693,7 +693,7 @@ bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
|
||||
if (this->UseAllocatedHardware) {
|
||||
this->SetupHardwareEnvironment();
|
||||
} else {
|
||||
cmSystemTools::UnsetEnv("CTEST_PROCESS_COUNT");
|
||||
cmSystemTools::UnsetEnv("CTEST_RESOURCE_GROUP_COUNT");
|
||||
}
|
||||
|
||||
return this->TestProcess->StartProcess(this->MultiTestHandler.Loop,
|
||||
@ -702,13 +702,13 @@ bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
|
||||
|
||||
void cmCTestRunTest::SetupHardwareEnvironment()
|
||||
{
|
||||
std::string processCount = "CTEST_PROCESS_COUNT=";
|
||||
std::string processCount = "CTEST_RESOURCE_GROUP_COUNT=";
|
||||
processCount += std::to_string(this->AllocatedHardware.size());
|
||||
cmSystemTools::PutEnv(processCount);
|
||||
|
||||
std::size_t i = 0;
|
||||
for (auto const& process : this->AllocatedHardware) {
|
||||
std::string prefix = "CTEST_PROCESS_";
|
||||
std::string prefix = "CTEST_RESOURCE_GROUP_";
|
||||
prefix += std::to_string(i);
|
||||
std::string resourceList = prefix + '=';
|
||||
prefix += '_';
|
||||
|
@ -1626,11 +1626,11 @@ std::string cmCTestTestHandler::FindExecutable(
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
bool cmCTestTestHandler::ParseProcessesProperty(
|
||||
bool cmCTestTestHandler::ParseResourceGroupsProperty(
|
||||
const std::string& val,
|
||||
std::vector<std::vector<cmCTestTestResourceRequirement>>& processes)
|
||||
std::vector<std::vector<cmCTestTestResourceRequirement>>& resourceGroups)
|
||||
{
|
||||
cmCTestProcessesLexerHelper lexer(processes);
|
||||
cmCTestProcessesLexerHelper lexer(resourceGroups);
|
||||
return lexer.ParseString(val);
|
||||
}
|
||||
|
||||
@ -2203,8 +2203,8 @@ bool cmCTestTestHandler::SetTestsProperties(
|
||||
if (key == "PROCESSOR_AFFINITY") {
|
||||
rt.WantAffinity = cmIsOn(val);
|
||||
}
|
||||
if (key == "PROCESSES") {
|
||||
if (!ParseProcessesProperty(val, rt.Processes)) {
|
||||
if (key == "RESOURCE_GROUPS") {
|
||||
if (!ParseResourceGroupsProperty(val, rt.ResourceGroups)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ public:
|
||||
std::set<std::string> FixturesCleanup;
|
||||
std::set<std::string> FixturesRequired;
|
||||
std::set<std::string> RequireSuccessDepends;
|
||||
std::vector<std::vector<cmCTestTestResourceRequirement>> Processes;
|
||||
std::vector<std::vector<cmCTestTestResourceRequirement>> ResourceGroups;
|
||||
// Private test generator properties used to track backtraces
|
||||
cmListFileBacktrace Backtrace;
|
||||
};
|
||||
@ -202,9 +202,9 @@ public:
|
||||
std::vector<std::string>& extraPaths,
|
||||
std::vector<std::string>& failed);
|
||||
|
||||
static bool ParseProcessesProperty(
|
||||
static bool ParseResourceGroupsProperty(
|
||||
const std::string& val,
|
||||
std::vector<std::vector<cmCTestTestResourceRequirement>>& processes);
|
||||
std::vector<std::vector<cmCTestTestResourceRequirement>>& resourceGroups);
|
||||
|
||||
using ListOfTests = std::vector<cmCTestTestProperties>;
|
||||
|
||||
|
@ -8,9 +8,9 @@ include_directories(
|
||||
set(CMakeLib_TESTS
|
||||
testArgumentParser.cxx
|
||||
testCTestBinPacker.cxx
|
||||
testCTestProcesses.cxx
|
||||
testCTestHardwareAllocator.cxx
|
||||
testCTestHardwareSpec.cxx
|
||||
testCTestResourceGroups.cxx
|
||||
testGeneratedFileStream.cxx
|
||||
testRST.cxx
|
||||
testRange.cxx
|
||||
|
@ -106,24 +106,25 @@ bool TestExpectedParseResult(const ExpectedParseResult& expected)
|
||||
std::vector<std::vector<cmCTestTestHandler::cmCTestTestResourceRequirement>>
|
||||
result;
|
||||
bool retval;
|
||||
if ((retval = cmCTestTestHandler::ParseProcessesProperty(
|
||||
if ((retval = cmCTestTestHandler::ParseResourceGroupsProperty(
|
||||
expected.String, result)) != expected.ExpectedReturnValue) {
|
||||
std::cout << "ParseProcessesProperty(\"" << expected.String
|
||||
std::cout << "ParseResourceGroupsProperty(\"" << expected.String
|
||||
<< "\") returned " << retval << ", should be "
|
||||
<< expected.ExpectedReturnValue << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result != expected.ExpectedValue) {
|
||||
std::cout << "ParseProcessesProperty(\"" << expected.String
|
||||
<< "\") did not yield expected set of processes" << std::endl;
|
||||
std::cout << "ParseResourceGroupsProperty(\"" << expected.String
|
||||
<< "\") did not yield expected set of resource groups"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int testCTestProcesses(int /*unused*/, char* /*unused*/ [])
|
||||
int testCTestResourceGroups(int /*unused*/, char* /*unused*/ [])
|
||||
{
|
||||
int retval = 0;
|
||||
|
@ -258,7 +258,7 @@ function(run_ShowOnly)
|
||||
add_test(ShowOnly \"${CMAKE_COMMAND}\" -E echo)
|
||||
set_tests_properties(ShowOnly PROPERTIES
|
||||
WILL_FAIL true
|
||||
PROCESSES \"2,threads:2,gpus:4;gpus:2,threads:4\"
|
||||
RESOURCE_GROUPS \"2,threads:2,gpus:4;gpus:2,threads:4\"
|
||||
REQUIRED_FILES RequiredFileDoesNotExist
|
||||
_BACKTRACE_TRIPLES \"file1;1;add_test;file0;;\"
|
||||
)
|
||||
|
@ -80,12 +80,12 @@ def check_willfail_property(p):
|
||||
assert p["name"] == "WILL_FAIL"
|
||||
assert p["value"] == True
|
||||
|
||||
def check_processes_property(p):
|
||||
def check_resource_groups_property(p):
|
||||
assert is_dict(p)
|
||||
assert sorted(p.keys()) == ["name", "value"]
|
||||
assert is_string(p["name"])
|
||||
assert is_list(p["value"])
|
||||
assert p["name"] == "PROCESSES"
|
||||
assert p["name"] == "RESOURCE_GROUPS"
|
||||
assert len(p["value"]) == 3
|
||||
|
||||
assert is_dict(p["value"][0])
|
||||
@ -147,7 +147,7 @@ def check_workingdir_property(p):
|
||||
def check_properties(p):
|
||||
assert is_list(p)
|
||||
assert len(p) == 4
|
||||
check_processes_property(p[0])
|
||||
check_resource_groups_property(p[0])
|
||||
check_reqfiles_property(p[1])
|
||||
check_willfail_property(p[2])
|
||||
check_workingdir_property(p[3])
|
||||
|
@ -11,7 +11,7 @@ function(add_hardware_test name sleep_time proc)
|
||||
else()
|
||||
add_test(NAME "${name}" COMMAND "${CTHWALLOC_COMMAND}" write "${CMAKE_BINARY_DIR}/cthwalloc.log" "${name}" "${sleep_time}")
|
||||
endif()
|
||||
set_property(TEST "${name}" PROPERTY PROCESSES "${proc}")
|
||||
set_property(TEST "${name}" PROPERTY RESOURCE_GROUPS "${proc}")
|
||||
list(APPEND HARDWARE_TESTS "${name}")
|
||||
set(HARDWARE_TESTS "${HARDWARE_TESTS}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
@ -38,7 +38,7 @@ function(run_cthwalloc_verify name tests)
|
||||
run_cmake_command(${name} "${CTHWALLOC_COMMAND}" verify "${RunCMake_SOURCE_DIR}/${name}.log" "${CMAKE_CURRENT_LIST_DIR}/hwspec.json" "${tests}")
|
||||
endfunction()
|
||||
|
||||
unset(ENV{CTEST_PROCESS_COUNT})
|
||||
unset(ENV{CTEST_RESOURCE_GROUP_COUNT})
|
||||
set(RunCMake_TEST_NO_CLEAN 1)
|
||||
file(REMOVE_RECURSE "${RunCMake_BINARY_DIR}/cthwalloc-write-proc-good1-build")
|
||||
file(MAKE_DIRECTORY "${RunCMake_BINARY_DIR}/cthwalloc-write-proc-good1-build")
|
||||
@ -49,75 +49,75 @@ dealloc widgets 0 1
|
||||
end test1
|
||||
]])
|
||||
run_cthwalloc_write_proc_nodel(cthwalloc-write-proc-good1 "1,widgets:2,transmogrifiers:1;2,widgets:1,widgets:2"
|
||||
CTEST_PROCESS_COUNT=3
|
||||
CTEST_PROCESS_0=widgets,transmogrifiers
|
||||
CTEST_PROCESS_0_WIDGETS=id:0,slots:2
|
||||
CTEST_PROCESS_0_TRANSMOGRIFIERS=id:calvin,slots:1
|
||||
CTEST_PROCESS_1=widgets
|
||||
"CTEST_PROCESS_1_WIDGETS=id:0,slots:1\\;id:2,slots:2"
|
||||
CTEST_PROCESS_2=widgets
|
||||
"CTEST_PROCESS_2_WIDGETS=id:0,slots:1\\;id:2,slots:2"
|
||||
CTEST_RESOURCE_GROUP_COUNT=3
|
||||
CTEST_RESOURCE_GROUP_0=widgets,transmogrifiers
|
||||
CTEST_RESOURCE_GROUP_0_WIDGETS=id:0,slots:2
|
||||
CTEST_RESOURCE_GROUP_0_TRANSMOGRIFIERS=id:calvin,slots:1
|
||||
CTEST_RESOURCE_GROUP_1=widgets
|
||||
"CTEST_RESOURCE_GROUP_1_WIDGETS=id:0,slots:1\\;id:2,slots:2"
|
||||
CTEST_RESOURCE_GROUP_2=widgets
|
||||
"CTEST_RESOURCE_GROUP_2_WIDGETS=id:0,slots:1\\;id:2,slots:2"
|
||||
)
|
||||
set(RunCMake_TEST_NO_CLEAN 0)
|
||||
run_cthwalloc_write_proc(cthwalloc-write-proc-good2 "widgets:8"
|
||||
CTEST_PROCESS_COUNT=1
|
||||
CTEST_PROCESS_0=widgets
|
||||
CTEST_PROCESS_0_WIDGETS=id:3,slots:8
|
||||
CTEST_RESOURCE_GROUP_COUNT=1
|
||||
CTEST_RESOURCE_GROUP_0=widgets
|
||||
CTEST_RESOURCE_GROUP_0_WIDGETS=id:3,slots:8
|
||||
)
|
||||
run_cthwalloc_write_proc(cthwalloc-write-proc-nocount "widgets:8")
|
||||
run_cthwalloc_write_proc(cthwalloc-write-proc-badcount "widgets:8"
|
||||
CTEST_PROCESS_COUNT=2
|
||||
CTEST_RESOURCE_GROUP_COUNT=2
|
||||
)
|
||||
run_cthwalloc_write_proc(cthwalloc-write-proc-nores "widgets:8"
|
||||
CTEST_PROCESS_COUNT=1
|
||||
CTEST_RESOURCE_GROUP_COUNT=1
|
||||
)
|
||||
run_cthwalloc_write_proc(cthwalloc-write-proc-badres "widgets:8"
|
||||
CTEST_PROCESS_COUNT=1
|
||||
CTEST_PROCESS_0=widgets,transmogrifiers
|
||||
CTEST_RESOURCE_GROUP_COUNT=1
|
||||
CTEST_RESOURCE_GROUP_0=widgets,transmogrifiers
|
||||
)
|
||||
run_cthwalloc_write_proc(cthwalloc-write-proc-nowidgets "widgets:8"
|
||||
CTEST_PROCESS_COUNT=1
|
||||
CTEST_PROCESS_0=widgets
|
||||
CTEST_RESOURCE_GROUP_COUNT=1
|
||||
CTEST_RESOURCE_GROUP_0=widgets
|
||||
)
|
||||
run_cthwalloc_write_proc(cthwalloc-write-proc-badwidgets1 "widgets:8"
|
||||
CTEST_PROCESS_COUNT=1
|
||||
CTEST_PROCESS_0=widgets
|
||||
CTEST_PROCESS_0_WIDGETS=
|
||||
CTEST_RESOURCE_GROUP_COUNT=1
|
||||
CTEST_RESOURCE_GROUP_0=widgets
|
||||
CTEST_RESOURCE_GROUP_0_WIDGETS=
|
||||
)
|
||||
run_cthwalloc_write_proc(cthwalloc-write-proc-badwidgets2 "widgets:8"
|
||||
CTEST_PROCESS_COUNT=1
|
||||
CTEST_PROCESS_0=widgets
|
||||
"CTEST_PROCESS_0_WIDGETS=id:3,slots:8\\;id:0,slots:1"
|
||||
CTEST_RESOURCE_GROUP_COUNT=1
|
||||
CTEST_RESOURCE_GROUP_0=widgets
|
||||
"CTEST_RESOURCE_GROUP_0_WIDGETS=id:3,slots:8\\;id:0,slots:1"
|
||||
)
|
||||
run_cthwalloc_write_proc(cthwalloc-write-proc-badwidgets3 "widgets:8"
|
||||
CTEST_PROCESS_COUNT=1
|
||||
CTEST_PROCESS_0=widgets
|
||||
CTEST_PROCESS_0_WIDGETS=id:3,slots:7
|
||||
CTEST_RESOURCE_GROUP_COUNT=1
|
||||
CTEST_RESOURCE_GROUP_0=widgets
|
||||
CTEST_RESOURCE_GROUP_0_WIDGETS=id:3,slots:7
|
||||
)
|
||||
run_cthwalloc_write_proc(cthwalloc-write-proc-badwidgets4 "widgets:8"
|
||||
CTEST_PROCESS_COUNT=1
|
||||
CTEST_PROCESS_0=widgets
|
||||
CTEST_PROCESS_0_WIDGETS=invalid
|
||||
CTEST_RESOURCE_GROUP_COUNT=1
|
||||
CTEST_RESOURCE_GROUP_0=widgets
|
||||
CTEST_RESOURCE_GROUP_0_WIDGETS=invalid
|
||||
)
|
||||
run_cthwalloc_write_proc(cthwalloc-write-proc-badwidgets5 "widgets:2,widgets:2"
|
||||
CTEST_PROCESS_COUNT=1
|
||||
CTEST_PROCESS_0=widgets
|
||||
"CTEST_PROCESS_0_WIDGETS=id:0,slots:2\\;id:0,slots:1"
|
||||
CTEST_RESOURCE_GROUP_COUNT=1
|
||||
CTEST_RESOURCE_GROUP_0=widgets
|
||||
"CTEST_RESOURCE_GROUP_0_WIDGETS=id:0,slots:2\\;id:0,slots:1"
|
||||
)
|
||||
run_cthwalloc_write_proc(cthwalloc-write-proc-badwidgets6 "widgets:2"
|
||||
CTEST_PROCESS_COUNT=1
|
||||
CTEST_PROCESS_0=widgets
|
||||
"CTEST_PROCESS_0_WIDGETS=id:0,slots:2\\;id:0,slots:1"
|
||||
CTEST_RESOURCE_GROUP_COUNT=1
|
||||
CTEST_RESOURCE_GROUP_0=widgets
|
||||
"CTEST_RESOURCE_GROUP_0_WIDGETS=id:0,slots:2\\;id:0,slots:1"
|
||||
)
|
||||
run_cthwalloc_write_proc(cthwalloc-write-proc-badwidgets7 "widgets:2,widgets:2"
|
||||
CTEST_PROCESS_COUNT=1
|
||||
CTEST_PROCESS_0=widgets
|
||||
CTEST_PROCESS_0_WIDGETS=id:0,slots:2
|
||||
CTEST_RESOURCE_GROUP_COUNT=1
|
||||
CTEST_RESOURCE_GROUP_0=widgets
|
||||
CTEST_RESOURCE_GROUP_0_WIDGETS=id:0,slots:2
|
||||
)
|
||||
|
||||
run_cthwalloc_write_noproc(cthwalloc-write-noproc-good1)
|
||||
run_cthwalloc_write_noproc(cthwalloc-write-noproc-count
|
||||
CTEST_PROCESS_COUNT=1
|
||||
CTEST_RESOURCE_GROUP_COUNT=1
|
||||
)
|
||||
|
||||
run_cthwalloc_verify(cthwalloc-verify-good1 "test1;test2")
|
||||
@ -162,6 +162,6 @@ run_ctest_hardware(notenough1 1 0)
|
||||
run_ctest_hardware(notenough2 1 0)
|
||||
run_ctest_hardware(ensure_parallel 2 0)
|
||||
|
||||
set(ENV{CTEST_PROCESS_COUNT} 2)
|
||||
set(ENV{CTEST_RESOURCE_GROUP_COUNT} 2)
|
||||
run_ctest_hardware(process_count 1 0)
|
||||
unset(ENV{CTEST_PROCESS_COUNT})
|
||||
unset(ENV{CTEST_RESOURCE_GROUP_COUNT})
|
||||
|
@ -26,11 +26,11 @@
|
||||
* This helper program is used to verify that the CTest hardware allocation
|
||||
* feature is working correctly. It consists of two stages:
|
||||
*
|
||||
* 1) write - This stage receives the PROCESSES property of the test and
|
||||
* compares it with the values passed in the CTEST_PROCESS_* environment
|
||||
* variables. If it received all of the resources it expected, then it
|
||||
* writes this information to a log file, which will be read in the verify
|
||||
* stage.
|
||||
* 1) write - This stage receives the RESOURCE_GROUPS property of the test and
|
||||
* compares it with the values passed in the CTEST_RESOURCE_GROUP_*
|
||||
* environment variables. If it received all of the resources it expected,
|
||||
* then it writes this information to a log file, which will be read in
|
||||
* the verify stage.
|
||||
* 2) verify - This stage compares the log file with the hardware spec file to
|
||||
* make sure that no resources were over-subscribed, deallocated without
|
||||
* being allocated, or allocated without being deallocated.
|
||||
@ -46,7 +46,7 @@ static int usageWrite(const char* argv0)
|
||||
{
|
||||
std::cout << "Usage: " << argv0
|
||||
<< " write <log-file> <test-name> <sleep-time-secs>"
|
||||
" [<processes-property>]"
|
||||
" [<resource-groups-property>]"
|
||||
<< std::endl;
|
||||
return 1;
|
||||
}
|
||||
@ -71,28 +71,30 @@ static int doWrite(int argc, char const* const* argv)
|
||||
std::string, std::vector<cmCTestMultiProcessHandler::HardwareAllocation>>>
|
||||
hardware;
|
||||
if (argc == 6) {
|
||||
// Parse processes property
|
||||
std::string processesProperty = argv[5];
|
||||
// Parse RESOURCE_GROUPS property
|
||||
std::string resourceGroupsProperty = argv[5];
|
||||
std::vector<
|
||||
std::vector<cmCTestTestHandler::cmCTestTestResourceRequirement>>
|
||||
processes;
|
||||
bool result =
|
||||
cmCTestTestHandler::ParseProcessesProperty(processesProperty, processes);
|
||||
resourceGroups;
|
||||
bool result = cmCTestTestHandler::ParseResourceGroupsProperty(
|
||||
resourceGroupsProperty, resourceGroups);
|
||||
(void)result;
|
||||
assert(result);
|
||||
|
||||
// Verify process count
|
||||
const char* processCountEnv = cmSystemTools::GetEnv("CTEST_PROCESS_COUNT");
|
||||
if (!processCountEnv) {
|
||||
std::cout << "CTEST_PROCESS_COUNT should be defined" << std::endl;
|
||||
// Verify group count
|
||||
const char* resourceGroupCountEnv =
|
||||
cmSystemTools::GetEnv("CTEST_RESOURCE_GROUP_COUNT");
|
||||
if (!resourceGroupCountEnv) {
|
||||
std::cout << "CTEST_RESOURCE_GROUP_COUNT should be defined" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
int processCount = std::atoi(processCountEnv);
|
||||
if (processes.size() != std::size_t(processCount)) {
|
||||
std::cout << "CTEST_PROCESS_COUNT does not match expected processes"
|
||||
<< std::endl
|
||||
<< "Expected: " << processes.size() << std::endl
|
||||
<< "Actual: " << processCount << std::endl;
|
||||
int resourceGroupCount = std::atoi(resourceGroupCountEnv);
|
||||
if (resourceGroups.size() != std::size_t(resourceGroupCount)) {
|
||||
std::cout
|
||||
<< "CTEST_RESOURCE_GROUP_COUNT does not match expected resource groups"
|
||||
<< std::endl
|
||||
<< "Expected: " << resourceGroups.size() << std::endl
|
||||
<< "Actual: " << resourceGroupCount << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -110,15 +112,15 @@ static int doWrite(int argc, char const* const* argv)
|
||||
std::size_t i = 0;
|
||||
cmsys::ofstream fout(logFile.c_str(), std::ios::app);
|
||||
fout << "begin " << testName << std::endl;
|
||||
for (auto& process : processes) {
|
||||
for (auto& resourceGroup : resourceGroups) {
|
||||
try {
|
||||
// Build and verify set of expected resources
|
||||
std::set<std::string> expectedResources;
|
||||
for (auto const& it : process) {
|
||||
for (auto const& it : resourceGroup) {
|
||||
expectedResources.insert(it.ResourceType);
|
||||
}
|
||||
|
||||
std::string prefix = "CTEST_PROCESS_";
|
||||
std::string prefix = "CTEST_RESOURCE_GROUP_";
|
||||
prefix += std::to_string(i);
|
||||
const char* actualResourcesCStr = cmSystemTools::GetEnv(prefix);
|
||||
if (!actualResourcesCStr) {
|
||||
@ -147,7 +149,7 @@ static int doWrite(int argc, char const* const* argv)
|
||||
std::vector<cmCTestMultiProcessHandler::HardwareAllocation>>
|
||||
hwEntry;
|
||||
for (auto const& type : actualResources) {
|
||||
auto it = process.begin();
|
||||
auto it = resourceGroup.begin();
|
||||
|
||||
std::string varName = prefix;
|
||||
varName += cmSystemTools::UpperCase(type);
|
||||
@ -161,7 +163,7 @@ static int doWrite(int argc, char const* const* argv)
|
||||
for (auto const& r : received) {
|
||||
while (it->ResourceType != type || it->UnitsNeeded == 0) {
|
||||
++it;
|
||||
if (it == process.end()) {
|
||||
if (it == resourceGroup.end()) {
|
||||
std::cout << varName << " did not list expected resources"
|
||||
<< std::endl;
|
||||
return 1;
|
||||
@ -198,7 +200,7 @@ static int doWrite(int argc, char const* const* argv)
|
||||
bool ended = false;
|
||||
while (it->ResourceType != type || it->UnitsNeeded == 0) {
|
||||
++it;
|
||||
if (it == process.end()) {
|
||||
if (it == resourceGroup.end()) {
|
||||
ended = true;
|
||||
break;
|
||||
}
|
||||
@ -225,8 +227,9 @@ static int doWrite(int argc, char const* const* argv)
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (cmSystemTools::GetEnv("CTEST_PROCESS_COUNT")) {
|
||||
std::cout << "CTEST_PROCESS_COUNT should not be defined" << std::endl;
|
||||
if (cmSystemTools::GetEnv("CTEST_RESOURCE_GROUP_COUNT")) {
|
||||
std::cout << "CTEST_RESOURCE_GROUP_COUNT should not be defined"
|
||||
<< std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -246,8 +249,8 @@ static int doWrite(int argc, char const* const* argv)
|
||||
return 1;
|
||||
}
|
||||
cmsys::ofstream fout(logFile.c_str(), std::ios::app);
|
||||
for (auto const& process : hardware) {
|
||||
for (auto const& it : process) {
|
||||
for (auto const& group : hardware) {
|
||||
for (auto const& it : group) {
|
||||
for (auto const& it2 : it.second) {
|
||||
fout << "dealloc " << it.first << " " << it2.Id << " " << it2.Slots
|
||||
<< std::endl;
|
||||
|
Loading…
Reference in New Issue
Block a user