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