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_LIBPROFILE_PROFILE_PROFILE_COMPILATION_INFO_H_ 18 #define ART_LIBPROFILE_PROFILE_PROFILE_COMPILATION_INFO_H_ 19 20 #include <set> 21 #include <vector> 22 23 #include "base/arena_containers.h" 24 #include "base/arena_object.h" 25 #include "base/atomic.h" 26 #include "base/bit_memory_region.h" 27 #include "base/hash_set.h" 28 #include "base/malloc_arena_pool.h" 29 #include "base/mem_map.h" 30 #include "base/safe_map.h" 31 #include "dex/dex_cache_resolved_classes.h" 32 #include "dex/dex_file.h" 33 #include "dex/dex_file_types.h" 34 #include "dex/method_reference.h" 35 #include "dex/type_reference.h" 36 37 namespace art { 38 39 /** 40 * Convenient class to pass around profile information (including inline caches) 41 * without the need to hold GC-able objects. 42 */ 43 struct ProfileMethodInfo { 44 struct ProfileInlineCache { ProfileInlineCacheProfileMethodInfo::ProfileInlineCache45 ProfileInlineCache(uint32_t pc, 46 bool missing_types, 47 const std::vector<TypeReference>& profile_classes) 48 : dex_pc(pc), is_missing_types(missing_types), classes(profile_classes) {} 49 50 const uint32_t dex_pc; 51 const bool is_missing_types; 52 const std::vector<TypeReference> classes; 53 }; 54 ProfileMethodInfoProfileMethodInfo55 explicit ProfileMethodInfo(MethodReference reference) : ref(reference) {} 56 ProfileMethodInfoProfileMethodInfo57 ProfileMethodInfo(MethodReference reference, const std::vector<ProfileInlineCache>& caches) 58 : ref(reference), 59 inline_caches(caches) {} 60 61 MethodReference ref; 62 std::vector<ProfileInlineCache> inline_caches; 63 }; 64 65 /** 66 * Profile information in a format suitable to be queried by the compiler and 67 * performing profile guided compilation. 68 * It is a serialize-friendly format based on information collected by the 69 * interpreter (ProfileInfo). 70 * Currently it stores only the hot compiled methods. 71 */ 72 class ProfileCompilationInfo { 73 public: 74 static const uint8_t kProfileMagic[]; 75 static const uint8_t kProfileVersion[]; 76 static const uint8_t kProfileVersionWithCounters[]; 77 static const char kDexMetadataProfileEntry[]; 78 79 static constexpr size_t kProfileVersionSize = 4; 80 static constexpr uint8_t kIndividualInlineCacheSize = 5; 81 82 // Data structures for encoding the offline representation of inline caches. 83 // This is exposed as public in order to make it available to dex2oat compilations 84 // (see compiler/optimizing/inliner.cc). 85 86 // A dex location together with its checksum. 87 struct DexReference { DexReferenceDexReference88 DexReference() : dex_checksum(0), num_method_ids(0) {} 89 DexReferenceDexReference90 DexReference(const std::string& location, uint32_t checksum, uint32_t num_methods) 91 : dex_location(location), dex_checksum(checksum), num_method_ids(num_methods) {} 92 93 bool operator==(const DexReference& other) const { 94 return dex_checksum == other.dex_checksum && 95 dex_location == other.dex_location && 96 num_method_ids == other.num_method_ids; 97 } 98 MatchesDexDexReference99 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 uint32_t num_method_ids; 107 }; 108 109 // Encodes a class reference in the profile. 110 // The owning dex file is encoded as the index (dex_profile_index) it has in the 111 // profile rather than as a full DexRefence(location,checksum). 112 // This avoids excessive string copying when managing the profile data. 113 // The dex_profile_index is an index in either of: 114 // - OfflineProfileMethodInfo#dex_references vector (public use) 115 // - DexFileData#profile_index (internal use). 116 // Note that the dex_profile_index is not necessary the multidex index. 117 // We cannot rely on the actual multidex index because a single profile may store 118 // data from multiple splits. This means that a profile may contain a classes2.dex from split-A 119 // and one from split-B. 120 struct ClassReference : public ValueObject { ClassReferenceClassReference121 ClassReference(uint8_t dex_profile_idx, const dex::TypeIndex type_idx) : 122 dex_profile_index(dex_profile_idx), type_index(type_idx) {} 123 124 bool operator==(const ClassReference& other) const { 125 return dex_profile_index == other.dex_profile_index && type_index == other.type_index; 126 } 127 bool operator<(const ClassReference& other) const { 128 return dex_profile_index == other.dex_profile_index 129 ? type_index < other.type_index 130 : dex_profile_index < other.dex_profile_index; 131 } 132 133 uint8_t dex_profile_index; // the index of the owning dex in the profile info 134 dex::TypeIndex type_index; // the type index of the class 135 }; 136 137 // The set of classes that can be found at a given dex pc. 138 using ClassSet = ArenaSet<ClassReference>; 139 140 // Encodes the actual inline cache for a given dex pc (whether or not the receiver is 141 // megamorphic and its possible types). 142 // If the receiver is megamorphic or is missing types the set of classes will be empty. 143 struct DexPcData : public ArenaObject<kArenaAllocProfile> { DexPcDataDexPcData144 explicit DexPcData(ArenaAllocator* allocator) 145 : is_missing_types(false), 146 is_megamorphic(false), 147 classes(std::less<ClassReference>(), allocator->Adapter(kArenaAllocProfile)) {} 148 void AddClass(uint16_t dex_profile_idx, const dex::TypeIndex& type_idx); SetIsMegamorphicDexPcData149 void SetIsMegamorphic() { 150 if (is_missing_types) return; 151 is_megamorphic = true; 152 classes.clear(); 153 } SetIsMissingTypesDexPcData154 void SetIsMissingTypes() { 155 is_megamorphic = false; 156 is_missing_types = true; 157 classes.clear(); 158 } 159 bool operator==(const DexPcData& other) const { 160 return is_megamorphic == other.is_megamorphic && 161 is_missing_types == other.is_missing_types && 162 classes == other.classes; 163 } 164 165 // Not all runtime types can be encoded in the profile. For example if the receiver 166 // type is in a dex file which is not tracked for profiling its type cannot be 167 // encoded. When types are missing this field will be set to true. 168 bool is_missing_types; 169 bool is_megamorphic; 170 ClassSet classes; 171 }; 172 173 // The inline cache map: DexPc -> DexPcData. 174 using InlineCacheMap = ArenaSafeMap<uint16_t, DexPcData>; 175 176 // Maps a method dex index to its inline cache. 177 using MethodMap = ArenaSafeMap<uint16_t, InlineCacheMap>; 178 179 // Profile method hotness information for a single method. Also includes a pointer to the inline 180 // cache map. 181 class MethodHotness { 182 public: 183 enum Flag { 184 kFlagHot = 0x1, 185 kFlagStartup = 0x2, 186 kFlagPostStartup = 0x4, 187 }; 188 IsHot()189 bool IsHot() const { 190 return (flags_ & kFlagHot) != 0; 191 } 192 IsStartup()193 bool IsStartup() const { 194 return (flags_ & kFlagStartup) != 0; 195 } 196 IsPostStartup()197 bool IsPostStartup() const { 198 return (flags_ & kFlagPostStartup) != 0; 199 } 200 AddFlag(Flag flag)201 void AddFlag(Flag flag) { 202 flags_ |= flag; 203 } 204 GetFlags()205 uint8_t GetFlags() const { 206 return flags_; 207 } 208 IsInProfile()209 bool IsInProfile() const { 210 return flags_ != 0; 211 } 212 213 private: 214 const InlineCacheMap* inline_cache_map_ = nullptr; 215 uint8_t flags_ = 0; 216 GetInlineCacheMap()217 const InlineCacheMap* GetInlineCacheMap() const { 218 return inline_cache_map_; 219 } 220 SetInlineCacheMap(const InlineCacheMap * info)221 void SetInlineCacheMap(const InlineCacheMap* info) { 222 inline_cache_map_ = info; 223 } 224 225 friend class ProfileCompilationInfo; 226 }; 227 228 // Encodes the full set of inline caches for a given method. 229 // The dex_references vector is indexed according to the ClassReference::dex_profile_index. 230 // i.e. the dex file of any ClassReference present in the inline caches can be found at 231 // dex_references[ClassReference::dex_profile_index]. 232 struct OfflineProfileMethodInfo { OfflineProfileMethodInfoOfflineProfileMethodInfo233 explicit OfflineProfileMethodInfo(const InlineCacheMap* inline_cache_map) 234 : inline_caches(inline_cache_map) {} 235 236 bool operator==(const OfflineProfileMethodInfo& other) const; 237 238 const InlineCacheMap* const inline_caches; 239 std::vector<DexReference> dex_references; 240 }; 241 242 // Public methods to create, extend or query the profile. 243 ProfileCompilationInfo(); 244 explicit ProfileCompilationInfo(ArenaPool* arena_pool); 245 246 ~ProfileCompilationInfo(); 247 248 // Add the given methods to the current profile object. 249 bool AddMethods(const std::vector<ProfileMethodInfo>& methods, MethodHotness::Flag flags); 250 251 // Add the given classes to the current profile object. 252 bool AddClasses(const std::set<DexCacheResolvedClasses>& resolved_classes); 253 254 // Add multiple type ids for classes in a single dex file. Iterator is for type_ids not 255 // class_defs. 256 template <class Iterator> AddClassesForDex(const DexFile * dex_file,Iterator index_begin,Iterator index_end)257 bool AddClassesForDex(const DexFile* dex_file, Iterator index_begin, Iterator index_end) { 258 DexFileData* data = GetOrAddDexFileData(dex_file); 259 if (data == nullptr) { 260 return false; 261 } 262 data->class_set.insert(index_begin, index_end); 263 return true; 264 } 265 // Add a single type id for a dex file. AddClassForDex(const TypeReference & ref)266 bool AddClassForDex(const TypeReference& ref) { 267 DexFileData* data = GetOrAddDexFileData(ref.dex_file); 268 if (data == nullptr) { 269 return false; 270 } 271 data->class_set.insert(ref.TypeIndex()); 272 return true; 273 } 274 275 276 // Add a method index to the profile (without inline caches). The method flags determine if it is 277 // hot, startup, or post startup, or a combination of the previous. 278 bool AddMethodIndex(MethodHotness::Flag flags, 279 const std::string& dex_location, 280 uint32_t checksum, 281 uint16_t method_idx, 282 uint32_t num_method_ids); 283 bool AddMethodIndex(MethodHotness::Flag flags, const MethodReference& ref); 284 285 // Add a method to the profile using its online representation (containing runtime structures). 286 bool AddMethod(const ProfileMethodInfo& pmi, MethodHotness::Flag flags); 287 288 // Bulk add sampled methods and/or hot methods for a single dex, fast since it only has one 289 // GetOrAddDexFileData call. 290 template <class Iterator> AddMethodsForDex(MethodHotness::Flag flags,const DexFile * dex_file,Iterator index_begin,Iterator index_end)291 bool AddMethodsForDex(MethodHotness::Flag flags, 292 const DexFile* dex_file, 293 Iterator index_begin, 294 Iterator index_end) { 295 DexFileData* data = GetOrAddDexFileData(dex_file); 296 if (data == nullptr) { 297 return false; 298 } 299 for (Iterator it = index_begin; it != index_end; ++it) { 300 DCHECK_LT(*it, data->num_method_ids); 301 if (!data->AddMethod(flags, *it)) { 302 return false; 303 } 304 } 305 return true; 306 } 307 308 // Add hotness flags for a simple method. 309 bool AddMethodHotness(const MethodReference& method_ref, const MethodHotness& hotness); 310 311 // Load or Merge profile information from the given file descriptor. 312 // If the current profile is non-empty the load will fail. 313 // If merge_classes is set to false, classes will not be merged/loaded. 314 // If filter_fn is present, it will be used to filter out profile data belonging 315 // to dex file which do not comply with the filter 316 // (i.e. for which filter_fn(dex_location, dex_checksum) is false). 317 using ProfileLoadFilterFn = std::function<bool(const std::string&, uint32_t)>; 318 // Profile filter method which accepts all dex locations. 319 // This is convenient to use when we need to accept all locations without repeating the same 320 // lambda. 321 static bool ProfileFilterFnAcceptAll(const std::string& dex_location, uint32_t checksum); 322 323 bool Load( 324 int fd, 325 bool merge_classes = true, 326 const ProfileLoadFilterFn& filter_fn = ProfileFilterFnAcceptAll); 327 328 // Verify integrity of the profile file with the provided dex files. 329 // If there exists a DexData object which maps to a dex_file, then it verifies that: 330 // - The checksums of the DexData and dex_file are equals. 331 // - No method id exceeds NumMethodIds corresponding to the dex_file. 332 // - No class id exceeds NumTypeIds corresponding to the dex_file. 333 // - For every inline_caches, class_ids does not exceed NumTypeIds corresponding to 334 // the dex_file they are in. 335 bool VerifyProfileData(const std::vector<const DexFile *> &dex_files); 336 337 // Load profile information from the given file 338 // If the current profile is non-empty the load will fail. 339 // If clear_if_invalid is true and the file is invalid the method clears the 340 // the file and returns true. 341 bool Load(const std::string& filename, bool clear_if_invalid); 342 343 // Merge the data from another ProfileCompilationInfo into the current object. Only merges 344 // classes if merge_classes is true. This is used for creating the boot profile since 345 // we don't want all of the classes to be image classes. 346 bool MergeWith(const ProfileCompilationInfo& info, bool merge_classes = true); 347 348 // Merge profile information from the given file descriptor. 349 bool MergeWith(const std::string& filename); 350 351 // Save the profile data to the given file descriptor. 352 bool Save(int fd); 353 354 // Save the current profile into the given file. The file will be cleared before saving. 355 bool Save(const std::string& filename, uint64_t* bytes_written); 356 357 // Return the number of methods that were profiled. 358 uint32_t GetNumberOfMethods() const; 359 360 // Return the number of resolved classes that were profiled. 361 uint32_t GetNumberOfResolvedClasses() const; 362 363 // Returns the profile method info for a given method reference. 364 MethodHotness GetMethodHotness(const MethodReference& method_ref) const; 365 MethodHotness GetMethodHotness(const std::string& dex_location, 366 uint32_t dex_checksum, 367 uint16_t dex_method_index) const; 368 369 // Return true if the class's type is present in the profiling info. 370 bool ContainsClass(const DexFile& dex_file, dex::TypeIndex type_idx) const; 371 372 // Return the method data for the given location and index from the profiling info. 373 // If the method index is not found or the checksum doesn't match, null is returned. 374 // Note: the inline cache map is a pointer to the map stored in the profile and 375 // its allocation will go away if the profile goes out of scope. 376 std::unique_ptr<OfflineProfileMethodInfo> GetMethod(const std::string& dex_location, 377 uint32_t dex_checksum, 378 uint16_t dex_method_index) const; 379 380 // Dump all the loaded profile info into a string and returns it. 381 // If dex_files is not empty then the method indices will be resolved to their 382 // names. 383 // This is intended for testing and debugging. 384 std::string DumpInfo(const std::vector<const DexFile*>& dex_files, 385 bool print_full_dex_location = true) const; 386 387 // Return the classes and methods for a given dex file through out args. The out args are the set 388 // of class as well as the methods and their associated inline caches. Returns true if the dex 389 // file is register and has a matching checksum, false otherwise. 390 bool GetClassesAndMethods(const DexFile& dex_file, 391 /*out*/std::set<dex::TypeIndex>* class_set, 392 /*out*/std::set<uint16_t>* hot_method_set, 393 /*out*/std::set<uint16_t>* startup_method_set, 394 /*out*/std::set<uint16_t>* post_startup_method_method_set) const; 395 396 // Perform an equality test with the `other` profile information. 397 bool Equals(const ProfileCompilationInfo& other); 398 399 // Return the class descriptors for all of the classes in the profiles' class sets. 400 std::set<DexCacheResolvedClasses> GetResolvedClasses( 401 const std::vector<const DexFile*>& dex_files_) const; 402 403 // Return the profile key associated with the given dex location. 404 static std::string GetProfileDexFileKey(const std::string& dex_location); 405 406 // Generate a test profile which will contain a percentage of the total maximum 407 // number of methods and classes (method_ratio and class_ratio). 408 static bool GenerateTestProfile(int fd, 409 uint16_t number_of_dex_files, 410 uint16_t method_ratio, 411 uint16_t class_ratio, 412 uint32_t random_seed); 413 414 // Generate a test profile which will randomly contain classes and methods from 415 // the provided list of dex files. 416 static bool GenerateTestProfile(int fd, 417 std::vector<std::unique_ptr<const DexFile>>& dex_files, 418 uint16_t method_percentage, 419 uint16_t class_percentage, 420 uint32_t random_seed); 421 422 // Check that the given profile method info contain the same data. 423 static bool Equals(const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi1, 424 const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi2); 425 GetAllocator()426 ArenaAllocator* GetAllocator() { return &allocator_; } 427 428 // Return all of the class descriptors in the profile for a set of dex files. 429 HashSet<std::string> GetClassDescriptors(const std::vector<const DexFile*>& dex_files); 430 431 // Return true if the fd points to a profile file. 432 bool IsProfileFile(int fd); 433 434 // Update the profile keys corresponding to the given dex files based on their current paths. 435 // This method allows fix-ups in the profile for dex files that might have been renamed. 436 // The new profile key will be constructed based on the current dex location. 437 // 438 // The matching [profile key <-> dex_file] is done based on the dex checksum and the number of 439 // methods ids. If neither is a match then the profile key is not updated. 440 // 441 // If the new profile key would collide with an existing key (for a different dex) 442 // the method returns false. Otherwise it returns true. 443 bool UpdateProfileKeys(const std::vector<std::unique_ptr<const DexFile>>& dex_files); 444 445 // Checks if the profile is empty. 446 bool IsEmpty() const; 447 448 // Clears all the data from the profile. 449 void ClearData(); 450 451 // Prepare the profile to store aggregation counters. 452 // This will change the profile version and allocate extra storage for the counters. 453 // It allocates 2 bytes for every possible method and class, so do not use in performance 454 // critical code which needs to be memory efficient. 455 void PrepareForAggregationCounters(); 456 457 // Returns true if the profile is configured to store aggregation counters. 458 bool StoresAggregationCounters() const; 459 460 // Returns the aggregation counter for the given method. 461 // Returns -1 if the method is not in the profile. 462 // CHECKs that the profile is configured to store aggregations counters. 463 int32_t GetMethodAggregationCounter(const MethodReference& method_ref) const; 464 // Returns the aggregation counter for the given class. 465 // Returns -1 if the class is not in the profile. 466 // CHECKs that the profile is configured to store aggregations counters. 467 int32_t GetClassAggregationCounter(const TypeReference& type_ref) const; 468 // Returns the number of times the profile was merged. 469 // CHECKs that the profile is configured to store aggregations counters. 470 uint16_t GetAggregationCounter() const; 471 472 // Return the version of this profile. 473 const uint8_t* GetVersion() const; 474 475 private: 476 enum ProfileLoadStatus { 477 kProfileLoadWouldOverwiteData, 478 kProfileLoadIOError, 479 kProfileLoadVersionMismatch, 480 kProfileLoadBadData, 481 kProfileLoadSuccess 482 }; 483 484 const uint32_t kProfileSizeWarningThresholdInBytes = 500000U; 485 const uint32_t kProfileSizeErrorThresholdInBytes = 1000000U; 486 487 // Internal representation of the profile information belonging to a dex file. 488 // Note that we could do without profile_key (the key used to encode the dex 489 // file in the profile) and profile_index (the index of the dex file in the 490 // profile) fields in this struct because we can infer them from 491 // profile_key_map_ and info_. However, it makes the profiles logic much 492 // simpler if we have references here as well. 493 struct DexFileData : public DeletableArenaObject<kArenaAllocProfile> { DexFileDataDexFileData494 DexFileData(ArenaAllocator* allocator, 495 const std::string& key, 496 uint32_t location_checksum, 497 uint16_t index, 498 uint32_t num_methods, 499 bool store_aggregation_counters) 500 : allocator_(allocator), 501 profile_key(key), 502 profile_index(index), 503 checksum(location_checksum), 504 method_map(std::less<uint16_t>(), allocator->Adapter(kArenaAllocProfile)), 505 class_set(std::less<dex::TypeIndex>(), allocator->Adapter(kArenaAllocProfile)), 506 num_method_ids(num_methods), 507 bitmap_storage(allocator->Adapter(kArenaAllocProfile)), 508 method_counters(allocator->Adapter(kArenaAllocProfile)), 509 class_counters(allocator->Adapter(kArenaAllocProfile)) { 510 bitmap_storage.resize(ComputeBitmapStorage(num_method_ids)); 511 if (!bitmap_storage.empty()) { 512 method_bitmap = 513 BitMemoryRegion(MemoryRegion( 514 &bitmap_storage[0], bitmap_storage.size()), 0, ComputeBitmapBits(num_method_ids)); 515 } 516 if (store_aggregation_counters) { 517 PrepareForAggregationCounters(); 518 } 519 } 520 ComputeBitmapBitsDexFileData521 static size_t ComputeBitmapBits(uint32_t num_method_ids) { 522 return num_method_ids * kBitmapIndexCount; 523 } ComputeBitmapStorageDexFileData524 static size_t ComputeBitmapStorage(uint32_t num_method_ids) { 525 return RoundUp(ComputeBitmapBits(num_method_ids), kBitsPerByte) / kBitsPerByte; 526 } 527 528 bool operator==(const DexFileData& other) const { 529 return checksum == other.checksum && 530 num_method_ids == other.num_method_ids && 531 method_map == other.method_map && 532 class_set == other.class_set && 533 (BitMemoryRegion::Compare(method_bitmap, other.method_bitmap) == 0) && 534 class_counters == other.class_counters && 535 method_counters == other.method_counters; 536 } 537 538 // Mark a method as executed at least once. 539 bool AddMethod(MethodHotness::Flag flags, size_t index); 540 MergeBitmapDexFileData541 void MergeBitmap(const DexFileData& other) { 542 DCHECK_EQ(bitmap_storage.size(), other.bitmap_storage.size()); 543 for (size_t i = 0; i < bitmap_storage.size(); ++i) { 544 bitmap_storage[i] |= other.bitmap_storage[i]; 545 } 546 } 547 548 void SetMethodHotness(size_t index, MethodHotness::Flag flags); 549 MethodHotness GetHotnessInfo(uint32_t dex_method_index) const; 550 void PrepareForAggregationCounters(); 551 552 int32_t GetMethodAggregationCounter(uint16_t method_index) const; 553 int32_t GetClassAggregationCounter(uint16_t type_index) const; 554 555 uint16_t GetNumMethodCounters() const; 556 557 bool ContainsClass(const dex::TypeIndex type_index) const; 558 559 // The allocator used to allocate new inline cache maps. 560 ArenaAllocator* const allocator_; 561 // The profile key this data belongs to. 562 std::string profile_key; 563 // The profile index of this dex file (matches ClassReference#dex_profile_index). 564 uint8_t profile_index; 565 // The dex checksum. 566 uint32_t checksum; 567 // The methods' profile information. 568 MethodMap method_map; 569 // The classes which have been profiled. Note that these don't necessarily include 570 // all the classes that can be found in the inline caches reference. 571 ArenaSet<dex::TypeIndex> class_set; 572 // Find the inline caches of the the given method index. Add an empty entry if 573 // no previous data is found. 574 InlineCacheMap* FindOrAddMethod(uint16_t method_index); 575 // Num method ids. 576 uint32_t num_method_ids; 577 ArenaVector<uint8_t> bitmap_storage; 578 BitMemoryRegion method_bitmap; 579 ArenaVector<uint16_t> method_counters; 580 ArenaVector<uint16_t> class_counters; 581 582 private: 583 enum BitmapIndex { 584 kBitmapIndexStartup, 585 kBitmapIndexPostStartup, 586 kBitmapIndexCount, 587 }; 588 MethodBitIndexDexFileData589 size_t MethodBitIndex(bool startup, size_t index) const { 590 DCHECK_LT(index, num_method_ids); 591 // The format is [startup bitmap][post startup bitmap] 592 // This compresses better than ([startup bit][post statup bit])* 593 594 return index + (startup 595 ? kBitmapIndexStartup * num_method_ids 596 : kBitmapIndexPostStartup * num_method_ids); 597 } 598 }; 599 600 // Return the profile data for the given profile key or null if the dex location 601 // already exists but has a different checksum 602 DexFileData* GetOrAddDexFileData(const std::string& profile_key, 603 uint32_t checksum, 604 uint32_t num_method_ids); 605 GetOrAddDexFileData(const DexFile * dex_file)606 DexFileData* GetOrAddDexFileData(const DexFile* dex_file) { 607 return GetOrAddDexFileData(GetProfileDexFileKey(dex_file->GetLocation()), 608 dex_file->GetLocationChecksum(), 609 dex_file->NumMethodIds()); 610 } 611 612 // Add a method to the profile using its offline representation. 613 // This is mostly used to facilitate testing. 614 bool AddMethod(const std::string& dex_location, 615 uint32_t dex_checksum, 616 uint16_t method_index, 617 uint32_t num_method_ids, 618 const OfflineProfileMethodInfo& pmi, 619 MethodHotness::Flag flags); 620 621 // Add a class index to the profile. 622 bool AddClassIndex(const std::string& dex_location, 623 uint32_t checksum, 624 dex::TypeIndex type_idx, 625 uint32_t num_method_ids); 626 627 // Add all classes from the given dex cache to the the profile. 628 bool AddResolvedClasses(const DexCacheResolvedClasses& classes); 629 630 // Encode the known dex_files into a vector. The index of a dex_reference will 631 // be the same as the profile index of the dex file (used to encode the ClassReferences). 632 void DexFileToProfileIndex(/*out*/std::vector<DexReference>* dex_references) const; 633 634 // Return the dex data associated with the given profile key or null if the profile 635 // doesn't contain the key. 636 const DexFileData* FindDexData(const std::string& profile_key, 637 uint32_t checksum, 638 bool verify_checksum = true) const; 639 640 // Return the dex data associated with the given dex file or null if the profile doesn't contain 641 // the key or the checksum mismatches. 642 const DexFileData* FindDexData(const DexFile* dex_file) const; 643 644 // Inflate the input buffer (in_buffer) of size in_size. It returns a buffer of 645 // compressed data for the input buffer of "compressed_data_size" size. 646 std::unique_ptr<uint8_t[]> DeflateBuffer(const uint8_t* in_buffer, 647 uint32_t in_size, 648 /*out*/uint32_t* compressed_data_size); 649 650 // Inflate the input buffer(in_buffer) of size in_size. out_size is the expected output 651 // size of the buffer. It puts the output in out_buffer. It returns Z_STREAM_END on 652 // success. On error, it returns Z_STREAM_ERROR if the compressed data is inconsistent 653 // and Z_DATA_ERROR if the stream ended prematurely or the stream has extra data. 654 int InflateBuffer(const uint8_t* in_buffer, 655 uint32_t in_size, 656 uint32_t out_size, 657 /*out*/uint8_t* out_buffer); 658 659 // Parsing functionality. 660 661 // The information present in the header of each profile line. 662 struct ProfileLineHeader { 663 std::string dex_location; 664 uint16_t class_set_size; 665 uint32_t method_region_size_bytes; 666 uint32_t checksum; 667 uint32_t num_method_ids; 668 }; 669 670 /** 671 * Encapsulate the source of profile data for loading. 672 * The source can be either a plain file or a zip file. 673 * For zip files, the profile entry will be extracted to 674 * the memory map. 675 */ 676 class ProfileSource { 677 public: 678 /** 679 * Create a profile source for the given fd. The ownership of the fd 680 * remains to the caller; as this class will not attempt to close it at any 681 * point. 682 */ Create(int32_t fd)683 static ProfileSource* Create(int32_t fd) { 684 DCHECK_GT(fd, -1); 685 return new ProfileSource(fd, MemMap::Invalid()); 686 } 687 688 /** 689 * Create a profile source backed by a memory map. The map can be null in 690 * which case it will the treated as an empty source. 691 */ Create(MemMap && mem_map)692 static ProfileSource* Create(MemMap&& mem_map) { 693 return new ProfileSource(/*fd*/ -1, std::move(mem_map)); 694 } 695 696 /** 697 * Read bytes from this source. 698 * Reading will advance the current source position so subsequent 699 * invocations will read from the las position. 700 */ 701 ProfileLoadStatus Read(uint8_t* buffer, 702 size_t byte_count, 703 const std::string& debug_stage, 704 std::string* error); 705 706 /** Return true if the source has 0 data. */ 707 bool HasEmptyContent() const; 708 /** Return true if all the information from this source has been read. */ 709 bool HasConsumedAllData() const; 710 711 private: ProfileSource(int32_t fd,MemMap && mem_map)712 ProfileSource(int32_t fd, MemMap&& mem_map) 713 : fd_(fd), mem_map_(std::move(mem_map)), mem_map_cur_(0) {} 714 IsMemMap()715 bool IsMemMap() const { return fd_ == -1; } 716 717 int32_t fd_; // The fd is not owned by this class. 718 MemMap mem_map_; 719 size_t mem_map_cur_; // Current position in the map to read from. 720 }; 721 722 // A helper structure to make sure we don't read past our buffers in the loops. 723 struct SafeBuffer { 724 public: SafeBufferSafeBuffer725 explicit SafeBuffer(size_t size) : storage_(new uint8_t[size]) { 726 ptr_current_ = storage_.get(); 727 ptr_end_ = ptr_current_ + size; 728 } 729 730 // Reads the content of the descriptor at the current position. 731 ProfileLoadStatus Fill(ProfileSource& source, 732 const std::string& debug_stage, 733 /*out*/std::string* error); 734 735 // Reads an uint value (high bits to low bits) and advances the current pointer 736 // with the number of bits read. 737 template <typename T> bool ReadUintAndAdvance(/*out*/ T* value); 738 739 // Compares the given data with the content current pointer. If the contents are 740 // equal it advances the current pointer by data_size. 741 bool CompareAndAdvance(const uint8_t* data, size_t data_size); 742 743 // Advances current pointer by data_size. 744 void Advance(size_t data_size); 745 746 // Returns the count of unread bytes. 747 size_t CountUnreadBytes(); 748 749 // Returns the current pointer. 750 const uint8_t* GetCurrentPtr(); 751 752 // Get the underlying raw buffer. GetSafeBuffer753 uint8_t* Get() { return storage_.get(); } 754 755 private: 756 std::unique_ptr<uint8_t[]> storage_; 757 uint8_t* ptr_end_; 758 uint8_t* ptr_current_; 759 }; 760 761 ProfileLoadStatus OpenSource(int32_t fd, 762 /*out*/ std::unique_ptr<ProfileSource>* source, 763 /*out*/ std::string* error); 764 765 // Entry point for profile loading functionality. 766 ProfileLoadStatus LoadInternal( 767 int32_t fd, 768 std::string* error, 769 bool merge_classes = true, 770 const ProfileLoadFilterFn& filter_fn = ProfileFilterFnAcceptAll); 771 772 // Read the profile header from the given fd and store the number of profile 773 // lines into number_of_dex_files. 774 ProfileLoadStatus ReadProfileHeader(ProfileSource& source, 775 /*out*/uint8_t* number_of_dex_files, 776 /*out*/uint32_t* size_uncompressed_data, 777 /*out*/uint32_t* size_compressed_data, 778 /*out*/std::string* error); 779 780 // Read the header of a profile line from the given fd. 781 ProfileLoadStatus ReadProfileLineHeader(SafeBuffer& buffer, 782 /*out*/ProfileLineHeader* line_header, 783 /*out*/std::string* error); 784 785 // Read individual elements from the profile line header. 786 bool ReadProfileLineHeaderElements(SafeBuffer& buffer, 787 /*out*/uint16_t* dex_location_size, 788 /*out*/ProfileLineHeader* line_header, 789 /*out*/std::string* error); 790 791 // Read a single profile line from the given fd. 792 ProfileLoadStatus ReadProfileLine(SafeBuffer& buffer, 793 uint8_t number_of_dex_files, 794 const ProfileLineHeader& line_header, 795 const SafeMap<uint8_t, uint8_t>& dex_profile_index_remap, 796 bool merge_classes, 797 /*out*/std::string* error); 798 799 // Read all the classes from the buffer into the profile `info_` structure. 800 bool ReadClasses(SafeBuffer& buffer, 801 const ProfileLineHeader& line_header, 802 /*out*/std::string* error); 803 804 // Read all the methods from the buffer into the profile `info_` structure. 805 bool ReadMethods(SafeBuffer& buffer, 806 uint8_t number_of_dex_files, 807 const ProfileLineHeader& line_header, 808 const SafeMap<uint8_t, uint8_t>& dex_profile_index_remap, 809 /*out*/std::string* error); 810 811 // Read the aggregation counters from the buffer. 812 bool ReadAggregationCounters(SafeBuffer& buffer, 813 DexFileData& dex_data, 814 /*out*/std::string* error); 815 816 // The method generates mapping of profile indices while merging a new profile 817 // data into current data. It returns true, if the mapping was successful. 818 bool RemapProfileIndex(const std::vector<ProfileLineHeader>& profile_line_headers, 819 const ProfileLoadFilterFn& filter_fn, 820 /*out*/SafeMap<uint8_t, uint8_t>* dex_profile_index_remap); 821 822 // Read the inline cache encoding from line_bufer into inline_cache. 823 bool ReadInlineCache(SafeBuffer& buffer, 824 uint8_t number_of_dex_files, 825 const SafeMap<uint8_t, uint8_t>& dex_profile_index_remap, 826 /*out*/InlineCacheMap* inline_cache, 827 /*out*/std::string* error); 828 829 // Encode the inline cache into the given buffer. 830 void AddInlineCacheToBuffer(std::vector<uint8_t>* buffer, 831 const InlineCacheMap& inline_cache); 832 833 // Return the number of bytes needed to encode the profile information 834 // for the methods in dex_data. 835 uint32_t GetMethodsRegionSize(const DexFileData& dex_data); 836 837 // Group `classes` by their owning dex profile index and put the result in 838 // `dex_to_classes_map`. 839 void GroupClassesByDex( 840 const ClassSet& classes, 841 /*out*/SafeMap<uint8_t, std::vector<dex::TypeIndex>>* dex_to_classes_map); 842 843 // Find the data for the dex_pc in the inline cache. Adds an empty entry 844 // if no previous data exists. 845 DexPcData* FindOrAddDexPc(InlineCacheMap* inline_cache, uint32_t dex_pc); 846 847 // Initializes the profile version to the desired one. 848 void InitProfileVersionInternal(const uint8_t version[]); 849 850 friend class ProfileCompilationInfoTest; 851 friend class CompilerDriverProfileTest; 852 friend class ProfileAssistantTest; 853 friend class Dex2oatLayoutTest; 854 855 MallocArenaPool default_arena_pool_; 856 ArenaAllocator allocator_; 857 858 // Vector containing the actual profile info. 859 // The vector index is the profile index of the dex data and 860 // matched DexFileData::profile_index. 861 ArenaVector<DexFileData*> info_; 862 863 // Cache mapping profile keys to profile index. 864 // This is used to speed up searches since it avoids iterating 865 // over the info_ vector when searching by profile key. 866 ArenaSafeMap<const std::string, uint8_t> profile_key_map_; 867 868 // The version of the profile. 869 // This may change if a "normal" profile is transformed to keep track 870 // of aggregation counters. 871 uint8_t version_[kProfileVersionSize]; 872 873 // Stored only when the profile is configured to keep track of aggregation counters. 874 uint16_t aggregation_count_; 875 }; 876 877 } // namespace art 878 879 #endif // ART_LIBPROFILE_PROFILE_PROFILE_COMPILATION_INFO_H_ 880