rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
perf_trace.cpp
Go to the documentation of this file.
1/**
2 * @file perf_trace.cpp
3 *
4 * https://github.com/rusefi/rusefi/wiki/Developer-Performance-Tracing
5 *
6 * See JsonOutput.java in rusEfi console
7 */
8
9#include "pch.h"
10
11#ifndef ENABLE_PERF_TRACE
12#error ENABLE_PERF_TRACE must be defined!
13#endif
14
15enum class EPhase : char
16{
17 Start,
18 End,
21};
22
23struct TraceEntry
24{
25 PE Event;
26 EPhase Phase;
27 int8_t IsrId;
28 uint8_t ThreadId;
29 uint32_t Timestamp;
30};
31
32// Ensure that the struct is the size we think it is - the binary layout is important
33static_assert(sizeof(TraceEntry) == 8);
34
35#define TRACE_BUFFER_LENGTH (BIG_BUFFER_SIZE / sizeof(TraceEntry))
36
37// This buffer stores a trace - we write the full buffer once, then disable tracing
39static size_t s_nextIdx = 0;
40
41static bool s_isTracing = false;
42
43static void stopTrace() {
44 s_isTracing = false;
45 s_nextIdx = 0;
46}
47
48static void perfEventImpl(PE event, EPhase phase) {
49#if EFI_PROD_CODE
50 // Bail if we aren't allowed to trace
51 if constexpr (!ENABLE_PERF_TRACE) {
52 return;
53 }
54
55 // Bail if we aren't tracing
56 if (!s_isTracing || !s_traceBuffer) {
57 return;
58 }
59
60 // todo: why doesn't getTimeNowLowerNt() work here?
61 // It returns 0 like we're in a unit test
62 uint32_t timestamp = port_rt_get_counter_value();
63
64 size_t idx;
65
66 // Critical section: disable interrupts to reserve an index.
67 // We could lock, but this gets called a LOT - so locks could
68 // significantly alter the results of the measurement.
69 // In addition, if we want to trace lock/unlock events, we can't
70 // be locking ourselves from the trace functionality.
71 {
72 uint32_t prim = __get_PRIMASK();
73 __disable_irq();
74
75 idx = s_nextIdx++;
76 if (s_nextIdx >= TRACE_BUFFER_LENGTH) {
77 stopTrace();
78 }
79
80 // Restore previous interrupt state - don't restore if they weren't enabled
81 if (!prim) {
82 __enable_irq();
83 }
84 }
85
86 // We can safely write data out of the lock, our spot is reserved
87 volatile TraceEntry& entry = s_traceBuffer.get<TraceEntry>()[idx];
88
89 entry.Event = event;
90 entry.Phase = phase;
91 // Get the current active interrupt - this is the "process ID"
92 auto isr = static_cast<int8_t>(SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk);
93 entry.IsrId = isr - 16;
94
95 // Get the current thread (if not interrupt) and use as the thread ID
96 if (isr == 0) {
97 entry.ThreadId = chThdGetSelfX()->threadId;
98 } else {
99 // Interrupts have no thread - all are T0
100 entry.ThreadId = 0;
101 }
102
103 entry.Timestamp = timestamp;
104#endif // EFI_PROD_CODE
105}
106
107void perfEventBegin(PE event) {
109}
110
111void perfEventEnd(PE event) {
113}
114
118
120#if EFI_TOOTH_LOGGER
121 // force release of the buffer if occupied by the tooth logger
122 if (IsToothLoggerEnabled()) {
123 // don't worry, it will be automatically enabled
124 // when the next TS_GET_COMPOSITE_BUFFER_DONE_DIFFERENTLY command arrives
126 }
127#endif // EFI_TOOTH_LOGGER
129 s_isTracing = true;
130}
131
133 // stop tracing if you try to get the buffer early
134 stopTrace();
135
136 // transfer ownership of the buffer to the caller
137 return efi::move(s_traceBuffer);
138}
BigBufferHandle getBigBuffer(BigBufferUser user)
const TBuffer * get() const
Definition big_buffer.h:34
constexpr remove_reference_t< _Ty > && move(_Ty &&_Arg) noexcept
Definition efilib.h:126
void perfEventInstantGlobal(PE event)
static bool s_isTracing
static BigBufferHandle s_traceBuffer
EPhase
@ InstantGlobal
@ InstantThread
static size_t s_nextIdx
static void stopTrace()
const BigBufferHandle perfTraceGetBuffer()
void perfEventBegin(PE event)
static void perfEventImpl(PE event, EPhase phase)
void perfTraceEnable()
void perfEventEnd(PE event)
PE
Definition perf_trace.h:18
void DisableToothLogger()
bool IsToothLoggerEnabled()