chrono_batch_render/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
104 / 106
98.1%
Branches:
89 / 94
94.7%
Functions:
6 / 6
100.0%

sensor_pipeline/definition.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 #include "chrono_batch_render/sensor_pipeline/definition.h"
3
4 #include <algorithm>
5 #include <bit>
6
7 #include <fmt/format.h>
8
9 namespace chrono::batch_render::sensor_pipeline {
10
11 namespace {
12
13 76 uint64_t StoredBytes(const SignalLayout& layout, uint64_t elements) {
14 152 const uint64_t channels =
15
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 72 times.
76 layout.element == ElementType::F16 ? (layout.channels + 1) / 2 * 2 : layout.channels;
16 152 const uint64_t raw =
17
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 2 times.
76 (layout.perCapture ? 1 : elements) * channels * kElementBytes[uint32_t(layout.element)];
18 76 return (raw + kArenaAlignment - 1) / kArenaAlignment * kArenaAlignment;
19 }
20
21 }
22
23 85 SegmentPlan SplitSegments(const ResolvedSensorPipeline& pipeline, const NodeRegistry& registry,
24 Fusion fusion) {
25 85 SegmentPlan plan;
26
1/1
✓ Branch 1 taken 85 times.
85 std::vector<int32_t> segmentOfNode(pipeline.nodes.size(), kBeforeSegments);
27 85 bool open = false;
28
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 85 times.
420 for (uint32_t node = 0; node < pipeline.nodes.size(); ++node) {
29 335 const NodeKind kind = registry[pipeline.nodes[node].def].kind;
30
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 251 times.
335 if (kind == NodeKind::Source) {
31 84 continue;
32 }
33
4/4
✓ Branch 0 taken 142 times.
✓ Branch 1 taken 109 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 137 times.
251 if (!(open && kind == NodeKind::Point && fusion == Fusion::Fused)) {
34
1/1
✓ Branch 1 taken 114 times.
114 plan.segments.push_back({kind, {}});
35 114 open = kind == NodeKind::Point || kind == NodeKind::Stencil;
36 }
37
1/1
✓ Branch 1 taken 251 times.
251 plan.segments.back().nodes.push_back(node);
38 251 segmentOfNode[node] = int32_t(plan.segments.size() - 1);
39 }
40
41
1/1
✓ Branch 1 taken 85 times.
85 std::vector<std::vector<uint32_t>> readers(pipeline.values.size());
42
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 85 times.
420 for (uint32_t node = 0; node < pipeline.nodes.size(); ++node) {
43
2/2
✓ Branch 0 taken 253 times.
✓ Branch 1 taken 335 times.
588 for (const uint32_t value : pipeline.nodes[node].inputs) {
44
2/2
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 1 time.
253 if (value != kNoValue) {
45
1/1
✓ Branch 1 taken 252 times.
252 readers[value].push_back(node);
46 }
47 }
48 }
49
50 85 const auto end = int32_t(plan.segments.size());
51
2/2
✓ Branch 0 taken 345 times.
✓ Branch 1 taken 85 times.
430 for (uint32_t value = 0; value < pipeline.values.size(); ++value) {
52 345 const ResolvedNode& maker = pipeline.nodes[pipeline.values[value].node];
53 345 const int32_t made = segmentOfNode[pipeline.values[value].node];
54 345 bool stored = false;
55 345 int32_t last = 0;
56
2/2
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 345 times.
597 for (const uint32_t reader : readers[value]) {
57
3/4
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 136 times.
252 if (segmentOfNode[reader] != made || made == kBeforeSegments) {
58 116 stored = true;
59
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 84 times.
148 last = std::max(last, segmentOfNode[reader]);
60 }
61 }
62
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 342 times.
345 const bool output = std::ranges::find(pipeline.outputs, value, &ResolvedOutput::value) !=
63 345 pipeline.outputs.end();
64
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 342 times.
345 if (output && made == kBeforeSegments) {
65 3 stored = true;
66 3 last = end;
67 }
68
4/4
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 84 times.
✓ Branch 2 taken 251 times.
✓ Branch 3 taken 10 times.
606 if (made != kBeforeSegments &&
69
2/2
✓ Branch 1 taken 251 times.
✓ Branch 2 taken 10 times.
261 std::ranges::find(maker.scratch, value) != maker.scratch.end()) {
70 10 stored = true;
71 10 last = made;
72 }
73
2/2
✓ Branch 0 taken 113 times.
✓ Branch 1 taken 222 times.
345 if (stored) {
74
1/1
✓ Branch 1 taken 123 times.
123 plan.stored.push_back({value, made, last});
75 }
76 }
77 170 return plan;
78 85 }
79
80 57 ArenaLayout LayoutArena(const SegmentPlan& plan, std::span<const SignalLayout> layouts,
81 uint64_t elements) {
82 57 struct Slot {
83 uint64_t offset = 0;
84 uint64_t bytes = 0;
85 int32_t last = 0;
86 };
87
88 57 ArenaLayout arena;
89
1/1
✓ Branch 1 taken 57 times.
57 arena.offsets.assign(layouts.size(), kNotStored);
90
1/1
✓ Branch 1 taken 57 times.
57 std::vector<StoredValue> order = plan.stored;
91 57 std::ranges::stable_sort(order, {}, &StoredValue::first);
92 57 std::vector<Slot> slots;
93
2/2
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 57 times.
133 for (const StoredValue& stored : order) {
94 76 const uint64_t bytes = StoredBytes(layouts[stored.value], elements);
95 76 Slot* best = nullptr;
96
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 76 times.
106 for (Slot& slot : slots) {
97
4/6
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
30 if (slot.last < stored.first && slot.bytes >= bytes &&
98
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ (best == nullptr || slot.bytes < best->bytes)) {
99 4 best = &slot;
100 }
101 }
102
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 4 times.
76 if (best == nullptr) {
103
1/1
✓ Branch 1 taken 72 times.
72 best = &slots.emplace_back(Slot{arena.bytes, bytes, 0});
104 72 arena.bytes += bytes;
105 }
106 76 best->last = stored.last;
107 76 arena.offsets[stored.value] = best->offset;
108 }
109 57 return arena;
110 57 }
111
112 83 SensorPipelineDefinition BuildDefinition(uint32_t id, const ResolvedSensorPipeline& pipeline,
113 const NodeRegistry& registry, Fusion fusion) {
114 83 SensorPipelineDefinition definition{.id = id, .pipeline = pipeline};
115
1/1
✓ Branch 1 taken 83 times.
83 definition.segments = SplitSegments(pipeline, registry, fusion);
116
2/2
✓ Branch 0 taken 325 times.
✓ Branch 1 taken 83 times.
408 for (const ResolvedNode& node : pipeline.nodes) {
117
1/1
✓ Branch 1 taken 325 times.
325 definition.parameterOffsets.push_back(definition.parameterWords);
118
2/2
✓ Branch 1 taken 193 times.
✓ Branch 2 taken 325 times.
518 for (const ParameterDef& parameter : registry[node.def].parameters) {
119 193 definition.parameterWords += parameter.words;
120 }
121 325 const std::vector<float>& initial = registry[node.def].state;
122
1/1
✓ Branch 1 taken 325 times.
325 definition.stateOffsets.push_back(uint32_t(definition.initialState.size()));
123
1/1
✓ Branch 1 taken 325 times.
325 definition.initialState.insert(definition.initialState.end(), initial.begin(),
124 initial.end());
125 }
126 83 return definition;
127 ✗ }
128
129 63 std::vector<uint32_t> PackWords(const SensorPipelineDefinition& definition,
130 const ResolvedSensorPipeline& instance,
131 const NodeRegistry& registry) {
132 63 std::vector<uint32_t> words(definition.parameterWords, 0);
133
2/2
✓ Branch 0 taken 284 times.
✓ Branch 1 taken 63 times.
347 for (uint32_t node = 0; node < instance.nodes.size(); ++node) {
134 284 const std::vector<float>& values = instance.nodes[node].parameters;
135 284 uint32_t index = 0;
136
2/2
✓ Branch 1 taken 190 times.
✓ Branch 2 taken 284 times.
474 for (const ParameterDef& parameter : registry[instance.nodes[node].def].parameters) {
137
2/2
✓ Branch 0 taken 196 times.
✓ Branch 1 taken 190 times.
386 for (uint32_t word = 0; word < parameter.words; ++word, ++index) {
138
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 189 times.
196 const float value = values[index];
139 196 words[definition.parameterOffsets[node] + index] =
140
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 189 times.
196 parameter.type == ParameterType::Int ? std::bit_cast<uint32_t>(int32_t(value))
141
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 186 times.
189 : parameter.type == ParameterType::Bool ? uint32_t(value != 0)
142 186 : std::bit_cast<uint32_t>(value);
143 }
144 }
145 }
146 63 return words;
147 }
148
149 14 std::string ReadParameter(const ParameterDef& parameter, std::string_view context, uint32_t word) {
150
3/3
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 8 times.
14 switch (parameter.type) {
151 3 case ParameterType::Int:
152 3 return fmt::format("asint({}.ParameterBits({}))", context, word);
153 3 case ParameterType::Bool:
154 3 return fmt::format("{}.ParameterBits({}) != 0", context, word);
155 case ParameterType::Float:
156 break;
157 }
158
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
8 if (parameter.words == 1) {
159 5 return fmt::format("{}.Parameter({})", context, word);
160 }
161 6 std::string components;
162
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3 times.
12 for (uint32_t component = 0; component < parameter.words; ++component) {
163
1/1
✓ Branch 1 taken 9 times.
9 components += fmt::format("{}{}.Parameter({})", component == 0 ? "" : ", ", context,
164
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
18 word + component);
165 }
166
1/1
✓ Branch 1 taken 3 times.
3 return fmt::format("float{}({})", parameter.words, components);
167 }
168
169 }
170