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 fullMethodName = "System_Frame";
31 } else {
32 const panda_file::File *pf = nullptr;
33 auto it = modulesMap_->find(pfId);
34 if (it != modulesMap_->end()) {
35 pf = it->second.get();
36 }
37
38 fullMethodName = ResolveName(pf, fileId);
39 }
40 stream << fullMethodName << "; ";
41 }
42 stream << count << "\n";
43 }
44
45 /* static */
WriteThreadId(std::ofstream & stream,uint32_t threadId)46 void TraceDumper::WriteThreadId(std::ofstream &stream, uint32_t threadId)
47 {
48 stream << "thread_id = " << threadId << "; ";
49 }
50
51 /* static */
WriteThreadStatus(std::ofstream & stream,SampleInfo::ThreadStatus threadStatus)52 void TraceDumper::WriteThreadStatus(std::ofstream &stream, SampleInfo::ThreadStatus threadStatus)
53 {
54 stream << "status = ";
55
56 switch (threadStatus) {
57 case SampleInfo::ThreadStatus::RUNNING: {
58 stream << "active; ";
59 break;
60 }
61 case SampleInfo::ThreadStatus::SUSPENDED: {
62 stream << "suspended; ";
63 break;
64 }
65 default: {
66 UNREACHABLE();
67 }
68 }
69 }
70
ResolveName(const panda_file::File * pf,uint64_t fileId) const71 std::string TraceDumper::ResolveName(const panda_file::File *pf, uint64_t fileId) const
72 {
73 if (pf == nullptr) {
74 return std::string("__unknown_module::" + std::to_string(fileId));
75 }
76
77 auto it = methodsMap_->find(pf);
78 if (it != methodsMap_->end()) {
79 return it->second.at(fileId);
80 }
81
82 return pf->GetFilename() + "::__unknown_" + std::to_string(fileId);
83 }
84
85 /* override */
ResolveStream(const SampleInfo & sample)86 std::ofstream &SingleCSVDumper::ResolveStream(const SampleInfo &sample)
87 {
88 if (option_ == DumpType::THREAD_SEPARATION_BY_TID) {
89 WriteThreadId(stream_, sample.threadInfo.threadId);
90 }
91 if (buildColdGraph_) {
92 WriteThreadStatus(stream_, sample.threadInfo.threadStatus);
93 }
94 return stream_;
95 }
96
97 /* override */
ResolveStream(const SampleInfo & sample)98 std::ofstream &MultipleCSVDumper::ResolveStream(const SampleInfo &sample)
99 {
100 auto it = threadIdMap_.find(sample.threadInfo.threadId);
101 if (it == threadIdMap_.end()) {
102 std::string filenameWithThreadId = AddThreadIdToFilename(filename_, sample.threadInfo.threadId);
103
104 auto returnPair = threadIdMap_.insert({sample.threadInfo.threadId, std::ofstream(filenameWithThreadId)});
105 it = returnPair.first;
106
107 auto isSuccessInsert = returnPair.second;
108 if (!isSuccessInsert) {
109 LOG(FATAL, PROFILER) << "Failed while insert in unordored_map";
110 }
111 }
112
113 WriteThreadId(it->second, sample.threadInfo.threadId);
114
115 if (buildColdGraph_) {
116 WriteThreadStatus(it->second, sample.threadInfo.threadStatus);
117 }
118
119 return it->second;
120 }
121
122 /* static */
AddThreadIdToFilename(const std::string & filename,uint32_t threadId)123 std::string MultipleCSVDumper::AddThreadIdToFilename(const std::string &filename, uint32_t threadId)
124 {
125 std::string filenameWithThreadId(filename);
126
127 std::size_t pos = filenameWithThreadId.find("csv");
128 if (pos == std::string::npos) {
129 LOG(FATAL, PROFILER) << "Incorrect output filename, *.csv format expected";
130 }
131
132 filenameWithThreadId.insert(pos - 1, std::to_string(threadId));
133
134 return filenameWithThreadId;
135 }
136
137 } // namespace ark::tooling::sampler
138