forked from aws/aws-iot-fleetwise-edge
-
Notifications
You must be signed in to change notification settings - Fork 0
/
TraceModule.h
438 lines (405 loc) · 14.8 KB
/
TraceModule.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include "EnumUtility.h"
#include "Timer.h"
#include <algorithm>
#include <atomic>
#include <chrono>
#include <cstdint>
#include <string>
namespace Aws
{
namespace IoTFleetWise
{
/**
* Different Variables defined at compile time used by all other modules
* For verbose print to work it needs to be also added to getVariableName()
* */
enum class TraceVariable
{
READ_SOCKET_FRAMES_0 = 0,
READ_SOCKET_FRAMES_1,
READ_SOCKET_FRAMES_2,
READ_SOCKET_FRAMES_3,
READ_SOCKET_FRAMES_4,
READ_SOCKET_FRAMES_5,
READ_SOCKET_FRAMES_6,
READ_SOCKET_FRAMES_7,
READ_SOCKET_FRAMES_8,
READ_SOCKET_FRAMES_9,
READ_SOCKET_FRAMES_10,
READ_SOCKET_FRAMES_11,
READ_SOCKET_FRAMES_12,
READ_SOCKET_FRAMES_13,
READ_SOCKET_FRAMES_14,
READ_SOCKET_FRAMES_15,
READ_SOCKET_FRAMES_16,
READ_SOCKET_FRAMES_17,
READ_SOCKET_FRAMES_18,
READ_SOCKET_FRAMES_19, // If you add more, update references to this
QUEUE_INSPECTION_TO_SENDER,
MAX_SYSTEMTIME_KERNELTIME_DIFF,
PM_MEMORY_NULL,
PM_MEMORY_INSUFFICIENT,
PM_COMPRESS_ERROR,
PM_STORE_ERROR,
CE_TOO_MANY_CONDITIONS,
CE_SIGNAL_ID_OUTBOUND,
CE_SAMPLE_SIZE_ZERO,
GE_COMPARE_PRECISION_ERROR,
GE_EVALUATE_ERROR_LAT_LON,
OBD_VIN_ERROR,
OBD_ENG_PID_REQ_ERROR,
OBD_TRA_PID_REQ_ERROR,
OBD_KEEP_ALIVE_ERROR,
DISCARDED_FRAMES,
POLLING_TIMESTAMP_COUNTER,
CE_PROCESSED_SIGNALS,
CE_PROCESSED_CAN_FRAMES,
CE_PROCESSED_DATA_FRAMES,
CE_PROCESSED_DTCS,
CE_TRIGGERS,
OBD_POSSIBLE_PRECISION_LOSS_UINT64,
OBD_POSSIBLE_PRECISION_LOSS_INT64,
MQTT_SIGNAL_MESSAGES_SENT_OUT, // Can be multiple messages per event id
MQTT_HEAP_USAGE,
SIGNAL_BUFFER_SIZE,
RAW_DATA_OVERWRITTEN_DATA_WITH_USED_HANDLE,
RAW_DATA_BUFFER_ELEMENTS_PER_TYPE,
RAW_DATA_BUFFER_MANAGER_BYTES,
// If you add more, remember to add the name to TraceModule::getVariableName
TRACE_VARIABLE_SIZE
};
/**
* Only add items at the end and do not delete items
*/
enum class TraceAtomicVariable
{
QUEUE_CONSUMER_TO_INSPECTION_SIGNALS = 0,
QUEUE_CONSUMER_TO_INSPECTION_CAN,
QUEUE_CONSUMER_TO_INSPECTION_DATA_FRAMES,
QUEUE_CONSUMER_TO_INSPECTION_DTCS,
NOT_TIME_MONOTONIC_FRAMES,
SUBSCRIBE_ERROR,
SUBSCRIBE_REJECT,
CONNECTION_FAILED,
CONNECTION_REJECTED,
CONNECTION_INTERRUPTED,
CONNECTION_RESUMED,
COLLECTION_SCHEME_ERROR,
// If you add more, remember to add the name to TraceModule::getAtomicVariableName
TRACE_ATOMIC_VARIABLE_SIZE
};
/**
* Different Sections defined at compile time used by all other modules
* For verbose print to work it needs to be also added to getSectionName()
* */
enum class TraceSection
{
BUILD_MQTT = 0,
FWE_STARTUP,
FWE_SHUTDOWN,
MANAGER_DECODER_BUILD,
MANAGER_COLLECTION_BUILD,
MANAGER_EXTRACTION,
CAN_DECODER_CYCLE_0,
CAN_DECODER_CYCLE_1,
CAN_DECODER_CYCLE_2,
CAN_DECODER_CYCLE_3,
CAN_DECODER_CYCLE_4,
CAN_DECODER_CYCLE_5,
CAN_DECODER_CYCLE_6,
CAN_DECODER_CYCLE_7,
CAN_DECODER_CYCLE_8,
CAN_DECODER_CYCLE_9,
CAN_DECODER_CYCLE_10,
CAN_DECODER_CYCLE_11,
CAN_DECODER_CYCLE_12,
CAN_DECODER_CYCLE_13,
CAN_DECODER_CYCLE_14,
CAN_DECODER_CYCLE_15,
CAN_DECODER_CYCLE_16,
CAN_DECODER_CYCLE_17,
CAN_DECODER_CYCLE_18,
CAN_DECODER_CYCLE_19, // If you add more, update references to this
COLLECTION_SCHEME_CHANGE_TO_FIRST_DATA,
// If you add more, remember to add the name to TraceModule::getSectionName
TRACE_SECTION_SIZE
};
/**
* @brief An interface that can be implemented by different classes to store or upload metrics
*/
class IMetricsReceiver
{
public:
virtual ~IMetricsReceiver() = default;
/**
* @brief set a value that will than be processed by the implementing class
*
* @param value the value as double
* @param name the displayed name of the metric
* @param unit the unit can be for example Seconds | Microseconds | Milliseconds | Bytes | Kilobytes | Megabytes |
* Gigabytes | Terabytes | Bits | Kilobits | Megabits | Gigabits | Terabits | Percent | Count | Bytes/Second |
* Kilobytes/Second | Megabytes/Second | Gigabytes/Second | Terabytes/Second | Bits/Second | Kilobits/Second |
* Megabits/Second | Gigabits/Second | Terabits/Second | Count/Second | None
*/
virtual void setMetric( const std::string &name, double value, const std::string &unit ) = 0;
};
/**
* @brief Other modules can use TraceModule to trace variables or execution times for later analysis
*
* The class is a Singleton
*/
class TraceModule
{
public:
/**
* @brief Singleton implementation which is thread safe with C++11
* */
static TraceModule &
get()
{
static TraceModule instance;
return instance;
}
/**
* @brief Set a variable defined in enum TraceVariable to trace its value
* The inline call is fast and can be used everywhere. Eventually a cache miss
* can occur.
*
* not thread safe for the same variable being set from different threads
* @param variable the variable define in enum TraceVariable
* @param value the uint64_t value that should be traced
*
*/
void
setVariable( TraceVariable variable, uint64_t value )
{
auto index = toUType( variable );
if ( ( variable < TraceVariable::TRACE_VARIABLE_SIZE ) && ( index >= 0 ) )
{
mVariableData[index].mCurrentValue = value;
mVariableData[index].mMaxValue = std::max( value, mVariableData[index].mMaxValue );
}
}
/**
* @brief Add to a variable defined in enum TraceVariable to trace its value
* The inline call is fast and can be used everywhere. Eventually a cache miss
* can occur.
*
* not thread safe for the same variable being set from different threads
* @param variable the variable define in enum TraceVariable
* @param value the uint64_t value that should be added
*
*/
void
addToVariable( TraceVariable variable, uint64_t value )
{
auto index = toUType( variable );
if ( ( variable < TraceVariable::TRACE_VARIABLE_SIZE ) && ( index >= 0 ) )
{
setVariable( variable, mVariableData[index].mCurrentValue + value );
}
}
/**
* @brief Increment a variable defined in enum TraceVariable to trace its value
* The inline call is fast and can be used everywhere. Eventually a cache miss
* can occur.
*
* not thread safe for the same variable being set from different threads
* @param variable the variable define in enum TraceVariable
*
*/
void
incrementVariable( TraceVariable variable )
{
addToVariable( variable, 1 );
}
/**
* @brief Add to a variable defined in enum TraceAtomicVariable to trace its value
*
* The value is initialized as 0 at the beginning. This function
* can be called from different threads. Will do platform dependent atomic operations
* used to implement std::atomic. So a few calls per microsecond should be fine
* on most platforms.
* There are no checks to avoid overflows/underflows.
*
* @param variable the variable define in enum TraceAtomicVariable
* @param add the uint64_t value that should be added to the traced variable
*
*/
void
addToAtomicVariable( TraceAtomicVariable variable, uint64_t add )
{
auto index = toUType( variable );
if ( ( variable < TraceAtomicVariable::TRACE_ATOMIC_VARIABLE_SIZE ) && ( index >= 0 ) )
{
uint64_t currentValue = mAtomicVariableData[index].mCurrentValue.fetch_add( add );
// If two threads add or increment in parallel the max value might be wrong
mAtomicVariableData[index].mMaxValue = std::max( currentValue + add, mAtomicVariableData[index].mMaxValue );
}
}
/**
* @brief Increment a variable defined in enum TraceAtomicVariable by one to trace its value
*
* The value is initialized as 0 at the beginning. This function
* can be called from different threads. Will do platform dependent atomic operations
* used to implement std::atomic. So a few calls per microsecond should be fine
* on most platforms.
* There are no checks to avoid overflows/underflows.
*
* @param variable the variable define in enum TraceAtomicVariable
*
*/
void
incrementAtomicVariable( TraceAtomicVariable variable )
{
addToAtomicVariable( variable, 1 );
}
/**
* @brief Subtract a value from a variable defined in enum TraceAtomicVariable to trace its value
*
* The value is initialized as 0 at the beginning. This function
* can be called from different threads. Will do platform dependent atomic operations
* used to implement std::atomic. So a few calls per microsecond should be fine
* on most platforms.
* There are no checks to avoid overflows/underflows.
*
* @param variable the variable define in enum TraceAtomicVariable
* @param sub the uint64_t value that should be subtracted to the traced variable
*
*/
void
subtractFromAtomicVariable( TraceAtomicVariable variable, uint64_t sub )
{
auto index = toUType( variable );
if ( ( variable < TraceAtomicVariable::TRACE_ATOMIC_VARIABLE_SIZE ) && ( index >= 0 ) )
{
mAtomicVariableData[index].mCurrentValue.fetch_sub( sub );
}
}
/**
* @brief Decrement a variable defined in enum TraceAtomicVariable by one to trace its value
*
* The value is initialized as 0 at the beginning. This function
* can be called from different threads. Will do platform dependent atomic operations
* used to implement std::atomic. So a few calls per microsecond should be fine
* on most platforms.
* There are no checks to avoid overflows/underflows.
*
* @param variable the variable define in enum TraceAtomicVariable
*
*/
void
decrementAtomicVariable( TraceAtomicVariable variable )
{
subtractFromAtomicVariable( variable, 1 );
}
/**
* @brief Get the maximum of a TraceVariable in the current observation window
* @param variable the TraceVariable which content should be returned.
*
* @return the max value of the current observation window
*
*/
uint64_t
getVariableMax( TraceVariable variable )
{
auto index = toUType( variable );
if ( ( variable < TraceVariable::TRACE_VARIABLE_SIZE ) && ( index >= 0 ) )
{
return mVariableData[index].mMaxValue;
}
return 0;
}
/**
* @brief Start a section which starts a timer until sectionEnd is called
* The time between sectionBegin and sectionEnd will be traced. So the
* max time the avg time of all executions of the same section will be
* traced.
* If the same TraceSection did already begin but not end the sectionBegin
* preceding this sectionBegin will be ignored.
* This is not thread safe so if the same section at the time begins or ends in two
* threads at the same time data recorded might be wrong.
*
* @param section the section that begins after the call to sectionBegin
*
*/
void sectionBegin( TraceSection section );
/**
* @brief End a section which ends a timer started at the last sectionBegin
* The time between sectionBegin and sectionEnd will be traced. So the
* max time the avg time of all executions of the same section will be
* traced.
* If the same TraceSection did not begin yet or already ended this call will be
* ignored.
* This is not thread safe so if the same section at the time begins or ends in two
* threads data recorded might be wrong.
*
* @param section the section that begins after the call to sectionBegin
*
*/
void sectionEnd( TraceSection section );
/**
* @brief Starts a new observation window for all variables and sections
*
* It might be interesting to collect for example the queue fill rate (traced
* with the maximum of a TraceVariable) over certain time spans. For example
* every second start a new observation window so you will get a trace giving the max
* of a traced variable for every second. Additionally the overall max is still saved.
* It is independent of the startNewObservationWindow so at any time you know what was
* the maximum since starting FWE.
* @param minimumObservationWindowTime if set higher than 0 the observation window will only be started if the
* current observation window is longer than the value
*/
void startNewObservationWindow( uint32_t minimumObservationWindowTime = 0 );
/**
* @brief prints all variables and section in a fixed format to stdout
*/
void print();
/**
* @brief Calls for all variables and section the profiler->setMetric
*
* Any usage of the metrics that is not printing them to stdout should be implemented over
* an IMetricsReceiver. The profiler pointer is not stored inside the class
* @param profiler The instance that all data should be sent.
*/
void forwardAllMetricsToMetricsReceiver( IMetricsReceiver *profiler );
private:
static const char *getVariableName( TraceVariable variable );
static const char *getAtomicVariableName( TraceAtomicVariable variable );
static const char *getSectionName( TraceSection section );
void updateAllTimeData();
struct VariableData
{
uint64_t mCurrentValue;
uint64_t mMaxValue; // The maximum in the current observation window
uint64_t mMaxValueAllTime;
};
struct AtomicVariableData
{
std::atomic<uint64_t> mCurrentValue;
uint64_t mMaxValue; // The maximum in the current observation window
uint64_t mMaxValueAllTime;
};
struct SectionData
{
uint32_t mHitCounter;
std::chrono::time_point<std::chrono::high_resolution_clock> mLastStartTime;
std::chrono::time_point<std::chrono::high_resolution_clock> mLastEndTime;
double mMaxSpent; // The maximum in the current observation window
double mMaxSpentAllTime;
double mMaxInterval; // The maximum in the current observation window
double mMaxIntervalAllTime;
double mTimeSpentSum;
double mIntervalSum;
bool mCurrentlyActive;
};
struct VariableData mVariableData[toUType( TraceVariable::TRACE_VARIABLE_SIZE )];
struct AtomicVariableData mAtomicVariableData[toUType( TraceAtomicVariable::TRACE_ATOMIC_VARIABLE_SIZE )];
struct SectionData mSectionData[toUType( TraceSection::TRACE_SECTION_SIZE )];
Timer mTimeSinceLastObservationWindow;
};
} // namespace IoTFleetWise
} // namespace Aws