Skip to content

Commit a70f40e

Browse files
[SL-ONLY] Initial SilabsTracing object (#106)
1 parent 39235d5 commit a70f40e

File tree

7 files changed

+1236
-0
lines changed

7 files changed

+1236
-0
lines changed

src/platform/silabs/Logging.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* See Project CHIP LICENSE file for licensing information. */
22
#include <platform/logging/LogV.h>
3+
#include <platform/silabs/Logging.h>
34

45
#include <lib/core/CHIPConfig.h>
56
#include <platform/CHIPDeviceConfig.h>
@@ -200,6 +201,13 @@ extern "C" void silabsLog(const char * aFormat, ...)
200201
va_end(v);
201202
}
202203

204+
#ifdef SILABS_LOG_ENABLED
205+
bool isLogInitialized()
206+
{
207+
return sLogInitialized;
208+
}
209+
#endif // SILABS_LOG_ENABLED
210+
203211
namespace chip {
204212
namespace DeviceLayer {
205213

src/platform/silabs/Logging.h

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/* See Project CHIP LICENSE file for licensing information. */
2+
#pragma once
3+
4+
bool isLogInitialized(void);

src/platform/silabs/tracing/BUILD.gn

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#/***************************************************************************
2+
# * @file BUILD.gn
3+
# * @brief Instrumenting for matter operation tracing for the Silicon Labs platform.
4+
# *******************************************************************************
5+
# * # License
6+
# * <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
7+
# *******************************************************************************
8+
# *
9+
# * The licensor of this software is Silicon Laboratories Inc. Your use of this
10+
# * software is governed by the terms of Silicon Labs Master Software License
11+
# * Agreement (MSLA) available at
12+
# * www.silabs.com/about-us/legal/master-software-license-agreement. This
13+
# * software is distributed to you in Source Code format and is governed by the
14+
# * sections of the MSLA applicable to Source Code.
15+
# *
16+
# ******************************************************************************/
17+
18+
import("//build_overrides/build.gni")
19+
import("//build_overrides/chip.gni")
20+
21+
static_library("SilabsTracing") {
22+
sources = [
23+
"SilabsTracing.cpp",
24+
"SilabsTracing.h",
25+
]
26+
27+
deps = [
28+
"${chip_root}/src/lib/core",
29+
"${chip_root}/src/lib/support",
30+
"${chip_root}/src/platform",
31+
"${chip_root}/src/system",
32+
]
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
/***************************************************************************
2+
* @file SilabsTracing.cpp
3+
* @brief Instrumenting for matter operation tracing for the Silicon Labs platform.
4+
*******************************************************************************
5+
* # License
6+
* <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
7+
*******************************************************************************
8+
*
9+
* The licensor of this software is Silicon Laboratories Inc. Your use of this
10+
* software is governed by the terms of Silicon Labs Master Software License
11+
* Agreement (MSLA) available at
12+
* www.silabs.com/about-us/legal/master-software-license-agreement. This
13+
* software is distributed to you in Source Code format and is governed by the
14+
* sections of the MSLA applicable to Source Code.
15+
*
16+
******************************************************************************/
17+
#include "SilabsTracing.h"
18+
#include <cstring>
19+
#include <lib/support/CodeUtils.h>
20+
#include <lib/support/PersistentData.h>
21+
22+
#if !CONFIG_BUILD_FOR_HOST_UNIT_TEST
23+
#include <Logging.h> // for isLogInitialized
24+
#endif
25+
26+
// The following functions needs to be implemented by the application to allows logging or storing the traces /
27+
// metrics. If the application does not implement them, the traces will simply be ignored.
28+
bool __attribute__((weak)) isLogInitialized()
29+
{
30+
return false;
31+
}
32+
33+
namespace chip {
34+
namespace Tracing {
35+
namespace Silabs {
36+
37+
// TODO add string mapping to log the operation names and types
38+
namespace {
39+
constexpr size_t kPersistentTimeTrackerBufferMax = SERIALIZED_TIME_TRACKERS_SIZE_BYTES;
40+
} // namespace
41+
struct TimeTrackerStorage : public TimeTracker, PersistentData<kPersistentTimeTrackerBufferMax>
42+
{
43+
// TODO implement the Persistent Array class and use it here for logging the watermark array
44+
};
45+
46+
SilabsTracer SilabsTracer::sInstance;
47+
48+
SilabsTracer::SilabsTracer()
49+
{
50+
VerifyOrDie(Init() == CHIP_NO_ERROR);
51+
}
52+
53+
void SilabsTracer::TraceBufferClear()
54+
{
55+
// Clear the time tracker list
56+
while (mTimeTrackerList.head != nullptr)
57+
{
58+
mTimeTrackerList.Remove(0);
59+
}
60+
mBufferedTrackerCount = 0;
61+
}
62+
63+
CHIP_ERROR SilabsTracer::Init()
64+
{
65+
TraceBufferClear();
66+
67+
// Initialize the time trackers
68+
memset(mLatestTimeTrackers, 0, sizeof(mLatestTimeTrackers));
69+
memset(mWatermarks, 0, sizeof(mWatermarks));
70+
71+
return CHIP_NO_ERROR;
72+
}
73+
74+
CHIP_ERROR SilabsTracer::StartWatermarksStorage(PersistentStorageDelegate * storage)
75+
{
76+
VerifyOrReturnError(nullptr != storage, CHIP_ERROR_INCORRECT_STATE);
77+
mStorage = storage;
78+
return CHIP_NO_ERROR;
79+
}
80+
81+
void SilabsTracer::TimeTraceBegin(TimeTraceOperation aOperation)
82+
{
83+
// Log the start time of the operation
84+
auto & tracker = mLatestTimeTrackers[static_cast<size_t>(aOperation)];
85+
tracker.mStartTime = System::SystemClock().GetMonotonicTimestamp();
86+
tracker.mOperation = aOperation;
87+
tracker.mType = OperationType::kBegin;
88+
tracker.mError = CHIP_NO_ERROR;
89+
90+
auto & watermark = mWatermarks[static_cast<size_t>(aOperation)];
91+
watermark.mTotalCount++;
92+
93+
OutputTrace(tracker);
94+
}
95+
96+
void SilabsTracer::TimeTraceEnd(TimeTraceOperation aOperation, CHIP_ERROR error)
97+
{
98+
auto & tracker = mLatestTimeTrackers[static_cast<size_t>(aOperation)];
99+
tracker.mEndTime = System::SystemClock().GetMonotonicTimestamp();
100+
tracker.mType = OperationType::kEnd;
101+
tracker.mError = error;
102+
103+
if (error == CHIP_NO_ERROR)
104+
{
105+
// Calculate the duration and update the time tracker
106+
auto duration = tracker.mEndTime - tracker.mStartTime;
107+
108+
auto & watermark = mWatermarks[static_cast<size_t>(aOperation)];
109+
watermark.mSuccessfullCount++;
110+
watermark.mMovingAverage = System::Clock::Milliseconds32(
111+
(watermark.mMovingAverage.count() * (watermark.mSuccessfullCount - 1) + duration.count()) /
112+
watermark.mSuccessfullCount);
113+
114+
if (duration > watermark.mMaxTimeMs)
115+
{
116+
watermark.mMaxTimeMs = System::Clock::Milliseconds32(duration);
117+
}
118+
119+
if (watermark.mMinTimeMs.count() == 0 || duration < watermark.mMinTimeMs)
120+
{
121+
watermark.mMinTimeMs = System::Clock::Milliseconds32(duration);
122+
}
123+
124+
if (duration > watermark.mMovingAverage)
125+
{
126+
watermark.mCountAboveAvg++;
127+
}
128+
}
129+
130+
OutputTrace(tracker);
131+
}
132+
133+
void SilabsTracer::TimeTraceInstant(TimeTraceOperation aOperation, CHIP_ERROR error)
134+
{
135+
TimeTracker tracker;
136+
tracker.mStartTime = System::SystemClock().GetMonotonicTimestamp();
137+
tracker.mEndTime = tracker.mStartTime;
138+
tracker.mOperation = aOperation;
139+
tracker.mType = OperationType::kInstant;
140+
tracker.mError = error;
141+
OutputTrace(tracker);
142+
}
143+
144+
CHIP_ERROR SilabsTracer::OutputTimeTracker(const TimeTracker & tracker)
145+
{
146+
VerifyOrReturnError(isLogInitialized(), CHIP_ERROR_UNINITIALIZED);
147+
ChipLogProgress(DeviceLayer,
148+
"TimeTracker - StartTime: %" PRIu32 ", EndTime: %" PRIu32 ", Operation: %" PRIu8 ", Type: %" PRIu8
149+
", Error: %" CHIP_ERROR_FORMAT,
150+
tracker.mStartTime.count(), tracker.mEndTime.count(), static_cast<uint8_t>(tracker.mOperation),
151+
static_cast<uint8_t>(tracker.mType), tracker.mError.Format());
152+
return CHIP_NO_ERROR;
153+
}
154+
155+
CHIP_ERROR SilabsTracer::OutputTrace(const TimeTracker & tracker)
156+
{
157+
// We allow error here as we want to buffer even if the logs are currently uninitialized
158+
OutputTimeTracker(tracker);
159+
160+
if (mBufferedTrackerCount < kMaxBufferedTraces - 1)
161+
{
162+
mTimeTrackerList.Insert(tracker);
163+
mBufferedTrackerCount++;
164+
}
165+
else if (mBufferedTrackerCount == kMaxBufferedTraces - 1)
166+
{
167+
// Save a tracker with TimeTraceOperation::kNumTraces and CHIP_ERROR_BUFFER_TOO_SMALL to indicate that the buffer is full
168+
TimeTracker resourceExhaustedTracker = tracker;
169+
resourceExhaustedTracker.mStartTime = System::SystemClock().GetMonotonicTimestamp();
170+
resourceExhaustedTracker.mEndTime = resourceExhaustedTracker.mStartTime;
171+
resourceExhaustedTracker.mOperation = TimeTraceOperation::kNumTraces;
172+
resourceExhaustedTracker.mType = OperationType::kInstant;
173+
resourceExhaustedTracker.mError = CHIP_ERROR_BUFFER_TOO_SMALL;
174+
mTimeTrackerList.Insert(resourceExhaustedTracker);
175+
return CHIP_ERROR_BUFFER_TOO_SMALL;
176+
}
177+
else
178+
{
179+
return CHIP_ERROR_BUFFER_TOO_SMALL;
180+
}
181+
182+
return CHIP_NO_ERROR;
183+
}
184+
185+
CHIP_ERROR SilabsTracer::OutputWaterMark(TimeTraceOperation aOperation)
186+
{
187+
size_t index = static_cast<size_t>(aOperation);
188+
auto & watermark = mWatermarks[index];
189+
190+
VerifyOrReturnError(isLogInitialized(), CHIP_ERROR_UNINITIALIZED);
191+
ChipLogProgress(DeviceLayer,
192+
"Trace %zu: TotalCount=%" PRIu32 ", SuccessFullCount=%" PRIu32 ", MaxTime=%" PRIu32 ", MinTime=%" PRIu32
193+
", AvgTime=%" PRIu32 ", CountAboveAvg=%" PRIu32 "",
194+
index, watermark.mTotalCount, watermark.mSuccessfullCount, watermark.mMaxTimeMs.count(),
195+
watermark.mMinTimeMs.count(), watermark.mMovingAverage.count(), watermark.mCountAboveAvg);
196+
197+
return CHIP_NO_ERROR;
198+
}
199+
200+
CHIP_ERROR SilabsTracer::OutputAllWaterMarks()
201+
{
202+
for (size_t i = 0; i < kNumTraces; ++i)
203+
{
204+
CHIP_ERROR err = OutputWaterMark(static_cast<TimeTraceOperation>(i));
205+
if (err != CHIP_NO_ERROR)
206+
{
207+
return err;
208+
}
209+
}
210+
return CHIP_NO_ERROR;
211+
}
212+
213+
CHIP_ERROR SilabsTracer::TraceBufferFlushAll()
214+
{
215+
auto * current = mTimeTrackerList.head;
216+
while (current != nullptr)
217+
{
218+
// We do not want to loose the traces if the logs are not initialized
219+
ReturnErrorOnFailure(OutputTimeTracker(current->mValue));
220+
current = current->mpNext;
221+
}
222+
223+
TraceBufferClear();
224+
return CHIP_NO_ERROR;
225+
}
226+
227+
CHIP_ERROR SilabsTracer::TraceBufferFlushByOperation(TimeTraceOperation aOperation)
228+
{
229+
230+
auto * current = mTimeTrackerList.head;
231+
auto * prev = static_cast<chip::SingleLinkedListNode<TimeTracker> *>(nullptr);
232+
while (current != nullptr)
233+
{
234+
if (current->mValue.mOperation == aOperation)
235+
{
236+
ReturnErrorOnFailure(OutputTimeTracker(current->mValue));
237+
if (prev == nullptr)
238+
{
239+
mTimeTrackerList.head = current->mpNext;
240+
}
241+
else
242+
{
243+
prev->mpNext = current->mpNext;
244+
}
245+
auto * temp = current;
246+
current = current->mpNext;
247+
free(temp);
248+
mBufferedTrackerCount--;
249+
}
250+
else
251+
{
252+
prev = current;
253+
current = current->mpNext;
254+
}
255+
}
256+
257+
return CHIP_NO_ERROR;
258+
}
259+
260+
// Save the traces in the NVM
261+
CHIP_ERROR SilabsTracer::SaveWatermarks()
262+
{
263+
VerifyOrReturnError(nullptr != mStorage, CHIP_ERROR_INCORRECT_STATE);
264+
// TODO implement the save of the watermarks in the NVM
265+
return CHIP_NO_ERROR;
266+
}
267+
268+
CHIP_ERROR SilabsTracer::LoadWatermarks()
269+
{
270+
VerifyOrReturnError(nullptr != mStorage, CHIP_ERROR_INCORRECT_STATE);
271+
// TODO implement the load of the watermarks from the NVM
272+
return CHIP_NO_ERROR;
273+
}
274+
275+
#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
276+
size_t SilabsTracer::GetTraceCount()
277+
{
278+
return mBufferedTrackerCount;
279+
}
280+
281+
CHIP_ERROR SilabsTracer::GetTraceByIndex(size_t index, const char *& trace) const
282+
{
283+
auto * current = mTimeTrackerList.head;
284+
for (size_t i = 0; i < index && current != nullptr; ++i)
285+
{
286+
current = current->mpNext;
287+
}
288+
VerifyOrReturnError(current != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
289+
trace = reinterpret_cast<const char *>(&current->mValue);
290+
return CHIP_NO_ERROR;
291+
}
292+
#endif
293+
294+
} // namespace Silabs
295+
} // namespace Tracing
296+
} // namespace chip

0 commit comments

Comments
 (0)