diff --git a/AGENTS.md b/AGENTS.md index fe54c717..6686795a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,6 +23,8 @@ CMake options (full table in `docs/getting-started.md`): - `DAQIRI_ENABLE_S3` — enable AWS SDK-backed asynchronous raw packet writes to S3 (off by default). - `DAQIRI_PREFER_SYSTEM_YAML_CPP` — prefer system `yaml-cpp` over the vendored `third_party/yaml-cpp` submodule (off by default; keep off when a conda/miniforge env is on `PATH`). +Package versions use CalVer (`YYYY.MM.PATCH`) from the top-level `VERSION` file. CMake reads that value into `project(daqiri VERSION ...)`, generates `daqiri/version.h`, feeds pkg-config/CMake package metadata, and exposes the same value in Python. `DAQIRI_ABI_VERSION` is separate and currently `0`; do not tie ABI policy to the CalVer year. + CUDA architectures default to `80;90` (A100, H100), with `121` (GB10) added when configuring with CUDA Toolkit 13.0 or newer. Override `CMAKE_CUDA_ARCHITECTURES` when targeting other GPUs. **Socket / ibverbs relationship**: the socket engine is always built and provides UDP/TCP directly; its RoCE path delegates to the `ibverbs` engine (internally the `rdma` engine — `src/engines/rdma/`, target `daqiri_rdma`, define `DAQIRI_ENGINE_RDMA`; `ibverbs` is only the user-facing name). `src/CMakeLists.txt` builds the ibverbs/rdma engine only when `ibverbs` is in `DAQIRI_ENGINE`, and the socket engine links it conditionally — so `socket` RoCE is available only when `ibverbs` was built, while plain UDP/TCP always works. @@ -68,6 +70,8 @@ clang-format -style=file -i -fallback-style=none **Single C++/CUDA shared library** (`libdaqiri.so`) exposing a C++ API through `#include `. The public surface is intentionally flat free-function helpers (`get_rx_burst`, `get_packet_ptr`, `set_udp_header`, …) that all operate on opaque DAQIRI-owned buffers. Applications never touch engine types directly. +`include/daqiri/daqiri.h` also includes the generated `daqiri/version.h`, exposing `DAQIRI_VERSION`, CalVer component macros, `DAQIRI_ABI_VERSION`, and inline helpers such as `daqiri::version_string()` and `daqiri::abi_version()`. + ### Engine abstraction `src/engine.h` defines `daqiri::Engine` — an (almost) ABC with ~50 virtual methods covering init, RX/TX burst dequeue/enqueue, header-fill helpers, buffer free, and RDMA connection setup. Engines live in `src/engines//` (`dpdk/`, `rdma/`, `socket/`, `ibverbs/`). `DAQIRI_ENGINE` selects the optional `dpdk` and `ibverbs` engines at CMake configure time; the `socket` engine is always built. The user-facing value `ibverbs` builds **two** internal engines that both use libibverbs: `rdma` (`src/engines/rdma/`, `DAQIRI_ENGINE_RDMA`, RoCE/InfiniBand for socket `roce://`) and `ibverbs` (`src/engines/ibverbs/`, `DAQIRI_ENGINE_IBVERBS`, the pure-DevX MPRQ raw-Ethernet engine). Each engine produces its own static library (`daqiri_dpdk`, `daqiri_rdma`, `daqiri_socket`, `daqiri_ibverbs`) linked into `daqiri_common`, and each adds a `DAQIRI_ENGINE_=1` compile definition. @@ -124,7 +128,7 @@ The web docs live in `docs/` and are built with [MkDocs Material](https://squidf **Keeping docs in sync with code:** before committing changes, scan for the recurring drift hotspots: - **Stream-type list** (`src/engines/*/`) — README Engines table, `docs/getting-started.md`, `docs/concepts.md` (Stream Types section + Support and testing admonition), `docs/api-reference/configuration.md` -- **CMake options / `DAQIRI_ENGINE` default** (`src/CMakeLists.txt:137`) — README Quick Start, `docs/getting-started.md`, this file's Build & run section +- **CMake options / `DAQIRI_ENGINE` default** (`src/CMakeLists.txt`) — README Quick Start, `docs/getting-started.md`, this file's Build & run section - **Benchmark binary or YAML names** (`examples/`) — the benchmark table above, `docs/benchmarks/raw_benchmarking.md`, the "Choosing an example config" decision tree in `docs/tutorials/configuration-walkthrough.md` (every YAML must have a leaf; CI's `scripts/check_doc_refs.py` enforces coverage), and per-platform performance docs (`docs/benchmarks/performance-*.md`) - **Public API include** (`#include `; source files under `include/daqiri/`) — `docs/api-reference/index.md`, `docs/api-reference/cpp.md`, `docs/api-reference/python.md`; if the change adds or renames a user-facing concept, also `docs/concepts.md` - **Python bindings** (`python/daqiri_common_pybind.cpp`) — `docs/api-reference/python.md` (function reference tables, enums/classes tables, GIL Behavior section) diff --git a/CMakeLists.txt b/CMakeLists.txt index 67520967..fc2d1dc2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,12 +19,30 @@ if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) set(DAQIRI_USING_DEFAULT_CUDA_ARCHITECTURES ON) endif() -project(daqiri VERSION 0.1.0 LANGUAGES C CXX CUDA) +file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" DAQIRI_PROJECT_VERSION) +string(STRIP "${DAQIRI_PROJECT_VERSION}" DAQIRI_PROJECT_VERSION) +if(NOT DAQIRI_PROJECT_VERSION MATCHES "^([0-9][0-9][0-9][0-9])\\.([1-9]|1[0-2])\\.(0|[1-9][0-9]*)$") + message(FATAL_ERROR "VERSION must use CalVer format YYYY.MM.PATCH, for example 2026.7.0") +endif() + +project(daqiri VERSION ${DAQIRI_PROJECT_VERSION} LANGUAGES C CXX CUDA) include(GNUInstallDirs) include(CMakePackageConfigHelpers) find_package(CUDAToolkit REQUIRED) +set(DAQIRI_ABI_VERSION "0" CACHE STRING "DAQIRI shared library ABI version") +if(NOT DAQIRI_ABI_VERSION MATCHES "^(0|[1-9][0-9]*)$") + message(FATAL_ERROR "DAQIRI_ABI_VERSION must be a non-negative integer") +endif() + +set(DAQIRI_GENERATED_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated/include") +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/daqiri_version.h.in + ${DAQIRI_GENERATED_INCLUDE_DIR}/daqiri/version.h + @ONLY +) + if(DAQIRI_USING_DEFAULT_CUDA_ARCHITECTURES AND CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 13.0) list(APPEND CMAKE_CUDA_ARCHITECTURES 121) @@ -68,7 +86,7 @@ configure_package_config_file( write_basic_package_version_file( ${CMAKE_CURRENT_BINARY_DIR}/daqiriConfigVersion.cmake VERSION ${PROJECT_VERSION} - COMPATIBILITY SameMajorVersion + COMPATIBILITY AnyNewerVersion ) if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}") @@ -150,3 +168,9 @@ install( DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT daqiri-cpp ) + +install( + FILES ${DAQIRI_GENERATED_INCLUDE_DIR}/daqiri/version.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/daqiri + COMPONENT daqiri-cpp +) diff --git a/VERSION b/VERSION new file mode 100644 index 00000000..874b07dc --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +2026.7.0 diff --git a/cmake/daqiri_version.h.in b/cmake/daqiri_version.h.in new file mode 100644 index 00000000..facd879c --- /dev/null +++ b/cmake/daqiri_version.h.in @@ -0,0 +1,34 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. + * All rights reserved. SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#define DAQIRI_VERSION "@PROJECT_VERSION@" +#define DAQIRI_VERSION_YEAR @PROJECT_VERSION_MAJOR@ +#define DAQIRI_VERSION_MONTH @PROJECT_VERSION_MINOR@ +#define DAQIRI_VERSION_PATCH @PROJECT_VERSION_PATCH@ +#define DAQIRI_ABI_VERSION @DAQIRI_ABI_VERSION@ + +namespace daqiri { + +inline constexpr const char* version_string() noexcept { return DAQIRI_VERSION; } +inline constexpr int version_year() noexcept { return DAQIRI_VERSION_YEAR; } +inline constexpr int version_month() noexcept { return DAQIRI_VERSION_MONTH; } +inline constexpr int version_patch() noexcept { return DAQIRI_VERSION_PATCH; } +inline constexpr int abi_version() noexcept { return DAQIRI_ABI_VERSION; } + +} // namespace daqiri diff --git a/docs/api-reference/cpp.md b/docs/api-reference/cpp.md index 92f1afa4..cbe3b2fb 100644 --- a/docs/api-reference/cpp.md +++ b/docs/api-reference/cpp.md @@ -16,6 +16,24 @@ For the terminology used here (*burst*, *segment*, *flow*, *queue*, *memory region*, *zero-copy ownership*, *RX reorder*), keep the [Concepts](../concepts.md) page open in a second tab. +## Version Metadata + +DAQIRI package versions use CalVer in `YYYY.MM.PATCH` form. The public +`daqiri/daqiri.h` header includes `daqiri/version.h`, which exposes compile-time +macros and inline C++ helpers: + +```cpp +#include + +static_assert(DAQIRI_VERSION_YEAR >= 2026); +const char *package_version = daqiri::version_string(); +int abi = daqiri::abi_version(); +``` + +`DAQIRI_ABI_VERSION` / `daqiri::abi_version()` is the shared-library ABI version +and is intentionally separate from the CalVer package version. The YAML +`common.version` field remains the configuration schema version. + ## Initialization ```cpp @@ -588,6 +606,9 @@ workflow sections above show the common call order and ownership rules. | Function | Purpose | | --- | --- | +| `version_string()` | Return the DAQIRI package version as `YYYY.MM.PATCH`. | +| `version_year()` / `version_month()` / `version_patch()` | Return the CalVer components. | +| `abi_version()` | Return the DAQIRI shared-library ABI version. | | `daqiri_init(NetworkConfig &config)` | Initialize DAQIRI from an already-populated config object. | | `daqiri_init(const std::string &yaml_string_or_path)` | Initialize from a YAML string or YAML file path. | | `daqiri_init_from_yaml_string(const std::string &yaml_string)` | Initialize from YAML content. | diff --git a/docs/api-reference/python.md b/docs/api-reference/python.md index 38bf0509..e36e153a 100644 --- a/docs/api-reference/python.md +++ b/docs/api-reference/python.md @@ -57,6 +57,19 @@ import daqiri The `daqiri` package re-exports the compiled `_daqiri` pybind11 module, so application code uses one import. +DAQIRI package versions use CalVer in `YYYY.MM.PATCH` form. The Python package +exposes `daqiri.__version__`, `daqiri.__version_info__`, and +`daqiri.__abi_version__`; the ABI version is intentionally separate from the +CalVer package version. The YAML `common.version` field remains the +configuration schema version. + +```python +import daqiri + +print(daqiri.__version__) +print(daqiri.version_string(), daqiri.abi_version()) +``` + PyYAML is required at runtime when calling `daqiri_init()` with a Python `dict` or a config-like object that provides `as_dict()`. @@ -492,6 +505,9 @@ The workflow sections above show the common call order and ownership rules. | Function | Purpose | | --- | --- | +| `version_string()` | Return the DAQIRI package version as `YYYY.MM.PATCH`. | +| `version_year()` / `version_month()` / `version_patch()` | Return the CalVer components. | +| `abi_version()` | Return the DAQIRI shared-library ABI version. | | `engine_type_from_string(str)` / `engine_type_to_string(type)` | Convert engine types. | | `stream_type_from_string(str)` / `stream_type_to_string(type)` | Convert stream types. | | `reorder_data_type_from_string(str)` / `reorder_data_type_to_string(type)` | Convert reorder data types. | @@ -605,6 +621,9 @@ encapsulation/push rules are configured in YAML under `tx.flows`. | `MAX_NUM_TX_QUEUES` | Maximum configured TX queues. | | `MAX_INTERFACES` | Maximum configured interfaces. | | `MAX_NUM_SEGS` | Maximum packet segments per burst. | +| `DAQIRI_VERSION` | DAQIRI package version as `YYYY.MM.PATCH`. | +| `DAQIRI_VERSION_YEAR` / `DAQIRI_VERSION_MONTH` / `DAQIRI_VERSION_PATCH` | CalVer components. | +| `DAQIRI_ABI_VERSION` | DAQIRI shared-library ABI version. | | `DAQIRI_BURST_FLAG_REORDERED` | Burst flag indicating a reordered aggregate. | | `DAQIRI_BURST_FLAG_REORDER_TIMEOUT` | Burst flag indicating a reorder timeout aggregate. | | `MEM_ACCESS_LOCAL` | Local memory access flag. | diff --git a/docs/getting-started.md b/docs/getting-started.md index 1686708f..cde53a58 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -176,10 +176,18 @@ find_package(daqiri REQUIRED) target_link_libraries(my_app PRIVATE daqiri::daqiri) ``` +DAQIRI uses CalVer package versions in `YYYY.MM.PATCH` form. Consumers that need +a minimum DAQIRI release can request it from CMake: + +```cmake +find_package(daqiri 2026.7.0 REQUIRED) +``` + Pkg-config consumers can use the installed `daqiri.pc` file: ```bash c++ my_app.cpp -o my_app $(pkg-config --cflags --libs daqiri) +pkg-config --modversion daqiri ``` Both methods use the same public C++ include: @@ -188,6 +196,11 @@ Both methods use the same public C++ include: #include ``` +`daqiri/version.h` is included by `daqiri/daqiri.h` and provides +`DAQIRI_VERSION`, `daqiri::version_string()`, and related CalVer helpers. +DAQIRI's shared-library ABI version is tracked separately through +`DAQIRI_ABI_VERSION` / `daqiri::abi_version()`. + ### CMake Options | Option | Default | Description | diff --git a/include/daqiri/daqiri.h b/include/daqiri/daqiri.h index 2bfbc3b1..41e8adeb 100644 --- a/include/daqiri/daqiri.h +++ b/include/daqiri/daqiri.h @@ -18,3 +18,4 @@ #pragma once #include +#include diff --git a/python/daqiri_common_pybind.cpp b/python/daqiri_common_pybind.cpp index 3b9682dd..462ec20f 100644 --- a/python/daqiri_common_pybind.cpp +++ b/python/daqiri_common_pybind.cpp @@ -905,6 +905,15 @@ PYBIND11_MODULE(_daqiri, m) { m.attr("DAQIRI_BURST_FLAG_REORDERED") = DAQIRI_BURST_FLAG_REORDERED; m.attr("DAQIRI_BURST_FLAG_REORDER_TIMEOUT") = DAQIRI_BURST_FLAG_REORDER_TIMEOUT; + m.attr("__version__") = version_string(); + m.attr("__version_info__") = + py::make_tuple(version_year(), version_month(), version_patch()); + m.attr("__abi_version__") = abi_version(); + m.attr("DAQIRI_VERSION") = DAQIRI_VERSION; + m.attr("DAQIRI_VERSION_YEAR") = DAQIRI_VERSION_YEAR; + m.attr("DAQIRI_VERSION_MONTH") = DAQIRI_VERSION_MONTH; + m.attr("DAQIRI_VERSION_PATCH") = DAQIRI_VERSION_PATCH; + m.attr("DAQIRI_ABI_VERSION") = DAQIRI_ABI_VERSION; m.attr("MEM_ACCESS_LOCAL") = py::int_(static_cast(MEM_ACCESS_LOCAL)); m.attr("MEM_ACCESS_RDMA_WRITE") = @@ -952,6 +961,11 @@ PYBIND11_MODULE(_daqiri, m) { m.def("get_engine_type", static_cast(&get_engine_type), "Get the current engine type"); + m.def("version_string", &version_string, "Get the DAQIRI package version"); + m.def("version_year", &version_year, "Get the DAQIRI CalVer year"); + m.def("version_month", &version_month, "Get the DAQIRI CalVer month"); + m.def("version_patch", &version_patch, "Get the DAQIRI CalVer patch number"); + m.def("abi_version", &abi_version, "Get the DAQIRI shared library ABI version"); m.def("engine_type_from_string", &engine_type_from_string, "str"_a, "Convert a string to an engine type"); m.def("engine_type_to_string", &engine_type_to_string, "type"_a, diff --git a/python/pybind11/__init__.py b/python/pybind11/__init__.py index d743eb9e..b4abedc1 100644 --- a/python/pybind11/__init__.py +++ b/python/pybind11/__init__.py @@ -13,4 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from . import _daqiri as _daqiri_module from ._daqiri import * # noqa: F401,F403 + +__version__ = _daqiri_module.__version__ +__version_info__ = _daqiri_module.__version_info__ +__abi_version__ = _daqiri_module.__abi_version__ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 21d3a086..b6a0dad5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -152,6 +152,7 @@ endif() target_include_directories(daqiri_common PUBLIC $ + $ $ $ PRIVATE @@ -232,6 +233,8 @@ set_target_properties(daqiri_common PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS ON OUTPUT_NAME "daqiri" EXPORT_NAME "daqiri" + VERSION "${CMAKE_PROJECT_VERSION}" + SOVERSION "${DAQIRI_ABI_VERSION}" INSTALL_RPATH "$ORIGIN" ) install( @@ -323,6 +326,7 @@ foreach(ENGINE IN LISTS DAQIRI_ENGINE_INTERNAL_LIST) PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../include + ${DAQIRI_GENERATED_INCLUDE_DIR} ${DAQIRI_SPDLOG_INCLUDE_DIR} ) target_link_libraries(${ENGINE_TARGET} PRIVATE CUDA::cudart ${DAQIRI_YAML_TARGET}) @@ -335,6 +339,8 @@ foreach(ENGINE IN LISTS DAQIRI_ENGINE_INTERNAL_LIST) set_target_properties(${ENGINE_TARGET} PROPERTIES OUTPUT_NAME "daqiri_${ENGINE_LOWER}" EXPORT_NAME "${ENGINE_LOWER}" + VERSION "${CMAKE_PROJECT_VERSION}" + SOVERSION "${DAQIRI_ABI_VERSION}" INSTALL_RPATH "$ORIGIN" ) install(TARGETS ${ENGINE_TARGET} diff --git a/src/metrics.cpp b/src/metrics.cpp index cf306af0..4f055c95 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -17,6 +17,8 @@ #include "metrics.h" +#include + #include #include #include @@ -190,7 +192,7 @@ class Registry { if (initialized_) { return; } auto provider = otel::metrics::Provider::GetMeterProvider(); - auto meter = provider->GetMeter("daqiri", "0.1.0"); + auto meter = provider->GetMeter("daqiri", version_string()); rx_packets_ = meter->CreateInt64ObservableCounter( "daqiri.rx.packets", "Packets received by DAQIRI", "{packet}"); tx_packets_ = meter->CreateInt64ObservableCounter(