-
Notifications
You must be signed in to change notification settings - Fork 0
Compile Configuration
MCCC 通过编译期宏实现零成本硬件适配。所有配置在编译时确定,不产生运行时分支开销。
| 宏名 | 默认值 | 说明 |
|---|---|---|
MCCC_QUEUE_DEPTH |
131072 | 环形缓冲区深度 (必须为 2 的幂) |
MCCC_CACHELINE_SIZE |
64 | 缓存行大小 (字节),用于 padding 防伪共享 |
MCCC_SINGLE_PRODUCER |
0 | 设为 1 启用 SPSC 模式 (wait-free) |
MCCC_SINGLE_CORE |
0 | 设为 1 启用单核模式 (relaxed 内存序) |
MCCC_MAX_MESSAGE_TYPES |
8 | 单条总线支持的最大消息类型数 |
MCCC_MAX_CALLBACKS_PER_TYPE |
16 | 每种消息类型的最大回调数 |
MCCC_MAX_SUBSCRIPTIONS_PER_COMPONENT |
16 | 每个 Component 的最大订阅数 |
STREAMING_DMA_ALIGNMENT |
64 | DMA 缓冲区对齐 (字节) |
环形缓冲区的槽位数量。必须为 2 的幂次方 (编译期 static_assert 检查),因为内部使用位掩码 (depth - 1) 替代取模运算。
推荐值:
- 服务器/工控: 131072 (128K, 默认)
- 资源受限 Linux: 32768 或 65536
- 嵌入式 MCU: 1024 或 4096
每个槽位的大小等于 sizeof(MessageEnvelope<PayloadVariant>)。总内存占用 = MCCC_QUEUE_DEPTH * sizeof(Envelope)。
用于在环形缓冲区的读写索引之间插入 padding,防止伪共享 (false sharing)。
推荐值:
- x86-64 / ARM Cortex-A: 64
- 无 D-Cache 的 MCU: 0 (关闭 padding,节省 RAM)
设为 0 时,不插入任何 padding,适用于无数据缓存的单核 MCU (如 Cortex-M0/M3)。
| 值 | 模式 | 入队策略 | 说明 |
|---|---|---|---|
| 0 | MPSC | CAS 自旋 (指数退避) | 多生产者安全,有 CAS 竞争开销 |
| 1 | SPSC | wait-free 直接写入 | 单生产者专用,无原子 RMW 操作 |
SPSC 模式下入队操作为 wait-free (非 lock-free),延迟确定性更好。但调用者必须保证仅有一个线程执行 Publish()。
| 值 | 内存序 | 屏障 | 说明 |
|---|---|---|---|
| 0 | acquire/release | 硬件 DMB (ARM) 或 MFENCE (x86) | 多核安全 |
| 1 | relaxed + signal_fence | 编译器屏障,无硬件屏障 | 仅单核安全 |
安全警告: 启用 MCCC_SINGLE_CORE=1 时,必须同时定义 MCCC_I_KNOW_SINGLE_CORE_IS_UNSAFE=1,否则编译失败。这是一个防呆机制,确保开发者明确理解:
- 单核模式的 relaxed 内存序在多核 CPU 上会导致数据竞争
- 仅适用于真正的单核 MCU (如 Cortex-M0/M3/M4) 或已确认绑定单核的场景
- ISR 与主循环之间的通信是安全的 (
atomic_signal_fence防止编译器重排)
// 启用单核模式必须同时定义两个宏
#define MCCC_SINGLE_CORE 1
#define MCCC_I_KNOW_SINGLE_CORE_IS_UNSAFE 1回调表 (DispatchTable) 的行数。每种消息类型占一行。超过此限制时 Subscribe() 返回失败。
回调表每一行的列数。同一消息类型最多注册的回调数量。超过此限制时 Subscribe() 返回失败。
Component 基类内部用 FixedVector 追踪已注册的订阅 ID,容量由此宏控制。超出时 SubscribeSafe()/SubscribeSimple() 返回失败。
DMA 传输缓冲区的对齐要求。用于需要 DMA 拷贝的场景 (如共享内存传输)。
针对资源受限的嵌入式 MCU (如 ARM Cortex-M4, 128KB~512KB SRAM):
add_definitions(
-DMCCC_QUEUE_DEPTH=1024
-DMCCC_CACHELINE_SIZE=0
-DMCCC_SINGLE_PRODUCER=1
-DMCCC_SINGLE_CORE=1
-DMCCC_I_KNOW_SINGLE_CORE_IS_UNSAFE=1
-DMCCC_MAX_MESSAGE_TYPES=4
-DMCCC_MAX_CALLBACKS_PER_TYPE=4
-DMCCC_MAX_SUBSCRIPTIONS_PER_COMPONENT=8
-DSTREAMING_DMA_ALIGNMENT=4
)内存占用估算 (假设 sizeof(Envelope) = 128 字节):
- 环形缓冲区: 1024 * 128 = 128 KB
- 回调表: 4 * 4 * 8 = 128 字节
- 总计: 约 128 KB
如果 SRAM 紧张,可进一步降低 MCCC_QUEUE_DEPTH 至 256 或 512。
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)cmake -B build \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_FLAGS="-DMCCC_QUEUE_DEPTH=65536 -DMCCC_SINGLE_PRODUCER=1"
cmake --build build -j$(nproc)cmake -B build \
-DCMAKE_TOOLCHAIN_FILE=arm-none-eabi.cmake \
-DCMAKE_BUILD_TYPE=MinSizeRel \
-DCMAKE_CXX_FLAGS="\
-DMCCC_QUEUE_DEPTH=1024 \
-DMCCC_CACHELINE_SIZE=0 \
-DMCCC_SINGLE_PRODUCER=1 \
-DMCCC_SINGLE_CORE=1 \
-DMCCC_I_KNOW_SINGLE_CORE_IS_UNSAFE=1 \
-fno-exceptions -fno-rtti"
cmake --build build -j$(nproc)多个线程/ISR 调用 Publish()?
|
+-- 是 --> MCCC_SINGLE_PRODUCER=0 (MPSC, CAS 自旋)
|
+-- 否 --> MCCC_SINGLE_PRODUCER=1 (SPSC, wait-free)
|
+-- 吞吐量提升约 14%
+-- 延迟确定性更好 (无 CAS 重试)
+-- 尾延迟 (P99) 大幅降低
SPSC 模式的典型应用场景:
- 单一采集线程 -> 处理线程 的数据管道
- ISR -> 主循环 的事件通知 (配合
MCCC_SINGLE_CORE=1) - 单一网络接收线程 -> 业务逻辑线程 的解耦
除编译期配置外,MCCC 还支持运行时切换性能模式:
auto& bus = AsyncBus<MyPayload>::Instance();
bus.SetPerformanceMode(PerformanceMode::BARE_METAL);| 模式 | 背压 | 统计 | 错误回调 | 适用场景 |
|---|---|---|---|---|
FULL_FEATURED |
有 | 有 | 有 | 开发调试,生产监控 |
BARE_METAL |
无 | 无 | 无 | 极致性能,嵌入式裸机 |
NO_STATS |
有 | 无 | 有 | 生产环境,需要背压保护 |
运行时模式可随时切换。模式切换本身是原子操作 (单个 store),不会引入竞争。
BARE_METAL 模式关闭所有运行时检查,适合已充分验证的生产部署或对延迟极度敏感的场景。在此模式下:
-
Publish()不检查背压,不更新统计计数器 - 队列满时消息静默丢弃,不触发错误回调
-
GetStatistics()返回全零快照