1 /* 2 * Copyright (c) 2022-2025 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 _KOALA_PROFILER_ 17 #define _KOALA_PROFILER_ 18 19 #include <stdint.h> 20 #include <stdio.h> 21 22 #include <unordered_map> 23 #include <string> 24 #include <vector> 25 #include <chrono> 26 #include <algorithm> 27 28 constexpr double PERCENTAGE_FACTOR = 100.0; 29 30 struct InteropProfilerRecord { 31 int64_t time; 32 int64_t count; InteropProfilerRecordInteropProfilerRecord33 InteropProfilerRecord(int64_t time, int64_t count) : time(time), count(count) {} 34 }; 35 36 class InteropProfiler { 37 private: 38 std::unordered_map<std::string, InteropProfilerRecord> records; 39 static InteropProfiler* _instance; InteropProfiler()40 InteropProfiler() {} 41 42 public: instance()43 static InteropProfiler* instance() { 44 if (!_instance) _instance = new InteropProfiler(); 45 return _instance; 46 } 47 record(const char * name,int64_t ns)48 void record(const char* name, int64_t ns) { 49 auto it = records.find(name); 50 if (it == records.end()) { 51 records.insert({name, InteropProfilerRecord(ns, 1)}); 52 } else { 53 it->second.time += ns; 54 it->second.count++; 55 } 56 } 57 report()58 std::string report() { 59 std::vector<std::pair<std::string, InteropProfilerRecord>> elems(records.begin(), records.end()); 60 std::sort(elems.begin(), elems.end(), 61 [](const std::pair<std::string, InteropProfilerRecord>&a, const std::pair<std::string, InteropProfilerRecord>&b) { 62 return b.second.time < a.second.time; 63 }); 64 int64_t total = 0; 65 std::for_each(elems.begin(), elems.end(), [&total](const std::pair<std::string, InteropProfilerRecord>&a) { 66 total += a.second.time; 67 }); 68 std::string result; 69 std::for_each(elems.begin(), elems.end(), [total, &result](const std::pair<std::string, InteropProfilerRecord>&a) { 70 auto ns = a.second.time; 71 auto count = a.second.count; 72 char buffer[1024]; 73 #ifdef __STDC_LIB_EXT1__ 74 errno_t res = snprintf_s(buffer, sizeof buffer, "for %s[%lld]: %.01f%% (%lld)\n", a.first.c_str(), 75 (long long)count, (double)ns / total * PERCENTAGE_FACTOR, (long long)ns); 76 if (res != EOK) { 77 return ""; 78 } 79 #else 80 snprintf(buffer, sizeof buffer, "for %s[%lld]: %.01f%% (%lld)\n", a.first.c_str(), 81 (long long)count, (double)ns / total * PERCENTAGE_FACTOR, (long long)ns); 82 #endif 83 result += buffer; 84 }); 85 return result; 86 } 87 reset()88 void reset() { 89 records.clear(); 90 } 91 }; 92 93 94 class InteropMethodCall { 95 private: 96 const char* name; 97 std::chrono::steady_clock::time_point begin; 98 public: InteropMethodCall(const char * name)99 InteropMethodCall(const char* name) : name(name) { 100 begin = std::chrono::steady_clock::now(); 101 } ~InteropMethodCall()102 ~InteropMethodCall() { 103 auto end = std::chrono::steady_clock::now(); 104 int64_t ns = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count(); 105 InteropProfiler::instance()->record(name, ns); 106 } 107 }; 108 109 #endif // _KOALA_PROFILER_