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:
Brad King 2019-11-04 16:11:11 -05:00
parent c1d5d5eb11
commit af9ed543b0
16 changed files with 213 additions and 206 deletions

View File

@ -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

View File

@ -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
========

View File

@ -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.

View 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.

View File

@ -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.

View File

@ -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(

View File

@ -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 += '_';

View File

@ -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;
}
}

View File

@ -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>;

View File

@ -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

View File

@ -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;

View File

@ -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;;\"
)

View File

@ -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])

View File

@ -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()

View File

@ -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})

View File

@ -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;