1 /**
2 * Copyright (c) 2021-2024 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
16 #include "trace_dumper.h"
17
18 namespace ark::tooling::sampler {
19
DumpTraces(const SampleInfo & sample,size_t count)20 void TraceDumper::DumpTraces(const SampleInfo &sample, size_t count)
21 {
22 std::ofstream &stream = ResolveStream(sample);
23
24 for (size_t i = sample.stackInfo.managedStackSize; i-- > 0;) {
25 uintptr_t pfId = sample.stackInfo.managedStack[i].pandaFilePtr;
26 uint64_t fileId = sample.stackInfo.managedStack[i].fileId;
27
28 std::string fullMethodName;
29 if (pfId == helpers::ToUnderlying(FrameKind::BRIDGE)) {
30 if (!buildSystemFrames_) {
31 continue;
32 }
33
34 fullMethodName = "System_Frame";
35 } else {
36 const panda_file::File *pf = nullptr;
37 auto it = modulesMap_->find(pfId);
38 if (it != modulesMap_->end()) {
39 pf = it->second.get();
40 }
41
42 fullMethodName = ResolveName(pf, fileId);
43 }
44 stream << fullMethodName << "; ";
45 }
46 stream << count << "\n";
47 }
48
SetBuildSystemFrames(bool buildSystemFrames)49 void TraceDumper::SetBuildSystemFrames(bool buildSystemFrames)
50 {
51 buildSystemFrames_ = buildSystemFrames;
52 }
53
54 /* static */
WriteThreadId(std::ofstream & stream,uint32_t threadId)55 void TraceDumper::WriteThreadId(std::ofstream &stream, uint32_t threadId)
56 {
57 stream << "thread_id = " << threadId << "; ";
58 }
59
60 /* static */
WriteThreadStatus(std::ofstream & stream,SampleInfo::ThreadStatus threadStatus)61 void TraceDumper::WriteThreadStatus(std::ofstream &stream, SampleInfo::ThreadStatus threadStatus)
62 {
63 stream << "status = ";
64
65 switch (threadStatus) {
66 case SampleInfo::ThreadStatus::RUNNING: {
67 stream << "active; ";
68 break;
69 }
70 case SampleInfo::ThreadStatus::SUSPENDED: {
71 stream << "suspended; ";
72 break;
73 }
74 default: {
75 UNREACHABLE();
76 }
77 }
78 }
79
ResolveName(const panda_file::File * pf,uint64_t fileId) const80 std::string TraceDumper::ResolveName(const panda_file::File *pf, uint64_t fileId) const
81 {
82 if (pf == nullptr) {
83 return std::string("__unknown_module::" + std::to_string(fileId));
84 }
85
86 auto it = methodsMap_->find(pf);
87 if (it != methodsMap_->end()) {
88 return it->second.at(fileId);
89 }
90
91 return pf->GetFilename() + "::__unknown_" + std::to_string(fileId);
92 }
93
94 /* override */
ResolveStream(const SampleInfo & sample)95 std::ofstream &SingleCSVDumper::ResolveStream(const SampleInfo &sample)
96 {
97 if (option_ == DumpType::THREAD_SEPARATION_BY_TID) {
98 WriteThreadId(stream_, sample.threadInfo.threadId);
99 }
100 if (buildColdGraph_) {
101 WriteThreadStatus(stream_, sample.threadInfo.threadStatus);
102 }
103 return stream_;
104 }
105
106 /* override */
ResolveStream(const SampleInfo & sample)107 std::ofstream &MultipleCSVDumper::ResolveStream(const SampleInfo &sample)
108 {
109 auto it = threadIdMap_.find(sample.threadInfo.threadId);
110 if (it == threadIdMap_.end()) {
111 std::string filenameWithThreadId = AddThreadIdToFilename(filename_, sample.threadInfo.threadId);
112
113 auto returnPair = threadIdMap_.insert({sample.threadInfo.threadId, std::ofstream(filenameWithThreadId)});
114 it = returnPair.first;
115
116 auto isSuccessInsert = returnPair.second;
117 if (!isSuccessInsert) {
118 LOG(FATAL, PROFILER) << "Failed while insert in unordored_map";
119 }
120 }
121
122 WriteThreadId(it->second, sample.threadInfo.threadId);
123
124 if (buildColdGraph_) {
125 WriteThreadStatus(it->second, sample.threadInfo.threadStatus);
126 }
127
128 return it->second;
129 }
130
131 /* static */
AddThreadIdToFilename(const std::string & filename,uint32_t threadId)132 std::string MultipleCSVDumper::AddThreadIdToFilename(const std::string &filename, uint32_t threadId)
133 {
134 std::string filenameWithThreadId(filename);
135
136 std::size_t pos = filenameWithThreadId.find("csv");
137 if (pos == std::string::npos) {
138 LOG(FATAL, PROFILER) << "Incorrect output filename, *.csv format expected";
139 }
140
141 filenameWithThreadId.insert(pos - 1, std::to_string(threadId));
142
143 return filenameWithThreadId;
144 }
145
146 } // namespace ark::tooling::sampler
147