Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Partial support of MacOs #405

Merged
merged 1 commit into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ endif ()
option(ENABLE_EXAMPLES "Enable Example Builds" ${GR_TOPLEVEL_PROJECT})

option(ENABLE_TESTING "Enable Test Builds" ${GR_TOPLEVEL_PROJECT})
if (ENABLE_TESTING AND UNIX AND NOT APPLE)
if (ENABLE_TESTING AND (UNIX OR APPLE))
list(APPEND CMAKE_CTEST_ARGUMENTS "--output-on-failure")
enable_testing()
if (ENABLE_COVERAGE)
Expand Down
4 changes: 2 additions & 2 deletions bench/benchmark.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ template<Numeric T>
std::string to_si_prefix(T value_base, std::string_view unit = "s", std::size_t significant_digits = 0) {
static constexpr std::array si_prefixes{'q', 'r', 'y', 'z', 'a', 'f', 'p', 'n', 'u', 'm', ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'R', 'Q'};
static constexpr long double base = 1000.0L;
long double value = value_base;
auto value = static_cast<long double>(value_base);

std::size_t exponent = 10U;
if (value == 0.0L) {
Expand Down Expand Up @@ -791,7 +791,7 @@ class benchmark : public ut::detail::test {
add_statistics(result_map, time_differences_ns);

result_map.try_emplace("total time", duration_s, "s", _precision);
result_map.try_emplace("ops/s", _n_scale_results * N_ITERATIONS / duration_s, "", std::max(1, _precision));
result_map.try_emplace("ops/s", static_cast<long double>(_n_scale_results * N_ITERATIONS) / duration_s, "", std::max(1, _precision));

if constexpr (MARKER_SIZE > 0) {
auto transposed_map = utils::convert<N_ITERATIONS>(marker_iter);
Expand Down
2 changes: 2 additions & 0 deletions blocks/http/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
if (NOT APPLE)
add_ut_test(qa_HttpBlock)
target_link_libraries(qa_HttpBlock PRIVATE gr-http)

if (EMSCRIPTEN)
target_link_options(qa_HttpBlock PRIVATE --pre-js=${CMAKE_CURRENT_SOURCE_DIR}/pre.js --emrun)
endif ()
endif ()
2 changes: 1 addition & 1 deletion core/benchmarks/bm_Buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

using namespace gr;

#if defined __has_include && not __EMSCRIPTEN__
#if defined(__has_include) && not defined(__EMSCRIPTEN__) && not defined(__APPLE__)
#if __has_include(<pthread.h>) && __has_include(<sched.h>)
#include <errno.h>
#include <pthread.h>
Expand Down
2 changes: 1 addition & 1 deletion core/include/gnuradio-4.0/WaitStrategy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ class SpinWait {
yieldProcessor();
}
}
#ifndef __EMSCRIPTEN__
#if not defined(__EMSCRIPTEN__) && not defined(__APPLE__)
static void yieldProcessor() noexcept { asm volatile("rep\nnop"); }
#else
static void yieldProcessor() noexcept { std::this_thread::sleep_for(std::chrono::milliseconds(1)); }
Expand Down
191 changes: 66 additions & 125 deletions core/include/gnuradio-4.0/thread/thread_affinity.hpp

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion core/test/qa_buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ const boost::ut::suite SequenceTests = [] {
"Sequence"_test = [] {
using namespace gr;
using signed_index_type = std::make_signed_t<std::size_t>;
#if not defined(__APPLE__)
expect(eq(alignof(Sequence), 64UZ));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this not hold for iOS?

#endif
expect(eq(0L, kInitialCursorValue));
expect(nothrow([] { Sequence(); }));
expect(nothrow([] { Sequence(2); }));
Expand Down Expand Up @@ -621,8 +623,9 @@ const boost::ut::suite StreamTagConcept = [] {
int64_t index;
std::string data;
};

#if not defined(__APPLE__)
expect(eq(sizeof(buffer_tag), 64UZ)) << "tag size";
#endif
BufferLike auto buffer = CircularBuffer<int32_t>(1024);
BufferLike auto tagBuffer = CircularBuffer<buffer_tag>(32);
expect(ge(buffer.size(), 1024u));
Expand Down
2 changes: 1 addition & 1 deletion core/test/qa_grc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ const boost::ut::suite GrcTests = [] {
}
};

#ifndef __EMSCRIPTEN__
#if not defined(__EMSCRIPTEN__) && not defined(__APPLE__)
"Basic graph loading and storing using plugins"_test = [] {
try {
using namespace gr;
Expand Down
92 changes: 51 additions & 41 deletions core/test/qa_thread_affinity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const boost::ut::suite ThreadAffinityTests = [] {
using namespace boost::ut;

"thread_exception"_test = [] {
expect(nothrow([]{gr::thread_pool::thread::thread_exception();}));
expect(nothrow([] { gr::thread_pool::thread::thread_exception(); }));
expect(gr::thread_pool::thread::thread_exception().name() == "thread_exception"_b);
expect(gr::thread_pool::thread::thread_exception().message(-1) == "unknown threading error code -1"_b);
expect(gr::thread_pool::thread::thread_exception().message(-2) == "unknown threading error code -2"_b);
Expand All @@ -19,7 +19,7 @@ const boost::ut::suite ThreadAffinityTests = [] {
};

"thread_helper"_test = [] {
#if not defined(__EMSCRIPTEN__)
#if not defined(__EMSCRIPTEN__) && not defined(__APPLE__)
expect(that % gr::thread_pool::thread::detail::getEnumPolicy(SCHED_FIFO) == gr::thread_pool::thread::Policy::FIFO);
expect(that % gr::thread_pool::thread::detail::getEnumPolicy(SCHED_RR) == gr::thread_pool::thread::Policy::ROUND_ROBIN);
expect(that % gr::thread_pool::thread::detail::getEnumPolicy(SCHED_OTHER) == gr::thread_pool::thread::Policy::OTHER);
Expand All @@ -28,14 +28,18 @@ const boost::ut::suite ThreadAffinityTests = [] {
expect(that % gr::thread_pool::thread::detail::getEnumPolicy(-2) == gr::thread_pool::thread::Policy::UNKNOWN);
};

#if not defined(__EMSCRIPTEN__)
#if not defined(__EMSCRIPTEN__) && not defined(__APPLE__)
"basic thread affinity"_test = [] {
using namespace gr::thread_pool;
std::atomic<bool> run = true;
const auto dummyAction = [&run]() { while (run) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); } };
std::thread testThread(dummyAction);
std::atomic<bool> run = true;
const auto dummyAction = [&run]() {
while (run) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
};
std::thread testThread(dummyAction);

constexpr std::array threadMap = { true, false, false, false };
constexpr std::array threadMap = {true, false, false, false};
thread::setThreadAffinity(threadMap, testThread);
auto affinity = thread::getThreadAffinity(testThread);
bool equal = true;
Expand All @@ -47,7 +51,7 @@ const boost::ut::suite ThreadAffinityTests = [] {
expect(equal) << fmt::format("set {{{}}} affinity map does not match get {{{}}} map", fmt::join(threadMap, ", "), fmt::join(affinity, ", "));

// tests w/o thread argument
constexpr std::array threadMapOn = { true, true };
constexpr std::array threadMapOn = {true, true};
thread::setThreadAffinity(threadMapOn);
affinity = thread::getThreadAffinity();
for (size_t i = 0; i < std::min(threadMapOn.size(), affinity.size()); i++) {
Expand All @@ -58,16 +62,16 @@ const boost::ut::suite ThreadAffinityTests = [] {
expect(equal) << fmt::format("set {{{}}} affinity map does not match get {{{}}} map", fmt::join(threadMap, ", "), fmt::join(affinity, ", "));

std::thread bogusThread;
expect(throws<std::system_error>([&]{ thread::getThreadAffinity(bogusThread); }));
expect(throws<std::system_error>([&]{ thread::setThreadAffinity(threadMapOn, bogusThread); }));
expect(throws<std::system_error>([&] { thread::getThreadAffinity(bogusThread); }));
expect(throws<std::system_error>([&] { thread::setThreadAffinity(threadMapOn, bogusThread); }));

run = false;
testThread.join();
};

"basic process affinity"_test = [] {
using namespace gr::thread_pool;
constexpr std::array threadMap = { true, false, false, false };
constexpr std::array threadMap = {true, false, false, false};
thread::setProcessAffinity(threadMap);
auto affinity = thread::getProcessAffinity();
bool equal = true;
Expand All @@ -77,29 +81,33 @@ const boost::ut::suite ThreadAffinityTests = [] {
}
}
expect(equal) << fmt::format("set {{{}}} affinity map does not match get {{{}}} map", fmt::join(threadMap, ", "), fmt::join(affinity, ", "));
constexpr std::array threadMapOn = { true, true, true, true };
constexpr std::array threadMapOn = {true, true, true, true};
thread::setProcessAffinity(threadMapOn);
expect(throws<std::system_error>([&]{ thread::getProcessAffinity(-1); }));
expect(throws<std::system_error>([&]{ thread::setProcessAffinity(threadMapOn, -1); }));
expect(throws<std::system_error>([&] { thread::getProcessAffinity(-1); }));
expect(throws<std::system_error>([&] { thread::setProcessAffinity(threadMapOn, -1); }));
};

"ThreadName"_test = [] {
using namespace gr::thread_pool;
expect(!thread::getThreadName().empty()) << "Thread name shouldn't be empty";
expect(nothrow([]{ thread::setThreadName("testCoreName"); }));
expect(nothrow([] { thread::setThreadName("testCoreName"); }));
expect(thread::getThreadName() == "testCoreName"_b);

std::atomic<bool> run = true;
const auto dummyAction = [&run]() { while (run) { std::this_thread::sleep_for(std::chrono::milliseconds(20)); } };
std::thread testThread(dummyAction);
const auto dummyAction = [&run]() {
while (run) {
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
};
std::thread testThread(dummyAction);
expect(!thread::getThreadName(testThread).empty()) << "Thread Name shouldn't be empty";
expect(nothrow([&]{ thread::setThreadName("testThreadName", testThread); }));
expect(nothrow([&] { thread::setThreadName("testThreadName", testThread); }));
thread::setThreadName("testThreadName", testThread);
expect(thread::getThreadName(testThread) == "testThreadName"_b);

std::thread uninitialisedTestThread;
expect(throws<std::system_error>([&]{ thread::getThreadName(uninitialisedTestThread); }));
expect(throws<std::system_error>([&]{ thread::setThreadName("name", uninitialisedTestThread); }));
expect(throws<std::system_error>([&] { thread::getThreadName(uninitialisedTestThread); }));
expect(throws<std::system_error>([&] { thread::setThreadName("name", uninitialisedTestThread); }));
run = false;
testThread.join();
};
Expand All @@ -109,7 +117,7 @@ const boost::ut::suite ThreadAffinityTests = [] {
expect(!thread::getProcessName().empty()) << "Process name shouldn't be empty";
expect(that % thread::getProcessName() == thread::getProcessName(thread::detail::getPid()));

expect(nothrow([]{ thread::setProcessName("TestProcessName"); }));
expect(nothrow([] { thread::setProcessName("TestProcessName"); }));
expect(thread::getProcessName() == "TestProcessName"_b);
};

Expand All @@ -119,27 +127,31 @@ const boost::ut::suite ThreadAffinityTests = [] {
expect(that % param.policy == OTHER);
expect(that % param.priority == 0);

expect(nothrow([]{ setProcessSchedulingParameter(OTHER, 0); }));
expect(throws<std::system_error>([]{ setProcessSchedulingParameter(OTHER, 0, -1); }));
expect(throws<std::system_error>([]{ setProcessSchedulingParameter(OTHER, 4); }));
expect(throws<std::system_error>([]{ setProcessSchedulingParameter(ROUND_ROBIN, 5); })); // missing rights -- because most users do not have CAP_SYS_NICE rights by default -- hard to unit-test
expect(nothrow([] { setProcessSchedulingParameter(OTHER, 0); }));
expect(throws<std::system_error>([] { setProcessSchedulingParameter(OTHER, 0, -1); }));
expect(throws<std::system_error>([] { setProcessSchedulingParameter(OTHER, 4); }));
expect(throws<std::system_error>([] { setProcessSchedulingParameter(ROUND_ROBIN, 5); })); // missing rights -- because most users do not have CAP_SYS_NICE rights by default -- hard to unit-test
param = getProcessSchedulingParameter();
expect(that % param.policy == OTHER);
expect(that % param.priority == 0);

expect(throws<std::system_error>([]{ getProcessSchedulingParameter(-1); }));
expect(throws<std::system_error>([]{ setProcessSchedulingParameter(ROUND_ROBIN, 5, -1); }));
expect(throws<std::system_error>([] { getProcessSchedulingParameter(-1); }));
expect(throws<std::system_error>([] { setProcessSchedulingParameter(ROUND_ROBIN, 5, -1); }));

expect(that % gr::thread_pool::thread::detail::getEnumPolicy(SCHED_FIFO) == gr::thread_pool::thread::FIFO);
expect(that % gr::thread_pool::thread::detail::getEnumPolicy(SCHED_RR) == gr::thread_pool::thread::ROUND_ROBIN);
expect(that % gr::thread_pool::thread::detail::getEnumPolicy(SCHED_OTHER) == gr::thread_pool::thread::OTHER);
};

"ThreadSchedulingParameter"_test = [] {
std::atomic<bool> run = true;
const auto dummyAction = [&run]() { while (run) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); } };
std::thread testThread(dummyAction);
std::thread bogusThread;
std::atomic<bool> run = true;
const auto dummyAction = [&run]() {
while (run) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
};
std::thread testThread(dummyAction);
std::thread bogusThread;

using namespace gr::thread_pool::thread;
struct SchedulingParameter param = getThreadSchedulingParameter(testThread);
Expand All @@ -148,23 +160,21 @@ const boost::ut::suite ThreadAffinityTests = [] {

setThreadSchedulingParameter(OTHER, 0, testThread);
setThreadSchedulingParameter(OTHER, 0);
expect(throws<std::system_error>([&]{ setThreadSchedulingParameter(OTHER, 0, bogusThread); }));
expect(throws<std::system_error>([&]{ setThreadSchedulingParameter(OTHER, 4, testThread); }));
expect(throws<std::system_error>([&]{ setThreadSchedulingParameter(OTHER, 4); }));
expect(throws<std::system_error>([&]{ setThreadSchedulingParameter(ROUND_ROBIN, 5, testThread); })); // missing rights -- because most users do not have CAP_SYS_NICE rights by default -- hard to unit-test
expect(throws<std::system_error>([&]{ setThreadSchedulingParameter(ROUND_ROBIN, 5); })); // missing rights -- because most users do not have CAP_SYS_NICE rights by default -- hard to unit-test
expect(throws<std::system_error>([&] { setThreadSchedulingParameter(OTHER, 0, bogusThread); }));
expect(throws<std::system_error>([&] { setThreadSchedulingParameter(OTHER, 4, testThread); }));
expect(throws<std::system_error>([&] { setThreadSchedulingParameter(OTHER, 4); }));
expect(throws<std::system_error>([&] { setThreadSchedulingParameter(ROUND_ROBIN, 5, testThread); })); // missing rights -- because most users do not have CAP_SYS_NICE rights by default -- hard to unit-test
expect(throws<std::system_error>([&] { setThreadSchedulingParameter(ROUND_ROBIN, 5); })); // missing rights -- because most users do not have CAP_SYS_NICE rights by default -- hard to unit-test
param = getThreadSchedulingParameter(testThread);
expect(that % param.policy == OTHER);

expect(throws<std::system_error>([&]{ getThreadSchedulingParameter(bogusThread); }));
expect(throws<std::system_error>([&]{ setThreadSchedulingParameter(ROUND_ROBIN, 5, bogusThread); }));
expect(throws<std::system_error>([&] { getThreadSchedulingParameter(bogusThread); }));
expect(throws<std::system_error>([&] { setThreadSchedulingParameter(ROUND_ROBIN, 5, bogusThread); }));

run = false;
testThread.join();
};
#endif
};

int
main() { /* tests are statically executed */
}
int main() { /* tests are statically executed */ }
2 changes: 1 addition & 1 deletion core/test/qa_thread_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const boost::ut::suite ThreadPoolTests = [] {
expect(ret.get() == 42_i);

auto taskName = pool.execute<"taskName", 0, -1>([] { return gr::thread_pool::thread::getThreadName(); });
#ifdef __EMSCRIPTEN__
#if defined(__EMSCRIPTEN__) || defined(__APPLE__)
expect(taskName.get() == "unknown thread name"_b);
#else
expect(taskName.get() == "taskName"_b);
Expand Down
Loading