1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "trace_converter.h"
16
17 #include <cinttypes>
18 #include <fcntl.h>
19 #include <sstream>
20 #include <tuple>
21 #include <unistd.h>
22 #include "common_types.pb.h"
23 #include "event_formatter.h"
24
25 namespace {
26 constexpr unsigned TS_MIN_LEN = 9;
27 constexpr unsigned US_DIGITS = 6;
28 constexpr unsigned PID_STR_MAX = 6;
29 constexpr unsigned CPU_STR_MAX = 3;
30 constexpr unsigned COMM_STR_MAX = 16;
31 constexpr unsigned TGID_STR_MAX = 5;
32 constexpr unsigned TRACE_TXT_HEADER_MAX = 1024;
33 constexpr char HEX_CHARS[] = "0123456789abcdef";
34 constexpr int OUTPUT_FILE_MODE = 0644;
35 constexpr int INVALID_FD = -1;
36 using Clock = std::chrono::steady_clock;
37 using TimePoint = Clock::time_point;
38 using MilliSeconds = std::chrono::milliseconds;
39 using EventFormatter = FTRACE_NS::EventFormatter;
40
41 /*
42 * trace_flag_type is an enumeration that holds different
43 * states when a trace occurs. These are:
44 * IRQS_OFF - interrupts were disabled
45 * IRQS_NOSUPPORT - arch does not support irqs_disabled_flags
46 * NEED_RESCHED - reschedule is requested
47 * HARDIRQ - inside an interrupt handler
48 * SOFTIRQ - inside a softirq handler
49 */
50 constexpr uint32_t TRACE_FLAG_IRQS_OFF = 0x01;
51 constexpr uint32_t TRACE_FLAG_IRQS_NOSUPPORT = 0x02;
52 constexpr uint32_t TRACE_FLAG_NEED_RESCHED = 0x04;
53 constexpr uint32_t TRACE_FLAG_HARDIRQ = 0x08;
54 constexpr uint32_t TRACE_FLAG_SOFTIRQ = 0x10;
55 constexpr uint32_t TRACE_FLAG_PREEMPT_RESCHED = 0x20;
56 constexpr uint32_t TRACE_FLAG_NMI = 0x40;
57
58 std::string ENTIRES_STATS_PREFIX = "# entries-in-buffer/entries-written:";
59 std::string PROCESSOR_NUMBER_PREFIX = "#P:";
60 std::string TRACE_TXT_HEADER_FORMAT = R"(# tracer: nop
61 #
62 # entries-in-buffer/entries-written: %lu/%lu #P:%d
63 #
64 # _-----=> irqs-off
65 # / _----=> need-resched
66 # | / _---=> hardirq/softirq
67 # || / _--=> preempt-depth
68 # ||| / delay
69 # TASK-PID TGID CPU# |||| TIMESTAMP FUNCTION
70 # | | | | |||| | |
71 )";
72
TimeDeltaMs(const TimePoint & a,const TimePoint & b)73 long TimeDeltaMs(const TimePoint& a, const TimePoint& b)
74 {
75 auto delta = std::chrono::duration_cast<MilliSeconds>(a - b);
76 return static_cast<long>(delta.count());
77 }
78
79 constexpr uint8_t HALF_BYTE_SIZE = 4;
80 constexpr uint8_t HALF_BYTE_MASK = 0x0F;
81
GetHighHalfByte(uint8_t value)82 uint8_t GetHighHalfByte(uint8_t value)
83 {
84 return (value >> HALF_BYTE_SIZE) & HALF_BYTE_MASK;
85 }
86
GetLowHalfByte(uint8_t value)87 uint8_t GetLowHalfByte(uint8_t value)
88 {
89 return value & HALF_BYTE_MASK;
90 }
91 } // namespace
92
SetInput(const std::string & input)93 void TraceConverter::SetInput(const std::string& input)
94 {
95 input_ = input;
96 }
97
SetOutput(const std::string & output)98 void TraceConverter::SetOutput(const std::string& output)
99 {
100 output_ = output;
101 }
102
PrintTraceFileHeader(const TraceFileHeader & header)103 void TraceConverter::PrintTraceFileHeader(const TraceFileHeader& header)
104 {
105 HILOG_INFO(LOG_CORE, "======== TRACE FILE HEADER ========");
106 HILOG_INFO(LOG_CORE, "magic: %" PRIx64, header.data_.magic_);
107 HILOG_INFO(LOG_CORE, "length: %" PRIu64, header.data_.length_);
108 HILOG_INFO(LOG_CORE, "version: %" PRIx32, header.data_.version_);
109 HILOG_INFO(LOG_CORE, "segments: %" PRIx32, header.data_.segments_);
110 std::string sha = "";
111 for (size_t i = 0; i < std::size(header.data_.sha256_); i++) {
112 sha.push_back(HEX_CHARS[GetHighHalfByte(header.data_.sha256_[i])]);
113 sha.push_back(HEX_CHARS[GetLowHalfByte(header.data_.sha256_[i])]);
114 }
115 HILOG_INFO(LOG_CORE, "SHA256: %s", sha.c_str());
116 HILOG_INFO(LOG_CORE, "-------- -------- -------- --------");
117 }
118
PrintCpuStats(const FtraceCpuStatsMsg & cpuStats)119 void TraceConverter::PrintCpuStats(const FtraceCpuStatsMsg& cpuStats)
120 {
121 auto status = cpuStats.status();
122 std::string statusName = "";
123 if (status == FtraceCpuStatsMsg::TRACE_START) {
124 statusName = "TRACE_START";
125 } else if (status == FtraceCpuStatsMsg::TRACE_END) {
126 statusName = "TRACE_END";
127 }
128 HILOG_INFO(LOG_CORE, "---- ---- ---- ---- ---- ----");
129 HILOG_INFO(LOG_CORE, "FtraceCpuStatsMsg:");
130 HILOG_INFO(LOG_CORE, "status: %s", statusName.c_str());
131 for (int i = 0; i < cpuStats.per_cpu_stats_size(); i++) {
132 HILOG_INFO(LOG_CORE, "per_cpu_stats[%d]: {", i);
133 HILOG_INFO(LOG_CORE, " cpu: %" PRIu64, cpuStats.per_cpu_stats(i).cpu());
134 HILOG_INFO(LOG_CORE, " entries: %" PRIu64, cpuStats.per_cpu_stats(i).entries());
135 HILOG_INFO(LOG_CORE, " overrun: %" PRIu64, cpuStats.per_cpu_stats(i).overrun());
136 HILOG_INFO(LOG_CORE, " commit_overrun: %" PRIu64, cpuStats.per_cpu_stats(i).commit_overrun());
137 HILOG_INFO(LOG_CORE, " bytes: %" PRIu64, cpuStats.per_cpu_stats(i).bytes());
138 HILOG_INFO(LOG_CORE, " oldest_event_ts: %.06f", cpuStats.per_cpu_stats(i).oldest_event_ts());
139 HILOG_INFO(LOG_CORE, " now_ts: %.06f", cpuStats.per_cpu_stats(i).now_ts());
140 HILOG_INFO(LOG_CORE, " dropped_events: %" PRIu64, cpuStats.per_cpu_stats(i).dropped_events());
141 HILOG_INFO(LOG_CORE, " read_events: %" PRIu64, cpuStats.per_cpu_stats(i).read_events());
142 HILOG_INFO(LOG_CORE, "}");
143 }
144 HILOG_INFO(LOG_CORE, "---- ---- ---- ---- ---- ----");
145 }
146
ParseCpuStats(const FtraceCpuStatsMsg & cpuStats)147 void TraceConverter::ParseCpuStats(const FtraceCpuStatsMsg& cpuStats)
148 {
149 auto status = cpuStats.status();
150 decltype(&startStats_) pStats = nullptr;
151 if (status == FtraceCpuStatsMsg::TRACE_START) {
152 startStats_.clear();
153 pStats = &startStats_;
154 } else if (status == FtraceCpuStatsMsg::TRACE_END) {
155 endStats_.clear();
156 pStats = &endStats_;
157 }
158 for (int i = 0; i < cpuStats.per_cpu_stats_size(); i++) {
159 if (pStats) {
160 pStats->push_back(cpuStats.per_cpu_stats(i));
161 }
162 }
163 }
164
SummarizeStats()165 void TraceConverter::SummarizeStats()
166 {
167 auto sumCpuStats = [](const std::vector<PerCpuStatsMsg>& cpuStats) -> PerCpuStatsMsg {
168 PerCpuStatsMsg sum = {};
169 for (auto stats : cpuStats) {
170 sum.set_entries(sum.entries() + stats.entries());
171 sum.set_read_events(sum.read_events() + stats.read_events());
172 }
173 return sum;
174 };
175 endSum_ = sumCpuStats(endStats_);
176 startSum_ = sumCpuStats(startStats_);
177 entriesInBuffer_ = endSum_.read_events() - startSum_.read_events();
178 }
179
180 // refers kernel function trace_print_lat_fmt
181 // https://github.com/torvalds/linux/blob/v4.19/kernel/trace/trace_output.c#L447
TraceFlagsToString(uint32_t flags,uint32_t preemptCount)182 std::string TraceConverter::TraceFlagsToString(uint32_t flags, uint32_t preemptCount)
183 {
184 std::string result = "";
185 char irqsOff = '.';
186 if (flags & TRACE_FLAG_IRQS_OFF) {
187 irqsOff = 'd';
188 } else if (flags & TRACE_FLAG_IRQS_NOSUPPORT) {
189 irqsOff = 'X';
190 }
191 result.push_back(irqsOff);
192
193 char needResched = '.';
194 bool isNeedResched = flags & TRACE_FLAG_NEED_RESCHED;
195 bool isPreemptResched = flags & TRACE_FLAG_PREEMPT_RESCHED;
196 if (isNeedResched && isPreemptResched) {
197 needResched = 'N';
198 } else if (isNeedResched) {
199 needResched = 'n';
200 } else if (isPreemptResched) {
201 needResched = 'p';
202 }
203 result.push_back(needResched);
204
205 bool nmiFlag = flags & TRACE_FLAG_NMI;
206 bool hardIrq = flags & TRACE_FLAG_HARDIRQ;
207 bool softIrq = flags & TRACE_FLAG_SOFTIRQ;
208 char irqChar = '.';
209 if (nmiFlag && hardIrq) {
210 irqChar = 'Z';
211 } else if (nmiFlag) {
212 irqChar = 'z';
213 } else if (hardIrq && softIrq) {
214 irqChar = 'H';
215 } else if (hardIrq) {
216 irqChar = 'h';
217 } else if (softIrq) {
218 irqChar = 's';
219 }
220 result.push_back(irqChar);
221
222 if (preemptCount) {
223 result.push_back("0123456789abcdef"[preemptCount & 0x0F]);
224 } else {
225 result.push_back('.');
226 }
227 return result;
228 }
229
FormatEvent(const FtraceEvent & event,int cpu)230 std::string TraceConverter::FormatEvent(const FtraceEvent& event, int cpu)
231 {
232 std::stringstream sout;
233 int pid = event.common_fields().pid();
234
235 // TASK(comm) part, refers __trace_find_cmdline
236 // https://github.com/torvalds/linux/blob/v4.19/kernel/trace/trace.c#L1978
237 std::string comm = "<...>";
238 if (comm.size()) {
239 comm = event.comm();
240 }
241 if (pid == 0) {
242 comm = "<idle>";
243 }
244 if (comm.size() < COMM_STR_MAX) {
245 comm = std::string(COMM_STR_MAX - comm.size(), ' ') + comm;
246 }
247 sout << comm << '-';
248
249 // PID part
250 std::string pidStr = std::to_string(pid);
251 if (pidStr.size() < PID_STR_MAX) {
252 pidStr.resize(PID_STR_MAX, ' ');
253 }
254 sout << pidStr;
255
256 // TGID part
257 std::string tgidStr = "-----";
258 if (parseGid_ && event.tgid() != 0) {
259 tgidStr = std::to_string(event.tgid());
260 if (tgidStr.size() < TGID_STR_MAX) {
261 tgidStr.insert(tgidStr.begin(), TGID_STR_MAX - tgidStr.size(), ' ');
262 }
263 }
264 sout << '(' << tgidStr << ')';
265
266 // CPU# part
267 std::string cpuStr = std::to_string(cpu);
268 if (cpuStr.size() < CPU_STR_MAX) {
269 cpuStr = std::string(CPU_STR_MAX - cpuStr.size(), '0') + cpuStr;
270 }
271 sout << " [" << cpuStr << "] ";
272
273 // flags part
274 uint32_t flags = event.common_fields().flags();
275 uint32_t preeptCount = event.common_fields().preempt_count();
276 if (parseFlags_ && (flags | preeptCount)) {
277 sout << TraceFlagsToString(flags, preeptCount) << " ";
278 } else {
279 sout << ".... ";
280 }
281
282 // TIMESTAMP part
283 std::string timestamp = "";
284 timestamp = std::to_string(event.timestamp());
285 auto tsLength = timestamp.length();
286 CHECK_TRUE(tsLength > TS_MIN_LEN, "", "invalid timestamp!");
287 std::string tsSecs = timestamp.substr(0, timestamp.size() - TS_MIN_LEN);
288 std::string tsMicroSecs = timestamp.substr(timestamp.size() - TS_MIN_LEN, US_DIGITS);
289 sout << tsSecs << '.' << tsMicroSecs << ": ";
290
291 // FUNCTION part
292 sout << EventFormatter::GetInstance().FormatEvent(event) << "\n";
293 return sout.str();
294 }
295
WriteEvent(const FtraceEvent & event,int cpu)296 bool TraceConverter::WriteEvent(const FtraceEvent& event, int cpu)
297 {
298 std::string line = FormatEvent(event, cpu);
299 CHECK_TRUE(line.size() > 0, false, "format event failed!");
300 auto nbytes = write(outputFd_, line.data(), line.size());
301 CHECK_TRUE(static_cast<size_t>(nbytes) == line.size(), false, "write event line FAILED!");
302 return true;
303 }
304
PrintTextHeader(const std::string & msg)305 void TraceConverter::PrintTextHeader(const std::string& msg)
306 {
307 HILOG_INFO(LOG_CORE, "==== ==== ==== %s ==== ==== ====", msg.c_str());
308 HILOG_INFO(LOG_CORE, "%s", textHeader_.c_str());
309 HILOG_INFO(LOG_CORE, "---- ---- ---- %s ---- ---- ----", msg.c_str());
310 }
311
WriteInitialHeader()312 bool TraceConverter::WriteInitialHeader()
313 {
314 std::vector<char> buffer(TRACE_TXT_HEADER_MAX);
315 int used = snprintf_s(buffer.data(), buffer.size(), buffer.size() - 1, TRACE_TXT_HEADER_FORMAT.c_str(), UINT32_MAX,
316 UINT32_MAX, UINT8_MAX);
317 CHECK_TRUE(used > 0, false, "format initial header failed!");
318 textHeader_.assign(&buffer[0], &buffer[used]);
319
320 auto nbytes = write(outputFd_, textHeader_.data(), textHeader_.size());
321 CHECK_TRUE(static_cast<size_t>(nbytes) == textHeader_.size(), false, "write inital header failed!");
322 PrintTextHeader("INITAL TRACE HEADER");
323 return true;
324 }
325
GenerateNewEntriesValue(uint32_t orginLength)326 std::string TraceConverter::GenerateNewEntriesValue(uint32_t orginLength)
327 {
328 std::string newEntriesValue = std::to_string(entriesInBuffer_);
329 newEntriesValue += '/';
330 newEntriesValue += std::to_string(entriesWritten_);
331 if (newEntriesValue.size() < orginLength) {
332 size_t paddingSpaces = orginLength - newEntriesValue.size();
333 std::string leftPadding(paddingSpaces >> 1, ' ');
334 std::string rightPadding(paddingSpaces - leftPadding.size(), ' ');
335 newEntriesValue = leftPadding + newEntriesValue + rightPadding; // align center
336 }
337 return newEntriesValue;
338 }
339
GenerateNewNumProcsValue(uint32_t originLength)340 std::string TraceConverter::GenerateNewNumProcsValue(uint32_t originLength)
341 {
342 std::string newNumProcsValue = std::to_string(numProcessors_);
343 if (newNumProcsValue.size() < originLength) {
344 size_t padding = originLength - newNumProcsValue.size();
345 std::string spaces(padding, ' ');
346 newNumProcsValue = spaces + newNumProcsValue; // align right
347 }
348 return newNumProcsValue;
349 }
350
351 // nppEnd
352 // |
353 // format: # entries-in-buffer/entries-written: 4294967295/4294967295 #P:255\n
354 // | | | |
355 // esp espEnd npp eol
WriteFinalHeader()356 bool TraceConverter::WriteFinalHeader()
357 {
358 HILOG_INFO(LOG_CORE, "WriteFinalHeader start!");
359 auto esp = textHeader_.find(ENTIRES_STATS_PREFIX); // entries stats prefix start
360 CHECK_TRUE(esp != std::string::npos, false, "entries stats prefix not found!");
361 auto espEnd = esp + ENTIRES_STATS_PREFIX.size(); // end of entries stats prefix
362
363 auto npp = textHeader_.find(PROCESSOR_NUMBER_PREFIX, espEnd); // number processor prefix
364 CHECK_TRUE(npp, false, "number processors prefix not found!");
365 auto nppEnd = npp + PROCESSOR_NUMBER_PREFIX.size();
366
367 auto eol = textHeader_.find('\n', nppEnd); // end of line
368 CHECK_TRUE(eol != std::string::npos, false, "entries stats line end not found!");
369
370 size_t entriesValueLen = npp - espEnd;
371 std::string newEntriesValue = GenerateNewEntriesValue(entriesValueLen);
372 CHECK_TRUE(newEntriesValue.size() == entriesValueLen, false, "entries value length mismatch: %zu/%zu",
373 entriesValueLen, newEntriesValue.size());
374 HILOG_DEBUG(LOG_CORE, "newEntriesValue: '%s'", newEntriesValue.c_str());
375
376 size_t numProcsValueLen = eol - nppEnd;
377 std::string newNumProcsValue = GenerateNewNumProcsValue(numProcsValueLen);
378 CHECK_TRUE(newNumProcsValue.size() == numProcsValueLen, false, "numProcs value length mismatch: %zu/%zu",
379 numProcsValueLen, newNumProcsValue.size());
380 HILOG_DEBUG(LOG_CORE, "newNumProcsValue: '%s'", newNumProcsValue.c_str());
381
382 auto headerLength = textHeader_.size();
383 textHeader_.replace(nppEnd, newNumProcsValue.size(), newNumProcsValue);
384 textHeader_.replace(espEnd, newEntriesValue.size(), newEntriesValue);
385 CHECK_TRUE(textHeader_.size() == headerLength, false, "header size mismatch %zu => %zu!", headerLength,
386 textHeader_.size());
387
388 lseek(outputFd_, 0, SEEK_SET); // move write postion to file head
389 auto nbytes = write(outputFd_, textHeader_.data(), textHeader_.size());
390 CHECK_TRUE(static_cast<size_t>(nbytes) == textHeader_.size(), false, "write final header failed!");
391 PrintTextHeader("FINAL TRACE HEADER");
392
393 // flush file buffer
394 CHECK_TRUE(fsync(outputFd_) == 0, false, "fsync %s FAILED, %d", output_.c_str(), errno);
395 HILOG_INFO(LOG_CORE, "WriteFinalHeader done!");
396 return true;
397 }
398
ReadAndParseEvents()399 bool TraceConverter::ReadAndParseEvents()
400 {
401 long resultCount = 0;
402 ProfilerPluginData pluginData;
403 auto parseStart = Clock::now();
404 while (reader_.Read(pluginData) > 0) {
405 resultCount++;
406 if (pluginData.name().find("trace") == std::string::npos) {
407 continue;
408 }
409
410 TracePluginResult result;
411 auto& data = pluginData.data();
412 CHECK_TRUE(result.ParseFromArray(data.data(), data.size()), false, "parse result failed!");
413
414 std::string progresss = "[" + std::to_string(resultCount) + "/" + std::to_string(numberResults_) + "]";
415 if (result.ftrace_cpu_stats_size() > 0) {
416 HILOG_INFO(LOG_CORE, "%s parse %d cpu stats result...", progresss.c_str(), result.ftrace_cpu_stats_size());
417 for (auto& cpuStats : result.ftrace_cpu_stats()) {
418 PrintCpuStats(cpuStats);
419 ParseCpuStats(cpuStats);
420 numProcessors_ = std::max(numProcessors_, cpuStats.per_cpu_stats_size());
421 }
422 cpuEventQeueue_.resize(numProcessors_, {});
423 } else if (result.symbols_detail_size() > 0) {
424 HILOG_INFO(LOG_CORE, "%s parse %d kernel symbols ...", progresss.c_str(), result.symbols_detail_size());
425 for (auto& msg : result.symbols_detail()) {
426 kernelSymbols_[msg.symbol_addr()] = msg.symbol_name();
427 }
428 } else if (result.ftrace_cpu_detail_size() > 0) {
429 HILOG_INFO(LOG_CORE, "%s parse %d cpu details...", progresss.c_str(), result.ftrace_cpu_detail_size());
430 for (auto& details : result.ftrace_cpu_detail()) {
431 const int cpu = details.cpu();
432 auto& eventQ = cpuEventQeueue_[cpu];
433 eventQ.reserve(eventQ.size() + details.event_size());
434 for (int i = 0; i < details.event_size(); i++) {
435 eventQ.push_back(details.event(i));
436 }
437 }
438 } else {
439 HILOG_WARN(LOG_CORE, "WARNING: other types of result...");
440 }
441 }
442 auto parseDone = Clock::now();
443 HILOG_INFO(LOG_CORE, "parsed done, results: %ld, time cost: %ld ms!", resultCount,
444 TimeDeltaMs(parseDone, parseStart));
445 HILOG_INFO(LOG_CORE, "CPU numbers: %d", numProcessors_);
446 return true;
447 }
448
ConvertAndWriteEvents()449 bool TraceConverter::ConvertAndWriteEvents()
450 {
451 uint64_t totalEvents = 0;
452 HILOG_INFO(LOG_CORE, "summary of events on each CPU:");
453 for (size_t i = 0; i < cpuEventQeueue_.size(); i++) {
454 totalEvents += cpuEventQeueue_[i].size();
455 HILOG_INFO(LOG_CORE, " events on CPU%zu: %zu", i, cpuEventQeueue_[i].size());
456 }
457 HILOG_INFO(LOG_CORE, "events on all CPU: %" PRIu64, totalEvents);
458
459 // GOAL: sort all events, and write its to file.
460 // on each event list, the events are ordered by timestamp
461 // so we can used multi-way merge algorithm.
462 std::vector<uint32_t> queueFront(numProcessors_, 0);
463 HILOG_INFO(LOG_CORE, "start convert and write events to output...");
464 auto writeStart = Clock::now();
465 for (uint64_t i = 0; i < totalEvents; i++) {
466 // firstly, pick an event with smallest timestamp
467 uint32_t cpuId = 0;
468 uint64_t minTs = UINT64_MAX;
469 for (int c = 0; c < numProcessors_; c++) {
470 uint32_t cursor = queueFront[c];
471 if (cursor >= cpuEventQeueue_[c].size()) { // no more event on this queue
472 continue;
473 }
474 uint64_t ts = cpuEventQeueue_[c][cursor].timestamp();
475 if (ts < minTs) {
476 minTs = ts;
477 cpuId = c;
478 }
479 }
480 // secondly, write picked event to file
481 CHECK_TRUE(WriteEvent(cpuEventQeueue_[cpuId][queueFront[cpuId]], cpuId), false,
482 "write event [%" PRIu64 "] for CPU%u failed!", i, cpuId);
483 queueFront[cpuId]++;
484 float progress = i * 100.0f / totalEvents;
485 HILOG_INFO(LOG_CORE, "progress = % 3.2f, ts = %" PRIu64 ", cpu = %u", progress, minTs, cpuId);
486 }
487 printf("\n");
488 auto writeDone = Clock::now();
489 HILOG_INFO(LOG_CORE, "convert and write events done, time cost: %ld ms!", TimeDeltaMs(writeDone, writeStart));
490 entriesWritten_ = static_cast<decltype(entriesWritten_)>(totalEvents);
491 return totalEvents;
492 }
493
Convert()494 bool TraceConverter::Convert()
495 {
496 char realPath[PATH_MAX + 1] = {0};
497
498 auto startTime = Clock::now();
499 CHECK_TRUE(access(input_.c_str(), R_OK) == 0, false, "input %s not found!", input_.c_str());
500 CHECK_TRUE(reader_.Open(input_), false, "open %s failed!", input_.c_str());
501
502 auto header = reader_.GetHeader();
503 PrintTraceFileHeader(header);
504 numberResults_ = (header.data_.segments_ >> 1); // pairs of (length segment, data segment)
505 HILOG_INFO(LOG_CORE, "number of results in trace file header: %u", numberResults_);
506
507 if ((output_.length() > PATH_MAX) || (realpath(output_.c_str(), realPath) == nullptr)) {
508 return false;
509 }
510 outputFd_ = open(realPath, O_CREAT | O_RDWR, OUTPUT_FILE_MODE);
511 CHECK_TRUE(outputFd_ != -1, false, "open %s failed!", output_.c_str());
512 CHECK_TRUE(WriteInitialHeader(), false, "write initial header failed!");
513
514 CHECK_TRUE(ReadAndParseEvents(), false, "read and parse events failed!");
515 CHECK_TRUE(ConvertAndWriteEvents(), false, "convert and write events failed!");
516 SummarizeStats();
517
518 CHECK_TRUE(WriteFinalHeader(), false, "write final header failed!");
519 CHECK_TRUE(close(outputFd_) == 0, false, "close %s FAILED, %d", output_.c_str(), errno);
520 outputFd_ = INVALID_FD;
521
522 auto endTime = Clock::now();
523 HILOG_INFO(LOG_CORE, "convert %s to %s done!", input_.c_str(), output_.c_str());
524 HILOG_INFO(LOG_CORE, "total time cost: %ld ms!", TimeDeltaMs(endTime, startTime));
525 return true;
526 }
527
SetParseGid(bool parseGid)528 void TraceConverter::SetParseGid(bool parseGid)
529 {
530 parseGid_ = parseGid;
531 }
532
SetParseFlags(bool parseFlags)533 void TraceConverter::SetParseFlags(bool parseFlags)
534 {
535 parseFlags_ = parseFlags;
536 }
537