• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 #include "ecmascript/cpu_profiler/profile_generator.h"
17 
18 #include <climits>
19 #include "ecmascript/cpu_profiler/cpu_profiler.h"
20 #include "ecmascript/interpreter/interpreter.h"
21 namespace panda::ecmascript {
22 bool ProfileGenerator::staticGcState_ = false;
ProfileGenerator()23 ProfileGenerator::ProfileGenerator()
24 {
25     stackTopLines_.push_back(0);
26     struct MethodKey methodkey;
27     struct MethodNode methodNode;
28     methodkey.method = reinterpret_cast<JSMethod*>(INT_MAX - 1);
29     methodMap_.insert(std::make_pair(methodkey, methodMap_.size() + 1));
30     methodNode.parentId = 0;
31     methodNode.codeEntry.codeType = "JS";
32     methodNodes_.push_back(methodNode);
33 }
34 
~ProfileGenerator()35 ProfileGenerator::~ProfileGenerator()
36 {
37     if (fileHandle_.is_open()) {
38         fileHandle_.close();
39     }
40 }
41 
AddSample(CVector<JSMethod * > sample,uint64_t sampleTimeStamp)42 void ProfileGenerator::AddSample(CVector<JSMethod *> sample, uint64_t sampleTimeStamp)
43 {
44     static int PreviousId = 0;
45     struct MethodKey methodkey;
46     struct MethodNode methodNode;
47     if (staticGcState_) {
48         methodkey.method = reinterpret_cast<JSMethod*>(INT_MAX);
49         methodNode.parentId = methodkey.parentId = PreviousId;
50         auto result = methodMap_.find(methodkey);
51         if (result == methodMap_.end()) {
52             methodNode.id = methodMap_.size() + 1;
53             methodMap_.insert(std::make_pair(methodkey, methodNode.id));
54             methodNode.codeEntry = GetGcInfo();
55             stackTopLines_.push_back(0);
56             methodNodes_.push_back(methodNode);
57         } else {
58             methodNode.id = result->second;
59         }
60         staticGcState_ = false;
61     } else {
62         for (auto method = sample.rbegin(); method != sample.rend(); method++) {
63             methodkey.method = *method;
64             if (method == sample.rbegin()) {
65                 methodNode.id = 1;
66                 continue;
67             } else {
68                 methodNode.parentId = methodkey.parentId = methodNode.id;
69             }
70             auto result = methodMap_.find(methodkey);
71             if (result == methodMap_.end()) {
72                 int id = methodMap_.size() + 1;
73                 methodMap_.insert(std::make_pair(methodkey, id));
74                 PreviousId = methodNode.id = id;
75                 methodNode.codeEntry = GetMethodInfo(methodkey.method);
76                 stackTopLines_.push_back(methodNode.codeEntry.lineNumber);
77                 methodNodes_.push_back(methodNode);
78             } else {
79                 PreviousId = methodNode.id = result->second;
80             }
81         }
82     }
83     static uint64_t threadStartTime = 0;
84     struct SampleInfo sampleInfo;
85     sampleInfo.id = methodNode.id == 0 ? PreviousId = 1, 1 : methodNode.id;
86     sampleInfo.line = stackTopLines_[methodNode.id];
87     if (threadStartTime == 0) {
88         sampleInfo.timeStamp = sampleTimeStamp - threadStartTime_;
89     } else {
90         sampleInfo.timeStamp = sampleTimeStamp - threadStartTime;
91     }
92     samples_.push_back(sampleInfo);
93     threadStartTime = sampleTimeStamp;
94 }
95 
WriteAddNodes()96 void ProfileGenerator::WriteAddNodes()
97 {
98     sampleData_ += "{\"args\":{\"data\":{\"cpuProfile\":{\"nodes\":[";
99     for (auto it : methodNodes_) {
100         sampleData_ += "{\"callFrame\":{\"codeType\":\"" + it.codeEntry.codeType + "\",";
101         if (it.parentId == 0) {
102             sampleData_ += "\"functionName\":\"(root)\",\"scriptId\":0},\"id\":1},";
103             continue;
104         }
105         if (it.codeEntry.codeType == "other" || it.codeEntry.codeType == "jsvm") {
106             sampleData_ += "\"functionName\":\"" + it.codeEntry.functionName + "\",\"scriptId\":" +
107                            std::to_string(it.codeEntry.scriptId) + "},\"id\":" + std::to_string(it.id);
108         } else {
109             sampleData_ += "\"columnNumber\":" + std::to_string(it.codeEntry.columnNumber) +
110                            ",\"functionName\":\"" + it.codeEntry.functionName + "\",\"lineNumber\":\"" +
111                            std::to_string(it.codeEntry.lineNumber) + "\",\"scriptId\":" +
112                            std::to_string(it.codeEntry.scriptId) + ",\"url\":\"" + it.codeEntry.url +
113                            "\"},\"id\":" + std::to_string(it.id);
114         }
115         sampleData_ += ",\"parent\":" + std::to_string(it.parentId) + "},";
116     }
117     sampleData_.pop_back();
118     sampleData_ += "],\"samples\":[";
119 }
120 
WriteAddSamples()121 void ProfileGenerator::WriteAddSamples()
122 {
123     if (samples_.empty()) {
124         return;
125     }
126     std::string sampleId = "";
127     std::string sampleLine = "";
128     std::string timeStamp = "";
129     for (auto it : samples_) {
130         sampleId += std::to_string(it.id) + ",";
131         sampleLine += std::to_string(it.line) + ",";
132         timeStamp += std::to_string(it.timeStamp) + ",";
133     }
134     sampleId.pop_back();
135     sampleLine.pop_back();
136     timeStamp.pop_back();
137     sampleData_ += sampleId + "]},\"lines\":[" + sampleLine + "],\"timeDeltas\":[" + timeStamp + "]}},";
138 }
139 
WriteMethodsAndSampleInfo(bool timeEnd)140 void ProfileGenerator::WriteMethodsAndSampleInfo(bool timeEnd)
141 {
142     if (methodNodes_.size() >= 10) { // 10:Number of nodes currently stored
143         WriteAddNodes();
144         WriteAddSamples();
145         methodNodes_.clear();
146         samples_.clear();
147     } else if (samples_.size() == 100 || timeEnd) { // 100:Number of samples currently stored
148         if (!methodNodes_.empty()) {
149             WriteAddNodes();
150             WriteAddSamples();
151             methodNodes_.clear();
152             samples_.clear();
153         } else if (!samples_.empty()) {
154             sampleData_ += "{\"args\":{\"data\":{\"cpuProfile\":{\"samples\":[";
155             WriteAddSamples();
156             samples_.clear();
157         } else {
158             return;
159         }
160     }
161     sampleData_ += "\"cat\":\"disabled-by-default-ark.cpu_profiler\",\"id\":"
162                     "\"0x2\",\"name\":\"ProfileChunk\",\"ph\":\"P\",\"pid\":";
163     pid_t pid = getpid();
164     pthread_t tid = syscall(SYS_gettid);
165     uint64_t ts = ProfileProcessor::GetMicrosecondsTimeStamp();
166     ts = ts % TIME_CHANGE;
167     struct timespec time = {0, 0};
168     clock_gettime(CLOCK_MONOTONIC, &time);
169     uint64_t tts = time.tv_nsec / 1000; // 1000:Nanoseconds to milliseconds.
170     sampleData_ += std::to_string(pid) + ",\"tid\":" +
171                    std::to_string(tid) + ",\"ts\":" +
172                    std::to_string(ts) + ",\"tts\":" +
173                    std::to_string(tts) + "},\n";
174 }
175 
GetMethodNodes() const176 CVector<struct MethodNode> ProfileGenerator::GetMethodNodes() const
177 {
178     return methodNodes_;
179 }
180 
GetSamples() const181 CDeque<struct SampleInfo> ProfileGenerator::GetSamples() const
182 {
183     return samples_;
184 }
185 
GetSampleData() const186 std::string ProfileGenerator::GetSampleData() const
187 {
188     return sampleData_;
189 }
190 
GetMethodInfo(JSMethod * method)191 struct StackInfo ProfileGenerator::GetMethodInfo(JSMethod *method)
192 {
193     struct StackInfo entry;
194     auto iter = CpuProfiler::staticStackInfo_.find(method);
195     if (iter != CpuProfiler::staticStackInfo_.end()) {
196         entry = iter->second;
197     }
198     return entry;
199 }
200 
GetGcInfo()201 struct StackInfo ProfileGenerator::GetGcInfo()
202 {
203     struct StackInfo gcEntry;
204     gcEntry.codeType = "jsvm";
205     gcEntry.functionName = "garbage collector";
206     return gcEntry;
207 }
208 
SetThreadStartTime(uint64_t threadStartTime)209 void ProfileGenerator::SetThreadStartTime(uint64_t threadStartTime)
210 {
211     threadStartTime_ = threadStartTime;
212 }
213 
SetStartsampleData(std::string sampleData)214 void ProfileGenerator::SetStartsampleData(std::string sampleData)
215 {
216     sampleData_ += sampleData;
217 }
218 
SetFileName(std::string & fileName)219 void ProfileGenerator::SetFileName(std::string &fileName)
220 {
221     fileName_ = fileName;
222 }
223 
GetFileName() const224 const std::string ProfileGenerator::GetFileName() const
225 {
226     return fileName_;
227 }
228 
ClearSampleData()229 void ProfileGenerator::ClearSampleData()
230 {
231     sampleData_.clear();
232 }
233 } // namespace panda::ecmascript