1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ART_RUNTIME_JIT_PROFILE_COMPILATION_INFO_H_ 18 #define ART_RUNTIME_JIT_PROFILE_COMPILATION_INFO_H_ 19 20 #include <set> 21 #include <vector> 22 23 #include "atomic.h" 24 #include "base/arena_object.h" 25 #include "base/arena_containers.h" 26 #include "dex_cache_resolved_classes.h" 27 #include "dex_file.h" 28 #include "dex_file_types.h" 29 #include "method_reference.h" 30 #include "safe_map.h" 31 32 namespace art { 33 34 /** 35 * Convenient class to pass around profile information (including inline caches) 36 * without the need to hold GC-able objects. 37 */ 38 struct ProfileMethodInfo { 39 struct ProfileClassReference { 40 ProfileClassReference() : dex_file(nullptr) {} 41 ProfileClassReference(const DexFile* dex, const dex::TypeIndex index) 42 : dex_file(dex), type_index(index) {} 43 44 const DexFile* dex_file; 45 dex::TypeIndex type_index; 46 }; 47 48 struct ProfileInlineCache { 49 ProfileInlineCache(uint32_t pc, 50 bool missing_types, 51 const std::vector<ProfileClassReference>& profile_classes) 52 : dex_pc(pc), is_missing_types(missing_types), classes(profile_classes) {} 53 54 const uint32_t dex_pc; 55 const bool is_missing_types; 56 const std::vector<ProfileClassReference> classes; 57 }; 58 59 ProfileMethodInfo(const DexFile* dex, uint32_t method_index) 60 : dex_file(dex), dex_method_index(method_index) {} 61 62 ProfileMethodInfo(const DexFile* dex, 63 uint32_t method_index, 64 const std::vector<ProfileInlineCache>& caches) 65 : dex_file(dex), dex_method_index(method_index), inline_caches(caches) {} 66 67 const DexFile* dex_file; 68 const uint32_t dex_method_index; 69 const std::vector<ProfileInlineCache> inline_caches; 70 }; 71 72 /** 73 * Profile information in a format suitable to be queried by the compiler and 74 * performing profile guided compilation. 75 * It is a serialize-friendly format based on information collected by the 76 * interpreter (ProfileInfo). 77 * Currently it stores only the hot compiled methods. 78 */ 79 class ProfileCompilationInfo { 80 public: 81 static const uint8_t kProfileMagic[]; 82 static const uint8_t kProfileVersion[]; 83 84 // Data structures for encoding the offline representation of inline caches. 85 // This is exposed as public in order to make it available to dex2oat compilations 86 // (see compiler/optimizing/inliner.cc). 87 88 // A dex location together with its checksum. 89 struct DexReference { 90 DexReference() : dex_checksum(0) {} 91 92 DexReference(const std::string& location, uint32_t checksum) 93 : dex_location(location), dex_checksum(checksum) {} 94 95 bool operator==(const DexReference& other) const { 96 return dex_checksum == other.dex_checksum && dex_location == other.dex_location; 97 } 98 99 bool MatchesDex(const DexFile* dex_file) const { 100 return dex_checksum == dex_file->GetLocationChecksum() && 101 dex_location == GetProfileDexFileKey(dex_file->GetLocation()); 102 } 103 104 std::string dex_location; 105 uint32_t dex_checksum; 106 }; 107 108 // Encodes a class reference in the profile. 109 // The owning dex file is encoded as the index (dex_profile_index) it has in the 110 // profile rather than as a full DexRefence(location,checksum). 111 // This avoids excessive string copying when managing the profile data. 112 // The dex_profile_index is an index in either of: 113 // - OfflineProfileMethodInfo#dex_references vector (public use) 114 // - DexFileData#profile_index (internal use). 115 // Note that the dex_profile_index is not necessary the multidex index. 116 // We cannot rely on the actual multidex index because a single profile may store 117 // data from multiple splits. This means that a profile may contain a classes2.dex from split-A 118 // and one from split-B. 119 struct ClassReference : public ValueObject { 120 ClassReference(uint8_t dex_profile_idx, const dex::TypeIndex type_idx) : 121 dex_profile_index(dex_profile_idx), type_index(type_idx) {} 122 123 bool operator==(const ClassReference& other) const { 124 return dex_profile_index == other.dex_profile_index && type_index == other.type_index; 125 } 126 bool operator<(const ClassReference& other) const { 127 return dex_profile_index == other.dex_profile_index 128 ? type_index < other.type_index 129 : dex_profile_index < other.dex_profile_index; 130 } 131 132 uint8_t dex_profile_index; // the index of the owning dex in the profile info 133 dex::TypeIndex type_index; // the type index of the class 134 }; 135 136 // The set of classes that can be found at a given dex pc. 137 using ClassSet = ArenaSet<ClassReference>; 138 139 // Encodes the actual inline cache for a given dex pc (whether or not the receiver is 140 // megamorphic and its possible types). 141 // If the receiver is megamorphic or is missing types the set of classes will be empty. 142 struct DexPcData : public ArenaObject<kArenaAllocProfile> { 143 explicit DexPcData(ArenaAllocator* arena) 144 : is_missing_types(false), 145 is_megamorphic(false), 146 classes(std::less<ClassReference>(), arena->Adapter(kArenaAllocProfile)) {} 147 void AddClass(uint16_t dex_profile_idx, const dex::TypeIndex& type_idx); 148 void SetIsMegamorphic() { 149 if (is_missing_types) return; 150 is_megamorphic = true; 151 classes.clear(); 152 } 153 void SetIsMissingTypes() { 154 is_megamorphic = false; 155 is_missing_types = true; 156 classes.clear(); 157 } 158 bool operator==(const DexPcData& other) const { 159 return is_megamorphic == other.is_megamorphic && 160 is_missing_types == other.is_missing_types && 161 classes == other.classes; 162 } 163 164 // Not all runtime types can be encoded in the profile. For example if the receiver 165 // type is in a dex file which is not tracked for profiling its type cannot be 166 // encoded. When types are missing this field will be set to true. 167 bool is_missing_types; 168 bool is_megamorphic; 169 ClassSet classes; 170 }; 171 172 // The inline cache map: DexPc -> DexPcData. 173 using InlineCacheMap = ArenaSafeMap<uint16_t, DexPcData>; 174 175 // Maps a method dex index to its inline cache. 176 using MethodMap = ArenaSafeMap<uint16_t, InlineCacheMap>; 177 178 // Encodes the full set of inline caches for a given method. 179 // The dex_references vector is indexed according to the ClassReference::dex_profile_index. 180 // i.e. the dex file of any ClassReference present in the inline caches can be found at 181 // dex_references[ClassReference::dex_profile_index]. 182 struct OfflineProfileMethodInfo { 183 explicit OfflineProfileMethodInfo(const InlineCacheMap* inline_cache_map) 184 : inline_caches(inline_cache_map) {} 185 186 bool operator==(const OfflineProfileMethodInfo& other) const; 187 188 const InlineCacheMap* const inline_caches; 189 std::vector<DexReference> dex_references; 190 }; 191 192 // Public methods to create, extend or query the profile. 193 ProfileCompilationInfo(); 194 explicit ProfileCompilationInfo(ArenaPool* arena_pool); 195 196 ~ProfileCompilationInfo(); 197 198 // Add the given methods and classes to the current profile object. 199 bool AddMethodsAndClasses(const std::vector<ProfileMethodInfo>& methods, 200 const std::set<DexCacheResolvedClasses>& resolved_classes); 201 202 // Load profile information from the given file descriptor. 203 // If the current profile is non-empty the load will fail. 204 bool Load(int fd); 205 206 // Load profile information from the given file 207 // If the current profile is non-empty the load will fail. 208 // If clear_if_invalid is true and the file is invalid the method clears the 209 // the file and returns true. 210 bool Load(const std::string& filename, bool clear_if_invalid); 211 212 // Merge the data from another ProfileCompilationInfo into the current object. 213 bool MergeWith(const ProfileCompilationInfo& info); 214 215 // Save the profile data to the given file descriptor. 216 bool Save(int fd); 217 218 // Save the current profile into the given file. The file will be cleared before saving. 219 bool Save(const std::string& filename, uint64_t* bytes_written); 220 221 // Return the number of methods that were profiled. 222 uint32_t GetNumberOfMethods() const; 223 224 // Return the number of resolved classes that were profiled. 225 uint32_t GetNumberOfResolvedClasses() const; 226 227 // Return true if the method reference is present in the profiling info. 228 bool ContainsMethod(const MethodReference& method_ref) const; 229 230 // Return true if the class's type is present in the profiling info. 231 bool ContainsClass(const DexFile& dex_file, dex::TypeIndex type_idx) const; 232 233 // Return the method data for the given location and index from the profiling info. 234 // If the method index is not found or the checksum doesn't match, null is returned. 235 // Note: the inline cache map is a pointer to the map stored in the profile and 236 // its allocation will go away if the profile goes out of scope. 237 std::unique_ptr<OfflineProfileMethodInfo> GetMethod(const std::string& dex_location, 238 uint32_t dex_checksum, 239 uint16_t dex_method_index) const; 240 241 // Dump all the loaded profile info into a string and returns it. 242 // If dex_files is not null then the method indices will be resolved to their 243 // names. 244 // This is intended for testing and debugging. 245 std::string DumpInfo(const std::vector<std::unique_ptr<const DexFile>>* dex_files, 246 bool print_full_dex_location = true) const; 247 std::string DumpInfo(const std::vector<const DexFile*>* dex_files, 248 bool print_full_dex_location = true) const; 249 250 // Return the classes and methods for a given dex file through out args. The out args are the set 251 // of class as well as the methods and their associated inline caches. Returns true if the dex 252 // file is register and has a matching checksum, false otherwise. 253 bool GetClassesAndMethods(const DexFile& dex_file, 254 /*out*/std::set<dex::TypeIndex>* class_set, 255 /*out*/std::set<uint16_t>* method_set) const; 256 257 // Perform an equality test with the `other` profile information. 258 bool Equals(const ProfileCompilationInfo& other); 259 260 // Return the class descriptors for all of the classes in the profiles' class sets. 261 std::set<DexCacheResolvedClasses> GetResolvedClasses( 262 const std::vector<const DexFile*>& dex_files_) const; 263 264 // Return the profile key associated with the given dex location. 265 static std::string GetProfileDexFileKey(const std::string& dex_location); 266 267 // Generate a test profile which will contain a percentage of the total maximum 268 // number of methods and classes (method_ratio and class_ratio). 269 static bool GenerateTestProfile(int fd, 270 uint16_t number_of_dex_files, 271 uint16_t method_ratio, 272 uint16_t class_ratio, 273 uint32_t random_seed); 274 275 // Generate a test profile which will randomly contain classes and methods from 276 // the provided list of dex files. 277 static bool GenerateTestProfile(int fd, 278 std::vector<std::unique_ptr<const DexFile>>& dex_files, 279 uint32_t random_seed); 280 281 // Check that the given profile method info contain the same data. 282 static bool Equals(const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi1, 283 const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi2); 284 285 ArenaAllocator* GetArena() { return &arena_; } 286 287 private: 288 enum ProfileLoadSatus { 289 kProfileLoadWouldOverwiteData, 290 kProfileLoadIOError, 291 kProfileLoadVersionMismatch, 292 kProfileLoadBadData, 293 kProfileLoadSuccess 294 }; 295 296 // Internal representation of the profile information belonging to a dex file. 297 // Note that we could do without profile_key (the key used to encode the dex 298 // file in the profile) and profile_index (the index of the dex file in the 299 // profile) fields in this struct because we can infer them from 300 // profile_key_map_ and info_. However, it makes the profiles logic much 301 // simpler if we have references here as well. 302 struct DexFileData : public DeletableArenaObject<kArenaAllocProfile> { 303 DexFileData(ArenaAllocator* arena, 304 const std::string& key, 305 uint32_t location_checksum, 306 uint16_t index) 307 : arena_(arena), 308 profile_key(key), 309 profile_index(index), 310 checksum(location_checksum), 311 method_map(std::less<uint16_t>(), arena->Adapter(kArenaAllocProfile)), 312 class_set(std::less<dex::TypeIndex>(), arena->Adapter(kArenaAllocProfile)) {} 313 314 // The arena used to allocate new inline cache maps. 315 ArenaAllocator* arena_; 316 // The profile key this data belongs to. 317 std::string profile_key; 318 // The profile index of this dex file (matches ClassReference#dex_profile_index). 319 uint8_t profile_index; 320 // The dex checksum. 321 uint32_t checksum; 322 // The methonds' profile information. 323 MethodMap method_map; 324 // The classes which have been profiled. Note that these don't necessarily include 325 // all the classes that can be found in the inline caches reference. 326 ArenaSet<dex::TypeIndex> class_set; 327 328 bool operator==(const DexFileData& other) const { 329 return checksum == other.checksum && method_map == other.method_map; 330 } 331 332 // Find the inline caches of the the given method index. Add an empty entry if 333 // no previous data is found. 334 InlineCacheMap* FindOrAddMethod(uint16_t method_index); 335 }; 336 337 // Return the profile data for the given profile key or null if the dex location 338 // already exists but has a different checksum 339 DexFileData* GetOrAddDexFileData(const std::string& profile_key, uint32_t checksum); 340 341 // Add a method index to the profile (without inline caches). 342 bool AddMethodIndex(const std::string& dex_location, uint32_t checksum, uint16_t method_idx); 343 344 // Add a method to the profile using its online representation (containing runtime structures). 345 bool AddMethod(const ProfileMethodInfo& pmi); 346 347 // Add a method to the profile using its offline representation. 348 // This is mostly used to facilitate testing. 349 bool AddMethod(const std::string& dex_location, 350 uint32_t dex_checksum, 351 uint16_t method_index, 352 const OfflineProfileMethodInfo& pmi); 353 354 // Add a class index to the profile. 355 bool AddClassIndex(const std::string& dex_location, uint32_t checksum, dex::TypeIndex type_idx); 356 357 // Add all classes from the given dex cache to the the profile. 358 bool AddResolvedClasses(const DexCacheResolvedClasses& classes); 359 360 // Search for the given method in the profile. 361 // If found, its inline cache map is returned, otherwise the method returns null. 362 const InlineCacheMap* FindMethod(const std::string& dex_location, 363 uint32_t dex_checksum, 364 uint16_t dex_method_index) const; 365 366 // Encode the known dex_files into a vector. The index of a dex_reference will 367 // be the same as the profile index of the dex file (used to encode the ClassReferences). 368 void DexFileToProfileIndex(/*out*/std::vector<DexReference>* dex_references) const; 369 370 // Return the dex data associated with the given profile key or null if the profile 371 // doesn't contain the key. 372 const DexFileData* FindDexData(const std::string& profile_key) const; 373 374 // Checks if the profile is empty. 375 bool IsEmpty() const; 376 377 // Parsing functionality. 378 379 // The information present in the header of each profile line. 380 struct ProfileLineHeader { 381 std::string dex_location; 382 uint16_t class_set_size; 383 uint32_t method_region_size_bytes; 384 uint32_t checksum; 385 }; 386 387 // A helper structure to make sure we don't read past our buffers in the loops. 388 struct SafeBuffer { 389 public: 390 explicit SafeBuffer(size_t size) : storage_(new uint8_t[size]) { 391 ptr_current_ = storage_.get(); 392 ptr_end_ = ptr_current_ + size; 393 } 394 395 // Reads the content of the descriptor at the current position. 396 ProfileLoadSatus FillFromFd(int fd, 397 const std::string& source, 398 /*out*/std::string* error); 399 400 // Reads an uint value (high bits to low bits) and advances the current pointer 401 // with the number of bits read. 402 template <typename T> bool ReadUintAndAdvance(/*out*/ T* value); 403 404 // Compares the given data with the content current pointer. If the contents are 405 // equal it advances the current pointer by data_size. 406 bool CompareAndAdvance(const uint8_t* data, size_t data_size); 407 408 // Returns true if the buffer has more data to read. 409 bool HasMoreData(); 410 411 // Get the underlying raw buffer. 412 uint8_t* Get() { return storage_.get(); } 413 414 private: 415 std::unique_ptr<uint8_t[]> storage_; 416 uint8_t* ptr_current_; 417 uint8_t* ptr_end_; 418 }; 419 420 // Entry point for profile loding functionality. 421 ProfileLoadSatus LoadInternal(int fd, std::string* error); 422 423 // Read the profile header from the given fd and store the number of profile 424 // lines into number_of_dex_files. 425 ProfileLoadSatus ReadProfileHeader(int fd, 426 /*out*/uint8_t* number_of_dex_files, 427 /*out*/std::string* error); 428 429 // Read the header of a profile line from the given fd. 430 ProfileLoadSatus ReadProfileLineHeader(int fd, 431 /*out*/ProfileLineHeader* line_header, 432 /*out*/std::string* error); 433 434 // Read individual elements from the profile line header. 435 bool ReadProfileLineHeaderElements(SafeBuffer& buffer, 436 /*out*/uint16_t* dex_location_size, 437 /*out*/ProfileLineHeader* line_header, 438 /*out*/std::string* error); 439 440 // Read a single profile line from the given fd. 441 ProfileLoadSatus ReadProfileLine(int fd, 442 uint8_t number_of_dex_files, 443 const ProfileLineHeader& line_header, 444 /*out*/std::string* error); 445 446 // Read all the classes from the buffer into the profile `info_` structure. 447 bool ReadClasses(SafeBuffer& buffer, 448 uint16_t classes_to_read, 449 const ProfileLineHeader& line_header, 450 /*out*/std::string* error); 451 452 // Read all the methods from the buffer into the profile `info_` structure. 453 bool ReadMethods(SafeBuffer& buffer, 454 uint8_t number_of_dex_files, 455 const ProfileLineHeader& line_header, 456 /*out*/std::string* error); 457 458 // Read the inline cache encoding from line_bufer into inline_cache. 459 bool ReadInlineCache(SafeBuffer& buffer, 460 uint8_t number_of_dex_files, 461 /*out*/InlineCacheMap* inline_cache, 462 /*out*/std::string* error); 463 464 // Encode the inline cache into the given buffer. 465 void AddInlineCacheToBuffer(std::vector<uint8_t>* buffer, 466 const InlineCacheMap& inline_cache); 467 468 // Return the number of bytes needed to encode the profile information 469 // for the methods in dex_data. 470 uint32_t GetMethodsRegionSize(const DexFileData& dex_data); 471 472 // Group `classes` by their owning dex profile index and put the result in 473 // `dex_to_classes_map`. 474 void GroupClassesByDex( 475 const ClassSet& classes, 476 /*out*/SafeMap<uint8_t, std::vector<dex::TypeIndex>>* dex_to_classes_map); 477 478 // Find the data for the dex_pc in the inline cache. Adds an empty entry 479 // if no previous data exists. 480 DexPcData* FindOrAddDexPc(InlineCacheMap* inline_cache, uint32_t dex_pc); 481 482 friend class ProfileCompilationInfoTest; 483 friend class CompilerDriverProfileTest; 484 friend class ProfileAssistantTest; 485 friend class Dex2oatLayoutTest; 486 487 ArenaPool default_arena_pool_; 488 ArenaAllocator arena_; 489 490 // Vector containing the actual profile info. 491 // The vector index is the profile index of the dex data and 492 // matched DexFileData::profile_index. 493 ArenaVector<DexFileData*> info_; 494 495 // Cache mapping profile keys to profile index. 496 // This is used to speed up searches since it avoids iterating 497 // over the info_ vector when searching by profile key. 498 ArenaSafeMap<const std::string, uint8_t> profile_key_map_; 499 }; 500 501 } // namespace art 502 503 #endif // ART_RUNTIME_JIT_PROFILE_COMPILATION_INFO_H_ 504