1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "bytrace_event_parser.h"
17 #include "binder_filter.h"
18 #include "cpu_filter.h"
19 #include "filter_filter.h"
20 #include "irq_filter.h"
21 #include "measure_filter.h"
22 #include "parting_string.h"
23 #include "process_filter.h"
24 #include "slice_filter.h"
25 #include "stat_filter.h"
26 #include "string_to_numerical.h"
27 #include "thread_state.h"
28 #include "ts_common.h"
29 namespace SysTuning {
30 namespace TraceStreamer {
31 namespace {
GetFunctionName(const std::string_view & text,const std::string_view & delimiter)32 std::string GetFunctionName(const std::string_view& text, const std::string_view& delimiter)
33 {
34 std::string str("");
35 if (delimiter.empty()) {
36 return str;
37 }
38
39 std::size_t foundIndex = text.find(delimiter);
40 if (foundIndex != std::string::npos) {
41 std::size_t funIndex = foundIndex + delimiter.size();
42 str = std::string(text.substr(funIndex, text.size() - funIndex));
43 }
44 return str;
45 }
46 } // namespace
47
BytraceEventParser(TraceDataCache * dataCache,const TraceStreamerFilters * filter)48 BytraceEventParser::BytraceEventParser(TraceDataCache* dataCache, const TraceStreamerFilters* filter)
49 : EventParserBase(dataCache, filter),
50 printEventParser_(traceDataCache_, streamFilters_)
51 {
52 eventToFunctionMap_ = {
53 {config_.eventNameMap_.at(TRACE_EVENT_SCHED_SWITCH),
54 bind(&BytraceEventParser::SchedSwitchEvent, this, std::placeholders::_1, std::placeholders::_2)},
55 {config_.eventNameMap_.at(TRACE_EVENT_TASK_RENAME),
56 bind(&BytraceEventParser::TaskRenameEvent, this, std::placeholders::_1, std::placeholders::_2)},
57 {config_.eventNameMap_.at(TRACE_EVENT_TASK_NEWTASK),
58 bind(&BytraceEventParser::TaskNewtaskEvent, this, std::placeholders::_1, std::placeholders::_2)},
59 {config_.eventNameMap_.at(TRACE_EVENT_TRACING_MARK_WRITE),
60 bind(&BytraceEventParser::TracingMarkWriteOrPrintEvent, this, std::placeholders::_1, std::placeholders::_2)},
61 {config_.eventNameMap_.at(TRACE_EVENT_PRINT),
62 bind(&BytraceEventParser::TracingMarkWriteOrPrintEvent, this, std::placeholders::_1, std::placeholders::_2)},
63 {config_.eventNameMap_.at(TRACE_EVENT_SCHED_WAKEUP),
64 bind(&BytraceEventParser::SchedWakeupEvent, this, std::placeholders::_1, std::placeholders::_2)},
65 {config_.eventNameMap_.at(TRACE_EVENT_SCHED_WAKING),
66 bind(&BytraceEventParser::SchedWakingEvent, this, std::placeholders::_1, std::placeholders::_2)},
67 {config_.eventNameMap_.at(TRACE_EVENT_CPU_IDLE),
68 bind(&BytraceEventParser::CpuIdleEvent, this, std::placeholders::_1, std::placeholders::_2)},
69 {config_.eventNameMap_.at(TRACE_EVENT_CPU_FREQUENCY),
70 bind(&BytraceEventParser::CpuFrequencyEvent, this, std::placeholders::_1, std::placeholders::_2)},
71 {config_.eventNameMap_.at(TRACE_EVENT_CPU_FREQUENCY_LIMITS),
72 bind(&BytraceEventParser::CpuFrequencyLimitsEvent, this, std::placeholders::_1, std::placeholders::_2)},
73 {config_.eventNameMap_.at(TRACE_EVENT_WORKQUEUE_EXECUTE_START),
74 bind(&BytraceEventParser::WorkqueueExecuteStartEvent, this, std::placeholders::_1, std::placeholders::_2)},
75 {config_.eventNameMap_.at(TRACE_EVENT_WORKQUEUE_EXECUTE_END),
76 bind(&BytraceEventParser::WorkqueueExecuteEndEvent, this, std::placeholders::_1, std::placeholders::_2)},
77 {config_.eventNameMap_.at(TRACE_EVENT_CLOCK_SET_RATE),
78 bind(&BytraceEventParser::SetRateEvent, this, std::placeholders::_1, std::placeholders::_2)},
79 {config_.eventNameMap_.at(TRACE_EVENT_CLOCK_ENABLE),
80 bind(&BytraceEventParser::ClockEnableEvent, this, std::placeholders::_1, std::placeholders::_2)},
81 {config_.eventNameMap_.at(TRACE_EVENT_CLOCK_DISABLE),
82 bind(&BytraceEventParser::ClockDisableEvent, this, std::placeholders::_1, std::placeholders::_2)},
83 {config_.eventNameMap_.at(TRACE_EVENT_REGULATOR_SET_VOLTAGE),
84 bind(&BytraceEventParser::RegulatorSetVoltageEvent, this, std::placeholders::_1, std::placeholders::_2)},
85 {config_.eventNameMap_.at(TRACE_EVENT_REGULATOR_SET_VOLTAGE_COMPLETE),
86 bind(&BytraceEventParser::RegulatorSetVoltageCompleteEvent, this, std::placeholders::_1,
87 std::placeholders::_2)},
88 {config_.eventNameMap_.at(TRACE_EVENT_REGULATOR_DISABLE),
89 bind(&BytraceEventParser::RegulatorDisableEvent, this, std::placeholders::_1, std::placeholders::_2)},
90 {config_.eventNameMap_.at(TRACE_EVENT_REGULATOR_DISABLE_COMPLETE),
91 bind(&BytraceEventParser::RegulatorDisableCompleteEvent, this, std::placeholders::_1, std::placeholders::_2)},
92 {config_.eventNameMap_.at(TRACE_EVENT_IPI_ENTRY),
93 bind(&BytraceEventParser::IpiEntryEvent, this, std::placeholders::_1, std::placeholders::_2)},
94 {config_.eventNameMap_.at(TRACE_EVENT_IPI_EXIT),
95 bind(&BytraceEventParser::IpiExitEvent, this, std::placeholders::_1, std::placeholders::_2)},
96 {config_.eventNameMap_.at(TRACE_EVENT_IRQ_HANDLER_ENTRY),
97 bind(&BytraceEventParser::IrqHandlerEntryEvent, this, std::placeholders::_1, std::placeholders::_2)},
98 {config_.eventNameMap_.at(TRACE_EVENT_IRQ_HANDLER_EXIT),
99 bind(&BytraceEventParser::IrqHandlerExitEvent, this, std::placeholders::_1, std::placeholders::_2)},
100 {config_.eventNameMap_.at(TRACE_EVENT_SOFTIRQ_RAISE),
101 bind(&BytraceEventParser::SoftIrqRaiseEvent, this, std::placeholders::_1, std::placeholders::_2)},
102 {config_.eventNameMap_.at(TRACE_EVENT_SOFTIRQ_ENTRY),
103 bind(&BytraceEventParser::SoftIrqEntryEvent, this, std::placeholders::_1, std::placeholders::_2)},
104 {config_.eventNameMap_.at(TRACE_EVENT_SOFTIRQ_EXIT),
105 bind(&BytraceEventParser::SoftIrqExitEvent, this, std::placeholders::_1, std::placeholders::_2)},
106 {config_.eventNameMap_.at(TRACE_EVENT_BINDER_TRANSACTION),
107 bind(&BytraceEventParser::BinderTransaction, this, std::placeholders::_1, std::placeholders::_2)},
108 {config_.eventNameMap_.at(TRACE_EVENT_BINDER_TRANSACTION_RECEIVED),
109 bind(&BytraceEventParser::BinderTransactionReceived, this, std::placeholders::_1, std::placeholders::_2)},
110 {config_.eventNameMap_.at(TRACE_EVENT_BINDER_TRANSACTION_ALLOC_BUF),
111 bind(&BytraceEventParser::BinderTransactionAllocBufEvent, this, std::placeholders::_1, std::placeholders::_2)},
112 {config_.eventNameMap_.at(TRACE_EVENT_SCHED_WAKEUP_NEW),
113 bind(&BytraceEventParser::SchedWakeupEvent, this, std::placeholders::_1, std::placeholders::_2)},
114 {config_.eventNameMap_.at(TRACE_EVENT_PROCESS_EXIT),
115 bind(&BytraceEventParser::ProcessExitEvent, this, std::placeholders::_1, std::placeholders::_2)}};
116 }
117
SchedSwitchEvent(const ArgsMap & args,const BytraceLine & line) const118 bool BytraceEventParser::SchedSwitchEvent(const ArgsMap& args, const BytraceLine& line) const
119 {
120 if (args.empty() || args.size() < MIN_SCHED_SWITCH_ARGS_COUNT) {
121 TS_LOGD("Failed to parse sched_switch event, no args or args size < 6");
122 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_SWITCH, STAT_EVENT_DATA_INVALID);
123 return false;
124 }
125 auto prevCommStr = std::string_view(args.at("prev_comm"));
126 auto nextCommStr = std::string_view(args.at("next_comm"));
127 auto prevPrioValue = base::StrToInt32(args.at("prev_prio"));
128 auto nextPrioValue = base::StrToInt32(args.at("next_prio"));
129 auto prevPidValue = base::StrToUInt32(args.at("prev_pid"));
130 auto nextPidValue = base::StrToUInt32(args.at("next_pid"));
131 if (!(!prevCommStr.empty() && prevPidValue.has_value() && prevPrioValue.has_value() && nextPidValue.has_value() &&
132 nextPrioValue.has_value())) {
133 TS_LOGD("Failed to parse sched_switch event");
134 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_SWITCH, STAT_EVENT_DATA_INVALID);
135 return false;
136 }
137 auto prevStateStr = args.at("prev_state");
138 auto threadState = ThreadState(prevStateStr.c_str());
139 uint64_t prevState = threadState.State();
140 if (!threadState.IsValid()) {
141 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_SWITCH, STAT_EVENT_DATA_INVALID);
142 }
143 auto nextInternalTid = 0;
144 auto uprevtid = 0;
145 if (streamFilters_->processFilter_->isThreadNameEmpty(nextPidValue.value())) {
146 nextInternalTid =
147 streamFilters_->processFilter_->UpdateOrCreateThreadWithName(line.ts, nextPidValue.value(), nextCommStr);
148 } else {
149 nextInternalTid = streamFilters_->processFilter_->UpdateOrCreateThread(line.ts, nextPidValue.value());
150 }
151 if (streamFilters_->processFilter_->isThreadNameEmpty(prevPidValue.value())) {
152 uprevtid =
153 streamFilters_->processFilter_->UpdateOrCreateThreadWithName(line.ts, prevPidValue.value(), prevCommStr);
154 } else {
155 uprevtid = streamFilters_->processFilter_->UpdateOrCreateThread(line.ts, prevPidValue.value());
156 }
157 streamFilters_->cpuFilter_->InsertSwitchEvent(line.ts, line.cpu, uprevtid,
158 static_cast<uint64_t>(prevPrioValue.value()), prevState,
159 nextInternalTid, static_cast<uint64_t>(nextPrioValue.value()));
160 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_SWITCH, STAT_EVENT_RECEIVED);
161 return true;
162 }
163
TaskRenameEvent(const ArgsMap & args,const BytraceLine & line) const164 bool BytraceEventParser::TaskRenameEvent(const ArgsMap& args, const BytraceLine& line) const
165 {
166 if (args.empty() || args.size() < MIN_TASK_RENAME_ARGS_COUNT) {
167 TS_LOGD("Failed to parse task_rename event, no args or args size < 2");
168 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TASK_RENAME, STAT_EVENT_DATA_INVALID);
169 return false;
170 }
171 auto prevCommStr = std::string_view(args.at("newcomm"));
172 auto pidValue = base::StrToUInt32(args.at("pid"));
173 streamFilters_->processFilter_->UpdateOrCreateThreadWithName(line.ts, pidValue.value(), prevCommStr);
174 return true;
175 }
176
TaskNewtaskEvent(const ArgsMap & args,const BytraceLine & line) const177 bool BytraceEventParser::TaskNewtaskEvent(const ArgsMap& args, const BytraceLine& line) const
178 {
179 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TASK_NEWTASK, STAT_EVENT_RECEIVED);
180 // the clone flag from txt trace from kernel original is HEX, but when it is converted from proto
181 // based trace, it will be OCT number, it is not stable, so we decide to ignore it
182 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TASK_NEWTASK, STAT_EVENT_NOTSUPPORTED);
183 return true;
184 }
185
TracingMarkWriteOrPrintEvent(const ArgsMap & args,const BytraceLine & line)186 bool BytraceEventParser::TracingMarkWriteOrPrintEvent(const ArgsMap& args, const BytraceLine& line)
187 {
188 UNUSED(args);
189 return printEventParser_.ParsePrintEvent(line.task, line.ts, line.pid, line.argsStr.c_str());
190 }
191 // prefer to use waking, unless no waking, can use wakeup
SchedWakeupEvent(const ArgsMap & args,const BytraceLine & line) const192 bool BytraceEventParser::SchedWakeupEvent(const ArgsMap& args, const BytraceLine& line) const
193 {
194 if (args.size() < MIN_SCHED_WAKEUP_ARGS_COUNT) {
195 TS_LOGD("Failed to parse SchedWakeupEvent event, no args or args size < 2");
196 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKEUP, STAT_EVENT_DATA_INVALID);
197 return false;
198 }
199 std::optional<uint32_t> wakePidValue = base::StrToUInt32(args.at("pid"));
200 if (!wakePidValue.has_value()) {
201 TS_LOGD("Failed to convert wake_pid");
202 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKEUP, STAT_EVENT_DATA_INVALID);
203 return false;
204 }
205 auto instants = traceDataCache_->GetInstantsData();
206 InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(line.ts, wakePidValue.value_or(0));
207
208 InternalTid wakeupFromPid = streamFilters_->processFilter_->UpdateOrCreateThread(line.ts, line.pid);
209
210 instants->AppendInstantEventData(line.ts, schedWakeupName_, internalTid, wakeupFromPid);
211 std::optional<uint32_t> targetCpu = base::StrToUInt32(args.at("target_cpu"));
212 if (targetCpu.has_value()) {
213 traceDataCache_->GetRawData()->AppendRawData(0, line.ts, RAW_SCHED_WAKEUP, targetCpu.value(), internalTid);
214 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKEUP, STAT_EVENT_RECEIVED);
215 }
216 return true;
217 }
218
SchedWakingEvent(const ArgsMap & args,const BytraceLine & line) const219 bool BytraceEventParser::SchedWakingEvent(const ArgsMap& args, const BytraceLine& line) const
220 {
221 if (args.empty() || args.size() < MIN_SCHED_WAKING_ARGS_COUNT) {
222 TS_LOGD("Failed to parse sched_waking event, no args or args size < 4");
223 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKING, STAT_EVENT_DATA_INVALID);
224 return false;
225 }
226 std::optional<uint32_t> wakePidValue = base::StrToUInt32(args.at("pid"));
227 auto wakePidStr = std::string_view(args.at("comm"));
228 if (!wakePidValue.has_value()) {
229 TS_LOGD("Failed to convert wake_pid");
230 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKING, STAT_EVENT_DATA_INVALID);
231 return false;
232 }
233 auto instants = traceDataCache_->GetInstantsData();
234 DataIndex wakePidStrIndex = traceDataCache_->GetDataIndex(wakePidStr);
235 InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThreadWithNameIndex(
236 line.ts, wakePidValue.value(), wakePidStrIndex);
237
238 DataIndex wakeByPidStrIndex = traceDataCache_->GetDataIndex(line.task);
239 InternalTid internalTidWakeup =
240 streamFilters_->processFilter_->UpdateOrCreateThreadWithNameIndex(line.ts, line.pid, wakeByPidStrIndex);
241 streamFilters_->cpuFilter_->InsertWakeupEvent(line.ts, internalTid);
242 InternalTid wakeupFromPid = streamFilters_->processFilter_->UpdateOrCreateThread(line.ts, line.pid);
243 instants->AppendInstantEventData(line.ts, schedWakingName_, internalTid, wakeupFromPid);
244 std::optional<uint32_t> targetCpu = base::StrToUInt32(args.at("target_cpu"));
245 if (targetCpu.has_value()) {
246 traceDataCache_->GetRawData()->AppendRawData(0, line.ts, RAW_SCHED_WAKING, targetCpu.value(),
247 internalTidWakeup);
248 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKING, STAT_EVENT_RECEIVED);
249 }
250
251 return true;
252 }
253
CpuIdleEvent(const ArgsMap & args,const BytraceLine & line) const254 bool BytraceEventParser::CpuIdleEvent(const ArgsMap& args, const BytraceLine& line) const
255 {
256 if (args.empty() || args.size() < MIN_CPU_IDLE_ARGS_COUNT) {
257 TS_LOGD("Failed to parse cpu_idle event, no args or args size < 2");
258 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_IDLE, STAT_EVENT_DATA_INVALID);
259 return false;
260 }
261 std::optional<uint32_t> eventCpuValue = base::StrToUInt32(args.at("cpu_id"));
262 std::optional<int64_t> newStateValue = base::StrToInt64(args.at("state"));
263 if (!eventCpuValue.has_value()) {
264 TS_LOGD("Failed to convert event cpu");
265 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_IDLE, STAT_EVENT_DATA_INVALID);
266 return false;
267 }
268 if (!newStateValue.has_value()) {
269 TS_LOGD("Failed to convert state");
270 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_IDLE, STAT_EVENT_DATA_INVALID);
271 return false;
272 }
273 // Add cpu_idle event to raw_data_table
274 auto cpuidleNameIndex = traceDataCache_->GetDataIndex(line.eventName.c_str());
275 streamFilters_->cpuMeasureFilter_->AppendNewMeasureData(eventCpuValue.value(), cpuidleNameIndex, line.ts,
276 config_.GetStateValue(newStateValue.value()));
277 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_IDLE, STAT_EVENT_RECEIVED);
278 return true;
279 }
280
CpuFrequencyEvent(const ArgsMap & args,const BytraceLine & line) const281 bool BytraceEventParser::CpuFrequencyEvent(const ArgsMap& args, const BytraceLine& line) const
282 {
283 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY, STAT_EVENT_RECEIVED);
284 if (args.empty() || args.size() < MIN_CPU_FREQUENCY_ARGS_COUNT) {
285 TS_LOGD("Failed to parse cpu_frequency event, no args or args size < 2");
286 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY, STAT_EVENT_DATA_INVALID);
287 return false;
288 }
289 std::optional<uint32_t> eventCpuValue = base::StrToUInt32(args.at("cpu_id"));
290 std::optional<int64_t> newStateValue = base::StrToInt64(args.at("state"));
291
292 if (!newStateValue.has_value()) {
293 TS_LOGD("Failed to convert state");
294 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY, STAT_EVENT_DATA_INVALID);
295 return false;
296 }
297 if (!eventCpuValue.has_value()) {
298 TS_LOGD("Failed to convert event cpu");
299 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY, STAT_EVENT_DATA_INVALID);
300 return false;
301 }
302
303 auto cpuidleNameIndex = traceDataCache_->GetDataIndex(line.eventName.c_str());
304 streamFilters_->cpuMeasureFilter_->AppendNewMeasureData(eventCpuValue.value(), cpuidleNameIndex, line.ts,
305 newStateValue.value());
306 return true;
307 }
CpuFrequencyLimitsEvent(const ArgsMap & args,const BytraceLine & line) const308 bool BytraceEventParser::CpuFrequencyLimitsEvent(const ArgsMap& args, const BytraceLine& line) const
309 {
310 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY_LIMITS, STAT_EVENT_RECEIVED);
311 if (args.empty() || args.size() < MIN_CPU_FREQUENCY_ARGS_COUNT) {
312 TS_LOGD("Failed to parse cpu_frequency event, no args or args size < 2");
313 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY_LIMITS, STAT_EVENT_DATA_INVALID);
314 return false;
315 }
316 std::optional<uint32_t> eventCpuValue = base::StrToUInt32(args.at("cpu_id"));
317 std::optional<int64_t> minValue = base::StrToInt64(args.at("min"));
318 std::optional<int64_t> maxValue = base::StrToInt64(args.at("max"));
319
320 if (!minValue.has_value()) {
321 TS_LOGD("Failed to get frequency minValue");
322 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY_LIMITS, STAT_EVENT_DATA_INVALID);
323 return false;
324 }
325 if (!maxValue.has_value()) {
326 TS_LOGD("Failed to get frequency maxValue");
327 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY_LIMITS, STAT_EVENT_DATA_INVALID);
328 return false;
329 }
330 if (!eventCpuValue.has_value()) {
331 TS_LOGD("Failed to get frequency cpu");
332 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY_LIMITS, STAT_EVENT_DATA_INVALID);
333 return false;
334 }
335
336 streamFilters_->cpuMeasureFilter_->AppendNewMeasureData(eventCpuValue.value(), cpuFrequencyLimitMaxNameId, line.ts,
337 maxValue.value());
338 streamFilters_->cpuMeasureFilter_->AppendNewMeasureData(eventCpuValue.value(), cpuFrequencyLimitMinNameId, line.ts,
339 minValue.value());
340 return true;
341 }
342
WorkqueueExecuteStartEvent(const ArgsMap & args,const BytraceLine & line) const343 bool BytraceEventParser::WorkqueueExecuteStartEvent(const ArgsMap& args, const BytraceLine& line) const
344 {
345 UNUSED(args);
346 auto splitStr = GetFunctionName(line.argsStr, "function ");
347 auto splitStrIndex = traceDataCache_->GetDataIndex(splitStr);
348 size_t result =
349 streamFilters_->sliceFilter_->BeginSlice(line.task, line.ts, line.pid, 0, workQueueId_, splitStrIndex);
350 traceDataCache_->GetInternalSlicesData()->AppendDistributeInfo();
351 if (result != INVALID_UINT32) {
352 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_WORKQUEUE_EXECUTE_START, STAT_EVENT_RECEIVED);
353 return true;
354 } else {
355 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_WORKQUEUE_EXECUTE_START, STAT_EVENT_DATA_LOST);
356 return false;
357 }
358 }
359
WorkqueueExecuteEndEvent(const ArgsMap & args,const BytraceLine & line) const360 bool BytraceEventParser::WorkqueueExecuteEndEvent(const ArgsMap& args, const BytraceLine& line) const
361 {
362 UNUSED(args);
363 if (streamFilters_->sliceFilter_->EndSlice(line.ts, line.pid, 0, workQueueId_)) {
364 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_WORKQUEUE_EXECUTE_END, STAT_EVENT_RECEIVED);
365 return true;
366 } else {
367 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_WORKQUEUE_EXECUTE_END, STAT_EVENT_NOTMATCH);
368 return false;
369 }
370 }
371
ProcessExitEvent(const ArgsMap & args,const BytraceLine & line) const372 bool BytraceEventParser::ProcessExitEvent(const ArgsMap& args, const BytraceLine& line) const
373 {
374 if (args.empty() || args.size() < MIN_PROCESS_EXIT_ARGS_COUNT) {
375 TS_LOGD("Failed to parse process_exit event, no args or args size < 2");
376 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PROCESS_EXIT, STAT_EVENT_DATA_INVALID);
377 return false;
378 }
379 auto comm = std::string_view(args.at("comm"));
380 auto pid = base::StrToUInt32(args.at("pid"));
381 if (!pid.has_value()) {
382 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PROCESS_EXIT, STAT_EVENT_DATA_INVALID);
383 return false;
384 }
385 auto itid = streamFilters_->processFilter_->UpdateOrCreateThreadWithName(line.ts, pid.value(), comm);
386 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PROCESS_EXIT, STAT_EVENT_RECEIVED);
387 if (streamFilters_->cpuFilter_->InsertProcessExitEvent(line.ts, line.cpu, itid)) {
388 return true;
389 } else {
390 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PROCESS_EXIT, STAT_EVENT_NOTMATCH);
391 return false;
392 }
393 }
394
SetRateEvent(const ArgsMap & args,const BytraceLine & line) const395 bool BytraceEventParser::SetRateEvent(const ArgsMap& args, const BytraceLine& line) const
396 {
397 if (args.empty() || args.size() < MIN_CLOCK_SET_RATE_ARGS_COUNT) {
398 TS_LOGD("Failed to parse clock_set_rate event, no args or args size < 3");
399 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_SET_RATE, STAT_EVENT_DATA_INVALID);
400 return false;
401 }
402 auto name = std::string_view(args.at("name"));
403 auto state = base::StrToInt64(args.at("state"));
404 auto cpu = base::StrToUInt64(args.at("cpu_id"));
405 DataIndex nameIndex = traceDataCache_->GetDataIndex(name);
406 streamFilters_->clockRateFilter_->AppendNewMeasureData(cpu.value(), nameIndex, line.ts, state.value());
407 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_SET_RATE, STAT_EVENT_RECEIVED);
408 return true;
409 }
410
ClockEnableEvent(const ArgsMap & args,const BytraceLine & line) const411 bool BytraceEventParser::ClockEnableEvent(const ArgsMap& args, const BytraceLine& line) const
412 {
413 if (args.empty() || args.size() < MIN_CLOCK_ENABLE_ARGS_COUNT) {
414 TS_LOGD("Failed to parse clock_enable event, no args or args size < 3");
415 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_ENABLE, STAT_EVENT_DATA_INVALID);
416 return false;
417 }
418 auto name = std::string_view(args.at("name"));
419 auto state = base::StrToInt64(args.at("state"));
420 auto cpuId = base::StrToUInt64(args.at("cpu_id"));
421 DataIndex nameIndex = traceDataCache_->GetDataIndex(name);
422 streamFilters_->clockEnableFilter_->AppendNewMeasureData(cpuId.value(), nameIndex, line.ts, state.value());
423 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_ENABLE, STAT_EVENT_RECEIVED);
424 return true;
425 }
ClockDisableEvent(const ArgsMap & args,const BytraceLine & line) const426 bool BytraceEventParser::ClockDisableEvent(const ArgsMap& args, const BytraceLine& line) const
427 {
428 if (args.empty() || args.size() < MIN_CLOCK_DISABLE_ARGS_COUNT) {
429 TS_LOGD("Failed to parse clock_disable event, no args or args size < 3");
430 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_DISABLE, STAT_EVENT_DATA_INVALID);
431 return false;
432 }
433 auto name = std::string_view(args.at("name"));
434 auto state = base::StrToInt64(args.at("state"));
435 auto cpuId = base::StrToUInt64(args.at("cpu_id"));
436 DataIndex nameIndex = traceDataCache_->GetDataIndex(name);
437 streamFilters_->clockDisableFilter_->AppendNewMeasureData(cpuId.value(), nameIndex, line.ts, state.value());
438 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_DISABLE, STAT_EVENT_RECEIVED);
439 return true;
440 }
441
RegulatorSetVoltageEvent(const ArgsMap & args,const BytraceLine & line) const442 bool BytraceEventParser::RegulatorSetVoltageEvent(const ArgsMap& args, const BytraceLine& line) const
443 {
444 UNUSED(args);
445 UNUSED(line);
446 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_REGULATOR_SET_VOLTAGE, STAT_EVENT_RECEIVED);
447 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_REGULATOR_SET_VOLTAGE, STAT_EVENT_NOTSUPPORTED);
448 return true;
449 }
RegulatorSetVoltageCompleteEvent(const ArgsMap & args,const BytraceLine & line) const450 bool BytraceEventParser::RegulatorSetVoltageCompleteEvent(const ArgsMap& args, const BytraceLine& line) const
451 {
452 UNUSED(args);
453 UNUSED(line);
454 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_REGULATOR_SET_VOLTAGE_COMPLETE, STAT_EVENT_RECEIVED);
455 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_REGULATOR_SET_VOLTAGE_COMPLETE,
456 STAT_EVENT_NOTSUPPORTED);
457 return true;
458 }
RegulatorDisableEvent(const ArgsMap & args,const BytraceLine & line) const459 bool BytraceEventParser::RegulatorDisableEvent(const ArgsMap& args, const BytraceLine& line) const
460 {
461 UNUSED(args);
462 UNUSED(line);
463 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_REGULATOR_DISABLE, STAT_EVENT_RECEIVED);
464 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_REGULATOR_DISABLE, STAT_EVENT_NOTSUPPORTED);
465 return true;
466 }
RegulatorDisableCompleteEvent(const ArgsMap & args,const BytraceLine & line) const467 bool BytraceEventParser::RegulatorDisableCompleteEvent(const ArgsMap& args, const BytraceLine& line) const
468 {
469 UNUSED(args);
470 UNUSED(line);
471 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_REGULATOR_DISABLE_COMPLETE, STAT_EVENT_RECEIVED);
472 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_REGULATOR_DISABLE_COMPLETE, STAT_EVENT_NOTSUPPORTED);
473 return true;
474 }
475
IpiEntryEvent(const ArgsMap & args,const BytraceLine & line) const476 bool BytraceEventParser::IpiEntryEvent(const ArgsMap& args, const BytraceLine& line) const
477 {
478 UNUSED(args);
479 UNUSED(line);
480 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IPI_ENTRY, STAT_EVENT_RECEIVED);
481 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IPI_ENTRY, STAT_EVENT_NOTSUPPORTED);
482 return true;
483 }
IpiExitEvent(const ArgsMap & args,const BytraceLine & line) const484 bool BytraceEventParser::IpiExitEvent(const ArgsMap& args, const BytraceLine& line) const
485 {
486 UNUSED(args);
487 UNUSED(line);
488 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IPI_EXIT, STAT_EVENT_RECEIVED);
489 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IPI_EXIT, STAT_EVENT_NOTSUPPORTED);
490 return true;
491 }
IrqHandlerEntryEvent(const ArgsMap & args,const BytraceLine & line) const492 bool BytraceEventParser::IrqHandlerEntryEvent(const ArgsMap& args, const BytraceLine& line) const
493 {
494 if (args.empty() || args.size() < MIN_IRQ_HANDLER_ENTRY_ARGS_COUNT) {
495 TS_LOGD("Failed to parse irq_handler_entry event, no args or args size < 2");
496 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_ENTRY, STAT_EVENT_DATA_INVALID);
497 return false;
498 }
499 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_ENTRY, STAT_EVENT_RECEIVED);
500 auto name = std::string_view(args.at("name"));
501 streamFilters_->irqFilter_->IrqHandlerEntry(line.ts, line.cpu, traceDataCache_->GetDataIndex(name));
502 return true;
503 }
IrqHandlerExitEvent(const ArgsMap & args,const BytraceLine & line) const504 bool BytraceEventParser::IrqHandlerExitEvent(const ArgsMap& args, const BytraceLine& line) const
505 {
506 if (args.empty() || args.size() < MIN_IRQ_HANDLER_EXIT_ARGS_COUNT) {
507 TS_LOGD("Failed to parse irq_handler_exit event, no args or args size < 2");
508 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_EXIT, STAT_EVENT_DATA_INVALID);
509 return false;
510 }
511 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_EXIT, STAT_EVENT_RECEIVED);
512 uint32_t ret = (args.at("ret") == "handled") ? 1 : 0;
513 streamFilters_->irqFilter_->IrqHandlerExit(line.ts, line.cpu, ret);
514 return true;
515 }
SoftIrqRaiseEvent(const ArgsMap & args,const BytraceLine & line) const516 bool BytraceEventParser::SoftIrqRaiseEvent(const ArgsMap& args, const BytraceLine& line) const
517 {
518 UNUSED(args);
519 UNUSED(line);
520 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_RAISE, STAT_EVENT_RECEIVED);
521 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_RAISE, STAT_EVENT_NOTSUPPORTED);
522 return true;
523 }
SoftIrqEntryEvent(const ArgsMap & args,const BytraceLine & line) const524 bool BytraceEventParser::SoftIrqEntryEvent(const ArgsMap& args, const BytraceLine& line) const
525 {
526 if (args.empty() || args.size() < MIN_SOFTIRQ_ENTRY_ARGS_COUNT) {
527 TS_LOGD("Failed to parse softirq_entry event, no args or args size < 2");
528 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SOFTIRQ_ENTRY, STAT_EVENT_DATA_INVALID);
529 return false;
530 }
531 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_ENTRY, STAT_EVENT_RECEIVED);
532 auto vec = base::StrToUInt32(args.at("vec"));
533 streamFilters_->irqFilter_->SoftIrqEntry(line.ts, line.cpu, vec.value());
534 return true;
535 }
SoftIrqExitEvent(const ArgsMap & args,const BytraceLine & line) const536 bool BytraceEventParser::SoftIrqExitEvent(const ArgsMap& args, const BytraceLine& line) const
537 {
538 if (args.empty() || args.size() < MIN_SOFTIRQ_EXIT_ARGS_COUNT) {
539 TS_LOGD("Failed to parse softirq_exit event, no args or args size < 2");
540 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_DATA_INVALID);
541 return false;
542 }
543 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_RECEIVED);
544 auto vec = base::StrToUInt32(args.at("vec"));
545 streamFilters_->irqFilter_->SoftIrqExit(line.ts, line.cpu, vec.value());
546 return true;
547 }
548
BinderTransaction(const ArgsMap & args,const BytraceLine & line) const549 bool BytraceEventParser::BinderTransaction(const ArgsMap& args, const BytraceLine& line) const
550 {
551 if (args.empty() || args.size() < MIN_BINDER_TRANSACTION_ARGS_COUNT) {
552 TS_LOGD("Failed to parse binder_transaction event, no args or args size < 7");
553 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION, STAT_EVENT_DATA_INVALID);
554 return false;
555 }
556 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION, STAT_EVENT_RECEIVED);
557 auto transactionId = base::StrToInt64(args.at("transaction"));
558 auto destNode = base::StrToUInt32(args.at("dest_node"));
559 auto destProc = base::StrToUInt32(args.at("dest_proc"));
560 auto destThread = base::StrToUInt32(args.at("dest_thread"));
561 auto isReply = base::StrToUInt32(args.at("reply"));
562 auto flags = base::StrToUInt32(args.at("flags"), base::INTEGER_RADIX_TYPE_HEX);
563 auto codeStr = base::StrToUInt32(args.at("code"), base::INTEGER_RADIX_TYPE_HEX);
564 TS_LOGD("ts:%lu, pid:%u, destNode:%u, destTgid:%u, destTid:%u, transactionId:%lu, isReply:%u flags:%u, code:%u",
565 line.ts, line.pid, destNode.value(), destProc.value(), destThread.value(), transactionId.value(),
566 isReply.value(), flags.value(), codeStr.value());
567 streamFilters_->binderFilter_->SendTraction(line.ts, line.pid, transactionId.value(), destNode.value(),
568 destProc.value(), destThread.value(), isReply.value(), flags.value(),
569 codeStr.value());
570 return true;
571 }
BinderTransactionReceived(const ArgsMap & args,const BytraceLine & line) const572 bool BytraceEventParser::BinderTransactionReceived(const ArgsMap& args, const BytraceLine& line) const
573 {
574 if (args.empty() || args.size() < MIN_BINDER_TRANSACTION_RECEIVED_ARGS_COUNT) {
575 TS_LOGD("Failed to parse binder_transaction_received event, no args or args size < 1");
576 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_RECEIVED, STAT_EVENT_DATA_INVALID);
577 return false;
578 }
579 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_RECEIVED, STAT_EVENT_RECEIVED);
580 auto transactionId = base::StrToInt64(args.at("transaction"));
581 streamFilters_->binderFilter_->ReceiveTraction(line.ts, line.pid, transactionId.value());
582 TS_LOGD("ts:%lu, pid:%u, transactionId:%lu", line.ts, line.pid, transactionId.value());
583 return true;
584 }
BinderTransactionAllocBufEvent(const ArgsMap & args,const BytraceLine & line) const585 bool BytraceEventParser::BinderTransactionAllocBufEvent(const ArgsMap& args, const BytraceLine& line) const
586 {
587 if (args.empty() || args.size() < MIN_BINDER_TRANSACTION_ALLOC_BUF_ARGS_COUNT) {
588 TS_LOGD("Failed to parse binder_transaction_alloc_buf event, no args or args size < 3");
589 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_ALLOC_BUF, STAT_EVENT_DATA_INVALID);
590 return false;
591 }
592 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_ALLOC_BUF, STAT_EVENT_RECEIVED);
593 auto dataSize = base::StrToUInt64(args.at("data_size"));
594 auto offsetsSize = base::StrToUInt64(args.at("offsets_size"));
595 streamFilters_->binderFilter_->TransactionAllocBuf(line.ts, line.pid, dataSize.value(), offsetsSize.value());
596 TS_LOGD("dataSize:%lu, offsetSize:%lu", dataSize.value(), offsetsSize.value());
597 return true;
598 }
ParseDataItem(const BytraceLine & line)599 void BytraceEventParser::ParseDataItem(const BytraceLine& line)
600 {
601 eventList_.push_back(std::move(std::make_unique<EventInfo>(line.ts, std::move(line))));
602 return;
603 }
GetDataSegArgs(BytraceLine & bufLine,ArgsMap & args,uint32_t & tgid) const604 void BytraceEventParser::GetDataSegArgs(BytraceLine& bufLine, ArgsMap& args, uint32_t& tgid) const
605 {
606 if (bufLine.tGidStr.at(0) != '-') {
607 tgid = base::StrToUInt32(bufLine.tGidStr).value_or(0);
608 } else {
609 tgid = 0;
610 }
611
612 for (base::PartingString ss(bufLine.argsStr, ' '); ss.Next();) {
613 std::string key;
614 std::string value;
615 if (!(std::string(ss.GetCur()).find("=") != std::string::npos)) {
616 key = "name";
617 value = ss.GetCur();
618 args.emplace(std::move(key), std::move(value));
619 continue;
620 }
621 for (base::PartingString inner(ss.GetCur(), '='); inner.Next();) {
622 if (key.empty()) {
623 key = inner.GetCur();
624 } else {
625 value = inner.GetCur();
626 }
627 }
628 args.emplace(std::move(key), std::move(value));
629 }
630 }
FilterAllEventsTemp()631 void BytraceEventParser::FilterAllEventsTemp()
632 {
633 size_t maxBuffSize = 1000 * 1000;
634 size_t maxQueue = 2;
635 if (eventList_.size() < maxBuffSize * maxQueue) {
636 return;
637 }
638 auto cmp = [](const std::unique_ptr<EventInfo>& a, const std::unique_ptr<EventInfo>& b) {
639 return a->eventTimestamp < b->eventTimestamp;
640 };
641 std::sort(eventList_.begin(), eventList_.end(), cmp);
642 auto endOfList = eventList_.begin() + maxBuffSize;
643 for (auto itor = eventList_.begin(); itor != endOfList; itor++) {
644 EventInfo* event = itor->get();
645 auto it = eventToFunctionMap_.find(event->line.eventName);
646 if (it != eventToFunctionMap_.end()) {
647 uint32_t tgid;
648 ArgsMap args;
649 GetDataSegArgs(event->line, args, tgid);
650 if (tgid) {
651 streamFilters_->processFilter_->UpdateOrCreateThreadWithPidAndName(event->line.pid, tgid,
652 event->line.task);
653 } else {
654 // When tgid is zero, only use tid create thread
655 streamFilters_->processFilter_->GetOrCreateThreadWithPid(event->line.pid, tgid);
656 }
657 if (it->second(args, event->line)) {
658 traceDataCache_->UpdateTraceTime(event->line.ts);
659 }
660 } else {
661 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_NOTSUPPORTED);
662 TS_LOGW("UnRecognizable event name:%s", event->line.eventName.c_str());
663 }
664 itor->reset();
665 }
666 eventList_.erase(eventList_.begin(), endOfList);
667 }
668
FilterAllEvents()669 void BytraceEventParser::FilterAllEvents()
670 {
671 auto cmp = [](const std::unique_ptr<EventInfo>& a, const std::unique_ptr<EventInfo>& b) {
672 return a->eventTimestamp < b->eventTimestamp;
673 };
674 std::sort(eventList_.begin(), eventList_.end(), cmp);
675 size_t maxBuffSize = 1000 * 1000;
676 while (eventList_.size()) {
677 int size = std::min(maxBuffSize, eventList_.size());
678 auto endOfList = eventList_.begin() + size;
679 for (auto itor = eventList_.begin(); itor != endOfList; itor++) {
680 EventInfo* event = itor->get();
681 BeginFilterEvents(event);
682 itor->reset();
683 }
684 eventList_.erase(eventList_.begin(), endOfList);
685 }
686 eventList_.clear();
687 streamFilters_->cpuFilter_->Finish();
688 traceDataCache_->dataDict_.Finish();
689 traceDataCache_->UpdataZeroThreadInfo();
690 }
691
BeginFilterEvents(EventInfo * event)692 void BytraceEventParser::BeginFilterEvents(EventInfo* event)
693 {
694 auto it = eventToFunctionMap_.find(event->line.eventName);
695 if (it != eventToFunctionMap_.end()) {
696 uint32_t tgid;
697 ArgsMap args;
698 GetDataSegArgs(event->line, args, tgid);
699 if (tgid) {
700 streamFilters_->processFilter_->UpdateOrCreateThreadWithPidAndName(event->line.pid, tgid, event->line.task);
701 } else {
702 // When tgid is zero, only use tid create thread
703 streamFilters_->processFilter_->GetOrCreateThreadWithPid(event->line.pid, tgid);
704 }
705 if (it->second(args, event->line)) {
706 traceDataCache_->UpdateTraceTime(event->line.ts);
707 }
708 } else {
709 traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_NOTSUPPORTED);
710 TS_LOGW("UnRecognizable event name:%s", event->line.eventName.c_str());
711 }
712 }
713
Clear() const714 void BytraceEventParser::Clear() const
715 {
716 streamFilters_->binderFilter_->Clear();
717 streamFilters_->sliceFilter_->Clear();
718 streamFilters_->cpuFilter_->Clear();
719 streamFilters_->irqFilter_->Clear();
720 streamFilters_->cpuMeasureFilter_->Clear();
721 streamFilters_->threadMeasureFilter_->Clear();
722 streamFilters_->threadFilter_->Clear();
723 streamFilters_->processMeasureFilter_->Clear();
724 streamFilters_->processFilterFilter_->Clear();
725 streamFilters_->clockEnableFilter_->Clear();
726 streamFilters_->clockDisableFilter_->Clear();
727 streamFilters_->clkRateFilter_->Clear();
728 streamFilters_->clkDisableFilter_->Clear();
729 streamFilters_->binderFilter_->Clear();
730 }
731 } // namespace TraceStreamer
732 } // namespace SysTuning
733