• 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 #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