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 #ifndef REPORT_JSON_FILE_H
17 #define REPORT_JSON_FILE_H
18
19 #include <algorithm>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <functional>
23 #include <map>
24
25 #include "debug_logger.h"
26 #include "perf_file_reader.h"
27 #include "utilities.h"
28 #include "virtual_runtime.h"
29
30 namespace OHOS {
31 namespace Developtools {
32 namespace HiPerf {
33 using jsonStringMap = std::map<std::string, std::string>;
34 using jsonStringVector = std::vector<std::string>;
35 using jsonIntVector = std::vector<int>;
36
37 template<class T>
OutputJsonKey(FILE * output,const T & value)38 void OutputJsonKey(FILE *output, const T &value)
39 {
40 if constexpr (std::is_same<T, std::string>::value) {
41 if (value.empty()) {
42 // for key vector [] mode, not key is needed
43 return;
44 }
45 fprintf(output, "\"%s\":", value.c_str());
46 } else if constexpr (std::is_same<T, std::string_view>::value) {
47 if (value.empty()) {
48 // for key vector [] mode, not key is needed
49 return;
50 }
51 fprintf(output, "\"%s\":", value.data());
52 } else if constexpr (std::is_same<typename std::decay<T>::type, char *>::value) {
53 if (value[0] == '\0') {
54 // same as value.empty()
55 return;
56 }
57 fprintf(output, "\"%s\":", value);
58 } else {
59 fprintf(output, "\"%s\":", std::to_string(value).c_str());
60 }
61 }
62 template<class T>
63 void OutputJsonValue(FILE *output, const T &value, const bool first = true)
64 {
65 if (!first) {
66 fprintf(output, ",");
67 }
68 if constexpr (std::is_same<T, std::string>::value) {
69 fprintf(output, "\"%s\"", value.c_str());
70 } else if constexpr (std::is_same<T, std::string_view>::value) {
71 fprintf(output, "\"%s\"", value.data());
72 } else if constexpr (std::is_same<T, int>::value) {
73 fprintf(output, "%s", std::to_string(value).c_str());
74 } else if constexpr (std::is_same<T, uint64_t>::value) {
75 fprintf(output, "%s", std::to_string(value).c_str());
76 } else if constexpr (std::is_same<T, bool>::value) {
77 fprintf(output, "%s", std::to_string(value).c_str());
78 } else if constexpr (std::is_same<T, size_t>::value) {
79 fprintf(output, "%s", std::to_string(value).c_str());
80 } else if constexpr (std::is_same<typename std::decay<T>::type, char *>::value) {
81 fprintf(output, "\"%s\"", value);
82 } else {
83 value.OutputJson(output);
84 }
85 }
86
87 /*
88 k:"v"
89 k:1
90 */
91 template<class K, class T>
92 void OutputJsonPair(FILE *output, const K &key, const T &value, const bool first = false)
93 {
94 if (!first) {
95 if (fprintf(output, ",") < 0) {
96 return;
97 }
98 }
99 // for id, symbol
100 OutputJsonKey(output, key);
101 // ReportFuncMapItem funcName.
102 OutputJsonValue(output, value);
103 }
104
105 /*
106 k:[v1,v2,v3]
107 */
108 template<class T>
109 void OutputJsonVectorList(FILE *output, const std::string &key, const std::vector<T> &value,
110 const bool first = false)
111 {
112 if (!first) {
113 if (fprintf(output, ",") < 0) {
114 return;
115 }
116 }
117 if (fprintf(output, "\"%s\":[", key.c_str()) != -1) {
118 auto it = value.begin();
119 while (it != value.end()) {
120 OutputJsonValue(output, *it, it == value.begin());
121 it++;
122 }
123 if (fprintf(output, "]") < 0) {
124 return;
125 }
126 }
127 }
128
129 /*
130 k:[v1,v2,v3]
131 */
132 template<class K, class V>
133 void OutputJsonMapList(FILE *output, const std::string &key, const std::map<K, V> &value,
134 const bool first = false)
135 {
136 if (!first) {
137 if (fprintf(output, ",") < 0) {
138 return;
139 }
140 }
141 if (fprintf(output, "\"%s\":[", key.c_str()) != -1) {
142 auto it = value.begin();
143 while (it != value.end()) {
144 OutputJsonValue(output, it->second, it == value.begin());
145 it++;
146 }
147 if (fprintf(output, "]") < 0) {
148 return;
149 }
150 }
151 }
152
153 /*
154 k:{k1:v1,k2:v2,k3:v3}
155 */
156 template<class K, class V>
157 void OutputJsonMap(FILE *output, const std::string &key, const std::map<K, V> &value,
158 const bool first = false)
159 {
160 if (!first) {
161 if (fprintf(output, ",") < 0) {
162 return;
163 }
164 }
165 if (fprintf(output, "\"%s\":{", key.c_str()) != -1) {
166 auto it = value.begin();
167 while (it != value.end()) {
168 OutputJsonPair(output, it->first, it->second, it == value.begin());
169 it++;
170 }
171 if (fprintf(output, "}") < 0) {
172 return;
173 }
174 }
175 }
176
177 template<class K, class V>
GetOrCreateMapItem(std::map<K,V> & map,const K & key)178 V &GetOrCreateMapItem(std::map<K, V> &map, const K &key)
179 {
180 if (map.count(key) == 0) {
181 map.emplace(key, (key));
182 }
183 return map.at(key);
184 }
185
186 struct ReportFuncMapItem {
187 int libId_ = -1;
188 std::string funcName_;
189 int reportFuncId_ = -1;
OutputJsonReportFuncMapItem190 void OutputJson(FILE *output) const
191 {
192 if (fprintf(output, "{") < 0) {
193 return;
194 }
195 OutputJsonPair(output, "file", libId_, true);
196 std::string funcName = StringReplace(funcName_, "\"", "");
197 OutputJsonPair(output, "symbol", funcName);
198 if (fprintf(output, "}") < 0) {
199 return;
200 }
201 }
ReportFuncMapItemReportFuncMapItem202 ReportFuncMapItem(int libId, std::string &funcName, int reportFuncId)
203 : libId_(libId), funcName_(funcName), reportFuncId_(reportFuncId) {}
204 };
205
206 struct ReportFuncItem {
207 int functionId_ = -1;
208 int functionInLibId_ = -1;
209 uint64_t sampleCount_ = 0;
210 uint64_t eventCount_ = 0;
211 uint64_t subTreeEventCount_ = 0;
ReportFuncItemReportFuncItem212 explicit ReportFuncItem(int functionId) : functionId_(functionId) {}
OutputJsonReportFuncItem213 void OutputJson(FILE *output) const
214 {
215 if (fprintf(output, "{") < 0) {
216 return;
217 }
218 OutputJsonPair(output, "symbol", functionId_, true);
219 OutputJsonVectorList(output, "counts",
220 std::vector<uint64_t> {sampleCount_, eventCount_, subTreeEventCount_});
221 if (fprintf(output, "}") < 0) {
222 return;
223 }
224 }
225 };
226
227 struct ReportCallNodeItem {
228 uint64_t selfEventCount_ = 0;
229 uint64_t subTreeEventCount_ = 0;
230 int functionId_ = -1;
231 int nodeIndex_ = -1;
232 bool reverseCaller_ = false;
233 std::string_view funcName_ = "";
234 std::string debug_ = "";
235 std::map<int, ReportCallNodeItem> childrenMap;
236
OutputJsonReportCallNodeItem237 void OutputJson(FILE *output) const
238 {
239 if (fprintf(output, "{") < 0) {
240 return;
241 }
242 OutputJsonPair(output, "selfEvents", selfEventCount_, true);
243 OutputJsonPair(output, "subEvents", subTreeEventCount_);
244 OutputJsonPair(output, "symbol", functionId_);
245 if (!funcName_.empty()) { // for debug
246 OutputJsonPair(output, "funcName", funcName_);
247 OutputJsonPair(output, "nodeIndex", nodeIndex_);
248 OutputJsonPair(output, "reversed", reverseCaller_);
249 }
250 OutputJsonMapList(output, "callStack", childrenMap);
251 if (fprintf(output, "}") < 0) {
252 return;
253 }
254 }
255
UpdateChildrenEventCountReportCallNodeItem256 uint64_t UpdateChildrenEventCount()
257 {
258 subTreeEventCount_ = selfEventCount_;
259 for (auto &pair : childrenMap) {
260 subTreeEventCount_ += pair.second.UpdateChildrenEventCount();
261 if (!funcName_.empty()) {
262 }
263 }
264 return subTreeEventCount_;
265 }
266
FindByFunctionIdReportCallNodeItem267 static bool FindByFunctionId(ReportCallNodeItem &a, int functionId)
268 {
269 return (a.functionId_ == functionId);
270 }
271
ReportCallNodeItemReportCallNodeItem272 explicit ReportCallNodeItem(int functionId) : functionId_(functionId) {}
273 };
274
275 struct ReportLibItem {
276 int libId_ = 0;
277 uint64_t eventCount_ = 0;
278 std::map<int, ReportFuncItem> funcs_;
OutputJsonReportLibItem279 void OutputJson(FILE *output) const
280 {
281 if (fprintf(output, "{") < 0) {
282 return;
283 }
284 OutputJsonPair(output, "fileId", libId_, true);
285 OutputJsonPair(output, "eventCount", eventCount_);
286 OutputJsonMapList(output, "functions", funcs_);
287 if (fprintf(output, "}") < 0) {
288 return;
289 }
290 }
291 };
292
293 struct ReportThreadItem {
294 pid_t tid_ = 0;
295 uint64_t eventCount_ = 0;
296 uint64_t sampleCount_ = 0;
297 std::map<int, ReportLibItem> libs_;
298 ReportCallNodeItem callNode;
299 ReportCallNodeItem callNodeReverse;
OutputJsonReportThreadItem300 void OutputJson(FILE *output) const
301 {
302 if (fprintf(output, "{") < 0) {
303 return;
304 }
305 OutputJsonPair(output, "tid", tid_, true);
306 OutputJsonPair(output, "eventCount", eventCount_);
307 OutputJsonPair(output, "sampleCount", sampleCount_);
308 OutputJsonMapList(output, "libs", libs_);
309 OutputJsonPair(output, "CallOrder", callNode);
310 OutputJsonPair(output, "CalledOrder", callNodeReverse);
311 if (fprintf(output, "}") < 0) {
312 return;
313 }
314 }
ReportThreadItemReportThreadItem315 ReportThreadItem(pid_t id) : tid_(id), callNode(-1), callNodeReverse(-1) {}
316 };
317
318 struct ReportProcessItem {
319 pid_t pid_ = 0;
320 uint64_t eventCount_ = 0;
321 std::map<pid_t, ReportThreadItem> threads_;
OutputJsonReportProcessItem322 void OutputJson(FILE *output) const
323 {
324 if (fprintf(output, "{") < 0) {
325 return;
326 }
327 OutputJsonPair(output, "pid", pid_, true);
328 OutputJsonPair(output, "eventCount", eventCount_);
329 OutputJsonMapList(output, "threads", threads_);
330 if (fprintf(output, "}") < 0) {
331 return;
332 }
333 }
ReportProcessItemReportProcessItem334 explicit ReportProcessItem(pid_t pid) : pid_(pid) {}
335 };
336
337 struct ReportConfigItem {
338 int index_ = -1;
339 std::string eventName_;
340 uint64_t eventCount_ = 0;
341 std::map<pid_t, ReportProcessItem> processes_;
OutputJsonReportConfigItem342 void OutputJson(FILE *output) const
343 {
344 if (fprintf(output, "{") < 0) {
345 return;
346 }
347 OutputJsonPair(output, "eventConfigName", eventName_, true);
348 OutputJsonPair(output, "eventCount", eventCount_);
349 OutputJsonMapList(output, "processes", processes_);
350 if (fprintf(output, "}") < 0) {
351 return;
352 }
353 }
ReportConfigItemReportConfigItem354 ReportConfigItem(int index, std::string eventName) : index_(index), eventName_(eventName) {}
355 };
356
357 static constexpr const int keyLibId = 0;
358 static constexpr const int keyfuncName = 1;
359
360 class ReportJsonFile {
361 public:
362 int nodeIndex_ = 0; // debug only
363 static bool debug_;
364 FILE *output_ = nullptr;
ReportJsonFile(const std::unique_ptr<PerfFileReader> & recordFileReader,const VirtualRuntime & virtualRuntime)365 ReportJsonFile(const std::unique_ptr<PerfFileReader> &recordFileReader,
366 const VirtualRuntime &virtualRuntime)
367 : recordFileReader_(recordFileReader), virtualRuntime_(virtualRuntime)
368 {
369 }
370
371 void UpdateReportSample(const uint64_t configid, const pid_t pid,
372 const pid_t tid, const uint64_t eventCount);
373 void UpdateReportCallStack(const uint64_t id, const pid_t pid, const pid_t tid, const uint64_t eventCount,
374 const std::vector<DfxFrame> &frames);
375 void UpdateCallNodeEventCount();
376 void ProcessSymbolsFiles(const std::vector<std::unique_ptr<SymbolsFile>> &symbolsFiles);
377
378 // json
379 bool OutputJson(FILE *output = nullptr);
380
381 std::map<std::vector<uint64_t>, ReportConfigItem> reportConfigItems_;
382
383 private:
384 const std::unique_ptr<PerfFileReader> &recordFileReader_;
385 const VirtualRuntime &virtualRuntime_;
386 std::vector<std::string_view> libList_;
387 int functionId_ = 0;
388 std::map<int, std::map<std::string, ReportFuncMapItem>> functionMap_;
389 void AddNewFunction(const int libId, std::string name);
390 void OutputJsonFunctionMap(FILE *output);
391
392 ReportConfigItem &GetConfig(const uint64_t id);
393 std::string GetConfigName(const uint64_t id);
394 uint32_t GetConfigIndex(const uint64_t id);
395
396 int GetFunctionID(const int libId, const std::string &function);
397 int GetLibID(const std::string_view filepath);
398
399 void OutputJsonFeatureString();
400 void OutputJsonRuntimeInfo();
401
402 void AddReportCallStack(const uint64_t eventCount, ReportCallNodeItem &callNode,
403 const std::vector<DfxFrame> &frames);
404 void AddReportCallStackReverse(const uint64_t eventCount, ReportCallNodeItem &callNode,
405 const std::vector<DfxFrame> &frames);
406 uint64_t sampleCount_ = 0;
407 };
408 } // namespace HiPerf
409 } // namespace Developtools
410 } // namespace OHOS
411 #endif // REPORT_JSON_FILE_H
412