1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
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 #include <iomanip>
16 #include <iostream>
17 #include <future>
18 #include <climits>
19 #include <sstream>
20 #include <charconv>
21 #include "ffrt_converter.h"
22
23 namespace SysTuning {
24 namespace TraceStreamer {
25 constexpr uint64_t INITIAL_TEXT_LINE_NUM = 2000000;
26 constexpr uint64_t MAX_MOCK_TID = 4294967295;
27 constexpr size_t BUFFER_SIZE = 1024 * 1024; // 1MB buffer
28
29 using PidMap = std::unordered_map<int, std::set<int>>;
30 using FfrtTidMap = std::unordered_map<int, std::pair<std::string, std::vector<int>>>;
31 using FfrtPids = std::unordered_map<int, FfrtTidMap>;
32 using WakeLogs = std::unordered_map<int, std::vector<int>>;
33 using FfrtWakeLogs = std::unordered_map<int, WakeLogs>;
34 using Info = const std::pair<int, std::set<int>>;
35 using ConVecStr = const std::vector<std::string>;
36
WriteOutputFile(std::ofstream & outfile,std::vector<std::string> & context_)37 static bool WriteOutputFile(std::ofstream &outfile, std::vector<std::string> &context_)
38 {
39 if (!outfile.is_open()) {
40 TS_LOGE("outFile is invalid.");
41 return false;
42 }
43
44 std::vector<char> file_buffer(BUFFER_SIZE);
45 outfile.rdbuf()->pubsetbuf(file_buffer.data(), file_buffer.size());
46
47 for (const auto& line : context_) {
48 outfile.write(line.c_str(), line.size());
49 outfile.put('\n');
50 }
51
52 outfile.close();
53 context_.clear();
54 return true;
55 }
56
RecoverTraceAndGenerateNewFile(ConStr & ffrtFileName,std::ofstream & outFile)57 bool FfrtConverter::RecoverTraceAndGenerateNewFile(ConStr &ffrtFileName, std::ofstream &outFile)
58 {
59 std::ifstream ffrtFile(ffrtFileName);
60 if (!ffrtFile.is_open() || !outFile.is_open()) {
61 TS_LOGE("ffrtFile or outFile is invalid.");
62 return false;
63 }
64
65 // reserve initial line size
66 context_.reserve(INITIAL_TEXT_LINE_NUM);
67 std::string line;
68 while (std::getline(ffrtFile, line)) {
69 context_.emplace_back(line);
70 }
71 ffrtFile.close();
72
73 FfrtPids ffrtPids;
74 FfrtWakeLogs ffrtWakeLogs;
75 ClassifyLogsForFfrtWorker(ffrtPids, ffrtWakeLogs);
76
77 if (tracingMarkerKey_.empty()) {
78 tracingMarkerKey_ = "tracing_mark_write: ";
79 }
80
81 if (osPlatformKet_ == "ohos") {
82 ConvertFrrtThreadToFfrtTaskOhos(ffrtPids, ffrtWakeLogs);
83 } else {
84 ConvertFrrtThreadToFfrtTaskNohos(ffrtPids, ffrtWakeLogs);
85 }
86
87 return WriteOutputFile(outFile, context_);
88 }
89
ExtractProcessId(ConStr & log)90 static uint32_t ExtractProcessId(ConStr& log)
91 {
92 size_t leftParen = log.find('(');
93 size_t rightParen = log.find(')', leftParen);
94 if (leftParen == std::string::npos || rightParen == std::string::npos || leftParen >= rightParen) {
95 return 0;
96 }
97
98 std::string processIdStr = log.substr(leftParen + 1, rightParen - leftParen - 1);
99 processIdStr.erase(0, processIdStr.find_first_not_of(" \t"));
100 size_t lastNonSpace = processIdStr.find_last_not_of(" \t");
101 if (lastNonSpace != std::string::npos) {
102 processIdStr.erase(lastNonSpace + 1);
103 }
104
105 if (processIdStr.find('-') != std::string::npos || processIdStr.empty()) {
106 return 0;
107 }
108
109 uint32_t processId = 0;
110 const int base = 10;
111 for (char c : processIdStr) {
112 if (!std::isdigit(c)) {
113 return 0;
114 }
115 processId = processId * base + (static_cast<int>(c) - static_cast<int>('0'));
116 if (processId > UINT32_MAX) {
117 return 0;
118 }
119 }
120 return processId;
121 }
122
ExtractThreadId(ConStr & log)123 static int ExtractThreadId(ConStr& log)
124 {
125 static const std::regex pattern(R"( \(\s*\d+\)\s+\[\d)");
126 std::smatch match;
127 if (std::regex_search(log, match, pattern)) {
128 std::string prefix = log.substr(0, match.position());
129 return std::stoull(prefix.substr(prefix.find_last_of('-') + 1));
130 }
131 return INT_MAX;
132 }
133
TrimRight(ConStr & str)134 static std::string TrimRight(ConStr& str)
135 {
136 auto end = std::find_if_not(str.rbegin(), str.rend(), [](unsigned char ch) {
137 return std::isspace(ch);
138 }).base();
139
140 return std::string(str.begin(), end);
141 }
142
ExtraceFfrtThreadInfoFromSchedSwitch(ConStr & log,std::string & tName,int & tid)143 static void ExtraceFfrtThreadInfoFromSchedSwitch(ConStr &log, std::string &tName, int& tid)
144 {
145 static std::string prevComm = "prev_comm";
146 static std::string prevPid = "prev_pid=";
147 size_t prevCommPos = log.find(prevComm);
148 size_t prevPidPos = log.find(prevPid);
149 if (prevCommPos != std::string::npos && prevPidPos != std::string::npos) {
150 if (prevCommPos < prevPidPos) {
151 std::string containName = log.substr(prevCommPos, prevPidPos - prevCommPos);
152 size_t tNameStartIndex = containName.find_first_of("=") + 1;
153 tName = containName.substr(tNameStartIndex, containName.size() - tNameStartIndex);
154 size_t startPos = prevPidPos + prevComm.size();
155 size_t tidLen = log.find(" ", prevPidPos) - prevPidPos - prevPid.size();
156 tid = std::stoull(log.substr(startPos, tidLen));
157 }
158 } else {
159 tName = "";
160 tid = -1;
161 }
162 }
163
ExtractTimeStr(ConStr & log)164 static std::string ExtractTimeStr(ConStr &log)
165 {
166 std::smatch match;
167 static const int spaceNum = 2;
168 static const std::regex timePattern = std::regex(R"( (\d+)\.(\d+):)");
169 if (std::regex_search(log, match, timePattern)) {
170 return match.str().substr(1, match.str().size() - spaceNum);
171 }
172 return "";
173 }
174
ExtractCpuId(ConStr & log)175 static std::string ExtractCpuId(ConStr &log)
176 {
177 std::smatch match;
178 static const int spaceNum = 3;
179 static const std::regex cpuidpattern = std::regex(R"(\) \[.*?\])");
180 if (std::regex_search(log, match, cpuidpattern)) {
181 return log.substr(match.position() + spaceNum, spaceNum);
182 }
183 return "";
184 }
185
ExtractTaskLable(ConStr & log)186 static std::string ExtractTaskLable(ConStr& log)
187 {
188 size_t pos = log.find("|H:FFRT");
189 if (pos != std::string::npos) { // ohos
190 size_t startPos = pos + std::string("|H:FFRT").length();
191 size_t endPos = log.find("|", startPos);
192 if (endPos != std::string::npos) {
193 return log.substr(startPos, endPos - startPos);
194 }
195 } else {
196 size_t startPos = log.find_last_of("[");
197 size_t endPos = log.find("]", startPos);
198 if (startPos != std::string::npos && endPos != std::string::npos) {
199 return log.substr(startPos + 1, endPos - startPos - 1);
200 }
201 }
202 return ""; // Return empty string if no label found
203 }
204
FindPrevAndNextPidForSchedSwitch(ConStr & log,int & prevPid,int & nextPid)205 static void FindPrevAndNextPidForSchedSwitch(ConStr &log, int &prevPid, int &nextPid)
206 {
207 static std::string prevPidStr = "prev_pid=";
208 static std::string nextPidStr = "next_pid=";
209 size_t prevPidPos = log.find(prevPidStr);
210 size_t nextPidPos = log.find(nextPidStr);
211 size_t startPos = prevPidPos + prevPidStr.size();
212 size_t pidLen = log.find(" ", prevPidPos) - prevPidPos - (prevPidStr.size() - 1);
213 prevPid = std::stoull(log.substr(startPos, pidLen));
214 startPos = nextPidPos + nextPidStr.size();
215 pidLen = log.find(" ", nextPidPos) - nextPidPos - (nextPidStr.size() - 1);
216 nextPid = std::stoull(log.substr(startPos, pidLen));
217 }
218
SetOSPlatformKey(const FfrtTidMap & ffrtTidMap)219 void FfrtConverter::SetOSPlatformKey(const FfrtTidMap &ffrtTidMap)
220 {
221 for (const auto& tinfo : ffrtTidMap) {
222 if (tinfo.second.first.find("ffrtwk") != std::string::npos) {
223 osPlatformKet_ = "nohos";
224 return;
225 }
226 if (tinfo.second.first.find("OS_FFRT_") != std::string::npos) {
227 osPlatformKet_ = "ohos";
228 return;
229 }
230 }
231 }
232
PushProcessNamePositions(ConStr & log,size_t & hyphenPos,size_t & spacePos,std::vector<size_t> & indexs)233 static void PushProcessNamePositions(ConStr &log, size_t &hyphenPos, size_t &spacePos, std::vector<size_t> &indexs)
234 {
235 bool allDigits = true;
236 for (size_t i = hyphenPos + 1; i < spacePos; ++i) {
237 if (!isdigit(log[i])) {
238 allDigits = false;
239 break;
240 }
241 }
242
243 if (allDigits && spacePos > hyphenPos + 1) {
244 bool foundStart = false;
245 size_t start = hyphenPos;
246 while (start > 0) {
247 if (isspace(log[start - 1])) {
248 foundStart = true;
249 break;
250 }
251 --start;
252 }
253 if (foundStart || start == 0) {
254 indexs.push_back(start);
255 }
256 }
257 }
258
FindProcessNamePositions(ConStr & log,std::vector<size_t> & indexs)259 static void FindProcessNamePositions(ConStr &log, std::vector<size_t> &indexs)
260 {
261 size_t pos = 0;
262 const size_t logLength = log.length();
263 while (pos < logLength) {
264 size_t hyphenPos = log.find('-', pos);
265 if (hyphenPos == std::string::npos) {
266 break;
267 }
268
269 size_t spacePos = hyphenPos + 1;
270 while (spacePos < logLength && !isspace(log[spacePos])) {
271 spacePos++;
272 }
273 if (spacePos < logLength && isspace(log[spacePos])) {
274 size_t bracketPos = spacePos;
275 while (bracketPos < logLength && isspace(log[bracketPos])) {
276 bracketPos++;
277 }
278 if (bracketPos < logLength && log[bracketPos] == '(') {
279 PushProcessNamePositions(log, hyphenPos, spacePos, indexs);
280 }
281 }
282 pos = hyphenPos + 1;
283 }
284 }
285
SplitLogs(std::vector<size_t> & indexs,std::vector<std::string> & newLogs,ConStr & log)286 static void SplitLogs(std::vector<size_t> &indexs, std::vector<std::string> &newLogs, ConStr& log)
287 {
288 for (int i = 0; i < indexs.size(); i++) {
289 int begin = indexs[i];
290 int end = (i + 1 < indexs.size()) ? indexs[i + 1] : static_cast<int>(log.size());
291 std::string logSplit = log.substr(begin, end - begin);
292 if (i + 1 < indexs.size()) {
293 logSplit += "\n";
294 }
295 newLogs.emplace_back(logSplit);
296 }
297 }
298
GenFfrtPids(FfrtPids & ffrtPids,Info & info,FfrtTidMap & ffrtTidMap,WakeLogs & traceMap)299 static void GenFfrtPids(FfrtPids& ffrtPids, Info &info, FfrtTidMap &ffrtTidMap, WakeLogs &traceMap)
300 {
301 for (const auto tid : info.second) {
302 if (ffrtTidMap.find(tid) != ffrtTidMap.end()) {
303 if (ffrtPids.find(info.first) == ffrtPids.end()) {
304 ffrtPids[info.first] = {};
305 }
306 ffrtPids[info.first][tid] = ffrtTidMap[tid];
307 ffrtPids[info.first][tid].second = traceMap[tid];
308 }
309 }
310 }
311
IsOldVersionTrace(ConStr & log)312 bool IsOldVersionTrace(ConStr &log)
313 {
314 static const std::string fPattern = " F|";
315 static const std::string hCo = "|H:Co";
316
317 size_t fPos = log.find(fPattern);
318 if (fPos == std::string::npos) {
319 return false;
320 }
321 size_t hCoPos = log.find(hCo, fPos + fPattern.size());
322 if (hCoPos != std::string::npos && hCoPos > fPos + fPattern.size()) {
323 bool valid = true;
324 std::string numStr = log.substr(fPos + fPattern.size(), hCoPos - fPos - fPattern.size());
325 int num = 0;
326 auto [ptr, ec] = std::from_chars(numStr.data(), numStr.data() + numStr.size(), num);
327 if (ec != std::errc{}) {
328 valid = false;
329 }
330 if (!valid) {
331 return false;
332 }
333 size_t afterCo = hCoPos + hCo.size();
334 while (afterCo < log.length() && isspace(log[afterCo])) {
335 ++afterCo;
336 }
337 if (afterCo < log.length() && isdigit(log[afterCo])) {
338 return true;
339 }
340 }
341 return false;
342 }
343
ClassifyLogsForFfrtWorker(FfrtPids & ffrtPids,FfrtWakeLogs & ffrtWakeLogs)344 void FfrtConverter::ClassifyLogsForFfrtWorker(FfrtPids& ffrtPids, FfrtWakeLogs& ffrtWakeLogs)
345 {
346 PidMap pidMap;
347 FfrtTidMap ffrtTidMap;
348 WakeLogs traceMap;
349 const size_t estimatedSize = context_.size();
350 const size_t oneHundred = 100;
351 const size_t fifty = 50;
352 const size_t ten = 10;
353 pidMap.reserve(estimatedSize / oneHundred);
354 ffrtTidMap.reserve(estimatedSize / fifty);
355 traceMap.reserve(estimatedSize / fifty);
356 #ifdef MUL_THREAD_EXEC
357 std::mutex pidMutex;
358 std::mutex tidMutex;
359 std::mutex traceMutex;
360 std::mutex contextMutex;
361 const size_t numThreads = std::thread::hardware_concurrency();
362 const size_t chunkSize = context_.size() / numThreads + 1;
363 std::vector<std::thread> threads;
364 threads.reserve(numThreads);
365 std::vector<std::vector<ContextUpdate>> threadUpdates(numThreads);
366
367 auto worker = [&](size_t threadId, size_t start, size_t end) {
368 std::vector<size_t> indexs;
369 indexs.reserve(10);
370 std::unordered_map<int, std::set<int>> localPidMap;
371 std::unordered_map<int, std::pair<std::string, std::vector<int>>> locFfrtTidMap;
372 std::unordered_map<int, std::vector<int>> locTraceMap;
373 std::vector<ContextUpdate>& updates = threadUpdates[threadId];
374
375 for (size_t lineno = start; lineno < end && lineno < context_.size(); ++lineno) {
376 const std::string& log = context_[lineno];
377 indexs.clear();
378 FindProcessNamePositions(log, indexs);
379
380 if (indexs.size() > 1) {
381 ContextUpdate update;
382 update.position = lineno;
383 for (size_t i = 0; i < indexs.size(); ++i) {
384 int begin = indexs[i];
385 end = (i + 1 < indexs.size()) ? indexs[i + 1] : static_cast<int>(log.size());
386 std::string logSplit = log.substr(begin, end - begin);
387 if (i + 1 < indexs.size()) {
388 logSplit += "\n";
389 }
390 update.new_logs.push_back(logSplit);
391 }
392 updates.push_back(update);
393 for (size_t i = 0; i < update.new_logs.size(); ++i) {
394 auto logInfo = LogInfo{update.new_logs[i], static_cast<int>(lineno + i), 0, 0};
395 FindFfrtProcClassifyLogs(logInfo, locTraceMap, localPidMap, locFfrtTidMap, ffrtWakeLogs);
396 }
397 } else {
398 auto logInfo = LogInfo{log, static_cast<int>(lineno), 0, 0};
399 FindFfrtProcClassifyLogs(logInfo, locTraceMap, localPidMap, locFfrtTidMap, ffrtWakeLogs);
400 }
401 }
402 {
403 std::lock_guard<std::mutex> lock(pidMutex);
404 for (const auto& [pid, tid_set] : localPidMap) {
405 pidMap[pid].insert(tid_set.begin(), tid_set.end());
406 }
407 }
408 {
409 std::lock_guard<std::mutex> lock(tidMutex);
410 for (const auto& [tid, info] : locFfrtTidMap) {
411 if (ffrtTidMap.find(tid) == ffrtTidMap.end()) {
412 ffrtTidMap[tid] = info;
413 }
414 }
415 }
416 {
417 std::lock_guard<std::mutex> lock(traceMutex);
418 for (const auto& [tid, traces] : locTraceMap) {
419 auto& target = traceMap[tid];
420 target.insert(target.end(), traces.begin(), traces.end());
421 }
422 }
423 };
424 for (size_t i = 0; i < numThreads; ++i) {
425 std::lock_guard<std::mutex> lock(contextMutex);
426 size_t start = i * chunkSize;
427 size_t end = std::min((i + 1) * chunkSize, context_.size());
428 threads.emplace_back(worker, i, start, end);
429 }
430 for (auto& thread : threads) {
431 thread.join();
432 }
433 std::vector<ContextUpdate> allUpdates;
434 for (const auto& threadUpdate : threadUpdates) {
435 allUpdates.insert(allUpdates.end(), threadUpdate.begin(), threadUpdate.end());
436 }
437 std::sort(allUpdates.begin(), allUpdates.end(),
438 [](const ContextUpdate& a, const ContextUpdate& b) {
439 return a.position > b.position;
440 });
441 for (const auto& update : allUpdates) {
442 context_.erase(context_.begin() + update.position);
443 context_.insert(context_.begin() + update.position,
444 update.new_logs.begin(), update.new_logs.end());
445 }
446 #else
447 uint64_t lineno = 0;
448 bool shouldCheck = true;
449 std::vector<size_t> indexs;
450 indexs.reserve(ten);
451 auto classifyLogs = [this, &traceMap, &pidMap, &ffrtTidMap, &ffrtWakeLogs](ConVecStr& newLogs, size_t startLineNo) {
452 for (size_t i = 0; i < newLogs.size(); ++i) {
453 auto logInfo = LogInfo{context_[startLineNo + i], static_cast<int>(startLineNo + i), 0, 0};
454 FindFfrtProcClassifyLogs(logInfo, traceMap, pidMap, ffrtTidMap, ffrtWakeLogs);
455 }
456 };
457 while (lineno < context_.size()) {
458 ConStr& log = context_[lineno];
459 indexs.clear();
460 FindProcessNamePositions(log, indexs);
461 if (shouldCheck && IsOldVersionTrace(log)) {
462 this->isOldVersionTrace_ = true;
463 shouldCheck = false;
464 }
465 if (indexs.size() > 1) {
466 std::vector<std::string> newLogs;
467 SplitLogs(indexs, newLogs, log);
468 context_.erase(context_.begin() + lineno);
469 context_.insert(context_.begin() + lineno, newLogs.begin(), newLogs.end());
470 classifyLogs(newLogs, lineno);
471 lineno += newLogs.size() - 1;
472 } else {
473 auto logInfo = LogInfo{context_[lineno], static_cast<int>(lineno), 0, 0};
474 FindFfrtProcClassifyLogs(logInfo, traceMap, pidMap, ffrtTidMap, ffrtWakeLogs);
475 }
476 ++lineno;
477 }
478 #endif
479 SetOSPlatformKey(ffrtTidMap);
480 for (auto& info : pidMap) {
481 GenFfrtPids(ffrtPids, info, ffrtTidMap, traceMap);
482 }
483 }
484
FindPatternStart(ConStr & log)485 static size_t FindPatternStart(ConStr &log)
486 {
487 size_t pos = 0;
488 while (pos < log.size()) {
489 pos = log.find(" (", pos);
490 if (pos == std::string::npos) {
491 return std::string::npos;
492 }
493
494 size_t rightBracket = log.find(')', pos + 2);
495 if (rightBracket == std::string::npos) {
496 return std::string::npos;
497 }
498
499 size_t bracketEnd = rightBracket + 1;
500 while (bracketEnd < log.length() && isspace(log[bracketEnd])) {
501 ++bracketEnd;
502 }
503
504 if (bracketEnd < log.length() &&
505 log[bracketEnd] == '[' &&
506 bracketEnd + 1 < log.length() &&
507 isdigit(log[bracketEnd + 1])) {
508 return pos;
509 }
510 pos = rightBracket + 1;
511 }
512 return std::string::npos;
513 }
514
FindPatternEnd(ConStr & log)515 static size_t FindPatternEnd(ConStr &log)
516 {
517 size_t pos = 0;
518 static std::string hr = "H:R";
519 while (pos < log.size()) {
520 pos = log.find(" F|", pos);
521 if (pos == std::string::npos) {
522 return std::string::npos;
523 }
524
525 size_t numStart = pos + 3;
526 size_t pipePos = log.find('|', numStart);
527 if (pipePos == std::string::npos) {
528 pos = numStart;
529 continue;
530 }
531
532 bool validNum = true;
533 for (size_t i = numStart; i < pipePos; ++i) {
534 if (!isdigit(log[i])) {
535 validNum = false;
536 break;
537 }
538 }
539 if (!validNum || numStart == pipePos) {
540 pos = pipePos + 1;
541 continue;
542 }
543
544 size_t rPos = pipePos + 1;
545 if (rPos + hr.size() - 1 < log.length() && log.substr(rPos, hr.size()) == hr) {
546 rPos += hr.size();
547 } else if (rPos < log.length() && log[rPos] == 'R') {
548 rPos += 1;
549 } else {
550 pos = pipePos + 1;
551 continue;
552 }
553
554 if (rPos < log.length() && (log[rPos] == '|' || isspace(log[rPos]))) {
555 size_t finalNum = rPos + 1;
556 while (finalNum < log.length() && isspace(log[finalNum])) {
557 finalNum++;
558 }
559
560 if (finalNum < log.length() && isdigit(log[finalNum])) {
561 return pos;
562 }
563 }
564 pos = rPos;
565 }
566 return std::string::npos;
567 }
568
ParseOtherTraceLogs(LogInfo logInfo,WakeLogs & traceMap,FfrtWakeLogs & ffrtWakeLogs)569 static void ParseOtherTraceLogs(LogInfo logInfo, WakeLogs &traceMap, FfrtWakeLogs &ffrtWakeLogs)
570 {
571 size_t matchPos = FindPatternStart(logInfo.log);
572 if (matchPos != std::string::npos) {
573 std::string tmp = logInfo.log.substr(0, matchPos);
574 logInfo.tid = std::stoull(tmp.substr(tmp.find_last_of('-') + 1));
575 if (traceMap.find(logInfo.tid) == traceMap.end()) {
576 traceMap[logInfo.tid] = {};
577 }
578 traceMap[logInfo.tid].emplace_back(logInfo.lineno);
579
580 if (FindPatternEnd(logInfo.log) != std::string::npos) {
581 std::string hStr = logInfo.log.substr(logInfo.log.find_last_of('|') + 1);
582 if (hStr[0] == 'H') {
583 hStr = hStr.substr(hStr.find_last_of(' ') + 1);
584 }
585 int wakee = std::stoull(hStr);
586 if (ffrtWakeLogs.find(logInfo.pid) == ffrtWakeLogs.end()) {
587 ffrtWakeLogs[logInfo.pid] = {};
588 }
589 if (ffrtWakeLogs[logInfo.pid].find(wakee) == ffrtWakeLogs[logInfo.pid].end()) {
590 ffrtWakeLogs[logInfo.pid][wakee] = {};
591 }
592 ffrtWakeLogs[logInfo.pid][wakee].emplace_back(logInfo.lineno);
593 }
594 }
595 }
596
SetTracingMarkerKey(LogInfo logInfo)597 void FfrtConverter::SetTracingMarkerKey(LogInfo logInfo)
598 {
599 if (tracingMarkerKey_.empty()) {
600 if (logInfo.log.find("tracing_mark_write: ") != std::string::npos) {
601 tracingMarkerKey_ = "tracing_mark_write: ";
602 } else if (logInfo.log.find("print: ") != std::string::npos) {
603 tracingMarkerKey_ = "print: ";
604 }
605 }
606 }
607
FindFfrtProcClassifyLogs(LogInfo logInfo,WakeLogs & traceMap,PidMap & pidMap,FfrtTidMap & ffrtTidMap,FfrtWakeLogs & ffrtWakeLogs)608 void FfrtConverter::FindFfrtProcClassifyLogs(LogInfo logInfo, WakeLogs &traceMap, PidMap &pidMap,
609 FfrtTidMap &ffrtTidMap, FfrtWakeLogs &ffrtWakeLogs)
610 {
611 bool isPrevCommFfrt = logInfo.log.find("prev_comm=ffrt") != std::string::npos;
612 bool isPrevCommFfrtOs = logInfo.log.find("prev_comm=OS_FFRT") != std::string::npos;
613 auto pid = ExtractProcessId(logInfo.log);
614 auto tid = ExtractThreadId(logInfo.log);
615 if (pidMap.find(pid) == pidMap.end()) {
616 pidMap[pid] = {};
617 }
618 pidMap[pid].insert(tid);
619 if (isPrevCommFfrt || isPrevCommFfrtOs) {
620 std::string tname;
621 ExtraceFfrtThreadInfoFromSchedSwitch(logInfo.log, tname, tid);
622 tname = TrimRight(tname);
623 if (ffrtTidMap.find(tid) == ffrtTidMap.end()) {
624 ffrtTidMap[tid] = {tname, {}};
625 }
626 }
627
628 SetTracingMarkerKey(logInfo);
629
630 if (logInfo.log.find("sched_switch: ") != std::string::npos) {
631 int prevTid;
632 int nextTid;
633 FindPrevAndNextPidForSchedSwitch(logInfo.log, prevTid, nextTid);
634 if (traceMap.find(prevTid) == traceMap.end()) {
635 traceMap[prevTid] = {};
636 }
637 traceMap[prevTid].emplace_back(logInfo.lineno);
638 if (traceMap.find(nextTid) == traceMap.end()) {
639 traceMap[nextTid] = {};
640 }
641 traceMap[nextTid].emplace_back(logInfo.lineno);
642 return;
643 }
644 static std::string pidStr = "pid=";
645 if ((logInfo.log.find("sched_wak") != std::string::npos) ||
646 (logInfo.log.find("sched_blocked_reason: ") != std::string::npos)) {
647 int pidPos = logInfo.log.find(pidStr);
648 int startStr = pidPos + pidStr.size();
649 int tidLen = logInfo.log.find(" ", pidPos) - pidPos - pidStr.size() + 1;
650 tid = std::stoull(logInfo.log.substr(startStr, tidLen));
651 if (traceMap.find(tid) == traceMap.end()) {
652 traceMap[tid] = {};
653 }
654 traceMap[tid].emplace_back(logInfo.lineno);
655 }
656 ParseOtherTraceLogs(LogInfo{logInfo.log, logInfo.lineno, static_cast<int>(pid), tid}, traceMap, ffrtWakeLogs);
657 }
658
IsNumeric(ConStr & str)659 static bool IsNumeric(ConStr &str)
660 {
661 bool result = true;
662 std::for_each(str.begin(), str.end(), [&](char c) {
663 if (!std::isdigit(c)) {
664 result = false;
665 }
666 });
667 return result;
668 }
669
GetQid(ConStr & containQid)670 static int GetQid(ConStr &containQid)
671 {
672 size_t oldPos = 0;
673 size_t newPos = 0;
674 while ((newPos = containQid.find("_", newPos)) != std::string::npos) {
675 std::string qidStr = containQid.substr(oldPos, newPos - oldPos);
676 if (IsNumeric(qidStr)) {
677 return std::stoull(qidStr);
678 }
679 newPos++;
680 oldPos = newPos;
681 }
682 if (oldPos != containQid.size()) {
683 std::string qidStr = containQid.substr(oldPos, containQid.size() - oldPos);
684 if (IsNumeric(qidStr)) {
685 return std::stoull(qidStr);
686 }
687 }
688 return -1;
689 }
690
GenMockTid(int pid,int gid)691 static std::string GenMockTid(int pid, int gid)
692 {
693 std::string mockTid = std::to_string(pid) + "0" + std::to_string(gid);
694 while (std::stoull(mockTid) > MAX_MOCK_TID) {
695 mockTid = mockTid.substr(1);
696 }
697 return mockTid;
698 }
699
MakeCoyieldFakeLog(FakeLogArgs & fakeLogArgs)700 static std::string MakeCoyieldFakeLog(FakeLogArgs &fakeLogArgs)
701 {
702 std::stringstream ss;
703 static const int spaceNum = 7;
704 std::string mockTid = GenMockTid(fakeLogArgs.pid, fakeLogArgs.taskRunning);
705 ss << " " << fakeLogArgs.taskLabel << "-" << mockTid << " (" << std::setw(spaceNum);
706 ss << std::right << fakeLogArgs.pid << ") [" << fakeLogArgs.cpuId << "] .... " << fakeLogArgs.timestamp;
707 ss << ": sched_switch: prev_comm=" << fakeLogArgs.taskLabel << " prev_pid=" << mockTid;
708 ss << " prev_prio=" << fakeLogArgs.prio << " prev_state=S ==> next_comm=" << fakeLogArgs.tname;
709 ss << " next_pid=" << fakeLogArgs.tid << " next_prio=" << fakeLogArgs.prio << "\n";
710 std::string fakeLog = ss.str();
711 return fakeLog;
712 }
713
MakeCostartFakeLog(FakeLogArgs & fakeLogArgs)714 static std::string MakeCostartFakeLog(FakeLogArgs &fakeLogArgs)
715 {
716 std::string mockTid = GenMockTid(fakeLogArgs.pid, fakeLogArgs.taskRunning);
717 std::stringstream ss;
718 static const int spaceNum = 7;
719 ss << fakeLogArgs.log << "\n " << fakeLogArgs.tname << "-" << fakeLogArgs.tid << " (" << std::setw(spaceNum);
720 ss << std::right << fakeLogArgs.pid << ") [" << fakeLogArgs.cpuId << "] .... " << fakeLogArgs.timestamp;
721 ss << ": sched_switch: prev_comm=" << fakeLogArgs.tname << " prev_pid=" << fakeLogArgs.tid << " prev_prio=";
722 ss << fakeLogArgs.prio << " prev_state=S ==> next_comm=" << fakeLogArgs.taskLabel;
723 ss << " next_pid=" << mockTid << " next_prio=" << fakeLogArgs.prio << "\n";
724 return ss.str();
725 }
726
MakeWakeupFakeLog(ConStr & log,const FakeLogArgs & fakeLogArgs,ConStr & tracingMarkerKey)727 static std::string MakeWakeupFakeLog(ConStr &log, const FakeLogArgs &fakeLogArgs, ConStr &tracingMarkerKey)
728 {
729 std::string mockTid = GenMockTid(fakeLogArgs.pid, fakeLogArgs.taskRunning);
730 std::stringstream fakeLogStrm;
731 fakeLogStrm << log.substr(0, log.find(tracingMarkerKey)) << "sched_wakeup: comm=" <<
732 fakeLogArgs.taskLabel << " pid=" << mockTid << " prio=" <<
733 fakeLogArgs.prio << " target_cpu=" << fakeLogArgs.cpuId;
734 return fakeLogStrm.str();
735 }
736
ReplaceSchedSwitchLog(ConStr & fakeLog,LogInfo logInfo,int gid,ConStr & label)737 static std::string ReplaceSchedSwitchLog(ConStr &fakeLog, LogInfo logInfo, int gid, ConStr &label)
738 {
739 std::string mockTid = GenMockTid(logInfo.pid, gid);
740 std::string result = fakeLog;
741
742 if (logInfo.log.find("prev_pid=" + std::to_string(logInfo.tid)) != std::string::npos) {
743 if (ExtractThreadId(fakeLog) == logInfo.tid) {
744 size_t index = fakeLog.find("(");
745 result = " " + label + "-" + mockTid + " " + fakeLog.substr(index);
746 }
747 result = result.substr(0, result.find("prev_comm=")) +
748 "prev_comm=" + label +
749 " " + result.substr(result.find("prev_pid="));
750 result = result.substr(0, result.find("prev_pid=")) +
751 "prev_pid=" + mockTid +
752 " " + result.substr(result.find("prev_prio="));
753 } else if (logInfo.log.find("next_pid=" + std::to_string(logInfo.tid)) != std::string::npos) {
754 result = result.substr(0, result.find("next_comm=")) +
755 "next_comm=" + label +
756 " " + result.substr(result.find("next_pid="));
757 result = result.substr(0, result.find("next_pid=")) +
758 "next_pid=" + mockTid +
759 " " + result.substr(result.find("next_prio="));
760 }
761 return result;
762 }
763
ReplaceSchedWakeLog(ConStr & fakeLog,ConStr & label,int pid,int gid)764 static std::string ReplaceSchedWakeLog(ConStr &fakeLog, ConStr &label, int pid, int gid)
765 {
766 std::string result = fakeLog;
767 result = result.substr(0, result.find("comm=")) + "comm=" + label + " " + result.substr(result.find("pid="));
768 // Replace "pid=" part
769 std::string mockTid = GenMockTid(pid, gid);
770 result = result.substr(0, result.find("pid=")) + "pid=" + mockTid + " " + result.substr(result.find("prio="));
771 return result;
772 }
773
ReplaceTracingMarkLog(ConStr & fakeLog,ConStr & label,int pid,int gid)774 static std::string ReplaceTracingMarkLog(ConStr &fakeLog, ConStr &label, int pid, int gid)
775 {
776 size_t index = fakeLog.find("(");
777 std::string mockTid = GenMockTid(pid, gid);
778 std::string result = " " + label + "-" + mockTid + " " + fakeLog.substr(index);
779 return result;
780 }
781
ReplaceSchedBlockLog(ConStr & fakeLog,int pid,int gid)782 static std::string ReplaceSchedBlockLog(ConStr &fakeLog, int pid, int gid)
783 {
784 std::string mockTid = GenMockTid(pid, gid);
785 std::string::size_type pos = fakeLog.find("pid=");
786 std::string result;
787 if (pos != std::string::npos) {
788 pos = fakeLog.find("iowait=", pos);
789 if (pos != std::string::npos) {
790 result = fakeLog.substr(0, fakeLog.find("pid=")) + "pid=" +
791 mockTid + " " + fakeLog.substr(pos);
792 } else {
793 result = fakeLog.substr(0, fakeLog.find("pid=")) + "pid=" +
794 mockTid + " " + fakeLog.substr(fakeLog.find("io_wait="));
795 }
796 }
797 return result;
798 }
799
ConvertWorkerLogToTask(ConStr & mark,int pid,int tid,int gid,ConStr & label)800 static std::string ConvertWorkerLogToTask(ConStr &mark, int pid, int tid, int gid, ConStr &label)
801 {
802 std::string fakeLog = mark;
803 if (mark.find("sched_switch: ") != std::string::npos) {
804 LogInfo logInfo = LogInfo{mark, -1, pid, tid};
805 return ReplaceSchedSwitchLog(fakeLog, logInfo, gid, label);
806 }
807 if (mark.find(": sched_wak") != std::string::npos) {
808 if (mark.find("pid=" + std::to_string(tid)) != std::string::npos) {
809 return ReplaceSchedWakeLog(fakeLog, label, pid, gid);
810 } else {
811 return ReplaceTracingMarkLog(fakeLog, label, pid, gid);
812 }
813 }
814 if (mark.find("sched_blocked_reason: ") != std::string::npos) {
815 if (mark.find("pid=" + std::to_string(tid)) != std::string::npos) {
816 return ReplaceSchedBlockLog(fakeLog, pid, gid);
817 } else {
818 return ReplaceTracingMarkLog(fakeLog, label, pid, gid);
819 }
820 }
821 return ReplaceTracingMarkLog(fakeLog, label, pid, gid);
822 }
823
FindGreaterThan(const std::vector<int> & vec,int target)824 static int FindGreaterThan(const std::vector<int> &vec, int target)
825 {
826 if (vec.size() == 0) {
827 return 0;
828 }
829 if (target >= vec.back()) {
830 return vec.size();
831 }
832 auto it = std::lower_bound(vec.begin(), vec.end(), target + 1);
833 if (it != vec.end() && *it > target) {
834 return std::distance(vec.begin(), it);
835 }
836 return vec.size();
837 }
838
HandleQueTaskInfoIn(ConStr & log,int lineno,int pid,QueueTaskInfo & queueTaskInfo)839 static bool HandleQueTaskInfoIn(ConStr &log, int lineno, int pid, QueueTaskInfo &queueTaskInfo)
840 {
841 static std::string sqStr = "sq_";
842 size_t sqPos = log.find("H:FFRTsq_");
843 if (sqPos != std::string::npos) {
844 size_t sqStart = log.find(sqStr);
845 std::string containInfo = log.substr(sqStart + sqStr.size());
846 size_t firstPipePos = containInfo.find_first_of("|");
847 if (firstPipePos != std::string::npos) {
848 std::string containQid = containInfo.substr(0, firstPipePos);
849 int qid = GetQid(containQid);
850 if (qid == -1) {
851 return true;
852 }
853 size_t gidStart = containQid.size() + 1;
854 int gid = std::stoull(containInfo.substr(gidStart, containInfo.find("|", gidStart) - gidStart));
855 if (queueTaskInfo[pid].find(gid) == queueTaskInfo[pid].end()) {
856 queueTaskInfo[pid][gid] = tidInfo{{lineno}, -1, gid, qid};
857 } else {
858 queueTaskInfo[pid][gid].begin.emplace_back(lineno);
859 }
860 }
861 }
862 return false;
863 }
864
HandleQueTaskInfoOut(ConStr & log,int lineno,int pid,QueueTaskInfo & queueTaskInfo)865 static void HandleQueTaskInfoOut(ConStr &log, int lineno, int pid, QueueTaskInfo &queueTaskInfo)
866 {
867 static std::string fStr = " F|";
868 size_t fPos = log.find(fStr);
869 if (fPos == std::string::npos) {
870 return;
871 }
872 size_t hPos = log.find("|H:F ", fPos);
873 if (hPos == std::string::npos) {
874 return;
875 }
876 std::string pidStr = log.substr(fPos + fStr.size(), hPos - (fPos + fStr.size()));
877 if (!pidStr.empty() && std::all_of(pidStr.begin(), pidStr.end(), ::isdigit)) {
878 int spacePos = hPos + fStr.size() + 1;
879 while (log[spacePos] == ' ') {
880 spacePos++;
881 }
882 bool spaceFlage = spacePos != std::string::npos && spacePos < log.length();
883 if (!spaceFlage) {
884 return;
885 }
886 std::string gidStr = log.substr(spacePos);
887 if (!gidStr.empty() && std::all_of(gidStr.begin(), gidStr.end(), ::isdigit)) {
888 int gid = std::stoull(gidStr);
889 if (queueTaskInfo[pid].find(gid) != queueTaskInfo[pid].end()) {
890 queueTaskInfo[pid][gid].end = lineno;
891 }
892 }
893 }
894 }
895
ExceQueTaskInfoPreLog(std::vector<int> & linenos,int pid,QueueTaskInfo & queueTaskInfo)896 void FfrtConverter::ExceQueTaskInfoPreLog(std::vector<int> &linenos, int pid, QueueTaskInfo &queueTaskInfo)
897 {
898 for (auto lineno : linenos) {
899 std::string &log = context_[lineno];
900
901 if (HandleQueTaskInfoIn(log, lineno, pid, queueTaskInfo)) {
902 continue;
903 }
904 HandleQueTaskInfoOut(log, lineno, pid, queueTaskInfo);
905 }
906 }
907
FindQueueTaskInfo(FfrtPids & ffrtPids,QueueTaskInfo & queueTaskInfo)908 void FfrtConverter::FindQueueTaskInfo(FfrtPids &ffrtPids, QueueTaskInfo &queueTaskInfo)
909 {
910 for (auto &pidItem : ffrtPids) {
911 int pid = pidItem.first;
912 queueTaskInfo[pid] = {}; // Initialize map for this pid
913
914 for (auto &tidItem : pidItem.second) {
915 std::vector<int> &linenos = tidItem.second.second;
916 std::sort(linenos.begin(), linenos.end());
917 ExceQueTaskInfoPreLog(linenos, pid, queueTaskInfo);
918 }
919 }
920 }
921
GenFfrtQueueTasks(FfrtQueueTasks & ffrtQueueTasks,QueueTaskInfo & queueTaskInfo)922 void GenFfrtQueueTasks(FfrtQueueTasks &ffrtQueueTasks, QueueTaskInfo &queueTaskInfo)
923 {
924 for (auto &pidItem : queueTaskInfo) {
925 int pid = pidItem.first;
926 ffrtQueueTasks[pid] = {};
927 for (auto &qidItem : pidItem.second) {
928 std::sort(qidItem.second.begin.begin(), qidItem.second.begin.end());
929 int qid = qidItem.second.qid;
930 if (ffrtQueueTasks[pid].find(qid) == ffrtQueueTasks[pid].end()) {
931 ffrtQueueTasks[pid][qid] = {};
932 }
933 ffrtQueueTasks[pid][qid].push_back(qidItem.second);
934 }
935 }
936 }
937
GenTaskGroups(std::vector<std::vector<tidInfo>> & taskGroups,std::pair<int,std::vector<tidInfo>> qidItem)938 static void GenTaskGroups(std::vector<std::vector<tidInfo>> &taskGroups, std::pair<int, std::vector<tidInfo>> qidItem)
939 {
940 for (auto &task : qidItem.second) {
941 if (task.end == -1) {
942 taskGroups.push_back({task});
943 continue;
944 }
945 bool inserted = false;
946 for (auto &group : taskGroups) {
947 if (group.back().end != -1 && task.begin[0] > group.back().end) {
948 group.emplace_back(task);
949 inserted = true;
950 break;
951 }
952 }
953 if (!inserted) {
954 taskGroups.push_back({task});
955 }
956 }
957 }
958
ExceTaskGroups(std::vector<tidInfo> & group,WakeLogs & wakeLogs,int firstGid)959 void FfrtConverter::ExceTaskGroups(std::vector<tidInfo> &group, WakeLogs &wakeLogs, int firstGid)
960 {
961 for (int i = 1; i < group.size(); i++) {
962 if (wakeLogs.find(group[i].gid) != wakeLogs.end()) {
963 int gid = group[i].gid;
964 wakeLogs[firstGid].insert(wakeLogs[firstGid].end(), wakeLogs[gid].begin(), wakeLogs[gid].end());
965 for (auto& lineno : group[i].begin) {
966 size_t strLen = context_[lineno].find_last_of("|") + 1;
967 context_[lineno] = context_[lineno].substr(0, strLen) + std::to_string(firstGid) + "\n";
968 }
969 }
970 }
971 }
972
HandleTaskGroups(std::vector<std::vector<tidInfo>> & taskGroups,WakeLogs & wakeLogs)973 void FfrtConverter::HandleTaskGroups(std::vector<std::vector<tidInfo>> &taskGroups, WakeLogs &wakeLogs)
974 {
975 for (auto& group : taskGroups) {
976 if (group.size() > 1) {
977 int firstGid = group[0].gid;
978 if (wakeLogs.find(firstGid) == wakeLogs.end()) {
979 wakeLogs[firstGid] = {};
980 }
981 ExceTaskGroups(group, wakeLogs, firstGid);
982 std::sort(wakeLogs[firstGid].begin(), wakeLogs[firstGid].end());
983 }
984 }
985 }
986
HandleFfrtQueueTasks(FfrtQueueTasks & ffrtQueueTasks,FfrtWakeLogs & ffrtWakeLogs)987 void FfrtConverter::HandleFfrtQueueTasks(FfrtQueueTasks &ffrtQueueTasks, FfrtWakeLogs& ffrtWakeLogs)
988 {
989 for (auto &pidItem : ffrtQueueTasks) {
990 WakeLogs tmp = {};
991 WakeLogs &wakeLogs = (ffrtWakeLogs.find(pidItem.first) != ffrtWakeLogs.end()) ?
992 ffrtWakeLogs[pidItem.first] : tmp;
993
994 for (auto &qidItem : pidItem.second) {
995 auto cmp = [](tidInfo& value1, tidInfo& value2) {return value1.begin[0] < value2.begin[0];};
996 std::sort(qidItem.second.begin(), qidItem.second.end(), cmp);
997
998 std::vector<std::vector<tidInfo>> taskGroups;
999 GenTaskGroups(taskGroups, qidItem);
1000 HandleTaskGroups(taskGroups, wakeLogs);
1001 }
1002 }
1003 }
1004
HandleMarks(ConStr & log,int lineno,int pid)1005 void FfrtConverter::HandleMarks(ConStr &log, int lineno, int pid)
1006 {
1007 static std::string lostTracingMark = tracingMarkerKey_ + "?";
1008 static std::string faultTracingMark = tracingMarkerKey_ + "<faulted>";
1009
1010 size_t lostMarkPos = log.find(lostTracingMark);
1011 size_t faultMarkPos = log.find(faultTracingMark);
1012 size_t tracingMarkerPos = log.find(tracingMarkerKey_);
1013
1014 if (lostMarkPos != std::string::npos || faultMarkPos != std::string::npos) {
1015 if (tracingMarkerPos != std::string::npos) {
1016 context_[lineno] = log.substr(0, tracingMarkerPos + tracingMarkerKey_.size())
1017 + "E|" + std::to_string(pid) + "\n";
1018 }
1019 }
1020 }
1021
HandleSchedSwitch(ConStr & mark,int tid,int & prio)1022 void HandleSchedSwitch(ConStr &mark, int tid, int &prio)
1023 {
1024 if (mark.find("sched_switch: ") != std::string::npos) {
1025 size_t prevPidPos = mark.find("prev_pid=" + std::to_string(tid));
1026 size_t nextPidPos = mark.find("next_pid=" + std::to_string(tid));
1027 if (prevPidPos != std::string::npos || nextPidPos != std::string::npos) {
1028 std::string pidTag = (prevPidPos != std::string::npos) ? "prev_prio=" : "next_prio=";
1029 size_t prioPos = mark.find(pidTag);
1030 if (prioPos != std::string::npos) {
1031 std::string prioStr = mark.substr(prioPos + pidTag.size());
1032 prio = std::stoull(prioStr.substr(0, prioStr.find(" ")));
1033 }
1034 }
1035 }
1036 }
1037
HandleFfrtTaskCo(ConStr & log,int lineno,bool & switchInFakeLog,bool & switchOutFakeLog)1038 bool FfrtConverter::HandleFfrtTaskCo(ConStr &log, int lineno, bool &switchInFakeLog, bool &switchOutFakeLog)
1039 {
1040 if (IsOldVersionTrace(log)) {
1041 context_[lineno] = "\n";
1042 if (switchInFakeLog) {
1043 switchInFakeLog = false;
1044 } else {
1045 switchOutFakeLog = true;
1046 }
1047 return true;
1048 }
1049 return false;
1050 }
1051
IsFfrtTaskBlockOrFinish(ConStr & log)1052 static bool IsFfrtTaskBlockOrFinish(ConStr &log)
1053 {
1054 static const std::string fStr = " F|";
1055 int fPos = log.find(fStr);
1056 if (fPos == std::string::npos) {
1057 return false;
1058 }
1059 size_t hPos = log.find("|H:", fPos);
1060 if (hPos != std::string::npos) {
1061 size_t typePos = hPos + fStr.size();
1062 if (typePos < log.length() &&
1063 (log[typePos] == 'F' || log[typePos] == 'B')) {
1064 int spacePos = typePos + 1;
1065 while (spacePos < log.length() && isspace(log[spacePos])) {
1066 ++spacePos;
1067 }
1068
1069 if (spacePos < log.length() && isdigit(log[spacePos])) {
1070 return true;
1071 }
1072 }
1073 }
1074 return false;
1075 }
1076
HandleFfrtTaskExecute(FakeLogArgs & fakLogArg,WakeLogs & wakeLogs,TaskLabels & taskLabels,std::string & label)1077 bool FfrtConverter::HandleFfrtTaskExecute(FakeLogArgs &fakLogArg, WakeLogs &wakeLogs,
1078 TaskLabels &taskLabels, std::string &label)
1079 {
1080 static const int spaceNum = 7;
1081 if (fakLogArg.log.find("|H:FFRT") != std::string::npos) {
1082 std::string missLog;
1083 if (fakLogArg.taskRunning != -1) {
1084 missLog = MakeCoyieldFakeLog(fakLogArg);
1085 std::stringstream ss;
1086 ss << " " << fakLogArg.tname << "-" << fakLogArg.tid << " (" <<
1087 std::setw(spaceNum) << std::right << fakLogArg.pid << ") [" <<
1088 fakLogArg.cpuId << "] .... " << fakLogArg.timestamp <<
1089 ": " << tracingMarkerKey_ << "E|" << fakLogArg.pid << "\n";
1090 missLog += ss.str();
1091 }
1092 if (label.find("ex_task") != std::string::npos) { return true; }
1093 int gid = -1;
1094 size_t pos = fakLogArg.log.find_last_of('|');
1095 if (pos != std::string::npos) {
1096 if (pos + 1 >= fakLogArg.log.size()) {
1097 return true;
1098 }
1099 std::string gidStr = fakLogArg.log.substr(pos + 1);
1100 auto [ptr, ec] = std::from_chars(gidStr.data(), gidStr.data() + gidStr.size(), gid);
1101 if (ec != std::errc{}) {
1102 return true;
1103 }
1104 }
1105 if (taskLabels[fakLogArg.pid].find(gid) == taskLabels[fakLogArg.pid].end()) {
1106 taskLabels[fakLogArg.pid][gid] = label;
1107 }
1108 fakLogArg.taskRunning = gid;
1109 fakLogArg.taskLabel = taskLabels[fakLogArg.pid][fakLogArg.taskRunning];
1110 std::string fakeLog = MakeCostartFakeLog(fakLogArg);
1111 context_[fakLogArg.lineno] = fakeLog;
1112 if (!missLog.empty()) {
1113 context_[fakLogArg.lineno] = missLog + context_[fakLogArg.lineno];
1114 }
1115 fakLogArg.switchInFakeLog = true;
1116 fakLogArg.switchOutFakeLog = false;
1117 if (wakeLogs.find(fakLogArg.taskRunning) != wakeLogs.end()) {
1118 int prevIndex = FindGreaterThan(wakeLogs[fakLogArg.taskRunning], fakLogArg.lineno);
1119 if (prevIndex > 0) {
1120 int linenoWake = wakeLogs[fakLogArg.taskRunning][prevIndex - 1];
1121 context_[linenoWake] = MakeWakeupFakeLog(context_[linenoWake], fakLogArg, tracingMarkerKey_);
1122 }
1123 }
1124 return true;
1125 }
1126 return false;
1127 }
1128
HandlePreLineno(FakeLogArgs & fakArg,WakeLogs & wakeLogs,TaskLabels & taskLabels,ConStr traceBeginMark,ConStr traceEndMark)1129 bool FfrtConverter::HandlePreLineno(FakeLogArgs &fakArg, WakeLogs &wakeLogs,
1130 TaskLabels &taskLabels, ConStr traceBeginMark, ConStr traceEndMark)
1131 {
1132 std::string label = ExtractTaskLable(fakArg.log);
1133 if (HandleFfrtTaskExecute(fakArg, wakeLogs, taskLabels, label)) {
1134 return true;
1135 }
1136 if (fakArg.taskRunning != -1) {
1137 if (this->isOldVersionTrace_) {
1138 if (HandleFfrtTaskCo(fakArg.log, fakArg.lineno, fakArg.switchInFakeLog, fakArg.switchOutFakeLog)) {
1139 return true;
1140 }
1141 if (fakArg.switchInFakeLog && (fakArg.log.find(traceBeginMark) != std::string::npos)) {
1142 context_[fakArg.lineno] = "\n";
1143 return true;
1144 }
1145 if (fakArg.switchOutFakeLog && (fakArg.log.find(traceEndMark) != std::string::npos)) {
1146 context_[fakArg.lineno] = "\n";
1147 return true;
1148 }
1149 }
1150 if (IsFfrtTaskBlockOrFinish(fakArg.log)) {
1151 std::string fakeLog = MakeCoyieldFakeLog(fakArg);
1152 context_[fakArg.lineno] = fakeLog;
1153 if (this->isOldVersionTrace_ && fakArg.switchOutFakeLog) {
1154 fakArg.switchOutFakeLog = false;
1155 }
1156 fakArg.taskRunning = -1;
1157 return true;
1158 }
1159 label = taskLabels[fakArg.pid][fakArg.taskRunning];
1160 std::string fakeLog = ConvertWorkerLogToTask(fakArg.log, fakArg.pid, fakArg.tid, fakArg.taskRunning, label);
1161 context_[fakArg.lineno] = fakeLog;
1162 return true;
1163 }
1164 return false;
1165 }
1166
ExceTaskLabelOhos(TaskLabels & taskLabels,FfrtWakeLogs & ffrtWakeLogs,std::pair<int,FfrtTidMap> pidItem,std::string traceBeginMark,std::string traceEndMark)1167 void FfrtConverter::ExceTaskLabelOhos(TaskLabels &taskLabels, FfrtWakeLogs &ffrtWakeLogs,
1168 std::pair<int, FfrtTidMap> pidItem, std::string traceBeginMark,
1169 std::string traceEndMark)
1170 {
1171 taskLabels[pidItem.first] = {};
1172 WakeLogs tmp = {};
1173 WakeLogs &wakeLogs = (ffrtWakeLogs.find(pidItem.first) != ffrtWakeLogs.end())
1174 ? ffrtWakeLogs[pidItem.first] : tmp;
1175
1176 for (auto &tidItem : pidItem.second) {
1177 std::string tname = tidItem.second.first;
1178 std::vector<int> linenos = tidItem.second.second;
1179 int prio = 120;
1180 bool switchInFakeLog = false;
1181 bool switchOutFakeLog = false;
1182 int taskRunning = -1;
1183
1184 for (auto lineno : linenos) {
1185 std::string &log = context_[lineno];
1186 HandleMarks(log, lineno, pidItem.first);
1187 HandleSchedSwitch(log, tidItem.first, prio);
1188
1189 std::string cpuId = ExtractCpuId(log);
1190 std::string timestamp = ExtractTimeStr(log);
1191 FakeLogArgs fakArg{pidItem.first, tidItem.first, taskRunning, prio, lineno,
1192 switchInFakeLog, switchOutFakeLog, log, tname,
1193 taskLabels[pidItem.first][taskRunning], cpuId, timestamp};
1194 HandlePreLineno(fakArg, wakeLogs, taskLabels, traceBeginMark, traceEndMark);
1195 }
1196 }
1197 }
1198
GenTaskLabelsOhos(FfrtPids & ffrtPids,FfrtWakeLogs & ffrtWakeLogs,TaskLabels & taskLabels)1199 void FfrtConverter::GenTaskLabelsOhos(FfrtPids &ffrtPids, FfrtWakeLogs& ffrtWakeLogs, TaskLabels &taskLabels)
1200 {
1201 static std::string traceBeginMark = tracingMarkerKey_ + "B";
1202 static std::string traceEndMark = tracingMarkerKey_ + "E";
1203 for (auto &pidItem : ffrtPids) {
1204 ExceTaskLabelOhos(taskLabels, ffrtWakeLogs, pidItem, traceBeginMark, traceEndMark);
1205 }
1206 }
1207
ConvertFrrtThreadToFfrtTaskOhos(FfrtPids & ffrtPids,FfrtWakeLogs & ffrtWakeLogs)1208 void FfrtConverter::ConvertFrrtThreadToFfrtTaskOhos(FfrtPids &ffrtPids, FfrtWakeLogs& ffrtWakeLogs)
1209 {
1210 QueueTaskInfo queueTaskInfo;
1211 FindQueueTaskInfo(ffrtPids, queueTaskInfo);
1212
1213 FfrtQueueTasks ffrtQueueTasks;
1214 GenFfrtQueueTasks(ffrtQueueTasks, queueTaskInfo);
1215 HandleFfrtQueueTasks(ffrtQueueTasks, ffrtWakeLogs);
1216
1217 TaskLabels taskLabels;
1218 taskLabels.reserve(ffrtPids.size());
1219 GenTaskLabelsOhos(ffrtPids, ffrtWakeLogs, taskLabels);
1220 }
1221
HandleHFfrtTaskExecute(FakeLogArgs & fakeArgs,WakeLogs & wakeLogs,TaskLabels & taskLabels,std::string label,std::unordered_map<int,int> & schedWakeFlag)1222 bool FfrtConverter::HandleHFfrtTaskExecute(FakeLogArgs &fakeArgs, WakeLogs &wakeLogs, TaskLabels &taskLabels,
1223 std::string label, std::unordered_map<int, int> &schedWakeFlag)
1224 {
1225 static const int spaceNum = 7;
1226 if (fakeArgs.log.find("|FFRT") == std::string::npos) {
1227 return false;
1228 }
1229 std::string missLog;
1230 if (fakeArgs.taskRunning != -1) {
1231 missLog = MakeCoyieldFakeLog(fakeArgs);
1232 std::stringstream ss;
1233 ss << " " << fakeArgs.tname << "-" << fakeArgs.tid << " (" <<
1234 std::setw(spaceNum) << std::right << fakeArgs.pid << ") [" <<
1235 fakeArgs.cpuId << "] .... " << fakeArgs.timestamp << ": " <<
1236 tracingMarkerKey_ << "E|" << fakeArgs.pid << "\n";
1237 missLog += ss.str();
1238 }
1239 if (label.find("executor_task") != std::string::npos) { return true; }
1240 int gid = -1;
1241 size_t pos = fakeArgs.log.find_last_of('|');
1242 if (pos != std::string::npos) {
1243 if (pos + 1 >= fakeArgs.log.size()) { return true; }
1244 std::string gidStr = fakeArgs.log.substr(pos + 1);
1245 auto [ptr, ec] = std::from_chars(gidStr.data(), gidStr.data() + gidStr.size(), gid);
1246 if (ec != std::errc{}) { return true; }
1247 }
1248 if (taskLabels[fakeArgs.pid].find(gid) == taskLabels[fakeArgs.pid].end()) {
1249 taskLabels[fakeArgs.pid][gid] = label;
1250 }
1251 fakeArgs.taskRunning = gid;
1252 FakeLogArgs fakArg2{fakeArgs.pid, fakeArgs.tid, fakeArgs.taskRunning, fakeArgs.prio, fakeArgs.lineno,
1253 fakeArgs.switchInFakeLog, fakeArgs.switchOutFakeLog, fakeArgs.log, fakeArgs.tname,
1254 taskLabels[fakeArgs.pid][fakeArgs.taskRunning], fakeArgs.cpuId, fakeArgs.timestamp};
1255 std::string fakeLog = MakeCostartFakeLog(fakArg2);
1256 context_[fakeArgs.lineno] = fakeLog;
1257 if (!missLog.empty()) {
1258 context_[fakeArgs.lineno] = missLog + context_[fakeArgs.lineno];
1259 }
1260 FakeLogArgs fakArg3{fakeArgs.pid, fakeArgs.tid, fakeArgs.taskRunning, fakeArgs.prio, fakeArgs.lineno,
1261 fakeArgs.switchInFakeLog, fakeArgs.switchOutFakeLog, fakeArgs.log, fakeArgs.tname,
1262 taskLabels[fakeArgs.pid][fakeArgs.taskRunning], fakeArgs.cpuId, fakeArgs.timestamp};
1263 if (wakeLogs.find(fakeArgs.taskRunning) != wakeLogs.end()) {
1264 int prevIndex = FindGreaterThan(wakeLogs[fakeArgs.taskRunning], fakeArgs.lineno);
1265 if (prevIndex > 0) {
1266 int linenoWake = wakeLogs[fakeArgs.taskRunning][prevIndex - 1];
1267 if (schedWakeFlag.find(linenoWake) == schedWakeFlag.end()) {
1268 context_[linenoWake] = MakeWakeupFakeLog(context_[linenoWake], fakArg3, tracingMarkerKey_);
1269 schedWakeFlag[linenoWake] = 0;
1270 }
1271 }
1272 }
1273 return true;
1274 }
1275
IsFfrtTaskBlockOrFinishNohos(ConStr & log)1276 static bool IsFfrtTaskBlockOrFinishNohos(ConStr &log)
1277 {
1278 static const std::string fStr = " F|";
1279 size_t fPos = log.find(fStr);
1280 if (fPos == std::string::npos) { return false; }
1281 size_t firstNumberEndPos = log.find('|', fPos + fStr.size());
1282 if (firstNumberEndPos == std::string::npos) { return false; }
1283 std::string firstNumber = log.substr(fPos + 3, firstNumberEndPos - (fPos + fStr.size()));
1284 bool isValidNumber = true;
1285 for (char c : firstNumber) {
1286 if (!std::isdigit(c)) {
1287 isValidNumber = false;
1288 break;
1289 }
1290 }
1291 if (!isValidNumber) { return false; }
1292 size_t typePos = firstNumberEndPos + 1;
1293 if (typePos < log.length() && (log[typePos] == 'B' || log[typePos] == 'F')) {
1294 size_t thirdPipePos = log.find('|', typePos + 1);
1295 if (thirdPipePos != std::string::npos) {
1296 size_t secondNumberPos = thirdPipePos + 1;
1297 if (secondNumberPos < log.length() && std::isdigit(log[secondNumberPos])) {
1298 return true;
1299 }
1300 }
1301 }
1302 return false;
1303 }
1304
HandlePreLinenoNohos(FakeLogArgs & fakArg,WakeLogs & wakeLogs,TaskLabels & taskLabels,std::unordered_map<int,int> & schedWakeFlag)1305 bool FfrtConverter::HandlePreLinenoNohos(FakeLogArgs &fakArg, WakeLogs &wakeLogs,
1306 TaskLabels &taskLabels, std::unordered_map<int, int> &schedWakeFlag)
1307 {
1308 std::string label = ExtractTaskLable(fakArg.log);
1309 if (HandleHFfrtTaskExecute(fakArg, wakeLogs, taskLabels, label, schedWakeFlag)) {
1310 return true;
1311 }
1312 if (fakArg.taskRunning != -1) {
1313 if (IsFfrtTaskBlockOrFinishNohos(fakArg.log)) {
1314 std::string fakeLog = MakeCoyieldFakeLog(fakArg);
1315 context_[fakArg.lineno] = fakeLog;
1316 fakArg.taskRunning = -1;
1317 return true;
1318 }
1319 label = taskLabels[fakArg.pid][fakArg.taskRunning];
1320 std::string fakeLog = ConvertWorkerLogToTask(fakArg.log, fakArg.pid, fakArg.tid, fakArg.taskRunning, label);
1321 context_[fakArg.lineno] = fakeLog;
1322 return true;
1323 }
1324 return false;
1325 }
ExceTaskLabelNohos(TaskLabels & taskLabels,FfrtWakeLogs & ffrtWakeLogs,std::pair<int,FfrtTidMap> pidItem,std::unordered_map<int,int> & schedWakeFlag)1326 void FfrtConverter::ExceTaskLabelNohos(TaskLabels &taskLabels, FfrtWakeLogs &ffrtWakeLogs,
1327 std::pair<int, FfrtTidMap> pidItem, std::unordered_map<int, int> &schedWakeFlag)
1328 {
1329 bool oneF = false;
1330 bool twoF = false;
1331 taskLabels[pidItem.first] = {};
1332 WakeLogs tmp = {};
1333 WakeLogs &wakeLogs = (ffrtWakeLogs.find(pidItem.first) != ffrtWakeLogs.end())
1334 ? ffrtWakeLogs[pidItem.first] : tmp;
1335
1336 for (auto& tidItem : pidItem.second) {
1337 std::string tname = tidItem.second.first;
1338 std::vector<int> linenos = tidItem.second.second;
1339 int prio = 120;
1340 int taskRunning = -1;
1341
1342 for (auto lineno : linenos) {
1343 std::string& log = context_[lineno];
1344
1345 HandleMarks(log, lineno, pidItem.first);
1346 HandleSchedSwitch(log, tidItem.first, prio);
1347
1348 std::string cpuId = ExtractCpuId(log);
1349 std::string timestamp = ExtractTimeStr(log);
1350 std::string label = ExtractTaskLable(log);
1351
1352 FakeLogArgs fakArg{pidItem.first, tidItem.first, taskRunning, prio, lineno,
1353 oneF, twoF, log, tname,
1354 taskLabels[pidItem.first][taskRunning], cpuId, timestamp};
1355 HandlePreLinenoNohos(fakArg, wakeLogs, taskLabels, schedWakeFlag);
1356 }
1357 }
1358 }
1359
ConvertFrrtThreadToFfrtTaskNohos(FfrtPids & ffrtPids,FfrtWakeLogs & ffrtWakeLogs)1360 void FfrtConverter::ConvertFrrtThreadToFfrtTaskNohos(FfrtPids &ffrtPids, FfrtWakeLogs &ffrtWakeLogs)
1361 {
1362 TaskLabels taskLabels;
1363 std::unordered_map<int, int> schedWakeFlag;
1364 taskLabels.reserve(ffrtPids.size());
1365 schedWakeFlag.reserve(ffrtWakeLogs.size());
1366
1367 for (auto &pidItem : ffrtPids) {
1368 ExceTaskLabelNohos(taskLabels, ffrtWakeLogs, pidItem, schedWakeFlag);
1369 }
1370 }
1371 } // namespace TraceStreamer
1372 } // namespace SysTuning
1373