Skip to content
Open
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: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
build/

# Prerequisites
*.d

Expand Down
96 changes: 96 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
cmake_minimum_required(VERSION 3.28)
project(TooManyCooks
VERSION 1.0.0
LANGUAGES CXX
DESCRIPTION "TooManyCooks - A runtime and concurrency library for C++20 coroutines"
)

# Require C++20 for coroutines and modules
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# Options
option(TMC_BUILD_MODULE "Build the C++20 module" ON)
option(TMC_USE_HWLOC "Enable hwloc support for topology detection" OFF)
option(TMC_DEBUG_TASK_ALLOC_COUNT "Enable task allocation counting for debugging" OFF)

# Create the main module library
add_library(tmc)

# Add the module source
target_sources(tmc
PUBLIC
FILE_SET CXX_MODULES FILES
modules/tmc.cppm
)

# Include directories for headers used by the module
target_include_directories(tmc
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)

# Compile definitions
# Module build requires external linkage for helper functions
target_compile_definitions(tmc PRIVATE TMC_MODULE_BUILD)

if(TMC_USE_HWLOC)
target_compile_definitions(tmc PUBLIC TMC_USE_HWLOC)
find_package(PkgConfig REQUIRED)
pkg_check_modules(HWLOC REQUIRED hwloc)
target_include_directories(tmc PUBLIC ${HWLOC_INCLUDE_DIRS})
target_link_libraries(tmc PUBLIC ${HWLOC_LIBRARIES})
endif()

if(TMC_DEBUG_TASK_ALLOC_COUNT)
target_compile_definitions(tmc PUBLIC TMC_DEBUG_TASK_ALLOC_COUNT)
endif()

# Platform-specific settings
if(UNIX AND NOT APPLE)
target_link_libraries(tmc PUBLIC pthread)
endif()

# Installation rules
include(GNUInstallDirs)

install(TARGETS tmc
EXPORT TooManyCooksTargets
FILE_SET CXX_MODULES DESTINATION ${CMAKE_INSTALL_LIBDIR}/modules
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

install(DIRECTORY include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)

install(EXPORT TooManyCooksTargets
FILE TooManyCooksTargets.cmake
NAMESPACE TooManyCooks::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TooManyCooks
)

# Create config file
include(CMakePackageConfigHelpers)

configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/TooManyCooksConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/TooManyCooksConfig.cmake"
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TooManyCooks
)

write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/TooManyCooksConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion
)

install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/TooManyCooksConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/TooManyCooksConfigVersion.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TooManyCooks
)
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ It also offers the option to create a [standalone compilation file](https://gith

For a minimal project template, see [tmc-hello-world](https://github.com/tzcnt/tmc-hello-world).

Using CMake, the library can be built as a C++20 module (which requires CMake 3.28 and any module-supporting build system, like Ninja).

### Configuration
TooManyCooks will work out of the box as a header-only library without any configuration.
However, some configuration options are available. See the documentation section [Build-Time Options](https://fleetcode.com/oss/tmc/docs/latest/build_flags.html) for more info.
Expand Down
5 changes: 5 additions & 0 deletions cmake/TooManyCooksConfig.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@PACKAGE_INIT@

include("${CMAKE_CURRENT_LIST_DIR}/TooManyCooksTargets.cmake")

check_required_components(TooManyCooks)
16 changes: 8 additions & 8 deletions include/tmc/detail/awaitable_customizer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ namespace tmc {
namespace detail {
namespace task_flags {
// Flags bitfield section
static inline constexpr size_t NONE = 0;
static inline constexpr size_t EACH = TMC_ONE_BIT << (TMC_PLATFORM_BITS - 1);
TMC_STATIC_LINKAGE constexpr size_t NONE = 0;
TMC_STATIC_LINKAGE constexpr size_t EACH = TMC_ONE_BIT << (TMC_PLATFORM_BITS - 1);

// Numeric bitfield sections
static inline constexpr size_t TASKNUM_HIGH_OFF = 10;
static inline constexpr size_t TASKNUM_LOW_OFF = 4;
static inline constexpr size_t TASKNUM_MASK =
TMC_STATIC_LINKAGE constexpr size_t TASKNUM_HIGH_OFF = 10;
TMC_STATIC_LINKAGE constexpr size_t TASKNUM_LOW_OFF = 4;
TMC_STATIC_LINKAGE constexpr size_t TASKNUM_MASK =
(TMC_ONE_BIT << TASKNUM_HIGH_OFF) - (TMC_ONE_BIT << TASKNUM_LOW_OFF);

// This is the continuation priority, not the current task's priority
static inline constexpr size_t PRIORITY_HIGH_OFF = 4;
static inline constexpr size_t PRIORITY_LOW_OFF = 0;
static inline constexpr size_t PRIORITY_MASK =
TMC_STATIC_LINKAGE constexpr size_t PRIORITY_HIGH_OFF = 4;
TMC_STATIC_LINKAGE constexpr size_t PRIORITY_LOW_OFF = 0;
TMC_STATIC_LINKAGE constexpr size_t PRIORITY_MASK =
(TMC_ONE_BIT << PRIORITY_HIGH_OFF) - (TMC_ONE_BIT << PRIORITY_LOW_OFF);

} // namespace task_flags
Expand Down
18 changes: 12 additions & 6 deletions include/tmc/detail/compat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
#include <atomic>
#include <cstddef>

#ifdef TMC_MODULE_BUILD
#define TMC_STATIC_LINKAGE inline
#else
#define TMC_STATIC_LINKAGE static inline
#endif

#if defined(_MSC_VER)

#ifdef __has_cpp_attribute
Expand Down Expand Up @@ -70,7 +76,7 @@
#endif
#define TMC_CPU_X86
#define TMC_CPU_PAUSE _mm_pause
static inline size_t TMC_CPU_TIMESTAMP() noexcept {
TMC_STATIC_LINKAGE size_t TMC_CPU_TIMESTAMP() noexcept {
return static_cast<size_t>(__rdtsc());
}
// Assume a 3.5GHz CPU if we can't get the value (on x86).
Expand All @@ -81,29 +87,29 @@ static inline size_t TMC_CPU_TIMESTAMP() noexcept {
// be running faster, and vice versa. For the current usage of this (the
// clustering threshold in tmc::channel) this seems like reasonable behavior
// anyway.
static inline const size_t TMC_CPU_FREQ = 3500000000;
TMC_STATIC_LINKAGE const size_t TMC_CPU_FREQ = 3500000000;
#elif defined(__arm__) || defined(_M_ARM) || defined(_M_ARM64) || \
defined(__aarch64__) || defined(__ARM_ACLE)
#define TMC_CPU_ARM
static inline void TMC_CPU_PAUSE() noexcept {
TMC_STATIC_LINKAGE void TMC_CPU_PAUSE() noexcept {
// Clang defines __yield intrinsic, but GCC doesn't, so we use asm
asm volatile("yield");
}
// Read the ARM "Virtual Counter" register.
// This ticks at a frequency independent of the processor frequency.
// https://developer.arm.com/documentation/ddi0406/cb/System-Level-Architecture/The-Generic-Timer/About-the-Generic-Timer/The-virtual-counter?lang=en
static inline size_t TMC_CPU_TIMESTAMP() noexcept {
TMC_STATIC_LINKAGE size_t TMC_CPU_TIMESTAMP() noexcept {
size_t count;
asm volatile("mrs %0, cntvct_el0; " : "=r"(count)::"memory");
return count;
}
// Read the ARM "Virtual Counter" frequency.
static inline size_t TMC_ARM_CPU_FREQ() noexcept {
TMC_STATIC_LINKAGE size_t TMC_ARM_CPU_FREQ() noexcept {
size_t freq;
asm volatile("mrs %0, cntfrq_el0; isb; " : "=r"(freq)::"memory");
return freq;
}
static inline const size_t TMC_CPU_FREQ = TMC_ARM_CPU_FREQ();
TMC_STATIC_LINKAGE const size_t TMC_CPU_FREQ = TMC_ARM_CPU_FREQ();
#endif

// clang-format tries to collapse the pragmas into one line...
Expand Down
3 changes: 2 additions & 1 deletion include/tmc/detail/concepts_work_item.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#pragma once

#include "tmc/detail/compat.hpp"
#include "tmc/detail/concepts_awaitable.hpp"
#include "tmc/task.hpp"

Expand Down Expand Up @@ -95,7 +96,7 @@ template <is_callable T> struct executable_kind_v_impl<T> {
static inline constexpr executable_kind value = executable_kind::CALLABLE;
};
template <typename T>
static inline constexpr executable_kind executable_kind_v =
TMC_STATIC_LINKAGE constexpr executable_kind executable_kind_v =
executable_kind_v_impl<T>::value;
/// end executable_kind<T>

Expand Down
20 changes: 9 additions & 11 deletions include/tmc/detail/container_cpu_quota.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ namespace tmc {
namespace detail {

#ifdef __linux__
namespace {

struct mount_point {
std::string mount_point_path;
Expand All @@ -37,7 +36,7 @@ struct cgroup_subsys {
std::string path;
};

std::vector<std::string> split_string(const std::string& s, char delim) {
inline std::vector<std::string> split_string(const std::string& s, char delim) {
std::vector<std::string> result;
std::stringstream ss(s);
std::string item;
Expand All @@ -47,7 +46,7 @@ std::vector<std::string> split_string(const std::string& s, char delim) {
return result;
}

std::vector<cgroup_subsys> parse_proc_cgroup(const std::string& path) {
inline std::vector<cgroup_subsys> parse_proc_cgroup(const std::string& path) {
std::vector<cgroup_subsys> result;
std::ifstream file(path);
if (!file.is_open()) {
Expand All @@ -69,7 +68,7 @@ std::vector<cgroup_subsys> parse_proc_cgroup(const std::string& path) {
return result;
}

std::vector<mount_point> parse_mountinfo(const std::string& path) {
inline std::vector<mount_point> parse_mountinfo(const std::string& path) {
std::vector<mount_point> result;
std::ifstream file(path);
if (!file.is_open()) {
Expand Down Expand Up @@ -104,7 +103,7 @@ std::vector<mount_point> parse_mountinfo(const std::string& path) {
return result;
}

bool is_cgroups_v2() {
inline bool is_cgroups_v2() {
auto mounts = parse_mountinfo("/proc/self/mountinfo");
for (const auto& mp : mounts) {
if (mp.fs_type == "cgroup2" && mp.mount_point_path == "/sys/fs/cgroup") {
Expand All @@ -114,7 +113,7 @@ bool is_cgroups_v2() {
return false;
}

std::string find_cgroup_v2_path() {
inline std::string find_cgroup_v2_path() {
auto subsystems = parse_proc_cgroup("/proc/self/cgroup");
for (const auto& subsys : subsystems) {
if (subsys.id == 0) {
Expand All @@ -124,7 +123,7 @@ std::string find_cgroup_v2_path() {
return "";
}

std::string find_cgroup_v1_path() {
inline std::string find_cgroup_v1_path() {
auto subsystems = parse_proc_cgroup("/proc/self/cgroup");
auto mounts = parse_mountinfo("/proc/self/mountinfo");

Expand Down Expand Up @@ -157,7 +156,7 @@ std::string find_cgroup_v1_path() {
return "";
}

int64_t read_int_from_file(const std::string& path) {
inline int64_t read_int_from_file(const std::string& path) {
std::ifstream file(path);
if (!file.is_open()) {
return -1;
Expand All @@ -169,7 +168,7 @@ int64_t read_int_from_file(const std::string& path) {
return value;
}

container_cpu_quota query_cgroups_v2() {
inline container_cpu_quota query_cgroups_v2() {
container_cpu_quota result;
result.cpu_count = 0.0;
result.status = container_cpu_status::UNLIMITED;
Expand Down Expand Up @@ -225,7 +224,7 @@ container_cpu_quota query_cgroups_v2() {
return result;
}

container_cpu_quota query_cgroups_v1() {
inline container_cpu_quota query_cgroups_v1() {
container_cpu_quota result;
result.cpu_count = 0.0;
result.status = container_cpu_status::UNLIMITED;
Expand Down Expand Up @@ -253,7 +252,6 @@ container_cpu_quota query_cgroups_v1() {
return result;
}

} // namespace
#endif

container_cpu_quota query_container_cpu_quota() {
Expand Down
5 changes: 5 additions & 0 deletions include/tmc/detail/impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,10 @@
#define TMC_DECL
#endif
#else // !TMC_STANDALONE_COMPILATION

#ifdef TMC_MODULE_BUILD
#define TMC_DECL
#else
#define TMC_DECL inline
#endif
#endif
Loading