GCC Code Coverage Report


Directory: csrc/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 91 / 0 / 91
Functions: 100.0% 1 / 0 / 1
Branches: 35.0% 7 / 0 / 20

evt3.c
Line Branch Exec Source
1
2 #include "evutils/evt3.h"
3 #include "evutils/types.h"
4 #include "evutils/parser.h"
5
6 #include <stdio.h>
7 #include <stdint.h>
8
9 #define EVT3_get_packet_type(packet) (((packet) >> 12) & 0xF)
10 #define EVT3_get_packet_data(packet) ((packet) & 0x0FFF)
11
12 enum EVT3_PacketType {
13 EVT3_EVT_ADDR_Y = 0x0,
14 EVT3_EVT_ADDR_X = 0x2,
15 EVT3_VECT_BASE_X = 0x3,
16 EVT3_VECT_12 = 0x4,
17 EVT3_VECT_8 = 0x5,
18 EVT3_EVT_TIME_LOW = 0x6,
19 EVT3_CONTINUED_4 = 0x7,
20 EVT3_EVT_TIME_HIGH = 0x8,
21 EVT3_EXT_TRIGGER = 0xA,
22 EVT3_OTHERS = 0xE,
23 EVT3_CONTINUED_12 = 0xF
24 };
25
26
27 typedef struct evt3_state_s {
28 uint32_t ts_high_high;
29 uint32_t ts_high;
30 uint32_t ts_low;
31 uint32_t ts;
32
33 uint16_t y;
34 uint16_t vecbase_x;
35 uint8_t vecbase_p;
36 } evt3_state_t;
37
38
39
40 84 size_t EVT3_state_size(void) {
41 84 return sizeof(evt3_state_t);
42 }
43
44
45 #define EMIT_SOA() do { \
46 unsigned has = (vec_valid != 0u); \
47 uint32_t lz = (uint32_t)__builtin_ctz(vec_valid | 0x80000000u); \
48 out_ts[n] = ts; \
49 out_x[n] = (uint16_t)(bx + lz); \
50 out_y[n] = y; \
51 out_p[n] = p; \
52 n += has; \
53 vec_valid &= vec_valid - 1u; \
54 } while (0)
55
56
57 __attribute__((always_inline))
58 static inline const uint16_t * EVT3_parse_vector_12_12_8_soa(
59 const uint16_t * __restrict__ current,
60 evt3_state_t * __restrict__ state,
61 timestamp_t* __restrict__ out_ts, uint16_t* __restrict__ out_x,
62 uint16_t* __restrict__ out_y, uint8_t* __restrict__ out_p,
63 size_t * n_events) {
64
65 46894109 uint32_t vec_valid = EVT3_get_packet_data(*current);
66 46894109 current++;
67
68
1/4
✓ Branch 0 taken 46889725 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
46889725 if(likely(EVT3_get_packet_type(*current) == EVT3_VECT_12)) {
69 46894109 vec_valid |= (uint32_t)(EVT3_get_packet_data(*current) << 12);
70 46894109 current++;
71
72
2/8
✓ Branch 0 taken 46889725 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4384 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
46894109 if (likely(EVT3_get_packet_type(*current) == EVT3_VECT_8)) {
73 46894109 vec_valid |= (uint32_t)(*current & 0x00FF) << 24;
74 46894109 current++;
75 }
76 }
77 46894109 const uint32_t ts = state->ts;
78 46894109 const uint16_t y = state->y;
79 46894109 const uint8_t p = state->vecbase_p;
80 46894109 const uint16_t bx = state->vecbase_x;
81 46894109 size_t n = *n_events;
82
83 46894109 EMIT_SOA(); EMIT_SOA(); EMIT_SOA(); EMIT_SOA(); /* 4 unconditional — no branch between them */
84
85
4/8
✓ Branch 0 taken 244738259 times.
✓ Branch 1 taken 46889725 times.
✓ Branch 2 taken 104900 times.
✓ Branch 3 taken 4384 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
291737268 while (vec_valid) { EMIT_SOA(); } /* tail: only pop>4 (~23%) re-enters */
86
87 46894109 *n_events = n;
88 46894109 state->vecbase_x = bx + 32;
89
90 46894109 return current;
91 }
92
93
94
95 // TODO: For future performance optimization, implement dynamic CPU dispatch
96 // (e.g., using __attribute__((target_clones("avx2", "default"))) on GCC/Clang)
97 // or manual cpuid + function pointers to enable SIMD decoding on supported
98 // hardware without breaking universal portability on older CPUs.
99
100
101 #define EVT3_INPUT_PADDING 4
102 EVUTILS_TARGET_CLONES
103 728 parser_result_t EVT3_parse_chunk_soa(
104 evt3_state_t *state,
105 const evt3_input_buffer_t *input_buffer,
106 event_buffer_soa_t *event_buffer,
107 trigger_buffer_soa_t *trigger_buffer) {
108
109 // Hoist variables for better optimization
110 728 const uint16_t *restrict current = input_buffer->begin;
111 728 const uint16_t * end_offset = input_buffer->end - EVT3_INPUT_PADDING;
112
113 // Event output buffers
114 728 const size_t events_capacity = event_buffer->capacity;
115 728 const size_t events_capacity_offset = events_capacity - 64; // We need to keep some space for vector messages
116 728 size_t n_events_read = event_buffer->size;
117
118 728 timestamp_t* restrict out_ts = event_buffer->t;
119 728 uint16_t* restrict out_x = event_buffer->x;
120 728 uint16_t* restrict out_y = event_buffer->y;
121 728 uint8_t* restrict out_p = event_buffer->p;
122
123 // Trigger output buffers
124 728 const size_t triggers_capacity = trigger_buffer->capacity;
125 728 size_t n_triggers_read = trigger_buffer->size;
126
127 728 timestamp_t* restrict trigger_ts = trigger_buffer->t;
128 728 uint8_t* restrict trigger_id = trigger_buffer->id;
129 728 uint8_t* restrict trigger_p = trigger_buffer->p;
130
131 // State variables
132 728 evt3_state_t local_state = *state;
133
134 728 parse_status_t status = EVUTILS_PARSE_OK;
135
136
137 // Main parsing looop
138 728 while(
139 495310954 current < end_offset &&
140 495311075 n_events_read < events_capacity_offset &&
141 n_triggers_read < triggers_capacity) {
142
143 495310347 uint32_t packet_type = EVT3_get_packet_type(*current);
144 495310347 uint32_t packet_data = EVT3_get_packet_data(*current);
145
146 // Most common case checks first
147 495310347 if(packet_type == EVT3_EVT_ADDR_X) {
148 267940330 out_ts[n_events_read] = local_state.ts;
149 267940330 out_y[n_events_read] = local_state.y;
150 267940330 out_x[n_events_read] = (packet_data & 0x7FF);
151 267940330 out_p[n_events_read] = (packet_data & 0x800) >> 11;
152 267940330 n_events_read++;
153 267940330 current++;
154 267940330 continue;
155 }
156 227370017 if(packet_type == EVT3_VECT_BASE_X) {
157 // Implementation omitted for brevity
158 31104420 local_state.vecbase_x = packet_data & 0x7FF;
159 31104420 local_state.vecbase_p = (packet_data & 0x800) >> 11;
160
161 31104420 current++;
162
163 // Parse vector messages
164 77994145 while (EVT3_get_packet_type(*current) == EVT3_VECT_12 && current < end_offset && n_events_read < events_capacity_offset) {
165 46889725 current = EVT3_parse_vector_12_12_8_soa(current, &local_state, out_ts, out_x, out_y, out_p, &n_events_read);
166 }
167
168 31104420 continue;
169 }
170
171 196265597 switch(packet_type) {
172 148130243 case EVT3_EVT_ADDR_Y:
173 148130243 local_state.y = packet_data & 0x7FF;
174 148130243 break;
175 8000681 case EVT3_EVT_TIME_HIGH:
176 {
177 8000681 uint32_t new_ts_high = packet_data << 12;
178
179 8000681 if(unlikely(new_ts_high < local_state.ts_high)) {
180 222 local_state.ts_high_high += 0x1000000;
181 }
182 8000681 local_state.ts_high = new_ts_high;
183
184 8000681 current++;
185 8000681 packet_type = EVT3_get_packet_type(*current);
186
187 8000681 if(unlikely(packet_type != EVT3_EVT_TIME_LOW)) {
188 3043089 continue;
189 }
190 4957592 packet_data = EVT3_get_packet_data(*current);
191 }
192 __attribute__((fallthrough));
193 42040932 case EVT3_EVT_TIME_LOW:
194 42040932 local_state.ts_low = packet_data;
195 42040932 local_state.ts = local_state.ts_high_high | local_state.ts_high | local_state.ts_low;
196 42040932 break;
197 175 case EVT3_EXT_TRIGGER:
198 175 trigger_ts[n_triggers_read] = local_state.ts;
199 175 trigger_id[n_triggers_read] = packet_data >> 8;
200 175 trigger_p[n_triggers_read] = packet_data & 0x1;
201 175 n_triggers_read++;
202 175 break;
203 4384 case EVT3_VECT_12:
204 4384 current = EVT3_parse_vector_12_12_8_soa(current, &local_state, out_ts, out_x, out_y, out_p, &n_events_read);
205 4384 continue;
206 break;
207 case EVT3_VECT_8:
208 case EVT3_EVT_ADDR_X:
209 case EVT3_VECT_BASE_X:
210 // printf("Unexpected packet type %d in vector parsing\n", packet_type);
211 __builtin_unreachable();
212 break;
213 3046774 case EVT3_OTHERS:
214 case EVT3_CONTINUED_12:
215 case EVT3_CONTINUED_4:
216 default:
217 3046774 break;
218 }
219 193218124 current++;
220 }
221
222 728 *state = local_state;
223
224 728 event_buffer->size = n_events_read;
225 728 trigger_buffer->size = n_triggers_read;
226
227
228 728 return (parser_result_t){
229 .current = (const void *)current,
230 .status = status
231 };
232 }
233
234