You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Support scalable WCT fan-out with up to 320 outputs
Summary
Wire-Cell Toolkit currently limits TBB-based FanoutCat components to a maximum of 10 output ports.
The current implementation is in:
tbb/inc/WireCellTbb/FanoutCat.h
It uses compile-time tuple-based TBB nodes, conceptually:
using tuple_type = std::tuple<msg_t, msg_t, ...>;
tbb::flow::function_node<msg_t, tuple_type>
tbb::flow::split_node<tuple_type>
The fan-out function produces one tuple element for each output, and the TBB split_node exposes one output port for each tuple element.
The implementation currently:
asserts that the requested output count is between 1 and 10;
explicitly dispatches to build_fanouter<N>();
instantiates tuple-based implementations only for N = 1...10.
The required use case is substantially larger:
WCT should support fan-out multiplicities of up to 320 outputs.
For this scale, simply extending the existing template dispatch from 10 to 320 is probably not an appropriate solution.
Background
Issue #236 proposed implementing multi-layer fan-in and fan-out structures in Jsonnet to work around historical TBB tuple and port-count limits.
Recent oneTBB versions appear to have removed or increased the earlier small fixed limit. However, removal of the old TBB limit does not necessarily make a single 320-element tuple-based node practical.
Potential concerns include:
compilation time;
compiler memory use;
object-file and binary size;
construction of very large tuple types;
explicit dispatch for hundreds of multiplicities;
template error complexity;
maintainability;
runtime graph-construction cost;
whether split_node is conceptually appropriate when all outputs carry the same message type.
Therefore, this issue should evaluate a scalable fan-out architecture rather than only increasing the existing hard-coded limit.
Required semantics
Before selecting an implementation, the required fan-out behavior should be documented.
Questions include:
Does every output receive the same input payload?
Is a separate msg_t wrapper created for each output?
Does each output need a distinct WCT sequence number?
Must each output preserve input ordering independently?
Must downstream nodes address outputs by port index?
Can outputs be connected or disconnected independently?
How should EOS be propagated?
What happens if one downstream branch is slow or rejects a message?
Is branch-specific backpressure required?
Are all 320 branches expected to be active simultaneously?
These semantics determine whether a broadcast node, dynamic distributor, or hierarchical fan-out tree is most appropriate.
Current WCT implementation
The current FanoutCat design is approximately:
tuple element 0 -> sequencer -> output 0
/
input -> function -> tuple element 1 -> sequencer -> output 1
\
...
tuple element N -> sequencer -> output N
The output-port count is embedded in the C++ type.
This design is manageable for small multiplicities but does not naturally scale to hundreds of outputs.
Candidate approaches
Option A: Extend the tuple-based implementation to 320
or use compile-time dispatch to generate the same range.
Advantages
Minimal conceptual change.
Existing port-index behavior is retained.
Existing sequencing behavior may be preserved.
Reuses the current TBB split_node design.
Disadvantages
Potentially very high compile-time cost.
Potentially high compiler memory consumption.
Large tuple and template types.
Increased binary size.
Hundreds of template instantiations.
Difficult compiler diagnostics.
A 320-element split_node may not be practical even if technically supported.
Supporting every value from 1 through 320 may be unnecessarily expensive.
Assessment
This option should be tested as a baseline, but it should not be assumed to be the preferred production solution.
Option B: Use broadcast semantics
If every downstream branch receives effectively the same message, the fan-out may be modeled as one sender connected to many successors.
Conceptually:
-> successor 0
/
input -> sender --> successor 1
\
-> ...
-> successor 319
A tbb::flow::broadcast_node<msg_t> or equivalent WCT sender may support many successors without encoding every successor as an element in a std::tuple.
Advantages
Output count becomes a runtime graph property.
No 320-element tuple.
No template instantiation for every multiplicity.
Simpler underlying TBB graph.
Naturally represents identical-message broadcast.
Disadvantages
WCT may currently require separately addressable output ports.
Per-output sequence numbers may not be generated automatically.
Per-branch buffering or ordering may differ from the current FanoutCat.
A single sender interface may not satisfy WCT graph-port conventions.
Slow-successor and rejected-message behavior must be clearly defined.
Assessment
This should be the preferred candidate when all outputs have equivalent message semantics and do not require distinct typed ports.
Option C: Implement a dynamic WCT fan-out distributor
Introduce a custom fan-out implementation whose number of branches is determined at runtime.
revive the hierarchical approach with updated justification; or
provide both a broadcast implementation and a hierarchical compatibility fallback.
Non-goals
This issue does not necessarily require equivalent 320-input fan-in support.
A 320-input synchronization node has different buffering, matching, latency, and memory implications and should be evaluated separately.
In particular, a queueing join_node with 320 inputs waits for one message from every input before emitting a tuple. That behavior may not match the application's actual aggregation requirements.
Suggested implementation phases
Phase 1: Requirements and benchmarks
Document exact output semantics.
Test oneTBB tuple limits.
Benchmark broadcast to 320 successors.
Prototype a generated fan-out tree.
Phase 2: Initial scalable implementation
Implement either:
broadcast-based fan-out; or
generated hierarchical fan-out.
Support up to 320 outputs and add correctness tests.
Phase 3: Interface and performance refinement
Hide internal implementation nodes.
Optimize message sharing and sequence handling.
Improve diagnostics.
Consider replacing the fixed maximum with a configurable safety limit.
Suggested acceptance criteria
WCT supports a configured fan-out of 320 outputs.
The implementation does not require manually listing template cases from 1 through 320.
A 320-element std::tuple is not required in the selected production design unless benchmarks clearly justify it.
Every connected output receives each expected message exactly once.
Every connected output receives EOS correctly.
Per-output ordering behavior is documented and tested.
Sequence-number behavior is documented and tested.
Behavior with slow or rejecting successors is documented.
Support scalable WCT fan-out with up to 320 outputs
Summary
Wire-Cell Toolkit currently limits TBB-based
FanoutCatcomponents to a maximum of 10 output ports.The current implementation is in:
It uses compile-time tuple-based TBB nodes, conceptually:
The fan-out function produces one tuple element for each output, and the TBB
split_nodeexposes one output port for each tuple element.The implementation currently:
build_fanouter<N>();N = 1...10.The required use case is substantially larger:
For this scale, simply extending the existing template dispatch from 10 to 320 is probably not an appropriate solution.
Background
Issue #236 proposed implementing multi-layer fan-in and fan-out structures in Jsonnet to work around historical TBB tuple and port-count limits.
Recent oneTBB versions appear to have removed or increased the earlier small fixed limit. However, removal of the old TBB limit does not necessarily make a single 320-element tuple-based node practical.
Potential concerns include:
split_nodeis conceptually appropriate when all outputs carry the same message type.Therefore, this issue should evaluate a scalable fan-out architecture rather than only increasing the existing hard-coded limit.
Required semantics
Before selecting an implementation, the required fan-out behavior should be documented.
Questions include:
msg_twrapper created for each output?These semantics determine whether a broadcast node, dynamic distributor, or hierarchical fan-out tree is most appropriate.
Current WCT implementation
The current
FanoutCatdesign is approximately:The output-port count is embedded in the C++ type.
This design is manageable for small multiplicities but does not naturally scale to hundreds of outputs.
Candidate approaches
Option A: Extend the tuple-based implementation to 320
The most direct change would be to instantiate:
or use compile-time dispatch to generate the same range.
Advantages
split_nodedesign.Disadvantages
split_nodemay not be practical even if technically supported.Assessment
This option should be tested as a baseline, but it should not be assumed to be the preferred production solution.
Option B: Use broadcast semantics
If every downstream branch receives effectively the same message, the fan-out may be modeled as one sender connected to many successors.
Conceptually:
A
tbb::flow::broadcast_node<msg_t>or equivalent WCT sender may support many successors without encoding every successor as an element in astd::tuple.Advantages
Disadvantages
FanoutCat.Assessment
This should be the preferred candidate when all outputs have equivalent message semantics and do not require distinct typed ports.
Option C: Implement a dynamic WCT fan-out distributor
Introduce a custom fan-out implementation whose number of branches is determined at runtime.
Conceptually:
The distributor could maintain a runtime collection of branch nodes or sender endpoints rather than representing them in one tuple type.
Each branch could include its own sequencing or buffering node if required.
Advantages
Disadvantages
Assessment
This is likely the most general long-term solution if WCT truly requires 320 distinct logical output ports.
Option D: Generate a hierarchical fan-out tree
Construct several bounded-size fan-out nodes in multiple layers.
For example, a branching factor of 8 can provide 320 leaves using several levels:
A branching factor of 10 can support up to 1,000 leaves with three levels.
Advantages
FanoutCatimplementation.Disadvantages
Assessment
This is a practical fallback and may be the lowest-risk near-term solution.
It should be compared against a broadcast or dynamic-distributor implementation.
Recommended direction
For a required maximum of 320 outputs, do not initially extend the existing tuple implementation directly to 320.
Instead:
The likely choices are:
Proposed tasks
1. Document the 320-output use case
Add a concrete description of the expected topology and message behavior.
Document:
2. Verify current oneTBB capability
Build minimal standalone tests using WCT's minimum supported TBB version.
Test a
split_nodewith tuple sizes such as:Record:
This test is intended to characterize the direct tuple approach, not necessarily to select it.
3. Test one sender with many successors
Build a TBB test using one sender or
broadcast_node<msg_t>connected to:Measure:
4. Prototype a dynamic WCT fan-out
Investigate a
FanoutCatreplacement that creates branch nodes dynamically.Requirements should include:
5. Prototype a hierarchical fan-out generator
Create a helper that accepts:
For example:
The helper should:
Determine whether this helper belongs in:
pgraph.jsonnet;6. Compare architectures
Benchmark at least:
split_node, if compilation succeeds;Compare:
7. Review message-copy behavior
Determine whether each branch receives:
msg_t;For 320 outputs, unnecessary deep copies could dominate runtime and memory use.
The implementation should share immutable payload data where possible while preserving branch-specific metadata when required.
8. Test ordering and EOS
Add tests covering:
9. Reassess issue #236
Issue #236 proposed multi-layer fan-in and fan-out Jsonnet helpers.
For a 320-output requirement, the multi-layer concept remains relevant even if recent oneTBB removed the original 10-port limit.
However, the rationale changes:
The new implementation should either:
Non-goals
This issue does not necessarily require equivalent 320-input fan-in support.
A 320-input synchronization node has different buffering, matching, latency, and memory implications and should be evaluated separately.
In particular, a queueing
join_nodewith 320 inputs waits for one message from every input before emitting a tuple. That behavior may not match the application's actual aggregation requirements.Suggested implementation phases
Phase 1: Requirements and benchmarks
Phase 2: Initial scalable implementation
Implement either:
Support up to 320 outputs and add correctness tests.
Phase 3: Interface and performance refinement
Suggested acceptance criteria
std::tupleis not required in the selected production design unless benchmarks clearly justify it.Initial recommendation
The initial implementation should prioritize:
Directly extending the current tuple-based implementation to 320 should be treated as an experiment and benchmark, not the default design.
Relevant files
Related issue