Skip to content

Commit ac1d58a

Browse files
authored
Merge pull request ceph#55328 from rosinL/wip-fix-64117
cmake/AddCephTest: bind crimson unittest to different cores Reviewed-by: Chunmei Liu <[email protected]> Reviewed-by: Samuel Just <[email protected]> Reviewed-by: Kefu Chai <[email protected]>
2 parents ed736fa + 7fe2323 commit ac1d58a

14 files changed

+131
-14
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ option(PG_DEBUG_REFS "PG Ref debugging is enabled" OFF)
608608

609609
option(WITH_TESTS "enable the build of ceph-test package scripts/binaries" ON)
610610
set(UNIT_TESTS_BUILT ${WITH_TESTS})
611-
set(CEPH_TEST_TIMEOUT 3600 CACHE STRING
611+
set(CEPH_TEST_TIMEOUT 7200 CACHE STRING
612612
"Maximum time before a CTest gets killed" )
613613

614614
# fio

cmake/modules/AddCephTest.cmake

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,27 @@ function(add_ceph_test test_name test_path)
1919
PATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}:${CMAKE_SOURCE_DIR}/src:$ENV{PATH}
2020
PYTHONPATH=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cython_modules/lib.3:${CMAKE_SOURCE_DIR}/src/pybind
2121
CEPH_BUILD_VIRTUALENV=${CEPH_BUILD_VIRTUALENV})
22-
# none of the tests should take more than 1 hour to complete
2322
set_property(TEST ${test_name}
2423
PROPERTY TIMEOUT ${CEPH_TEST_TIMEOUT})
24+
# Crimson seastar unittest always run with --smp N to start N threads. By default, crimson seastar unittest
25+
# will take cpu cores[0, N), starting one thread per core. When running many crimson seastar unittests
26+
# parallely, the front N cpu cores are shared, and the left cpu cores are idle. Lots of cpu cores are wasted.
27+
# Using CTest resource allocation feature(https://cmake.org/cmake/help/latest/manual/ctest.1.html#resource-allocation),
28+
# ctest can specify cpu cores resources to crimson seastar unittests.
29+
# 3 steps to enable CTest resource allocation feature:
30+
# Step 1: Generate a resource specification file to describe available resource, $(nproc) CPUs with id 0 to $(nproc) - 1
31+
# Step 2: Set RESOURCE_GROUPS property to a test with value "${smp_count},cpus:1"
32+
# Step 3: Read a series of environment variables CTEST_RESOURCE_GROUP_* and set seastar smp_opts while running a test
33+
list(FIND ARGV "--smp" smp_pos)
34+
if(smp_pos GREATER -1)
35+
if(smp_pos EQUAL ARGC)
36+
message(FATAL_ERROR "${test_name} --smp requires an argument")
37+
endif()
38+
math(EXPR i "${smp_pos} + 1")
39+
list(GET ARGV ${i} smp_count)
40+
set_property(TEST ${test_name}
41+
PROPERTY RESOURCE_GROUPS "${smp_count},cpus:1")
42+
endif()
2543
endfunction()
2644

2745
option(WITH_GTEST_PARALLEL "Enable running gtest based tests in parallel" OFF)

run-make-check.sh

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ source src/script/run-make.sh
2222

2323
set -e
2424

25+
function gen_ctest_resource_file() {
26+
local file_name=$(mktemp /tmp/ctest-resource-XXXXXX)
27+
local max_cpuid=$(($(nproc) - 1))
28+
jq -n '$ARGS.positional | map({id:., slots:1}) | {cpus:.} | {version: {major:1, minor:0}, local:[.]}' \
29+
--args $(seq 0 $max_cpuid) > $file_name
30+
echo "$file_name"
31+
}
32+
2533
function run() {
2634
# to prevent OSD EMFILE death on tests, make sure ulimit >= 1024
2735
$DRY_RUN ulimit -n $(ulimit -Hn)
@@ -43,14 +51,16 @@ function run() {
4351
fi
4452

4553
CHECK_MAKEOPTS=${CHECK_MAKEOPTS:-$DEFAULT_MAKEOPTS}
54+
CTEST_RESOURCE_FILE=$(gen_ctest_resource_file)
55+
CHECK_MAKEOPTS+=" --resource-spec-file ${CTEST_RESOURCE_FILE}"
4656
if in_jenkins; then
4757
if ! ctest $CHECK_MAKEOPTS --no-compress-output --output-on-failure --test-output-size-failed 1024000 -T Test; then
4858
# do not return failure, as the jenkins publisher will take care of this
49-
rm -fr ${TMPDIR:-/tmp}/ceph-asok.*
59+
rm -fr ${TMPDIR:-/tmp}/ceph-asok.* ${CTEST_RESOURCE_FILE}
5060
fi
5161
else
5262
if ! $DRY_RUN ctest $CHECK_MAKEOPTS --output-on-failure; then
53-
rm -fr ${TMPDIR:-/tmp}/ceph-asok.*
63+
rm -fr ${TMPDIR:-/tmp}/ceph-asok.* ${CTEST_RESOURCE_FILE}
5464
return 1
5565
fi
5666
fi

src/test/crimson/ctest_utils.h

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2+
// vim: ts=8 sw=2 smarttab
3+
4+
#pragma once
5+
6+
#include <cstdlib>
7+
#include <iostream>
8+
#include <optional>
9+
#include <regex>
10+
#include <string>
11+
#include <vector>
12+
13+
#include <boost/algorithm/string.hpp>
14+
#include <fmt/format.h>
15+
#include <seastar/core/resource.hh>
16+
#include <seastar/core/app-template.hh>
17+
18+
struct ctest_resource {
19+
int id;
20+
int slots;
21+
ctest_resource(int id, int slots) : id(id), slots(slots) {}
22+
};
23+
24+
static std::vector<ctest_resource> parse_ctest_resources(const std::string& resource_spec) {
25+
std::vector<std::string> resources;
26+
boost::split(resources, resource_spec, boost::is_any_of(";"));
27+
std::regex res_regex("id:([0-9]+),slots:([0-9]+)");
28+
std::vector<ctest_resource> ctest_resources;
29+
for (auto& resource : resources) {
30+
std::smatch matched;
31+
if (std::regex_match(resource, matched, res_regex)) {
32+
int id = std::stoi(matched[1].str());
33+
int slots = std::stoi(matched[2].str());
34+
ctest_resources.emplace_back(id, slots);
35+
}
36+
}
37+
return ctest_resources;
38+
}
39+
40+
static std::optional<seastar::resource::cpuset> get_cpuset_from_ctest_resource_group() {
41+
int nr_groups = 0;
42+
auto group_count = std::getenv("CTEST_RESOURCE_GROUP_COUNT");
43+
if (group_count != nullptr) {
44+
nr_groups = std::stoi(group_count);
45+
} else {
46+
return {};
47+
}
48+
49+
seastar::resource::cpuset cpuset;
50+
for (int num = 0; num < nr_groups; num++) {
51+
std::string resource_type_name;
52+
fmt::format_to(std::back_inserter(resource_type_name), "CTEST_RESOURCE_GROUP_{}", num);
53+
// only a single resource type is supported for now
54+
std::string resource_type = std::getenv(resource_type_name.data());
55+
if (resource_type == "cpus") {
56+
std::transform(resource_type.begin(), resource_type.end(), resource_type.begin(), ::toupper);
57+
std::string resource_group;
58+
fmt::format_to(std::back_inserter(resource_group), "CTEST_RESOURCE_GROUP_{}_{}", num, resource_type);
59+
std::string resource_spec = std::getenv(resource_group.data());
60+
for (auto& resource : parse_ctest_resources(resource_spec)) {
61+
// each id has a single cpu slot
62+
cpuset.insert(resource.id);
63+
}
64+
} else {
65+
fmt::print(std::cerr, "unsupported resource type: {}", resource_type);
66+
}
67+
}
68+
return cpuset;
69+
}
70+
71+
static seastar::app_template::seastar_options get_smp_opts_from_ctest() {
72+
seastar::app_template::seastar_options opts;
73+
auto cpuset = get_cpuset_from_ctest_resource_group();
74+
if (cpuset) {
75+
opts.smp_opts.cpuset.set_value(*cpuset);
76+
}
77+
return opts;
78+
}

src/test/crimson/seastar_runner.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <seastar/core/alien.hh>
1414
#include <seastar/core/thread.hh>
1515

16+
#include "test/crimson/ctest_utils.h"
17+
1618
struct SeastarRunner {
1719
static constexpr eventfd_t APP_RUNNING = 1;
1820
static constexpr eventfd_t APP_NOT_RUN = 2;
@@ -26,7 +28,7 @@ struct SeastarRunner {
2628
bool begin_signaled = false;
2729

2830
SeastarRunner() :
29-
begin_fd{seastar::file_desc::eventfd(0, 0)} {}
31+
app{get_smp_opts_from_ctest()}, begin_fd{seastar::file_desc::eventfd(0, 0)} {}
3032

3133
~SeastarRunner() {}
3234

src/test/crimson/test_alien_echo.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "crimson/net/Connection.h"
99
#include "crimson/net/Dispatcher.h"
1010
#include "crimson/net/Messenger.h"
11+
#include "test/crimson/ctest_utils.h"
1112

1213
#include <seastar/core/alien.hh>
1314
#include <seastar/core/app-template.hh>
@@ -266,7 +267,7 @@ int main(int argc, char** argv)
266267
}
267268

268269
auto count = vm["count"].as<unsigned>();
269-
seastar::app_template app;
270+
seastar::app_template app{get_smp_opts_from_ctest()};
270271
SeastarContext sc;
271272
auto job = sc.with_seastar([&] {
272273
auto fut = seastar::alien::submit_to(app.alien(), 0, [addr, role, count] {

src/test/crimson/test_alienstore_thread_pool.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "crimson/common/config_proxy.h"
77
#include "crimson/os/alienstore/thread_pool.h"
88
#include "include/msgr.h"
9+
#include "test/crimson/ctest_utils.h"
910

1011
using namespace std::chrono_literals;
1112
using ThreadPool = crimson::os::ThreadPool;
@@ -37,7 +38,7 @@ seastar::future<> test_void_return(ThreadPool& tp) {
3738

3839
int main(int argc, char** argv)
3940
{
40-
seastar::app_template app;
41+
seastar::app_template app{get_smp_opts_from_ctest()};
4142
return app.run(argc, argv, [] {
4243
std::vector<const char*> args;
4344
std::string cluster;

src/test/crimson/test_buffer.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <seastar/core/future-util.hh>
44
#include <seastar/core/reactor.hh>
55
#include "include/buffer.h"
6+
#include "test/crimson/ctest_utils.h"
67

78
// allocate a foreign buffer on each cpu, collect them all into a bufferlist,
89
// and destruct it on this cpu
@@ -36,7 +37,7 @@ seastar::future<> test_foreign_bufferlist()
3637

3738
int main(int argc, char** argv)
3839
{
39-
seastar::app_template app;
40+
seastar::app_template app{get_smp_opts_from_ctest()};
4041
return app.run(argc, argv, [] {
4142
return seastar::now().then(
4243
&test_foreign_bufferlist

src/test/crimson/test_config.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "common/ceph_argparse.h"
77
#include "common/config_obs.h"
88
#include "crimson/common/config_proxy.h"
9+
#include "test/crimson/ctest_utils.h"
910

1011
using namespace std::literals;
1112
using Config = crimson::common::ConfigProxy;
@@ -88,7 +89,7 @@ static seastar::future<> test_config()
8889

8990
int main(int argc, char** argv)
9091
{
91-
seastar::app_template app;
92+
seastar::app_template app{get_smp_opts_from_ctest()};
9293
return app.run(argc, argv, [&] {
9394
return test_config().then([] {
9495
std::cout << "All tests succeeded" << std::endl;

src/test/crimson/test_messenger.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <seastar/core/with_timeout.hh>
3030

3131
#include "test_messenger.h"
32+
#include "test/crimson/ctest_utils.h"
3233

3334
using namespace std::chrono_literals;
3435
namespace bpo = boost::program_options;
@@ -3845,7 +3846,7 @@ seastar::future<int> do_test(seastar::app_template& app)
38453846

38463847
int main(int argc, char** argv)
38473848
{
3848-
seastar::app_template app;
3849+
seastar::app_template app{get_smp_opts_from_ctest()};
38493850
app.add_options()
38503851
("verbose,v", bpo::value<bool>()->default_value(false),
38513852
"chatty if true")

0 commit comments

Comments
 (0)