Home | History | Annotate | Download | only in jit
      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