• 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) {
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