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 <cstdlib>
21 #include <functional>
22 #include <map>
23 #include <stdio.h>
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, 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, bool first = false)
93 {
94 if (!first) {
95 if (fprintf(output, ",") < 0) {
96 return;
97 }
98 }
99 OutputJsonKey(output, key);
100 OutputJsonValue(output, value);
101 }
102
103 /*
104 k:[v1,v2,v3]
105 */
106 template<class T>
107 void OutputJsonVectorList(FILE *output, const std::string &key, const std::vector<T> &value,
108 bool first = false)
109 {
110 if (!first) {
111 if (fprintf(output, ",") < 0) {
112 return;
113 }
114 }
115 if (fprintf(output, "\"%s\":[", key.c_str()) != -1) {
116 auto it = value.begin();
117 while (it != value.end()) {
118 OutputJsonValue(output, *it, it == value.begin());
119 it++;
120 }
121 if (fprintf(output, "]") < 0) {
122 return;
123 }
124 }
125 }
126
127 /*
128 k:[v1,v2,v3]
129 */
130 template<class K, class V>
131 void OutputJsonMapList(FILE *output, const std::string &key, const std::map<K, V> &value,
132 bool first = false)
133 {
134 if (!first) {
135 if (fprintf(output, ",") < 0) {
136 return;
137 }
138 }
139 if (fprintf(output, "\"%s\":[", key.c_str()) != -1) {
140 auto it = value.begin();
141 while (it != value.end()) {
142 OutputJsonValue(output, it->second, it == value.begin());
143 it++;
144 }
145 if (fprintf(output, "]") < 0) {
146 return;
147 }
148 }
149 }
150
151 /*
152 k:{k1:v1,k2:v2,k3:v3}
153 */
154 template<class K, class V>
155 void OutputJsonMap(FILE *output, const std::string &key, const std::map<K, V> &value,
156 bool first = false)
157 {
158 if (!first) {
159 if (fprintf(output, ",") < 0) {
160 return;
161 }
162 }
163 if (fprintf(output, "\"%s\":{", key.c_str()) != -1) {
164 auto it = value.begin();
165 while (it != value.end()) {
166 OutputJsonPair(output, it->first, it->second, it == value.begin());
167 it++;
168 }
169 if (fprintf(output, "}") < 0) {
170 return;
171 }
172 }
173 }
174
175 template<class K, class V>
GetOrCreateMapItem(std::map<K,V> & map,const K & key)176 V &GetOrCreateMapItem(std::map<K, V> &map, const K &key)
177 {
178 if (map.count(key) == 0) {
179 map.emplace(key, (key));
180 return map.at(key);
181 } else {
182 return map.at(key);
183 }
184 }
185
186 struct ReportFuncMapItem {
187 int libId_ = -1;
188 std::string_view funcName_;
OutputJsonReportFuncMapItem189 void OutputJson(FILE *output) const
190 {
191 if (fprintf(output, "{") < 0) {
192 return;
193 }
194 OutputJsonPair(output, "file", libId_, true);
195 OutputJsonPair(output, "symbol", funcName_);
196 if (fprintf(output, "}") < 0) {
197 return;
198 }
199 }
ReportFuncMapItemReportFuncMapItem200 ReportFuncMapItem(int libId, std::string_view funcName) : libId_(libId), funcName_(funcName) {}
201 };
202
203 struct ReportFuncItem {
204 int functionId_ = -1;
205 int functionInLibId_ = -1;
206 uint64_t sampleCount_ = 0;
207 uint64_t eventCount_ = 0;
208 uint64_t subTreeEventCount_ = 0;
ReportFuncItemReportFuncItem209 explicit ReportFuncItem(int functionId) : functionId_(functionId) {}
OutputJsonReportFuncItem210 void OutputJson(FILE *output) const
211 {
212 if (fprintf(output, "{") < 0) {
213 return;
214 }
215 OutputJsonPair(output, "symbol", functionId_, true);
216 OutputJsonVectorList(output, "counts",
217 std::vector<uint64_t> {sampleCount_, eventCount_, subTreeEventCount_});
218 if (fprintf(output, "}") < 0) {
219 return;
220 }
221 }
222 };
223
224 struct ReportCallNodeItem {
225 uint64_t selfEventCount_ = 0;
226 uint64_t subTreeEventCount_ = 0;
227 int functionId_ = -1;
228 int nodeIndex_ = -1;
229 bool reverseCaller_ = false;
230 std::string_view funcName_ = "";
231 std::string debug_ = "";
232 std::map<int, ReportCallNodeItem> childrenMap;
233
OutputJsonReportCallNodeItem234 void OutputJson(FILE *output) const
235 {
236 if (fprintf(output, "{") < 0) {
237 return;
238 }
239 OutputJsonPair(output, "selfEvents", selfEventCount_, true);
240 OutputJsonPair(output, "subEvents", subTreeEventCount_);
241 OutputJsonPair(output, "symbol", functionId_);
242 if (!funcName_.empty()) { // for debug
243 OutputJsonPair(output, "funcName", funcName_);
244 OutputJsonPair(output, "nodeIndex", nodeIndex_);
245 OutputJsonPair(output, "reversed", reverseCaller_);
246 }
247 OutputJsonMapList(output, "callStack", childrenMap);
248 if (fprintf(output, "}") < 0) {
249 return;
250 }
251 }
252
UpdateChildrenEventCountReportCallNodeItem253 uint64_t UpdateChildrenEventCount()
254 {
255 subTreeEventCount_ = selfEventCount_;
256 for (auto &pair : childrenMap) {
257 subTreeEventCount_ += pair.second.UpdateChildrenEventCount();
258 if (!funcName_.empty()) {
259 }
260 }
261 return subTreeEventCount_;
262 }
263
FindByFunctionIdReportCallNodeItem264 static bool FindByFunctionId(ReportCallNodeItem &a, int functionId)
265 {
266 return (a.functionId_ == functionId);
267 }
268
ReportCallNodeItemReportCallNodeItem269 explicit ReportCallNodeItem(int functionId) : functionId_(functionId) {}
270 };
271
272 struct ReportLibItem {
273 int libId_ = 0;
274 uint64_t eventCount_ = 0;
275 std::map<int, ReportFuncItem> funcs_;
OutputJsonReportLibItem276 void OutputJson(FILE *output) const
277 {
278 if (fprintf(output, "{") < 0) {
279 return;
280 }
281 OutputJsonPair(output, "fileId", libId_, true);
282 OutputJsonPair(output, "eventCount", eventCount_);
283 OutputJsonMapList(output, "functions", funcs_);
284 if (fprintf(output, "}") < 0) {
285 return;
286 }
287 }
288 };
289
290 struct ReportThreadItem {
291 pid_t tid_ = 0;
292 uint64_t eventCount_ = 0;
293 uint64_t sampleCount_ = 0;
294 std::map<int, ReportLibItem> libs_;
295 ReportCallNodeItem callNode;
296 ReportCallNodeItem callNodeReverse;
OutputJsonReportThreadItem297 void OutputJson(FILE *output) const
298 {
299 if (fprintf(output, "{") < 0) {
300 return;
301 }
302 OutputJsonPair(output, "tid", tid_, true);
303 OutputJsonPair(output, "eventCount", eventCount_);
304 OutputJsonPair(output, "sampleCount", sampleCount_);
305 OutputJsonMapList(output, "libs", libs_);
306 OutputJsonPair(output, "CallOrder", callNode);
307 OutputJsonPair(output, "CalledOrder", callNodeReverse);
308 if (fprintf(output, "}") < 0) {
309 return;
310 }
311 }
ReportThreadItemReportThreadItem312 ReportThreadItem(pid_t id) : tid_(id), callNode(-1), callNodeReverse(-1) {}
313 };
314
315 struct ReportProcessItem {
316 pid_t pid_ = 0;
317 uint64_t eventCount_ = 0;
318 std::map<pid_t, ReportThreadItem> threads_;
OutputJsonReportProcessItem319 void OutputJson(FILE *output) const
320 {
321 if (fprintf(output, "{") < 0) {
322 return;
323 }
324 OutputJsonPair(output, "pid", pid_, true);
325 OutputJsonPair(output, "eventCount", eventCount_);
326 OutputJsonMapList(output, "threads", threads_);
327 if (fprintf(output, "}") < 0) {
328 return;
329 }
330 }
ReportProcessItemReportProcessItem331 explicit ReportProcessItem(pid_t pid) : pid_(pid) {}
332 };
333
334 struct ReportConfigItem {
335 int index_;
336 std::string eventName_;
337 uint64_t eventCount_ = 0;
338 std::map<pid_t, ReportProcessItem> processes_;
OutputJsonReportConfigItem339 void OutputJson(FILE *output) const
340 {
341 if (fprintf(output, "{") < 0) {
342 return;
343 }
344 OutputJsonPair(output, "eventConfigName", eventName_, true);
345 OutputJsonPair(output, "eventCount", eventCount_);
346 OutputJsonMapList(output, "processes", processes_);
347 if (fprintf(output, "}") < 0) {
348 return;
349 }
350 }
ReportConfigItemReportConfigItem351 ReportConfigItem(int index, std::string eventName) : index_(index), eventName_(eventName) {}
352 };
353
354 using functionKey = std::tuple<int, std::string_view>;
355 static constexpr const int keyLibId = 0;
356 static constexpr const int keyfuncName = 1;
357
358 class ReportJsonFile {
359 public:
360 int nodeIndex_ = 0; // debug only
361 static bool debug_;
362 FILE *output_ = nullptr;
ReportJsonFile(const std::unique_ptr<PerfFileReader> & recordFileReader,const VirtualRuntime & virtualRuntime)363 ReportJsonFile(const std::unique_ptr<PerfFileReader> &recordFileReader,
364 const VirtualRuntime &virtualRuntime)
365 : recordFileReader_(recordFileReader), virtualRuntime_(virtualRuntime)
366 {
367 }
368
369 void UpdateReportSample(uint64_t configid, pid_t pid, pid_t tid, uint64_t eventCount);
370 void UpdateReportCallStack(uint64_t id, pid_t pid, pid_t tid, uint64_t eventCount,
371 std::vector<CallFrame> &frames);
372 void UpdateCallNodeEventCount();
373 void ProcessSymbolsFiles(const std::vector<std::unique_ptr<SymbolsFile>> &symbolsFiles);
374
375 // json
376 bool OutputJson(FILE *output = nullptr);
377
378 std::map<std::vector<uint64_t>, ReportConfigItem> reportConfigItems_;
379
380 private:
381 const std::unique_ptr<PerfFileReader> &recordFileReader_;
382 const VirtualRuntime &virtualRuntime_;
383 std::vector<std::string_view> libList_;
384 std::vector<functionKey> functionList_;
385 std::map<int, ReportFuncMapItem> functionMap_;
386 void addNewFunction(int libId, std::string_view name);
387
388 ReportConfigItem &GetConfig(uint64_t id);
389 std::string GetConfigName(uint64_t id);
390 uint32_t GetConfigIndex(uint64_t id);
391
392 int GetFuncionID(int libId, std::string_view function);
393 int GetLibID(std::string_view filepath);
394
395 void OutputJsonFeatureString();
396 void OutputJsonRuntimeInfo();
397
398 void AddReportCallStack(uint64_t eventCount, ReportCallNodeItem &callNode,
399 const std::vector<CallFrame> &frames);
400 void AddReportCallStackReverse(uint64_t eventCount, ReportCallNodeItem &callNode,
401 const std::vector<CallFrame> &frames);
402 uint64_t sampleCount_ = 0;
403
404 FRIEND_TEST(ReportJsonFileTest, UpdateReportSample);
405 FRIEND_TEST(ReportJsonFileTest, UpdateReportCallStack);
406 FRIEND_TEST(ReportJsonFileTest, UpdateCallNodeEventCount);
407 FRIEND_TEST(ReportJsonFileTest, ProcessSymbolsFiles);
408 FRIEND_TEST(ReportJsonFileTest, GetFuncionID);
409 FRIEND_TEST(ReportJsonFileTest, GetLibID);
410 FRIEND_TEST(ReportJsonFileTest, GetConfigIndex);
411 FRIEND_TEST(ReportJsonFileTest, GetConfigName);
412 FRIEND_TEST(ReportJsonFileTest, GetConfig);
413 friend class ReportJsonFileTest;
414 };
415 } // namespace HiPerf
416 } // namespace Developtools
417 } // namespace OHOS
418 #endif // REPORT_JSON_FILE_H
419