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