summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMoritz Haase <Moritz.Haase@bmw.de>2025-06-20 09:02:16 +0200
committerSteve Sakoman <steve@sakoman.com>2025-06-25 08:11:58 -0700
commit9bc0069f8b3968250c4245c8a81b65fdacabfba5 (patch)
treeb083f3f62ece576a01eea7a99c915f6f71c44372
parent104f728b6504c558ffbc5fa102c1cd8862a75b46 (diff)
downloadpoky-kirkstone.tar.gz
cmake: Correctly handle cost data of tests with arbitrary chars in namekirkstone
ctest automatically optimizes the order of (parallel) test execution based on historic test case runtime via the COST property (see [0]), which can have a significant impact on overall test run times. Sadly this feature is broken in CMake < 4.0.0 for test cases that have spaces in their name (see [1]). This commit is a backport of f24178f3 (which itself backports the upstream fix). the patch was adapted slightly to apply cleanly to the older CMake version in kirkstone. As repeated test runs are expected to mainly take place inside the SDK, the patch is only applied to 'nativesdk' builds. [0]: https://cmake.org/cmake/help/latest/prop_test/COST.html [1]: https://gitlab.kitware.com/cmake/cmake/-/issues/26594 Reported-By: John Drouhard <john@drouhard.dev> (From OE-Core rev: f6a160f7ea57af6dfeca003e6c05aa42419fb755) Signed-off-by: Moritz Haase <Moritz.Haase@bmw.de> Signed-off-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org> Signed-off-by: Steve Sakoman <steve@sakoman.com>
-rw-r--r--meta/recipes-devtools/cmake/cmake-native_3.22.3.bb2
-rw-r--r--meta/recipes-devtools/cmake/cmake/0001-ctest-Allow-arbitrary-characters-in-test-names-of-CT.patch205
-rw-r--r--meta/recipes-devtools/cmake/cmake_3.22.3.bb1
3 files changed, 207 insertions, 1 deletions
diff --git a/meta/recipes-devtools/cmake/cmake-native_3.22.3.bb b/meta/recipes-devtools/cmake/cmake-native_3.22.3.bb
index 45ea78ae00..447554aa2e 100644
--- a/meta/recipes-devtools/cmake/cmake-native_3.22.3.bb
+++ b/meta/recipes-devtools/cmake/cmake-native_3.22.3.bb
@@ -49,7 +49,7 @@ do_compile() {
49do_install() { 49do_install() {
50 oe_runmake 'DESTDIR=${D}' install 50 oe_runmake 'DESTDIR=${D}' install
51 51
52 # The following codes are here because eSDK needs to provide compatibilty 52 # The following codes are here because eSDK needs to provide compatibility
53 # for SDK. That is, eSDK could also be used like traditional SDK. 53 # for SDK. That is, eSDK could also be used like traditional SDK.
54 mkdir -p ${D}${datadir}/cmake 54 mkdir -p ${D}${datadir}/cmake
55 install -m 644 ${WORKDIR}/OEToolchainConfig.cmake ${D}${datadir}/cmake/ 55 install -m 644 ${WORKDIR}/OEToolchainConfig.cmake ${D}${datadir}/cmake/
diff --git a/meta/recipes-devtools/cmake/cmake/0001-ctest-Allow-arbitrary-characters-in-test-names-of-CT.patch b/meta/recipes-devtools/cmake/cmake/0001-ctest-Allow-arbitrary-characters-in-test-names-of-CT.patch
new file mode 100644
index 0000000000..10fc4f545e
--- /dev/null
+++ b/meta/recipes-devtools/cmake/cmake/0001-ctest-Allow-arbitrary-characters-in-test-names-of-CT.patch
@@ -0,0 +1,205 @@
1From 4f992e105bf4a85062bb439ca63daefc8a992f94 Mon Sep 17 00:00:00 2001
2From: John Drouhard <john@drouhard.dev>
3Date: Thu, 9 Jan 2025 20:34:42 -0600
4Subject: [PATCH] ctest: Allow arbitrary characters in test names of
5 CTestCostData.txt
6
7This changes the way lines in CTestCostData.txt are parsed to allow for
8spaces in the test name.
9
10It does so by looking for space characters from the end; and once two
11have been found, assumes everything from the beginning up to that
12second-to-last-space is the test name.
13
14Additionally, parsing the file should be much more efficient since there
15is no string or vector heap allocation per line. The std::string used by
16the parse function to convert the int and float should be within most
17standard libraries' small string optimization.
18
19Fixes: #26594
20
21Upstream-Status: Backport [4.0.0, 040da7d83216ace59710407e8ce35d5fd38e1340]
22Signed-off-by: Moritz Haase <Moritz.Haase@bmw.de>
23---
24 Source/CTest/cmCTestMultiProcessHandler.cxx | 80 +++++++++++++++------
25 Source/CTest/cmCTestMultiProcessHandler.h | 3 +-
26 Tests/CTestTestScheduler/CMakeLists.txt | 4 +-
27 3 files changed, 64 insertions(+), 23 deletions(-)
28
29diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
30index d90c4a64651e4d53cc219abe76cb10a342e8aa35..311d2368bcc99abfb4b61c77032b26a440bc5bde 100644
31--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
32+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
33@@ -19,6 +19,7 @@
34 #include <vector>
35
36 #include <cm/memory>
37+#include <cm/string_view>
38 #include <cmext/algorithm>
39
40 #include <cm3p/json/value.h>
41@@ -41,6 +42,51 @@
42 #include "cmUVSignalHackRAII.h" // IWYU pragma: keep
43 #include "cmWorkingDirectory.h"
44
45+namespace {
46+
47+struct CostEntry
48+{
49+ cm::string_view name;
50+ int prevRuns;
51+ float cost;
52+};
53+
54+cm::optional<CostEntry> splitCostLine(cm::string_view line)
55+{
56+ std::string part;
57+ cm::string_view::size_type pos1 = line.size();
58+ cm::string_view::size_type pos2 = line.find_last_of(' ', pos1);
59+ auto findNext = [line, &part, &pos1, &pos2]() -> bool {
60+ if (pos2 != cm::string_view::npos) {
61+ cm::string_view sub = line.substr(pos2 + 1, pos1 - pos2 - 1);
62+ part.assign(sub.begin(), sub.end());
63+ pos1 = pos2;
64+ if (pos1 > 0) {
65+ pos2 = line.find_last_of(' ', pos1 - 1);
66+ }
67+ return true;
68+ }
69+ return false;
70+ };
71+
72+ // parse the cost
73+ if (!findNext()) {
74+ return cm::nullopt;
75+ }
76+ float cost = static_cast<float>(atof(part.c_str()));
77+
78+ // parse the previous runs
79+ if (!findNext()) {
80+ return cm::nullopt;
81+ }
82+ int prev = atoi(part.c_str());
83+
84+ // from start to the last found space is the name
85+ return CostEntry{ line.substr(0, pos1), prev, cost };
86+}
87+
88+}
89+
90 namespace cmsys {
91 class RegularExpression;
92 }
93@@ -691,24 +737,21 @@ void cmCTestMultiProcessHandler::UpdateCostData()
94 if (line == "---") {
95 break;
96 }
97- std::vector<std::string> parts = cmSystemTools::SplitString(line, ' ');
98 // Format: <name> <previous_runs> <avg_cost>
99- if (parts.size() < 3) {
100+ cm::optional<CostEntry> entry = splitCostLine(line);
101+ if (!entry) {
102 break;
103 }
104
105- std::string name = parts[0];
106- int prev = atoi(parts[1].c_str());
107- float cost = static_cast<float>(atof(parts[2].c_str()));
108-
109- int index = this->SearchByName(name);
110+ int index = this->SearchByName(entry->name);
111 if (index == -1) {
112 // This test is not in memory. We just rewrite the entry
113- fout << name << " " << prev << " " << cost << "\n";
114+ fout << entry->name << " " << entry->prevRuns << " " << entry->cost
115+ << "\n";
116 } else {
117 // Update with our new average cost
118- fout << name << " " << this->Properties[index]->PreviousRuns << " "
119- << this->Properties[index]->Cost << "\n";
120+ fout << entry->name << " " << this->Properties[index]->PreviousRuns
121+ << " " << this->Properties[index]->Cost << "\n";
122 temp.erase(index);
123 }
124 }
125@@ -744,28 +787,25 @@ void cmCTestMultiProcessHandler::ReadCostData()
126 break;
127 }
128
129- std::vector<std::string> parts = cmSystemTools::SplitString(line, ' ');
130+ // Format: <name> <previous_runs> <avg_cost>
131+ cm::optional<CostEntry> entry = splitCostLine(line);
132
133 // Probably an older version of the file, will be fixed next run
134- if (parts.size() < 3) {
135+ if (!entry) {
136 fin.close();
137 return;
138 }
139
140- std::string name = parts[0];
141- int prev = atoi(parts[1].c_str());
142- float cost = static_cast<float>(atof(parts[2].c_str()));
143-
144- int index = this->SearchByName(name);
145+ int index = this->SearchByName(entry->name);
146 if (index == -1) {
147 continue;
148 }
149
150- this->Properties[index]->PreviousRuns = prev;
151+ this->Properties[index]->PreviousRuns = entry->prevRuns;
152 // When not running in parallel mode, don't use cost data
153 if (this->ParallelLevel > 1 && this->Properties[index] &&
154 this->Properties[index]->Cost == 0) {
155- this->Properties[index]->Cost = cost;
156+ this->Properties[index]->Cost = entry->cost;
157 }
158 }
159 // Next part of the file is the failed tests
160@@ -778,7 +818,7 @@ void cmCTestMultiProcessHandler::ReadCostData()
161 }
162 }
163
164-int cmCTestMultiProcessHandler::SearchByName(std::string const& name)
165+int cmCTestMultiProcessHandler::SearchByName(cm::string_view name)
166 {
167 int index = -1;
168
169diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h
170index 5de42f9e3209f4b7f0e856afc458e8b4a35d87b7..11e995d9e06ba9fdb0e086dc3e5e4175f8158cd0 100644
171--- a/Source/CTest/cmCTestMultiProcessHandler.h
172+++ b/Source/CTest/cmCTestMultiProcessHandler.h
173@@ -10,6 +10,7 @@
174 #include <string>
175 #include <vector>
176
177+#include <cm/string_view>
178 #include <cm3p/uv.h>
179 #include <stddef.h>
180
181@@ -111,7 +112,7 @@ protected:
182 void UpdateCostData();
183 void ReadCostData();
184 // Return index of a test based on its name
185- int SearchByName(std::string const& name);
186+ int SearchByName(cm::string_view name);
187
188 void CreateTestCostList();
189
190diff --git a/Tests/CTestTestScheduler/CMakeLists.txt b/Tests/CTestTestScheduler/CMakeLists.txt
191index a3f0f27cdcb901bb309bb6cb6cd9307ce1ba20a2..daf6ce2b23d8c048334ae1047759130b246dccef 100644
192--- a/Tests/CTestTestScheduler/CMakeLists.txt
193+++ b/Tests/CTestTestScheduler/CMakeLists.txt
194@@ -1,9 +1,9 @@
195-cmake_minimum_required (VERSION 2.8.12)
196+cmake_minimum_required(VERSION 3.19)
197 project (CTestTestScheduler)
198 include (CTest)
199
200 add_executable (Sleep sleep.c)
201
202 foreach (time RANGE 1 4)
203- add_test (TestSleep${time} Sleep ${time})
204+ add_test ("TestSleep ${time}" Sleep ${time})
205 endforeach ()
diff --git a/meta/recipes-devtools/cmake/cmake_3.22.3.bb b/meta/recipes-devtools/cmake/cmake_3.22.3.bb
index 752c37ba7d..04a0f0e793 100644
--- a/meta/recipes-devtools/cmake/cmake_3.22.3.bb
+++ b/meta/recipes-devtools/cmake/cmake_3.22.3.bb
@@ -10,6 +10,7 @@ SRC_URI:append:class-nativesdk = " \
10 file://cmake-setup.py \ 10 file://cmake-setup.py \
11 file://environment.d-cmake.sh \ 11 file://environment.d-cmake.sh \
12 file://0001-CMakeDetermineSystem-use-oe-environment-vars-to-load.patch \ 12 file://0001-CMakeDetermineSystem-use-oe-environment-vars-to-load.patch \
13 file://0001-ctest-Allow-arbitrary-characters-in-test-names-of-CT.patch \
13" 14"
14 15
15LICENSE:append = " & BSD-1-Clause & MIT" 16LICENSE:append = " & BSD-1-Clause & MIT"