1 /**
2  * Copyright (c) 2021-2024 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 #include "runtime/dprofiler/dprofiler.h"
17 
18 #include <chrono>
19 
20 #include "dprof/profiling_data.h"
21 #include "libpandabase/os/thread.h"
22 #include "libpandabase/serializer/serializer.h"
23 #include "libpandabase/utils/logger.h"
24 #include "runtime/include/class.h"
25 #include "runtime/include/method.h"
26 #include "runtime/include/runtime.h"
27 #include "runtime/include/runtime_notification.h"
28 
29 namespace ark {
30 
31 class DProfilerListener : public RuntimeListener {
32 public:
DProfilerListener(DProfiler *dprofiler)33     explicit DProfilerListener(DProfiler *dprofiler) : dprofiler_(dprofiler) {}
34 
35     void VmDeath() override
36     {
37         Runtime::GetCurrent()->GetClassLinker()->EnumerateClasses([this](Class *klass) -> bool {
38             dprofiler_->AddClass(klass);
39             return true;
40         });
41         dprofiler_->Dump();
42     }
43 
44     ~DProfilerListener() override = default;
45 
46     DEFAULT_COPY_SEMANTIC(DProfilerListener);
47     DEFAULT_MOVE_SEMANTIC(DProfilerListener);
48 
49 private:
50     DProfiler *dprofiler_;
51 };
52 
GetFullName(const Method *method)53 static PandaString GetFullName(const Method *method)
54 {
55     return reinterpret_cast<const char *>(method->GetClassName().data) + PandaString(".") +
56            reinterpret_cast<const char *>(method->GetName().data);
57 }
58 
GetHash()59 static uint64_t GetHash()
60 {
61     auto t = std::chrono::steady_clock::now();
62     return std::chrono::time_point_cast<std::chrono::nanoseconds>(t).time_since_epoch().count();
63 }
64 
DProfiler(std::string_view appName, Runtime *runtime)65 DProfiler::DProfiler(std::string_view appName, Runtime *runtime)
66     : runtime_(runtime),
67       profilingData_(
68           MakePandaUnique<dprof::ProfilingData>(appName.data(), GetHash(), os::thread::GetCurrentThreadId())),
69       listener_(MakePandaUnique<DProfilerListener>(this))
70 {
71     runtime_->GetNotificationManager()->AddListener(listener_.get(), RuntimeNotificationManager::Event::VM_EVENTS);
72 }
73 
AddClass(const Class *klass)74 void DProfiler::AddClass(const Class *klass)
75 {
76     for (const auto &method : klass->GetMethods()) {
77         if (method.GetHotnessCounter() != 0) {
78             if (!hotMethods_.insert(&method).second) {
79                 LOG(ERROR, DPROF) << "Method already exsists: " << GetFullName(&method);
80             }
81         }
82     }
83 }
84 
Dump()85 void DProfiler::Dump()
86 {
87     PandaUnorderedMap<PandaString, uint32_t> methodInfoMap;
88     for (const Method *method : hotMethods_) {
89         auto ret = methodInfoMap.emplace(std::make_pair(GetFullName(method), method->GetHotnessCounter()));
90         if (!ret.second) {
91             LOG(ERROR, DPROF) << "Method already exists: " << ret.first->first;
92         }
93     }
94 
95     std::vector<uint8_t> buffer;
96     auto ret = serializer::TypeToBuffer(methodInfoMap, buffer);
97     if (!ret) {
98         LOG(ERROR, DPROF) << "Cannot serialize method_info_map. Error: " << ret.Error();
99         return;
100     }
101 
102     profilingData_->SetFeatureDate("hotness_counters.v1", std::move(buffer));
103     profilingData_->DumpAndResetFeatures();
104 }
105 
106 }  // namespace ark
107