• 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 #ifndef PANDA_RUNTIME_PROFILE_DUMP_INFO_H_
16 #define PANDA_RUNTIME_PROFILE_DUMP_INFO_H_
17 
18 #include <map>
19 #include <set>
20 #include <string>
21 #include <unordered_set>
22 #include <vector>
23 
24 #include "libpandabase/utils/logger.h"
25 #include "libpandafile/file.h"
26 #include "runtime/include/mem/panda_containers.h"
27 #include "runtime/include/mem/panda_smart_pointers.h"
28 #include "runtime/include/mem/panda_string.h"
29 
30 // NB! suppose that, panda file can always provide such profile file format data!
31 // NB! we use serializer saving way which means the profile file is just binary file!
32 // profile header
33 //      magic
34 //      version
35 //      checksum?(ommit)
36 //      #lines
37 // Line1:
38 //      profileline header
39 //          file location
40 //          #method
41 //          #class
42 //          checksum
43 //      methods index/id(#method)
44 //      class index/id(#class)
45 // LineN:
46 //      ...
47 
48 namespace ark {
49 
50 /*
51  * Any newly added information, we have to change the following info naturally, especially
52  * ExtractedResolvedClasses
53  */
54 struct ExtractedMethod {
ExtractedMethodExtractedMethod55     ExtractedMethod(const panda_file::File *file, panda_file::File::EntityId pfFileId)
56         : pandaFile(file), fileId(pfFileId)
57     {
58     }
59     const panda_file::File *pandaFile;  // NOLINT(misc-non-private-member-variables-in-classes)
60     panda_file::File::EntityId fileId;  // NOLINT(misc-non-private-member-variables-in-classes)
61 };
62 
63 struct ExtractedResolvedClasses {
64 public:
65     // NOLINTNEXTLINE(modernize-pass-by-value)
ExtractedResolvedClassesExtractedResolvedClasses66     ExtractedResolvedClasses(const PandaString &location, uint32_t checksum)
67         : panda_file_location_(location), panda_file_checksum_(checksum)
68     {
69     }
70 
CompareExtractedResolvedClasses71     int Compare(const ExtractedResolvedClasses &other) const
72     {
73         if (panda_file_checksum_ != other.panda_file_checksum_) {
74             return static_cast<int>(panda_file_checksum_ - other.panda_file_checksum_);
75         }
76         return panda_file_location_.compare(other.panda_file_location_);
77     }
78 
79     template <class InputIt>
AddClassesExtractedResolvedClasses80     void AddClasses(InputIt begin, InputIt end) const
81     {
82         classes_.insert(begin, end);
83     }
84 
AddClassExtractedResolvedClasses85     void AddClass(uint32_t classindex) const
86     {
87         classes_.insert(classindex);
88     }
89 
90     // NOLINTNEXTLINE(readability-const-return-type)
GetPandaFileLocationExtractedResolvedClasses91     const PandaString GetPandaFileLocation() const
92     {
93         return panda_file_location_;
94     }
95 
GetPandaFileChecksumExtractedResolvedClasses96     uint32_t GetPandaFileChecksum() const
97     {
98         return panda_file_checksum_;
99     }
100 
GetClassesExtractedResolvedClasses101     const PandaUnorderedSet<uint32_t> &GetClasses() const
102     {
103         return classes_;
104     }
105 
106 private:
107     const PandaString panda_file_location_;  // NOLINT(readability-identifier-naming)
108     const uint32_t panda_file_checksum_;     // NOLINT(readability-identifier-naming)
109     // Array of resolved class def indexes. we leave this as extension
110     mutable PandaUnorderedSet<uint32_t> classes_;
111 };
112 
113 // we define this for PandaSet find() function
114 inline bool operator<(const ExtractedResolvedClasses &a, const ExtractedResolvedClasses &b)
115 {
116     return a.Compare(b) < 0;
117 }
118 
119 class ProfileDumpInfo {
120 public:
121     // Content of profile header
122     static const uint8_t kProfileMagic[];    // NOLINT(modernize-avoid-c-arrays, readability-identifier-naming)
123     static const uint8_t kProfileVersion[];  // NOLINT(modernize-avoid-c-arrays, readability-identifier-naming)
124 
125     /*
126      * Saves the profile data to the given file descriptor.
127      */
128     bool Save(int fd);
129 
130     /*
131      * Loads profile information from the given file descriptor.
132      */
133     bool Load(int fd);
134 
135     /*
136      * Merge the data from another ProfileDumpInfo into the current object.
137      */
138     bool MergeWith(const ProfileDumpInfo &other);
139 
140     /*
141      * Add the given methods and classes to the current profile object
142      */
143     bool AddMethodsAndClasses(const PandaVector<ExtractedMethod> &methods,
144                               const PandaSet<ExtractedResolvedClasses> &resolvedClasses);
145 
146     /*
147      * Loads and merges profile information from the given file into the current cache
148      * object and tries to save it back to disk.
149      *
150      * If `force` is true then the save will be forced regardless of bad data or mismatched version.
151      */
152     bool MergeAndSave(const PandaString &filename, ssize_t *bytesWritten, bool force);
153 
154     /*
155      * Returns the number of methods that were profiled.
156      */
157     uint64_t GetNumberOfMethods() const;
158 
159     /*
160      * Returns the number of resolved classes that were profiled.
161      */
162     uint64_t GetNumberOfResolvedClasses() const;
163 
164     /*
165      * Returns true if the method reference is present in the profiling info.
166      */
167     bool ContainsMethod(const ExtractedMethod &methodRef) const;
168 
169     /*
170      * Returns true if the class is present in the profiling info.
171      */
172     bool ContainsClass(const panda_file::File &pandafile, uint32_t classDefIdx) const;
173 
174 private:
175     enum ProfileLoadSatus {
176         PROFILE_LOAD_IO_ERROR,
177         PROFILE_LOAD_VERSION_MISMATCH,
178         PROFILE_LOAD_BAD_DATA,
179         PROFILE_LOAD_EMPTYFILE,
180         PROFILE_LOAD_SUCCESS
181     };
182 
183     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
184     struct ProfileLineHeader {
185         PandaString pandaFileLocation;
186         uint32_t methodSetSize;
187         uint32_t classSetSize;
188         uint32_t checksum;
189     };
190 
191     // A helper structure to make sure we don't read past our buffers in the loops.
192     struct SerializerBuffer {
193     public:
SerializerBufferSerializerBuffer194         explicit SerializerBuffer(size_t size)
195         {
196             // NOLINTNEXTLINE(modernize-avoid-c-arrays)
197             storage_ = MakePandaUnique<uint8_t[]>(size);
198             ptrCurrent_ = storage_.get();
199             ptrEnd_ = ptrCurrent_ + size;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic
200         }
201 
202         ProfileLoadSatus FillFromFd(int fd, const PandaString &source, PandaString *error);
203 
204         template <typename T>
205         T ReadUintAndAdvance();
206 
207         bool CompareAndAdvance(const uint8_t *data, size_t dataSize);
208 
GetSerializerBuffer209         uint8_t *Get()
210         {
211             return storage_.get();
212         }
213 
214     private:
215         PandaUniquePtr<uint8_t[]> storage_;  // NOLINT(modernize-avoid-c-arrays)
216         uint8_t *ptrCurrent_;
217         uint8_t *ptrEnd_;
218     };
219 
220     struct MethodWrapper {
MethodWrapperMethodWrapper221         explicit MethodWrapper(uint32_t index) : methodId(index) {}
222         uint32_t methodId;  // NOLINT(misc-non-private-member-variables-in-classes)
223 
224         bool operator==(const MethodWrapper &other) const
225         {
226             return methodId == other.methodId;
227         }
228 
229         bool operator<(const MethodWrapper &other) const
230         {
231             return methodId < other.methodId;
232         }
233     };
234 
235     struct ClassWrapper {
ClassWrapperClassWrapper236         explicit ClassWrapper(uint32_t index) : classId(index) {}
237         uint32_t classId;  // NOLINT(misc-non-private-member-variables-in-classes)
238 
239         bool operator==(const ClassWrapper &other) const
240         {
241             return classId == other.classId;
242         }
243 
244         bool operator<(const ClassWrapper &other) const
245         {
246             return classId < other.classId;
247         }
248     };
249 
250     struct ProfileLineData {
ProfileLineDataProfileLineData251         explicit ProfileLineData(uint32_t fileChecksum) : checksum(fileChecksum) {}
252         uint32_t checksum;                         // NOLINT(misc-non-private-member-variables-in-classes)
253         PandaSet<MethodWrapper> methodWrapperSet;  // NOLINT(misc-non-private-member-variables-in-classes)
254         PandaSet<ClassWrapper> classWrapperSet;    // NOLINT(misc-non-private-member-variables-in-classes)
255 
256         bool operator==(const ProfileLineData &other) const
257         {
258             return checksum == other.checksum && methodWrapperSet == other.methodWrapperSet &&
259                    classWrapperSet == other.classWrapperSet;
260         }
261 
262         // NOLINTNEXTLINE(readability-identifier-naming)
emptyProfileLineData263         bool empty() const
264         {
265             return methodWrapperSet.empty() && classWrapperSet.empty();
266         }
267     };
268 
269     ProfileLoadSatus LoadInternal(int fd, PandaString *error);
270     ProfileLoadSatus ReadProfileHeader(int fd, uint32_t *numberOfLines, PandaString *error);
271     ProfileLoadSatus ReadProfileLineHeader(int fd, ProfileLineHeader *lineHeader, PandaString *error);
272     ProfileLoadSatus ReadProfileLine(int fd, const ProfileLineHeader &lineHeader, PandaString *error);
273     // NOLINTNEXTLINE(google-runtime-references)
274     bool ProcessLine(SerializerBuffer &lineBuffer, uint32_t methodSetSize, uint32_t classSetSize, uint32_t checksum,
275                      const PandaString &pandaFileLocation);
276 
277     bool AddMethodWrapper(const PandaString &pandaFileLocation, uint32_t checksum, const MethodWrapper &methodToAdd);
278     bool AddClassWrapper(const PandaString &pandaFileLocation, uint32_t checksum, const ClassWrapper &classToAdd);
279     bool AddResolvedClasses(const ExtractedResolvedClasses &classes);
280     ProfileLineData *GetOrAddProfileLineData(const PandaString &pandaFileLocation, uint32_t checksum);
281     bool Save(const PandaString &filename, ssize_t *bytesWritten, int fd);
282 
283     PandaMap<const PandaString, ProfileLineData> dumpInfo_;
284 };
285 
286 }  // namespace ark
287 
288 #endif
289