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