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