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 #ifndef PANDA_RUNTIME_TOOLING_SAMPLER_SAMPLE_INFO_H
17 #define PANDA_RUNTIME_TOOLING_SAMPLER_SAMPLE_INFO_H
18
19 #include <array>
20 #include <cstring>
21 #include <securec.h>
22 #include <string>
23
24 #include "libpandabase/macros.h"
25 #include "libpandabase/os/thread.h"
26
27 namespace ark::tooling::sampler {
28
29 // Saving one sample info
30 struct SampleInfo {
31 enum class ThreadStatus : uint32_t { UNDECLARED = 0, RUNNING = 1, SUSPENDED = 2 };
32
33 struct ManagedStackFrameId {
34 uintptr_t fileId {0};
35 uintptr_t pandaFilePtr {0};
36 };
37
38 struct StackInfo {
39 static constexpr size_t MAX_STACK_DEPTH = 100;
40 uintptr_t managedStackSize {0};
41 // We can't use dynamic memory 'cause of usage inside the signal handler
42 std::array<ManagedStackFrameId, MAX_STACK_DEPTH> managedStack;
43 };
44
45 struct ThreadInfo {
46 // Id of the thread from which sample was obtained
47 uint32_t threadId {0};
48 ThreadStatus threadStatus {ThreadStatus::UNDECLARED};
49 };
50
51 ThreadInfo threadInfo {};
52 StackInfo stackInfo {};
53 };
54
55 // Saving one module info (panda file, .so)
56 struct FileInfo {
57 uintptr_t ptr {0};
58 uint32_t checksum {0};
59 std::string pathname;
60 };
61
62 enum class FrameKind : uintptr_t { BRIDGE = 1 };
63
64 bool operator==(const SampleInfo &lhs, const SampleInfo &rhs);
65 bool operator!=(const SampleInfo &lhs, const SampleInfo &rhs);
66 bool operator==(const FileInfo &lhs, const FileInfo &rhs);
67 bool operator!=(const FileInfo &lhs, const FileInfo &rhs);
68 bool operator==(const SampleInfo::ManagedStackFrameId &lhs, const SampleInfo::ManagedStackFrameId &rhs);
69 bool operator!=(const SampleInfo::ManagedStackFrameId &lhs, const SampleInfo::ManagedStackFrameId &rhs);
70 bool operator==(const SampleInfo::StackInfo &lhs, const SampleInfo::StackInfo &rhs);
71 bool operator!=(const SampleInfo::StackInfo &lhs, const SampleInfo::StackInfo &rhs);
72 bool operator==(const SampleInfo::ThreadInfo &lhs, const SampleInfo::ThreadInfo &rhs);
73 bool operator!=(const SampleInfo::ThreadInfo &lhs, const SampleInfo::ThreadInfo &rhs);
74
ReadUintptrTBitMisaligned(const void * ptr)75 inline uintptr_t ReadUintptrTBitMisaligned(const void *ptr)
76 {
77 /*
78 * Pointer might be misaligned
79 * To avoid of UB we should read misaligned adresses with memcpy
80 */
81 uintptr_t value = 0;
82 [[maybe_unused]] int r = memcpy_s(&value, sizeof(value), ptr, sizeof(value));
83 ASSERT(r == 0);
84 return value;
85 }
86
ReadUint32TBitMisaligned(const void * ptr)87 inline uint32_t ReadUint32TBitMisaligned(const void *ptr)
88 {
89 uint32_t value = 0;
90 [[maybe_unused]] int r = memcpy_s(&value, sizeof(value), ptr, sizeof(value));
91 ASSERT(r == 0);
92 return value;
93 }
94
95 inline bool operator==(const SampleInfo::ManagedStackFrameId &lhs, const SampleInfo::ManagedStackFrameId &rhs)
96 {
97 return lhs.fileId == rhs.fileId && lhs.pandaFilePtr == rhs.pandaFilePtr;
98 }
99
100 inline bool operator!=(const SampleInfo::ManagedStackFrameId &lhs, const SampleInfo::ManagedStackFrameId &rhs)
101 {
102 return !(lhs == rhs);
103 }
104
105 inline bool operator==(const FileInfo &lhs, const FileInfo &rhs)
106 {
107 return lhs.ptr == rhs.ptr && lhs.pathname == rhs.pathname;
108 }
109
110 inline bool operator!=(const FileInfo &lhs, const FileInfo &rhs)
111 {
112 return !(lhs == rhs);
113 }
114
115 inline bool operator==(const SampleInfo::StackInfo &lhs, const SampleInfo::StackInfo &rhs)
116 {
117 if (lhs.managedStackSize != rhs.managedStackSize) {
118 return false;
119 }
120 for (uint32_t i = 0; i < lhs.managedStackSize; ++i) {
121 if (lhs.managedStack[i] != rhs.managedStack[i]) {
122 return false;
123 }
124 }
125 return true;
126 }
127
128 inline bool operator!=(const SampleInfo::StackInfo &lhs, const SampleInfo::StackInfo &rhs)
129 {
130 return !(lhs == rhs);
131 }
132
133 inline bool operator==(const SampleInfo::ThreadInfo &lhs, const SampleInfo::ThreadInfo &rhs)
134 {
135 return lhs.threadId == rhs.threadId && lhs.threadStatus == rhs.threadStatus;
136 }
137
138 inline bool operator!=(const SampleInfo::ThreadInfo &lhs, const SampleInfo::ThreadInfo &rhs)
139 {
140 return !(lhs == rhs);
141 }
142
143 inline bool operator==(const SampleInfo &lhs, const SampleInfo &rhs)
144 {
145 if (lhs.threadInfo != rhs.threadInfo) {
146 return false;
147 }
148 if (lhs.stackInfo != rhs.stackInfo) {
149 return false;
150 }
151 return true;
152 }
153
154 inline bool operator!=(const SampleInfo &lhs, const SampleInfo &rhs)
155 {
156 return !(lhs == rhs);
157 }
158
159 } // namespace ark::tooling::sampler
160
161 // Definind std::hash for SampleInfo to use it as an unordered_map key
162 namespace std {
163
164 template <>
165 struct hash<ark::tooling::sampler::SampleInfo> {
166 std::size_t operator()(const ark::tooling::sampler::SampleInfo &s) const
167 {
168 auto stackInfo = s.stackInfo;
169 ASSERT(stackInfo.managedStackSize <= ark::tooling::sampler::SampleInfo::StackInfo::MAX_STACK_DEPTH);
170 size_t summ = 0;
171 for (size_t i = 0; i < stackInfo.managedStackSize; ++i) {
172 summ += stackInfo.managedStack[i].pandaFilePtr ^ stackInfo.managedStack[i].fileId;
173 }
174 constexpr uint32_t THREAD_STATUS_SHIFT = 20;
175 return std::hash<size_t>()(
176 (summ ^ stackInfo.managedStackSize) +
177 (s.threadInfo.threadId ^ (static_cast<uint32_t>(s.threadInfo.threadStatus) << THREAD_STATUS_SHIFT)));
178 }
179 };
180
181 // Definind std::hash for FileInfo to use it as an unordered_set key
182 template <>
183 struct hash<ark::tooling::sampler::FileInfo> {
184 size_t operator()(const ark::tooling::sampler::FileInfo &m) const
185 {
186 size_t h1 = std::hash<uintptr_t> {}(m.ptr);
187 size_t h2 = std::hash<uint32_t> {}(m.checksum);
188 size_t h3 = std::hash<std::string> {}(m.pathname);
189 return h1 ^ (h2 << 1U) ^ (h3 << 2U);
190 }
191 };
192
193 } // namespace std
194
195 #endif // PANDA_RUNTIME_TOOLING_SAMPLER_SAMPLE_INFO_H
196