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 30namespace OHOS { 31namespace Developtools { 32namespace HiPerf { 33using jsonStringMap = std::map<std::string, std::string>; 34using jsonStringVector = std::vector<std::string>; 35using jsonIntVector = std::vector<int>; 36 37template<class T> 38void 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} 62template<class T> 63void 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*/ 91template<class K, class T> 92void 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 // for id, symbol 100 OutputJsonKey(output, key); 101 // ReportFuncMapItem funcName. 102 OutputJsonValue(output, value); 103} 104 105/* 106 k:[v1,v2,v3] 107*/ 108template<class T> 109void OutputJsonVectorList(FILE *output, const std::string &key, const std::vector<T> &value, 110 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*/ 132template<class K, class V> 133void OutputJsonMapList(FILE *output, const std::string &key, const std::map<K, V> &value, 134 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*/ 156template<class K, class V> 157void OutputJsonMap(FILE *output, const std::string &key, const std::map<K, V> &value, 158 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 177template<class K, class V> 178V &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 186struct ReportFuncMapItem { 187 int libId_ = -1; 188 std::string funcName_; 189 int reportFuncId_ = -1; 190 void OutputJson(FILE *output) const 191 { 192 if (fprintf(output, "{") < 0) { 193 return; 194 } 195 OutputJsonPair(output, "file", libId_, true); 196 OutputJsonPair(output, "symbol", funcName_); 197 if (fprintf(output, "}") < 0) { 198 return; 199 } 200 } 201 ReportFuncMapItem(int libId, std::string &funcName, int reportFuncId) 202 : libId_(libId), funcName_(funcName), reportFuncId_(reportFuncId) {} 203}; 204 205struct ReportFuncItem { 206 int functionId_ = -1; 207 int functionInLibId_ = -1; 208 uint64_t sampleCount_ = 0; 209 uint64_t eventCount_ = 0; 210 uint64_t subTreeEventCount_ = 0; 211 explicit ReportFuncItem(int functionId) : functionId_(functionId) {} 212 void OutputJson(FILE *output) const 213 { 214 if (fprintf(output, "{") < 0) { 215 return; 216 } 217 OutputJsonPair(output, "symbol", functionId_, true); 218 OutputJsonVectorList(output, "counts", 219 std::vector<uint64_t> {sampleCount_, eventCount_, subTreeEventCount_}); 220 if (fprintf(output, "}") < 0) { 221 return; 222 } 223 } 224}; 225 226struct ReportCallNodeItem { 227 uint64_t selfEventCount_ = 0; 228 uint64_t subTreeEventCount_ = 0; 229 int functionId_ = -1; 230 int nodeIndex_ = -1; 231 bool reverseCaller_ = false; 232 std::string_view funcName_ = ""; 233 std::string debug_ = ""; 234 std::map<int, ReportCallNodeItem> childrenMap; 235 236 void OutputJson(FILE *output) const 237 { 238 if (fprintf(output, "{") < 0) { 239 return; 240 } 241 OutputJsonPair(output, "selfEvents", selfEventCount_, true); 242 OutputJsonPair(output, "subEvents", subTreeEventCount_); 243 OutputJsonPair(output, "symbol", functionId_); 244 if (!funcName_.empty()) { // for debug 245 OutputJsonPair(output, "funcName", funcName_); 246 OutputJsonPair(output, "nodeIndex", nodeIndex_); 247 OutputJsonPair(output, "reversed", reverseCaller_); 248 } 249 OutputJsonMapList(output, "callStack", childrenMap); 250 if (fprintf(output, "}") < 0) { 251 return; 252 } 253 } 254 255 uint64_t UpdateChildrenEventCount() 256 { 257 subTreeEventCount_ = selfEventCount_; 258 for (auto &pair : childrenMap) { 259 subTreeEventCount_ += pair.second.UpdateChildrenEventCount(); 260 if (!funcName_.empty()) { 261 } 262 } 263 return subTreeEventCount_; 264 } 265 266 static bool FindByFunctionId(ReportCallNodeItem &a, int functionId) 267 { 268 return (a.functionId_ == functionId); 269 } 270 271 explicit ReportCallNodeItem(int functionId) : functionId_(functionId) {} 272}; 273 274struct ReportLibItem { 275 int libId_ = 0; 276 uint64_t eventCount_ = 0; 277 std::map<int, ReportFuncItem> funcs_; 278 void OutputJson(FILE *output) const 279 { 280 if (fprintf(output, "{") < 0) { 281 return; 282 } 283 OutputJsonPair(output, "fileId", libId_, true); 284 OutputJsonPair(output, "eventCount", eventCount_); 285 OutputJsonMapList(output, "functions", funcs_); 286 if (fprintf(output, "}") < 0) { 287 return; 288 } 289 } 290}; 291 292struct ReportThreadItem { 293 pid_t tid_ = 0; 294 uint64_t eventCount_ = 0; 295 uint64_t sampleCount_ = 0; 296 std::map<int, ReportLibItem> libs_; 297 ReportCallNodeItem callNode; 298 ReportCallNodeItem callNodeReverse; 299 void OutputJson(FILE *output) const 300 { 301 if (fprintf(output, "{") < 0) { 302 return; 303 } 304 OutputJsonPair(output, "tid", tid_, true); 305 OutputJsonPair(output, "eventCount", eventCount_); 306 OutputJsonPair(output, "sampleCount", sampleCount_); 307 OutputJsonMapList(output, "libs", libs_); 308 OutputJsonPair(output, "CallOrder", callNode); 309 OutputJsonPair(output, "CalledOrder", callNodeReverse); 310 if (fprintf(output, "}") < 0) { 311 return; 312 } 313 } 314 ReportThreadItem(pid_t id) : tid_(id), callNode(-1), callNodeReverse(-1) {} 315}; 316 317struct ReportProcessItem { 318 pid_t pid_ = 0; 319 uint64_t eventCount_ = 0; 320 std::map<pid_t, ReportThreadItem> threads_; 321 void OutputJson(FILE *output) const 322 { 323 if (fprintf(output, "{") < 0) { 324 return; 325 } 326 OutputJsonPair(output, "pid", pid_, true); 327 OutputJsonPair(output, "eventCount", eventCount_); 328 OutputJsonMapList(output, "threads", threads_); 329 if (fprintf(output, "}") < 0) { 330 return; 331 } 332 } 333 explicit ReportProcessItem(pid_t pid) : pid_(pid) {} 334}; 335 336struct ReportConfigItem { 337 int index_; 338 std::string eventName_; 339 uint64_t eventCount_ = 0; 340 std::map<pid_t, ReportProcessItem> processes_; 341 void OutputJson(FILE *output) const 342 { 343 if (fprintf(output, "{") < 0) { 344 return; 345 } 346 OutputJsonPair(output, "eventConfigName", eventName_, true); 347 OutputJsonPair(output, "eventCount", eventCount_); 348 OutputJsonMapList(output, "processes", processes_); 349 if (fprintf(output, "}") < 0) { 350 return; 351 } 352 } 353 ReportConfigItem(int index, std::string eventName) : index_(index), eventName_(eventName) {} 354}; 355 356static constexpr const int keyLibId = 0; 357static constexpr const int keyfuncName = 1; 358 359class ReportJsonFile { 360public: 361 int nodeIndex_ = 0; // debug only 362 static bool debug_; 363 FILE *output_ = nullptr; 364 ReportJsonFile(const std::unique_ptr<PerfFileReader> &recordFileReader, 365 const VirtualRuntime &virtualRuntime) 366 : recordFileReader_(recordFileReader), virtualRuntime_(virtualRuntime) 367 { 368 } 369 370 void UpdateReportSample(uint64_t configid, pid_t pid, pid_t tid, uint64_t eventCount); 371 void UpdateReportCallStack(uint64_t id, pid_t pid, pid_t tid, uint64_t eventCount, 372 std::vector<DfxFrame> &frames); 373 void UpdateCallNodeEventCount(); 374 void ProcessSymbolsFiles(const std::vector<std::unique_ptr<SymbolsFile>> &symbolsFiles); 375 376 // json 377 bool OutputJson(FILE *output = nullptr); 378 379 std::map<std::vector<uint64_t>, ReportConfigItem> reportConfigItems_; 380 381private: 382 const std::unique_ptr<PerfFileReader> &recordFileReader_; 383 const VirtualRuntime &virtualRuntime_; 384 std::vector<std::string_view> libList_; 385 int functionId_ = 0; 386 std::map<int, std::map<std::string, ReportFuncMapItem>> functionMap_; 387 void AddNewFunction(int libId, std::string name); 388 void OutputJsonFunctionMap(FILE *output); 389 390 ReportConfigItem &GetConfig(uint64_t id); 391 std::string GetConfigName(uint64_t id); 392 uint32_t GetConfigIndex(uint64_t id); 393 394 int GetFunctionID(int libId, const std::string &function); 395 int GetLibID(std::string_view filepath); 396 397 void OutputJsonFeatureString(); 398 void OutputJsonRuntimeInfo(); 399 400 void AddReportCallStack(uint64_t eventCount, ReportCallNodeItem &callNode, 401 const std::vector<DfxFrame> &frames); 402 void AddReportCallStackReverse(uint64_t eventCount, ReportCallNodeItem &callNode, 403 const std::vector<DfxFrame> &frames); 404 uint64_t sampleCount_ = 0; 405 406 FRIEND_TEST(ReportJsonFileTest, UpdateReportSample); 407 FRIEND_TEST(ReportJsonFileTest, UpdateReportCallStack); 408 FRIEND_TEST(ReportJsonFileTest, UpdateCallNodeEventCount); 409 FRIEND_TEST(ReportJsonFileTest, ProcessSymbolsFiles); 410 FRIEND_TEST(ReportJsonFileTest, GetFunctionID); 411 FRIEND_TEST(ReportJsonFileTest, GetLibID); 412 FRIEND_TEST(ReportJsonFileTest, GetConfigIndex); 413 FRIEND_TEST(ReportJsonFileTest, GetConfigName); 414 FRIEND_TEST(ReportJsonFileTest, GetConfig); 415 friend class ReportJsonFileTest; 416}; 417} // namespace HiPerf 418} // namespace Developtools 419} // namespace OHOS 420#endif // REPORT_JSON_FILE_H 421