• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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