Dawn Framework 1.0
Universal data acquisition framework for embedded systems
statsrms.hxx
1// dawn/include/dawn/prog/statsrms.hxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#pragma once
7
8#include <algorithm>
9#include <cmath>
10#include <cstdint>
11#include <limits>
12#include <new>
13#include <vector>
14
15#include "dawn/io/ddata.hxx"
16#include "dawn/io/common.hxx"
17#include "dawn/porting/config.hxx"
18#include "dawn/prog/common.hxx"
19#include "dawn/prog/process.hxx"
20
21namespace dawn
22{
31{
32public:
33 explicit CProgStatsRms(CDescObject &desc)
34 : CProgProcess(desc)
35 {
36 }
37
38#ifdef CONFIG_DAWN_OBJECT_HAS_NAME
39 const char *getClassNameStr() const override
40 {
41 return "rms";
42 }
43#endif
44
45 constexpr static SObjectId::ObjectId objectId(uint16_t inst)
46 {
49 }
50
51 constexpr static SObjectCfg::ObjectCfgId cfgId(bool rw, uint8_t size, uint8_t id)
52 {
56 rw,
57 size,
58 id);
59 }
60
61 constexpr static SObjectCfg::ObjectCfgId cfgIdIOBind(uint16_t size = 2)
62 {
63 return CProgStatsRms::cfgId(false, size, PROG_STATS_CFG_IOBIND);
64 }
65
66protected:
68 CIOCommon *output,
69 io_ddata_t *ioData,
70 io_ddata_t *outputData,
71 SBindState **state) override
72 {
73 (void)output;
74 (void)outputData;
75
76 switch (src->getDtype())
77 {
78#ifdef CONFIG_DAWN_DTYPE_INT8
80 return allocStateInt<int8_t>(ioData->getItems(), state);
81#endif
82#ifdef CONFIG_DAWN_DTYPE_UINT8
84 return allocStateInt<uint8_t>(ioData->getItems(), state);
85#endif
86#ifdef CONFIG_DAWN_DTYPE_INT16
88 return allocStateInt<int16_t>(ioData->getItems(), state);
89#endif
90#ifdef CONFIG_DAWN_DTYPE_UINT16
92 return allocStateInt<uint16_t>(ioData->getItems(), state);
93#endif
94#ifdef CONFIG_DAWN_DTYPE_INT32
96 return allocStateInt<int32_t>(ioData->getItems(), state);
97#endif
98#ifdef CONFIG_DAWN_DTYPE_UINT32
100 return allocStateInt<uint32_t>(ioData->getItems(), state);
101#endif
102#ifdef CONFIG_DAWN_DTYPE_INT64
104 return allocStateInt<int64_t>(ioData->getItems(), state);
105#endif
106#ifdef CONFIG_DAWN_DTYPE_UINT64
108 return allocStateInt<uint64_t>(ioData->getItems(), state);
109#endif
110#ifdef CONFIG_DAWN_DTYPE_FLOAT
112 return allocStateFloat<float>(ioData->getItems(), state);
113#endif
114#ifdef CONFIG_DAWN_DTYPE_DOUBLE
116 return allocStateFloat<double>(ioData->getItems(), state);
117#endif
118 default:
119 {
120 DAWNERR("stats rms: unsupported dtype %d\n", src->getDtype());
121 return -ENOTSUP;
122 }
123 }
124 }
125
126 void handle(CIOCommon *output,
127 io_ddata_t *data,
128 io_ddata_t *ioData,
129 io_ddata_t *outputData,
130 bool &initsample) override
131 {
132 handleWithState(output, data, ioData, outputData, initsample, nullptr);
133 }
134
136 io_ddata_t *data,
137 io_ddata_t *ioData,
138 io_ddata_t *outputData,
139 bool &initsample,
140 void *state) override
141 {
142 if (state == nullptr)
143 {
144 DAWNERR("stats rms: missing state\n");
145 return;
146 }
147
148 if (initsample)
149 {
150 static_cast<SBindState *>(state)->reset();
151 initsample = false;
152 }
153
154 switch (data->getDtype())
155 {
156#ifdef CONFIG_DAWN_DTYPE_INT8
158 handleInt<int8_t>(output, data, ioData, outputData, state);
159 break;
160#endif
161#ifdef CONFIG_DAWN_DTYPE_UINT8
163 handleInt<uint8_t>(output, data, ioData, outputData, state);
164 break;
165#endif
166#ifdef CONFIG_DAWN_DTYPE_INT16
168 handleInt<int16_t>(output, data, ioData, outputData, state);
169 break;
170#endif
171#ifdef CONFIG_DAWN_DTYPE_UINT16
173 handleInt<uint16_t>(output, data, ioData, outputData, state);
174 break;
175#endif
176#ifdef CONFIG_DAWN_DTYPE_INT32
178 handleInt<int32_t>(output, data, ioData, outputData, state);
179 break;
180#endif
181#ifdef CONFIG_DAWN_DTYPE_UINT32
183 handleInt<uint32_t>(output, data, ioData, outputData, state);
184 break;
185#endif
186#ifdef CONFIG_DAWN_DTYPE_INT64
188 handleInt<int64_t>(output, data, ioData, outputData, state);
189 break;
190#endif
191#ifdef CONFIG_DAWN_DTYPE_UINT64
193 handleInt<uint64_t>(output, data, ioData, outputData, state);
194 break;
195#endif
196#ifdef CONFIG_DAWN_DTYPE_FLOAT
198 handleFloat<float>(output, data, ioData, outputData, state);
199 break;
200#endif
201#ifdef CONFIG_DAWN_DTYPE_DOUBLE
203 handleFloat<double>(output, data, ioData, outputData, state);
204 break;
205#endif
206 default:
207 {
208 DAWNERR("stats rms: unsupported dtype %d\n", data->getDtype());
209 break;
210 }
211 }
212 }
213
214private:
215 struct SStateInt final : public SBindState
216 {
217 uint32_t count = 0;
218 uint32_t items = 0;
219 std::vector<uint64_t> sumsq;
220
221 void reset() override
222 {
223 count = 0;
224 std::fill(sumsq.begin(), sumsq.end(), 0);
225 }
226 };
227
228 template<typename T>
229 struct SStateFloat final : public SBindState
230 {
231 uint32_t count = 0;
232 uint32_t items = 0;
233 std::vector<T> sumsq;
234
235 void reset() override
236 {
237 count = 0;
238 std::fill(sumsq.begin(), sumsq.end(), static_cast<T>(0));
239 }
240 };
241
242 template<typename T>
243 int allocStateInt(size_t items, SBindState **state)
244 {
245 (void)sizeof(T);
246
247 SStateInt *st = new (std::nothrow) SStateInt();
248 if (st == nullptr)
249 {
250 return -ENOMEM;
251 }
252
253 st->items = items;
254 st->sumsq.assign(items, 0);
255 if (st->sumsq.size() != items)
256 {
257 delete st;
258 return -ENOMEM;
259 }
260
261 *state = st;
262 return OK;
263 }
264
265 template<typename T>
266 int allocStateFloat(size_t items, SBindState **state)
267 {
268 SStateFloat<T> *st = new (std::nothrow) SStateFloat<T>();
269 if (st == nullptr)
270 {
271 return -ENOMEM;
272 }
273
274 st->items = items;
275 st->sumsq.assign(items, static_cast<T>(0));
276 if (st->sumsq.size() != items)
277 {
278 delete st;
279 return -ENOMEM;
280 }
281
282 *state = st;
283 return OK;
284 }
285
286 static uint64_t saturatedAdd(uint64_t a, uint64_t b)
287 {
288 if (UINT64_MAX - a < b)
289 {
290 return UINT64_MAX;
291 }
292
293 return a + b;
294 }
295
296 template<typename T>
297 static uint64_t intMagnitude(T v)
298 {
299 if constexpr (std::numeric_limits<T>::is_signed)
300 {
301 if (v < 0)
302 {
303 return static_cast<uint64_t>(0) - static_cast<uint64_t>(v);
304 }
305 }
306
307 return static_cast<uint64_t>(v);
308 }
309
310 static uint64_t squareSat(uint64_t v)
311 {
312 if (v > UINT32_MAX)
313 {
314 return UINT64_MAX;
315 }
316
317 return v * v;
318 }
319
320 static uint64_t isqrt64(uint64_t x)
321 {
322 uint64_t root = 0;
323 uint64_t bit = static_cast<uint64_t>(1) << 62;
324
325 while (bit > x)
326 {
327 bit >>= 2;
328 }
329
330 while (bit != 0)
331 {
332 if (x >= root + bit)
333 {
334 x -= root + bit;
335 root = (root >> 1) + bit;
336 }
337 else
338 {
339 root >>= 1;
340 }
341
342 bit >>= 2;
343 }
344
345 return root;
346 }
347
348 template<typename T>
349 static T castIntRms(uint64_t v)
350 {
351 const uint64_t vmax = static_cast<uint64_t>(std::numeric_limits<T>::max());
352
353 if (v > vmax)
354 {
355 return std::numeric_limits<T>::max();
356 }
357
358 return static_cast<T>(v);
359 }
360
361 template<typename T>
362 void handleInt(CIOCommon *output,
363 io_ddata_t *data,
364 io_ddata_t *ioData,
365 io_ddata_t *outputData,
366 void *state)
367 {
368 int ret;
369 SStateInt *st = static_cast<SStateInt *>(state);
370
371 std::memcpy(ioData->getDataPtr(), data->getDataPtr(), ioData->getDataSize());
372
373 if (st->items != ioData->getItems())
374 {
375 DAWNERR("stats rms: item count changed from %u to %zu\n", st->items, ioData->getItems());
376 return;
377 }
378
379 st->count += 1;
380
381 for (size_t i = 0; i < ioData->getItems(); i++)
382 {
383 const uint64_t sq = squareSat(intMagnitude(ioData->get<T>(i)));
384 const uint64_t sumsq = saturatedAdd(st->sumsq[i], sq);
385 const uint64_t meanSq = sumsq / st->count;
386
387 st->sumsq[i] = sumsq;
388 outputData->get<T>(i) = castIntRms<T>(isqrt64(meanSq));
389 }
390
391 ret = output->setData(*outputData);
392 if (ret != OK)
393 {
394 DAWNERR("failed to set rms value %d\n", ret);
395 }
396 }
397
398 template<typename T>
399 void handleFloat(CIOCommon *output,
400 io_ddata_t *data,
401 io_ddata_t *ioData,
402 io_ddata_t *outputData,
403 void *state)
404 {
405 int ret;
406 SStateFloat<T> *st = static_cast<SStateFloat<T> *>(state);
407
408 std::memcpy(ioData->getDataPtr(), data->getDataPtr(), ioData->getDataSize());
409
410 if (st->items != ioData->getItems())
411 {
412 DAWNERR("stats rms: item count changed from %u to %zu\n", st->items, ioData->getItems());
413 return;
414 }
415
416 st->count += 1;
417
418 for (size_t i = 0; i < ioData->getItems(); i++)
419 {
420 const T x = ioData->get<T>(i);
421 const T sumsq = st->sumsq[i] + x * x;
422
423 st->sumsq[i] = sumsq;
424 outputData->get<T>(i) = std::sqrt(sumsq / static_cast<T>(st->count));
425 }
426
427 ret = output->setData(*outputData);
428 if (ret != OK)
429 {
430 DAWNERR("failed to set rms value %d\n", ret);
431 }
432 }
433};
434} // Namespace dawn
Descriptor wrapper for individual object configuration.
Base class for all I/O objects.
Definition common.hxx:27
uint8_t getDtype() const
Get data type field.
Definition object.cxx:175
@ PROG_CLASS_STATS_RMS
Running RMS (root mean square) calculator.
Definition common.hxx:59
Base class for callback-driven sample processing Program objects.
Definition process.hxx:28
@ PROG_STATS_CFG_IOBIND
I/O binding configuration.
Definition process.hxx:35
Running RMS statistics Program.
Definition statsrms.hxx:31
void handle(CIOCommon *output, io_ddata_t *data, io_ddata_t *ioData, io_ddata_t *outputData, bool &initsample)
Process incoming sample.
Definition statsrms.hxx:126
int bindStateAlloc(CIOCommon *src, CIOCommon *output, io_ddata_t *ioData, io_ddata_t *outputData, SBindState **state)
Allocate optional per-binding derived state.
Definition statsrms.hxx:67
void handleWithState(CIOCommon *output, io_ddata_t *data, io_ddata_t *ioData, io_ddata_t *outputData, bool &initsample, void *state)
Process incoming sample with optional per-binding state.
Definition statsrms.hxx:135
static ObjectCfgId objectCfg(uint8_t type, uint16_t cls, uint8_t dtype, bool rw, uint16_t size, uint8_t id)
Construct 32-bit ConfigID from component fields.
uint32_t ObjectCfgId
ConfigID type - single 32-bit value.
Definition objectcfg.hxx:60
Out-of-tree user-extension hooks for Dawn.
Definition bindable.hxx:13
@ OBJTYPE_PROG
Program/algorithm object type.
Definition objectid.hxx:202
@ DTYPE_FLOAT
IEEE 754 single-precision floating point (32-bit).
Definition objectid.hxx:112
@ DTYPE_INT32
Signed 32-bit integer (-2147483648 to 2147483647).
Definition objectid.hxx:92
@ DTYPE_UINT8
Unsigned 8-bit integer (0 to 255).
Definition objectid.hxx:80
@ DTYPE_INT16
Signed 16-bit integer (-32768 to 32767).
Definition objectid.hxx:84
@ DTYPE_INT8
Signed 8-bit integer (-128 to 127).
Definition objectid.hxx:76
@ DTYPE_ANY
Wildcard data type (matches any actual type).
Definition objectid.hxx:68
@ DTYPE_UINT64
Unsigned 64-bit integer.
Definition objectid.hxx:104
@ DTYPE_UINT16
Unsigned 16-bit integer (0 to 65535).
Definition objectid.hxx:88
@ DTYPE_DOUBLE
IEEE 754 double-precision floating point (64-bit).
Definition objectid.hxx:120
@ DTYPE_INT64
Signed 64-bit integer.
Definition objectid.hxx:100
@ DTYPE_UINT32
Unsigned 32-bit integer (0 to 4294967295).
Definition objectid.hxx:96
uint32_t ObjectId
ObjectID type - single 32-bit value.
Definition objectid.hxx:44
static ObjectId objectId(uint8_t type, uint16_t cls, uint8_t dtype, uint8_t flags, uint16_t priv)
Construct 32-bit ObjectID from component fields.
Definition objectid.hxx:290
Heap-allocated dynamic I/O data buffer.
Definition ddata.hxx:21
uint8_t getDtype() const
Get data type enum for introspection.
Definition ddata.hxx:217
size_t getItems()
Get number of items per batch.
Definition ddata.hxx:128