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