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