Home | History | Annotate | Download | only in profile
      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 {
     45     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 
     55   explicit ProfileMethodInfo(MethodReference reference) : ref(reference) {}
     56 
     57   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 {
     88     DexReference() : dex_checksum(0), num_method_ids(0) {}
     89 
     90     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 
     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     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 {
    121     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> {
    144     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);
    149     void SetIsMegamorphic() {
    150       if (is_missing_types) return;
    151       is_megamorphic = true;
    152       classes.clear();
    153     }
    154     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 
    189     bool IsHot() const {
    190       return (flags_ & kFlagHot) != 0;
    191     }
    192 
    193     bool IsStartup() const {
    194       return (flags_ & kFlagStartup) != 0;
    195     }
    196 
    197     bool IsPostStartup() const {
    198       return (flags_ & kFlagPostStartup) != 0;
    199     }
    200 
    201     void AddFlag(Flag flag) {
    202       flags_ |= flag;
    203     }
    204 
    205     uint8_t GetFlags() const {
    206       return flags_;
    207     }
    208 
    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 
    217     const InlineCacheMap* GetInlineCacheMap() const {
    218       return inline_cache_map_;
    219     }
    220 
    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 {
    233     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>
    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.
    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>
    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 
    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> {
    494     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 
    521     static size_t ComputeBitmapBits(uint32_t num_method_ids) {
    522       return num_method_ids * kBitmapIndexCount;
    523     }
    524     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 
    541     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 
    589     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 
    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      */
    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      */
    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:
    712     ProfileSource(int32_t fd, MemMap&& mem_map)
    713         : fd_(fd), mem_map_(std::move(mem_map)), mem_map_cur_(0) {}
    714 
    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:
    725     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.
    753     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