Fix build and C++ tests for FreeBSD (#10480)
This commit is contained in:
parent
e8a962575a
commit
09d32f1f2b
33
.github/workflows/freebsd.yml
vendored
Normal file
33
.github/workflows/freebsd.yml
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
name: FreeBSD
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read # to fetch code (actions/checkout)
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: A job to run test in FreeBSD
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: 'true'
|
||||||
|
- name: Test in FreeBSD
|
||||||
|
id: test
|
||||||
|
uses: vmactions/freebsd-vm@v1
|
||||||
|
with:
|
||||||
|
usesh: true
|
||||||
|
prepare: |
|
||||||
|
pkg install -y cmake git ninja googletest
|
||||||
|
|
||||||
|
run: |
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -GNinja -DGOOGLE_TEST=ON
|
||||||
|
ninja -v
|
||||||
|
./testxgboost
|
||||||
@ -77,6 +77,8 @@ namespace utils {
|
|||||||
|
|
||||||
template <typename PollFD>
|
template <typename PollFD>
|
||||||
int PollImpl(PollFD* pfd, int nfds, std::chrono::seconds timeout) noexcept(true) {
|
int PollImpl(PollFD* pfd, int nfds, std::chrono::seconds timeout) noexcept(true) {
|
||||||
|
// For Windows and Linux, negative timeout means infinite timeout. For freebsd,
|
||||||
|
// INFTIM(-1) should be used instead.
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
#if IS_MINGW()
|
#if IS_MINGW()
|
||||||
@ -87,7 +89,7 @@ int PollImpl(PollFD* pfd, int nfds, std::chrono::seconds timeout) noexcept(true)
|
|||||||
#endif // IS_MINGW()
|
#endif // IS_MINGW()
|
||||||
|
|
||||||
#else
|
#else
|
||||||
return poll(pfd, nfds, std::chrono::milliseconds(timeout).count());
|
return poll(pfd, nfds, timeout.count() < 0 ? -1 : std::chrono::milliseconds(timeout).count());
|
||||||
#endif // IS_MINGW()
|
#endif // IS_MINGW()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -75,8 +75,11 @@ using CollAPIThreadLocalStore = dmlc::ThreadLocalStore<CollAPIEntry>;
|
|||||||
|
|
||||||
void WaitImpl(TrackerHandleT *ptr, std::chrono::seconds timeout) {
|
void WaitImpl(TrackerHandleT *ptr, std::chrono::seconds timeout) {
|
||||||
constexpr std::int64_t kDft{collective::DefaultTimeoutSec()};
|
constexpr std::int64_t kDft{collective::DefaultTimeoutSec()};
|
||||||
std::chrono::seconds wait_for{collective::HasTimeout(timeout) ? std::min(kDft, timeout.count())
|
std::int64_t timeout_clipped = kDft;
|
||||||
: kDft};
|
if (collective::HasTimeout(timeout)) {
|
||||||
|
timeout_clipped = std::min(kDft, static_cast<std::int64_t>(timeout.count()));
|
||||||
|
}
|
||||||
|
std::chrono::seconds wait_for{timeout_clipped};
|
||||||
|
|
||||||
common::Timer timer;
|
common::Timer timer;
|
||||||
timer.Start();
|
timer.Start();
|
||||||
@ -171,7 +174,19 @@ XGB_DLL int XGTrackerFree(TrackerHandle handle) {
|
|||||||
common::Timer timer;
|
common::Timer timer;
|
||||||
timer.Start();
|
timer.Start();
|
||||||
// Make sure no one else is waiting on the tracker.
|
// Make sure no one else is waiting on the tracker.
|
||||||
while (!ptr->first.unique()) {
|
|
||||||
|
// Quote from https://en.cppreference.com/w/cpp/memory/shared_ptr/use_count#Notes:
|
||||||
|
//
|
||||||
|
// In multithreaded environment, `use_count() == 1` does not imply that the object is
|
||||||
|
// safe to modify because accesses to the managed object by former shared owners may not
|
||||||
|
// have completed, and because new shared owners may be introduced concurrently.
|
||||||
|
//
|
||||||
|
// - We don't have the first case since we never access the raw pointer.
|
||||||
|
//
|
||||||
|
// - We don't hve the second case for most of the scenarios since tracker is an unique
|
||||||
|
// object, if the free function is called before another function calls, it's likely
|
||||||
|
// to be a bug in the user code. The use_count should only decrease in this function.
|
||||||
|
while (ptr->first.use_count() != 1) {
|
||||||
auto ela = timer.Duration().count();
|
auto ela = timer.Duration().count();
|
||||||
if (collective::HasTimeout(ptr->first->Timeout()) && ela > ptr->first->Timeout().count()) {
|
if (collective::HasTimeout(ptr->first->Timeout()) && ela > ptr->first->Timeout().count()) {
|
||||||
LOG(WARNING) << "Time out " << ptr->first->Timeout().count()
|
LOG(WARNING) << "Time out " << ptr->first->Timeout().count()
|
||||||
|
|||||||
@ -22,10 +22,12 @@ namespace xgboost::collective {
|
|||||||
SockAddress MakeSockAddress(StringView host, in_port_t port) {
|
SockAddress MakeSockAddress(StringView host, in_port_t port) {
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
std::memset(&hints, 0, sizeof(hints));
|
std::memset(&hints, 0, sizeof(hints));
|
||||||
hints.ai_protocol = SOCK_STREAM;
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
struct addrinfo *res = nullptr;
|
struct addrinfo *res = nullptr;
|
||||||
int sig = getaddrinfo(host.c_str(), nullptr, &hints, &res);
|
int sig = getaddrinfo(host.c_str(), nullptr, &hints, &res);
|
||||||
if (sig != 0) {
|
if (sig != 0) {
|
||||||
|
LOG(FATAL) << "Failed to get addr info for: " << host
|
||||||
|
<< ", error: " << gai_strerror(sig);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (res->ai_family == static_cast<std::int32_t>(SockDomain::kV4)) {
|
if (res->ai_family == static_cast<std::int32_t>(SockDomain::kV4)) {
|
||||||
|
|||||||
@ -105,7 +105,7 @@ inline Json MakeTrackerConfig(std::string host, std::int32_t n_workers,
|
|||||||
config["port"] = Integer{0};
|
config["port"] = Integer{0};
|
||||||
config["n_workers"] = Integer{n_workers};
|
config["n_workers"] = Integer{n_workers};
|
||||||
config["sortby"] = Integer{static_cast<std::int32_t>(Tracker::SortBy::kHost)};
|
config["sortby"] = Integer{static_cast<std::int32_t>(Tracker::SortBy::kHost)};
|
||||||
config["timeout"] = timeout.count();
|
config["timeout"] = static_cast<std::int64_t>(timeout.count());
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -68,14 +68,20 @@ TEST(ColumnSampler, GPUTest) {
|
|||||||
// Test if different threads using the same seed produce the same result
|
// Test if different threads using the same seed produce the same result
|
||||||
TEST(ColumnSampler, ThreadSynchronisation) {
|
TEST(ColumnSampler, ThreadSynchronisation) {
|
||||||
Context ctx;
|
Context ctx;
|
||||||
const int64_t num_threads = 100;
|
// NOLINTBEGIN(clang-analyzer-deadcode.DeadStores)
|
||||||
|
#if defined(__linux__)
|
||||||
|
std::int64_t const n_threads = std::thread::hardware_concurrency() * 128;
|
||||||
|
#else
|
||||||
|
std::int64_t const n_threads = std::thread::hardware_concurrency();
|
||||||
|
#endif
|
||||||
|
// NOLINTEND(clang-analyzer-deadcode.DeadStores)
|
||||||
int n = 128;
|
int n = 128;
|
||||||
size_t iterations = 10;
|
size_t iterations = 10;
|
||||||
size_t levels = 5;
|
size_t levels = 5;
|
||||||
std::vector<bst_feature_t> reference_result;
|
std::vector<bst_feature_t> reference_result;
|
||||||
std::vector<float> feature_weights;
|
std::vector<float> feature_weights;
|
||||||
bool success = true; // Cannot use google test asserts in multithreaded region
|
bool success = true; // Cannot use google test asserts in multithreaded region
|
||||||
#pragma omp parallel num_threads(num_threads)
|
#pragma omp parallel num_threads(n_threads)
|
||||||
{
|
{
|
||||||
for (auto j = 0ull; j < iterations; j++) {
|
for (auto j = 0ull; j < iterations; j++) {
|
||||||
ColumnSampler cs(j);
|
ColumnSampler cs(j);
|
||||||
|
|||||||
@ -59,7 +59,11 @@ TEST(DMatrixCache, MultiThread) {
|
|||||||
std::size_t constexpr kRows = 2, kCols = 1, kCacheSize = 3;
|
std::size_t constexpr kRows = 2, kCols = 1, kCacheSize = 3;
|
||||||
auto p_fmat = RandomDataGenerator(kRows, kCols, 0).GenerateDMatrix();
|
auto p_fmat = RandomDataGenerator(kRows, kCols, 0).GenerateDMatrix();
|
||||||
|
|
||||||
auto n = std::thread::hardware_concurrency() * 128u;
|
#if defined(__linux__)
|
||||||
|
auto const n = std::thread::hardware_concurrency() * 128;
|
||||||
|
#else
|
||||||
|
auto const n = std::thread::hardware_concurrency();
|
||||||
|
#endif
|
||||||
CHECK_NE(n, 0);
|
CHECK_NE(n, 0);
|
||||||
std::vector<std::shared_ptr<CacheForTest>> results(n);
|
std::vector<std::shared_ptr<CacheForTest>> results(n);
|
||||||
|
|
||||||
|
|||||||
@ -267,8 +267,14 @@ TEST(Learner, MultiThreadedPredict) {
|
|||||||
learner->Configure();
|
learner->Configure();
|
||||||
|
|
||||||
std::vector<std::thread> threads;
|
std::vector<std::thread> threads;
|
||||||
for (uint32_t thread_id = 0;
|
|
||||||
thread_id < 2 * std::thread::hardware_concurrency(); ++thread_id) {
|
#if defined(__linux__)
|
||||||
|
auto n_threads = std::thread::hardware_concurrency() * 4u;
|
||||||
|
#else
|
||||||
|
auto n_threads = std::thread::hardware_concurrency();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (decltype(n_threads) thread_id = 0; thread_id < n_threads; ++thread_id) {
|
||||||
threads.emplace_back([learner, p_data] {
|
threads.emplace_back([learner, p_data] {
|
||||||
size_t constexpr kIters = 10;
|
size_t constexpr kIters = 10;
|
||||||
auto &entry = learner->GetThreadLocal().prediction_entry;
|
auto &entry = learner->GetThreadLocal().prediction_entry;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user