Commit 016601e5 authored by Brad King's avatar Brad King
Browse files

Merge branch 'backport-ctest-resource-groups'

parents 370fe149 c1435d98
......@@ -17,7 +17,7 @@ Perform the :ref:`CTest Test Step` as a :ref:`Dashboard Client`.
[EXCLUDE_FIXTURE_SETUP <regex>]
[EXCLUDE_FIXTURE_CLEANUP <regex>]
[PARALLEL_LEVEL <level>]
[HARDWARE_SPEC_FILE <file>]
[RESOURCE_SPEC_FILE <file>]
[TEST_LOAD <threshold>]
[SCHEDULE_RANDOM <ON|OFF>]
[STOP_TIME <time-of-day>]
......@@ -83,10 +83,10 @@ The options are:
Specify a positive number representing the number of tests to
be run in parallel.
``HARDWARE_SPEC_FILE <file>``
``RESOURCE_SPEC_FILE <file>``
Specify a
:ref:`hardware specification file <ctest-hardware-specification-file>`. See
:ref:`ctest-hardware-allocation` for more information.
:ref:`resource specification file <ctest-resource-specification-file>`. See
:ref:`ctest-resource-allocation` for more information.
``TEST_LOAD <threshold>``
While running tests in parallel, try not to start tests when they
......
......@@ -415,10 +415,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
......
......@@ -90,14 +90,14 @@ Options
See `Label and Subproject Summary`_.
``--hardware-spec-file <file>``
Run CTest with :ref:`hardware allocation <ctest-hardware-allocation>` enabled,
``--resource-spec-file <file>``
Run CTest with :ref:`resource allocation <ctest-resource-allocation>` enabled,
using the
:ref:`hardware specification file <ctest-hardware-specification-file>`
:ref:`resource specification file <ctest-resource-specification-file>`
specified in ``<file>``.
When ``ctest`` is run as a `Dashboard Client`_ this sets the
``HardwareSpecFile`` option of the `CTest Test Step`_.
``ResourceSpecFile`` option of the `CTest Test Step`_.
``--test-load <level>``
While running tests in parallel (e.g. with ``-j``), try not to start
......@@ -980,10 +980,10 @@ Arguments to the command may specify some of the step settings.
Configuration settings include:
``HardwareSpecFile``
``ResourceSpecFile``
Specify a
:ref:`hardware specification file <ctest-hardware-specification-file>`. See
:ref:`ctest-hardware-allocation` for more information.
:ref:`resource specification file <ctest-resource-specification-file>`. See
:ref:`ctest-resource-allocation` for more information.
``LabelsForSubprojects``
Specify a semicolon-separated list of labels that will be treated as
......@@ -1294,22 +1294,22 @@ model is defined as follows:
Test properties.
Can contain keys for each of the supported test properties.
.. _`ctest-hardware-allocation`:
.. _`ctest-resource-allocation`:
Hardware Allocation
Resource Allocation
===================
CTest provides a mechanism for tests to specify the hardware that they need and
how much of it they need, and for users to specify the hardware availiable on
CTest provides a mechanism for tests to specify the resources that they need
in a fine-grained way, and for users to specify the resources availiable on
the running machine. This allows CTest to internally keep track of which
hardware is in use and which is free, scheduling tests in a way that prevents
them from trying to claim hardware that is not available.
resources are in use and which are free, scheduling tests in a way that
prevents them from trying to claim resources that are not available.
A common use case for this feature is for tests that require the use of a GPU.
Multiple tests can simultaneously allocate memory from a GPU, but if too many
tests try to do this at once, some of them will fail to allocate, resulting in
a failed test, even though the test would have succeeded if it had the memory
it needed. By using the hardware allocation feature, each test can specify how
it needed. By using the resource allocation feature, each test can specify how
much memory it requires from a GPU, allowing CTest to schedule tests in a way
that running several of these tests at once does not exhaust the GPU's memory
pool.
......@@ -1325,36 +1325,35 @@ When a test is executed, and slots from a resource are allocated to that test,
tests may assume that they have exclusive use of those slots for the duration
of the test's process.
The CTest hardware allocation feature consists of two inputs:
The CTest resource 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 :ref:`resource specification file <ctest-resource-specification-file>`,
described below, which describes the resources available on the system.
* 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
When CTest runs a test, the resources allocated to that test are passed in the
form of a set of
:ref:`environment variables <ctest-hardware-environment-variables>` as
:ref:`environment variables <ctest-resource-environment-variables>` as
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-resource-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`:
.. _`ctest-resource-specification-file`:
Hardware Specification File
Resource Specification File
---------------------------
The hardware specification file is a JSON file which is passed to CTest, either
on the :manual:`ctest(1)` command line as ``--hardware-spec-file``, or as the
``HARDWARE_SPEC_FILE`` argument of :command:`ctest_test`. The hardware
The resource specification file is a JSON file which is passed to CTest, either
on the :manual:`ctest(1)` command line as ``--resource-spec-file``, or as the
``RESOURCE_SPEC_FILE`` argument of :command:`ctest_test`. The resource
specification file must be a JSON object. All examples in this document assume
the following hardware specification file:
the following resource specification file:
.. code-block:: json
......@@ -1391,11 +1390,11 @@ the following hardware specification file:
The members are:
``local``
A JSON array consisting of CPU sockets present on the system. Currently, only
one socket is supported.
A JSON array of resource sets present on the system. Currently, this array
is restricted to being of size 1.
Each socket is a JSON object with members whose names are equal to the
desired resource types, such as ``gpu``. These names must start with a
Each array element is a JSON object with members whose names are equal to the
desired resource types, such as ``gpus``. These names must start with a
lowercase letter or an underscore, and subsequent characters can be a
lowercase letter, a digit, or an underscore. Uppercase letters are not
allowed, because certain platforms have case-insensitive environment
......@@ -1436,12 +1435,12 @@ 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`:
.. _`ctest-resource-environment-variables`:
Environment Variables
---------------------
......@@ -1449,65 +1448,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,
``--resource-spec-file``, or if :command:`ctest_test` has been given a
``RESOURCE_SPEC_FILE``. If no resource 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
cryptography chip ``card0``.
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``, 1 slot from GPU
``3``, 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:`resource specification file <ctest-resource-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
========
......
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.
RESOURCE_GROUPS
---------------
Specify resources required by a test, grouped in a way that is meaningful to
the test. See :ref:`resource allocation <ctest-resource-allocation>`
for more information on how this property integrates into the CTest resource
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-resource-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-resource-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.
......@@ -192,8 +192,8 @@ Autogen
CTest
-----
* :manual:`ctest(1)` now has the ability to serialize tests based on hardware
requirements for each test. See :ref:`ctest-hardware-allocation` for
* :manual:`ctest(1)` now has the ability to schedule tests based on resource
requirements for each test. See :ref:`ctest-resource-allocation` for
details.
* A new test property, :prop_test:`SKIP_REGULAR_EXPRESSION`, has been added.
......
......@@ -921,14 +921,14 @@ set(CTEST_SRCS cmCTest.cxx
CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
CTest/cmCTestGenericHandler.cxx
CTest/cmCTestHandlerCommand.cxx
CTest/cmCTestHardwareAllocator.cxx
CTest/cmCTestHardwareSpec.cxx
CTest/cmCTestResourceAllocator.cxx
CTest/cmCTestResourceSpec.cxx
CTest/cmCTestLaunch.cxx
CTest/cmCTestMemCheckCommand.cxx
CTest/cmCTestMemCheckHandler.cxx
CTest/cmCTestMultiProcessHandler.cxx
CTest/cmCTestProcessesLexerHelper.cxx
CTest/cmCTestReadCustomFilesCommand.cxx
CTest/cmCTestResourceGroupsLexerHelper.cxx
CTest/cmCTestRunScriptCommand.cxx
CTest/cmCTestRunTest.cxx
CTest/cmCTestScriptHandler.cxx
......@@ -960,9 +960,9 @@ set(CTEST_SRCS cmCTest.cxx
CTest/cmCTestP4.cxx
CTest/cmCTestP4.h
LexerParser/cmCTestProcessesLexer.cxx
LexerParser/cmCTestProcessesLexer.h
LexerParser/cmCTestProcessesLexer.in.l
LexerParser/cmCTestResourceGroupsLexer.cxx
LexerParser/cmCTestResourceGroupsLexer.h
LexerParser/cmCTestResourceGroupsLexer.in.l
)
# Build CTestLib
......
......@@ -23,7 +23,7 @@ namespace {
/*
* The following algorithm is used to do two things:
*
* 1) Determine if a test's hardware requirements can fit within the hardware
* 1) Determine if a test's resource requirements can fit within the resources
* present on the system, and
* 2) Do the actual allocation
*
......@@ -34,46 +34,46 @@ namespace {
* more combinations can be tried.
*/
template <typename AllocationStrategy>
static bool AllocateCTestHardware(
const std::map<std::string, cmCTestHardwareAllocator::Resource>& hardware,
const std::vector<std::string>& hardwareSorted, std::size_t currentIndex,
static bool AllocateCTestResources(
const std::map<std::string, cmCTestResourceAllocator::Resource>& resources,
const std::vector<std::string>& resourcesSorted, std::size_t currentIndex,
std::vector<cmCTestBinPackerAllocation*>& allocations)
{
// Iterate through all large enough resources until we find a solution
std::size_t hardwareIndex = 0;
while (hardwareIndex < hardwareSorted.size()) {
auto const& resource = hardware.at(hardwareSorted[hardwareIndex]);
std::size_t resourceIndex = 0;
while (resourceIndex < resourcesSorted.size()) {
auto const& resource = resources.at(resourcesSorted[resourceIndex]);
if (resource.Free() >=
static_cast<unsigned int>(allocations[currentIndex]->SlotsNeeded)) {
// Preemptively allocate the resource
allocations[currentIndex]->Id = hardwareSorted[hardwareIndex];
allocations[currentIndex]->Id = resourcesSorted[resourceIndex];
if (currentIndex + 1 >= allocations.size()) {
// We have a solution
return true;
}
// Move the resource up the list until it is sorted again
auto hardware2 = hardware;
auto hardwareSorted2 = hardwareSorted;
hardware2[hardwareSorted2[hardwareIndex]].Locked +=
auto resources2 = resources;
auto resourcesSorted2 = resourcesSorted;
resources2[resourcesSorted2[resourceIndex]].Locked +=
allocations[currentIndex]->SlotsNeeded;
AllocationStrategy::IncrementalSort(hardware2, hardwareSorted2,
hardwareIndex);
AllocationStrategy::IncrementalSort(resources2, resourcesSorted2,
resourceIndex);
// Recurse one level deeper
if (AllocateCTestHardware<AllocationStrategy>(
hardware2, hardwareSorted2, currentIndex + 1, allocations)) {
if (AllocateCTestResources<AllocationStrategy>(
resources2, resourcesSorted2, currentIndex + 1, allocations)) {
return true;
}
}
// No solution found here, deallocate the resource and try the next one
allocations[currentIndex]->Id.clear();
auto freeSlots = hardware.at(hardwareSorted.at(hardwareIndex)).Free();
auto freeSlots = resources.at(resourcesSorted.at(resourceIndex)).Free();
do {
++hardwareIndex;
} while (hardwareIndex < hardwareSorted.size() &&
hardware.at(hardwareSorted.at(hardwareIndex)).Free() ==
++resourceIndex;
} while (resourceIndex < resourcesSorted.size() &&
resources.at(resourcesSorted.at(resourceIndex)).Free() ==
freeSlots);
}
......@@ -82,8 +82,8 @@ static bool AllocateCTestHardware(
}
template <typename AllocationStrategy>
static bool AllocateCTestHardware(
const std::map<std::string, cmCTestHardwareAllocator::Resource>& hardware,
static bool AllocateCTestResources(
const std::map<std::string, cmCTestResourceAllocator::Resource>& resources,
std::vector<cmCTestBinPackerAllocation>& allocations)
{
// Sort the resource requirements in descending order by slots needed
......@@ -99,103 +99,105 @@ static bool AllocateCTestHardware(
});
// Sort the resources according to sort strategy
std::vector<std::string> hardwareSorted;
hardwareSorted.reserve(hardware.size());
for (auto const& hw : hardware) {
hardwareSorted.push_back(hw.first);
std::vector<std::string> resourcesSorted;
resourcesSorted.reserve(resources.size());
for (auto const& res : resources) {
resourcesSorted.push_back(res.first);
}
AllocationStrategy::InitialSort(hardware, hardwareSorted);
AllocationStrategy::InitialSort(resources, resourcesSorted);
// Do the actual allocation
return AllocateCTestHardware<AllocationStrategy>(
hardware, hardwareSorted, std::size_t(0), allocationsPtr);
return AllocateCTestResources<AllocationStrategy>(
resources, resourcesSorted, std::size_t(0), allocationsPtr);
}
class RoundRobinAllocationStrategy
{
public:
static void InitialSort(
const std::map<std::string, cmCTestHardwareAllocator::Resource>& hardware,
std::vector<std::string>& hardwareSorted);
const std::map<std::string, cmCTestResourceAllocator::Resource>& resources,
std::vector<std::string>& resourcesSorted);
static void IncrementalSort(
const std::map<std::string, cmCTestHardwareAllocator::Resource>& hardware,
std::vector<std::string>& hardwareSorted, std::size_t lastAllocatedIndex);
const std::map<std::string, cmCTestResourceAllocator::Resource>& resources,
std::vector<std::string>& resourcesSorted, std::size_t lastAllocatedIndex);
};
void RoundRobinAllocationStrategy::InitialSort(
const std::map<std::string, cmCTestHardwareAllocator::Resource>& hardware,
std::vector<std::string>& hardwareSorted)
const std::map<std::string, cmCTestResourceAllocator::Resource>& resources,
std::vector<std::string>& resourcesSorted)
{
std::stable_sort(
hardwareSorted.rbegin(), hardwareSorted.rend(),
[&hardware](const std::string& id1, const std::string& id2) {
return hardware.at(id1).Free() < hardware.at(id2).Free();
resourcesSorted.rbegin(), resourcesSorted.rend(),
[&resources](const std::string& id1, const std::string& id2) {
return resources.at(id1).Free() < resources.at(id2).Free();
});
}
void RoundRobinAllocationStrategy::IncrementalSort(