summaryrefslogtreecommitdiff
path: root/runtime/jit/offline_profiling_info.h
blob: 0b26f9bd0c08c28394343649f91aad6047297e57 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ART_RUNTIME_JIT_OFFLINE_PROFILING_INFO_H_
#define ART_RUNTIME_JIT_OFFLINE_PROFILING_INFO_H_

#include <set>
#include <vector>

#include "atomic.h"
#include "dex_cache_resolved_classes.h"
#include "dex_file.h"
#include "method_reference.h"
#include "safe_map.h"

namespace art {

// TODO: rename file.
/**
 * Profile information in a format suitable to be queried by the compiler and
 * performing profile guided compilation.
 * It is a serialize-friendly format based on information collected by the
 * interpreter (ProfileInfo).
 * Currently it stores only the hot compiled methods.
 */
class ProfileCompilationInfo {
 public:
  static const uint8_t kProfileMagic[];
  static const uint8_t kProfileVersion[];

  // Add the given methods and classes to the current profile object.
  bool AddMethodsAndClasses(const std::vector<MethodReference>& methods,
                            const std::set<DexCacheResolvedClasses>& resolved_classes);
  // Loads profile information from the given file descriptor.
  bool Load(int fd);
  // Merge the data from another ProfileCompilationInfo into the current object.
  bool MergeWith(const ProfileCompilationInfo& info);
  // Saves the profile data to the given file descriptor.
  bool Save(int fd);
  // Loads and merges profile information from the given file into the current
  // object and tries to save it back to disk.
  // If `force` is true then the save will go through even if the given file
  // has bad data or its version does not match. In this cases the profile content
  // is ignored.
  bool MergeAndSave(const std::string& filename, uint64_t* bytes_written, bool force);

  // Returns the number of methods that were profiled.
  uint32_t GetNumberOfMethods() const;
  // Returns the number of resolved classes that were profiled.
  uint32_t GetNumberOfResolvedClasses() const;

  // Returns true if the method reference is present in the profiling info.
  bool ContainsMethod(const MethodReference& method_ref) const;

  // Returns true if the class is present in the profiling info.
  bool ContainsClass(const DexFile& dex_file, uint16_t class_def_idx) const;

  // Dumps all the loaded profile info into a string and returns it.
  // If dex_files is not null then the method indices will be resolved to their
  // names.
  // This is intended for testing and debugging.
  std::string DumpInfo(const std::vector<const DexFile*>* dex_files,
                       bool print_full_dex_location = true) const;

  bool Equals(const ProfileCompilationInfo& other);

  static std::string GetProfileDexFileKey(const std::string& dex_location);

  // Returns the class descriptors for all of the classes in the profiles' class sets.
  // Note the dex location is actually the profile key, the caller needs to call back in to the
  // profile info stuff to generate a map back to the dex location.
  std::set<DexCacheResolvedClasses> GetResolvedClasses() const;

  // Clears the resolved classes from the current object.
  void ClearResolvedClasses();

  static bool GenerateTestProfile(int fd,
                                  uint16_t number_of_dex_files,
                                  uint16_t method_ratio,
                                  uint16_t class_ratio);

 private:
  enum ProfileLoadSatus {
    kProfileLoadIOError,
    kProfileLoadVersionMismatch,
    kProfileLoadBadData,
    kProfileLoadSuccess
  };

  struct DexFileData {
    explicit DexFileData(uint32_t location_checksum) : checksum(location_checksum) {}
    uint32_t checksum;
    std::set<uint16_t> method_set;
    std::set<uint16_t> class_set;

    bool operator==(const DexFileData& other) const {
      return checksum == other.checksum && method_set == other.method_set;
    }
  };

  using DexFileToProfileInfoMap = SafeMap<const std::string, DexFileData>;

  DexFileData* GetOrAddDexFileData(const std::string& dex_location, uint32_t checksum);
  bool AddMethodIndex(const std::string& dex_location, uint32_t checksum, uint16_t method_idx);
  bool AddClassIndex(const std::string& dex_location, uint32_t checksum, uint16_t class_idx);
  bool AddResolvedClasses(const DexCacheResolvedClasses& classes);

  // Parsing functionality.

  struct ProfileLineHeader {
    std::string dex_location;
    uint16_t method_set_size;
    uint16_t class_set_size;
    uint32_t checksum;
  };

  // A helper structure to make sure we don't read past our buffers in the loops.
  struct SafeBuffer {
   public:
    explicit SafeBuffer(size_t size) : storage_(new uint8_t[size]) {
      ptr_current_ = storage_.get();
      ptr_end_ = ptr_current_ + size;
    }

    // Reads the content of the descriptor at the current position.
    ProfileLoadSatus FillFromFd(int fd,
                                const std::string& source,
                                /*out*/std::string* error);

    // Reads an uint value (high bits to low bits) and advances the current pointer
    // with the number of bits read.
    template <typename T> T ReadUintAndAdvance();

    // Compares the given data with the content current pointer. If the contents are
    // equal it advances the current pointer by data_size.
    bool CompareAndAdvance(const uint8_t* data, size_t data_size);

    // Get the underlying raw buffer.
    uint8_t* Get() { return storage_.get(); }

   private:
    std::unique_ptr<uint8_t> storage_;
    uint8_t* ptr_current_;
    uint8_t* ptr_end_;
  };

  ProfileLoadSatus LoadInternal(int fd, std::string* error);

  ProfileLoadSatus ReadProfileHeader(int fd,
                                     /*out*/uint16_t* number_of_lines,
                                     /*out*/std::string* error);

  ProfileLoadSatus ReadProfileLineHeader(int fd,
                                         /*out*/ProfileLineHeader* line_header,
                                         /*out*/std::string* error);
  ProfileLoadSatus ReadProfileLine(int fd,
                                   const ProfileLineHeader& line_header,
                                   /*out*/std::string* error);

  bool ProcessLine(SafeBuffer& line_buffer,
                   uint16_t method_set_size,
                   uint16_t class_set_size,
                   uint32_t checksum,
                   const std::string& dex_location);

  friend class ProfileCompilationInfoTest;
  friend class CompilerDriverProfileTest;
  friend class ProfileAssistantTest;

  DexFileToProfileInfoMap info_;
};

}  // namespace art

#endif  // ART_RUNTIME_JIT_OFFLINE_PROFILING_INFO_H_