blob: 580be047b3611d02615a988045dbb923b3bffbfa [file] [log] [blame]
Calin Juravle31f2c152015-10-23 17:56:15 +01001/*
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
Calin Juravle33083d62017-01-18 15:29:12 -080017#include "profile_compilation_info.h"
Calin Juravle31f2c152015-10-23 17:56:15 +010018
Calin Juravle64142952016-03-21 14:37:55 +000019#include "errno.h"
20#include <limits.h>
Shubham Ajmera4d198e02017-05-12 17:45:29 +000021#include <string>
Calin Juravle4d77b6a2015-12-01 18:38:09 +000022#include <vector>
Calin Juravle7bcdb532016-06-07 16:14:47 +010023#include <stdlib.h>
Calin Juravle31f2c152015-10-23 17:56:15 +010024#include <sys/file.h>
25#include <sys/stat.h>
26#include <sys/uio.h>
Shubham Ajmera4d198e02017-05-12 17:45:29 +000027#include <sys/types.h>
28#include <unistd.h>
29#include <sys/types.h>
30#include <unistd.h>
31#include <zlib.h>
32#include <base/time_utils.h>
Calin Juravle31f2c152015-10-23 17:56:15 +010033
Calin Juravlecc3171a2017-05-19 16:47:53 -070034#include "base/arena_allocator.h"
35#include "base/dumpable.h"
Calin Juravle31f2c152015-10-23 17:56:15 +010036#include "base/mutex.h"
Calin Juravle877fd962016-01-05 14:29:29 +000037#include "base/scoped_flock.h"
Calin Juravle66f55232015-12-08 15:09:10 +000038#include "base/stl_util.h"
Mathieu Chartier32ce2ad2016-03-04 14:58:03 -080039#include "base/systrace.h"
Calin Juravle877fd962016-01-05 14:29:29 +000040#include "base/unix_file/fd_file.h"
Calin Juravle31f2c152015-10-23 17:56:15 +010041#include "jit/profiling_info.h"
Calin Juravle877fd962016-01-05 14:29:29 +000042#include "os.h"
Calin Juravle31f2c152015-10-23 17:56:15 +010043#include "safe_map.h"
Andreas Gampec6ea7d02017-02-01 16:46:28 -080044#include "utils.h"
Shubham Ajmera4d198e02017-05-12 17:45:29 +000045#include "android-base/file.h"
Calin Juravle31f2c152015-10-23 17:56:15 +010046
47namespace art {
48
Calin Juravle64142952016-03-21 14:37:55 +000049const uint8_t ProfileCompilationInfo::kProfileMagic[] = { 'p', 'r', 'o', '\0' };
Mathieu Chartiercebf99c2017-06-05 11:06:52 -070050// Last profile version: Move startup methods to use a bitmap. Also add support for post-startup
51// methods.
Mathieu Chartierea650f32017-05-24 12:04:13 -070052const uint8_t ProfileCompilationInfo::kProfileVersion[] = { '0', '0', '8', '\0' };
Calin Juravle64142952016-03-21 14:37:55 +000053
54static constexpr uint16_t kMaxDexFileKeyLength = PATH_MAX;
55
Calin Juravlec4588572016-06-08 14:24:13 +010056// Debug flag to ignore checksums when testing if a method or a class is present in the profile.
Calin Juravle7bcdb532016-06-07 16:14:47 +010057// Used to facilitate testing profile guided compilation across a large number of apps
Calin Juravlec4588572016-06-08 14:24:13 +010058// using the same test profile.
59static constexpr bool kDebugIgnoreChecksum = false;
60
Calin Juravle589e71e2017-03-03 16:05:05 -080061static constexpr uint8_t kIsMissingTypesEncoding = 6;
62static constexpr uint8_t kIsMegamorphicEncoding = 7;
Calin Juravle940eb0c2017-01-30 19:30:44 -080063
64static_assert(sizeof(InlineCache::kIndividualCacheSize) == sizeof(uint8_t),
65 "InlineCache::kIndividualCacheSize does not have the expect type size");
Calin Juravle589e71e2017-03-03 16:05:05 -080066static_assert(InlineCache::kIndividualCacheSize < kIsMegamorphicEncoding,
67 "InlineCache::kIndividualCacheSize is larger than expected");
68static_assert(InlineCache::kIndividualCacheSize < kIsMissingTypesEncoding,
Calin Juravle940eb0c2017-01-30 19:30:44 -080069 "InlineCache::kIndividualCacheSize is larger than expected");
70
Calin Juravlecc3171a2017-05-19 16:47:53 -070071ProfileCompilationInfo::ProfileCompilationInfo(ArenaPool* custom_arena_pool)
Calin Juravlee6f87cc2017-05-24 17:41:05 -070072 : default_arena_pool_(),
73 arena_(custom_arena_pool),
74 info_(arena_.Adapter(kArenaAllocProfile)),
75 profile_key_map_(std::less<const std::string>(), arena_.Adapter(kArenaAllocProfile)) {
Calin Juravlecc3171a2017-05-19 16:47:53 -070076}
77
78ProfileCompilationInfo::ProfileCompilationInfo()
Calin Juravlee6f87cc2017-05-24 17:41:05 -070079 : default_arena_pool_(/*use_malloc*/true, /*low_4gb*/false, "ProfileCompilationInfo"),
80 arena_(&default_arena_pool_),
81 info_(arena_.Adapter(kArenaAllocProfile)),
82 profile_key_map_(std::less<const std::string>(), arena_.Adapter(kArenaAllocProfile)) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -070083}
84
85ProfileCompilationInfo::~ProfileCompilationInfo() {
Calin Juravlee6f87cc2017-05-24 17:41:05 -070086 VLOG(profiler) << Dumpable<MemStats>(arena_.GetMemStats());
Calin Juravle798ba162017-05-23 23:01:53 -070087 for (DexFileData* data : info_) {
88 delete data;
89 }
Calin Juravlecea9e9d2017-03-23 19:04:59 -070090}
91
Calin Juravle940eb0c2017-01-30 19:30:44 -080092void ProfileCompilationInfo::DexPcData::AddClass(uint16_t dex_profile_idx,
93 const dex::TypeIndex& type_idx) {
Calin Juravle589e71e2017-03-03 16:05:05 -080094 if (is_megamorphic || is_missing_types) {
Calin Juravle940eb0c2017-01-30 19:30:44 -080095 return;
96 }
Calin Juravlee6f87cc2017-05-24 17:41:05 -070097
98 // Perform an explicit lookup for the type instead of directly emplacing the
99 // element. We do this because emplace() allocates the node before doing the
100 // lookup and if it then finds an identical element, it shall deallocate the
101 // node. For Arena allocations, that's essentially a leak.
102 ClassReference ref(dex_profile_idx, type_idx);
103 auto it = classes.find(ref);
104 if (it != classes.end()) {
105 // The type index exists.
106 return;
107 }
108
109 // Check if the adding the type will cause the cache to become megamorphic.
110 if (classes.size() + 1 >= InlineCache::kIndividualCacheSize) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800111 is_megamorphic = true;
112 classes.clear();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700113 return;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800114 }
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700115
116 // The type does not exist and the inline cache will not be megamorphic.
117 classes.insert(ref);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800118}
119
Calin Juravle34900cc2016-02-05 16:19:19 +0000120// Transform the actual dex location into relative paths.
121// Note: this is OK because we don't store profiles of different apps into the same file.
122// Apps with split apks don't cause trouble because each split has a different name and will not
123// collide with other entries.
Calin Juravle31708b72016-02-05 19:44:05 +0000124std::string ProfileCompilationInfo::GetProfileDexFileKey(const std::string& dex_location) {
Calin Juravle34900cc2016-02-05 16:19:19 +0000125 DCHECK(!dex_location.empty());
126 size_t last_sep_index = dex_location.find_last_of('/');
127 if (last_sep_index == std::string::npos) {
128 return dex_location;
129 } else {
Calin Juravle31708b72016-02-05 19:44:05 +0000130 DCHECK(last_sep_index < dex_location.size());
131 return dex_location.substr(last_sep_index + 1);
Calin Juravle34900cc2016-02-05 16:19:19 +0000132 }
133}
134
Mathieu Chartierea650f32017-05-24 12:04:13 -0700135bool ProfileCompilationInfo::AddSampledMethod(bool startup,
136 const std::string& dex_location,
137 uint32_t checksum,
138 uint16_t method_idx,
139 uint32_t num_method_ids) {
140 DexFileData* data = GetOrAddDexFileData(GetProfileDexFileKey(dex_location),
141 checksum,
142 num_method_ids);
143 if (data == nullptr) {
144 return false;
145 }
146 data->AddSampledMethod(startup, method_idx);
147 return true;
148}
149
Calin Juravle67265462016-03-18 16:23:40 +0000150bool ProfileCompilationInfo::AddMethodsAndClasses(
Calin Juravle940eb0c2017-01-30 19:30:44 -0800151 const std::vector<ProfileMethodInfo>& methods,
Calin Juravle67265462016-03-18 16:23:40 +0000152 const std::set<DexCacheResolvedClasses>& resolved_classes) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800153 for (const ProfileMethodInfo& method : methods) {
154 if (!AddMethod(method)) {
Calin Juravle67265462016-03-18 16:23:40 +0000155 return false;
156 }
157 }
158 for (const DexCacheResolvedClasses& dex_cache : resolved_classes) {
159 if (!AddResolvedClasses(dex_cache)) {
160 return false;
161 }
162 }
163 return true;
164}
165
Calin Juravledcab1902017-05-12 19:18:47 -0700166bool ProfileCompilationInfo::Load(const std::string& filename, bool clear_if_invalid) {
Calin Juravle67265462016-03-18 16:23:40 +0000167 ScopedTrace trace(__PRETTY_FUNCTION__);
Calin Juravle67265462016-03-18 16:23:40 +0000168 std::string error;
Calin Juravledf674c42017-04-27 19:30:16 -0700169 int flags = O_RDWR | O_NOFOLLOW | O_CLOEXEC;
170 // There's no need to fsync profile data right away. We get many chances
171 // to write it again in case something goes wrong. We can rely on a simple
172 // close(), no sync, and let to the kernel decide when to write to disk.
Narayan Kamatha3d27eb2017-05-11 13:50:59 +0100173 ScopedFlock profile_file = LockedFile::Open(filename.c_str(), flags,
174 /*block*/false, &error);
175
176 if (profile_file.get() == nullptr) {
Calin Juravle67265462016-03-18 16:23:40 +0000177 LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
178 return false;
179 }
180
Narayan Kamatha3d27eb2017-05-11 13:50:59 +0100181 int fd = profile_file->Fd();
Calin Juravle67265462016-03-18 16:23:40 +0000182
Calin Juravledcab1902017-05-12 19:18:47 -0700183 ProfileLoadSatus status = LoadInternal(fd, &error);
Calin Juravle5d1bd0a2016-03-24 20:33:22 +0000184 if (status == kProfileLoadSuccess) {
Calin Juravledcab1902017-05-12 19:18:47 -0700185 return true;
186 }
187
188 if (clear_if_invalid &&
189 ((status == kProfileLoadVersionMismatch) || (status == kProfileLoadBadData))) {
190 LOG(WARNING) << "Clearing bad or obsolete profile data from file "
191 << filename << ": " << error;
Narayan Kamatha3d27eb2017-05-11 13:50:59 +0100192 if (profile_file->ClearContent()) {
Calin Juravledcab1902017-05-12 19:18:47 -0700193 return true;
Calin Juravle5d1bd0a2016-03-24 20:33:22 +0000194 } else {
Calin Juravledcab1902017-05-12 19:18:47 -0700195 PLOG(WARNING) << "Could not clear profile file: " << filename;
196 return false;
Calin Juravle5d1bd0a2016-03-24 20:33:22 +0000197 }
Calin Juravledcab1902017-05-12 19:18:47 -0700198 }
199
200 LOG(WARNING) << "Could not load profile data from file " << filename << ": " << error;
201 return false;
202}
203
204bool ProfileCompilationInfo::Save(const std::string& filename, uint64_t* bytes_written) {
205 ScopedTrace trace(__PRETTY_FUNCTION__);
Calin Juravledcab1902017-05-12 19:18:47 -0700206 std::string error;
207 int flags = O_WRONLY | O_NOFOLLOW | O_CLOEXEC;
208 // There's no need to fsync profile data right away. We get many chances
209 // to write it again in case something goes wrong. We can rely on a simple
210 // close(), no sync, and let to the kernel decide when to write to disk.
Narayan Kamatha3d27eb2017-05-11 13:50:59 +0100211 ScopedFlock profile_file = LockedFile::Open(filename.c_str(), flags,
212 /*block*/false, &error);
213 if (profile_file.get() == nullptr) {
Calin Juravledcab1902017-05-12 19:18:47 -0700214 LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
Calin Juravle67265462016-03-18 16:23:40 +0000215 return false;
216 }
217
Narayan Kamatha3d27eb2017-05-11 13:50:59 +0100218 int fd = profile_file->Fd();
Calin Juravledcab1902017-05-12 19:18:47 -0700219
Calin Juravle5d1bd0a2016-03-24 20:33:22 +0000220 // We need to clear the data because we don't support appending to the profiles yet.
Narayan Kamatha3d27eb2017-05-11 13:50:59 +0100221 if (!profile_file->ClearContent()) {
Calin Juravle67265462016-03-18 16:23:40 +0000222 PLOG(WARNING) << "Could not clear profile file: " << filename;
223 return false;
224 }
225
226 // This doesn't need locking because we are trying to lock the file for exclusive
227 // access and fail immediately if we can't.
228 bool result = Save(fd);
229 if (result) {
Calin Juravledcab1902017-05-12 19:18:47 -0700230 int64_t size = GetFileSizeBytes(filename);
231 if (size != -1) {
232 VLOG(profiler)
233 << "Successfully saved profile info to " << filename << " Size: "
234 << size;
235 if (bytes_written != nullptr) {
236 *bytes_written = static_cast<uint64_t>(size);
237 }
Calin Juravle67265462016-03-18 16:23:40 +0000238 }
239 } else {
240 VLOG(profiler) << "Failed to save profile info to " << filename;
241 }
242 return result;
243}
244
Calin Juravle64142952016-03-21 14:37:55 +0000245// Returns true if all the bytes were successfully written to the file descriptor.
246static bool WriteBuffer(int fd, const uint8_t* buffer, size_t byte_count) {
247 while (byte_count > 0) {
248 int bytes_written = TEMP_FAILURE_RETRY(write(fd, buffer, byte_count));
249 if (bytes_written == -1) {
Calin Juravle877fd962016-01-05 14:29:29 +0000250 return false;
251 }
Calin Juravle64142952016-03-21 14:37:55 +0000252 byte_count -= bytes_written; // Reduce the number of remaining bytes.
253 buffer += bytes_written; // Move the buffer forward.
254 }
Calin Juravle877fd962016-01-05 14:29:29 +0000255 return true;
Calin Juravle31f2c152015-10-23 17:56:15 +0100256}
257
Calin Juravle64142952016-03-21 14:37:55 +0000258// Add the string bytes to the buffer.
259static void AddStringToBuffer(std::vector<uint8_t>* buffer, const std::string& value) {
260 buffer->insert(buffer->end(), value.begin(), value.end());
261}
262
263// Insert each byte, from low to high into the buffer.
264template <typename T>
265static void AddUintToBuffer(std::vector<uint8_t>* buffer, T value) {
266 for (size_t i = 0; i < sizeof(T); i++) {
267 buffer->push_back((value >> (i * kBitsPerByte)) & 0xff);
268 }
269}
270
271static constexpr size_t kLineHeaderSize =
Calin Juravle940eb0c2017-01-30 19:30:44 -0800272 2 * sizeof(uint16_t) + // class_set.size + dex_location.size
Mathieu Chartierea650f32017-05-24 12:04:13 -0700273 3 * sizeof(uint32_t); // method_map.size + checksum + num_method_ids
Calin Juravle31f2c152015-10-23 17:56:15 +0100274
275/**
276 * Serialization format:
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000277 * magic,version,number_of_dex_files,uncompressed_size_of_zipped_data,compressed_data_size,
Mathieu Chartiercebf99c2017-06-05 11:06:52 -0700278 * zipped[dex_location1,number_of_classes1,methods_region_size,dex_location_checksum1
279 * num_method_ids,
Calin Juravle940eb0c2017-01-30 19:30:44 -0800280 * method_encoding_11,method_encoding_12...,class_id1,class_id2...
Mathieu Chartiercebf99c2017-06-05 11:06:52 -0700281 * startup/post startup bitmap,
282 * dex_location2,number_of_classes2,methods_region_size,dex_location_checksum2, num_method_ids,
Calin Juravle940eb0c2017-01-30 19:30:44 -0800283 * method_encoding_21,method_encoding_22...,,class_id1,class_id2...
Mathieu Chartiercebf99c2017-06-05 11:06:52 -0700284 * startup/post startup bitmap,
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000285 * .....]
Calin Juravle940eb0c2017-01-30 19:30:44 -0800286 * The method_encoding is:
287 * method_id,number_of_inline_caches,inline_cache1,inline_cache2...
288 * The inline_cache is:
289 * dex_pc,[M|dex_map_size], dex_profile_index,class_id1,class_id2...,dex_profile_index2,...
290 * dex_map_size is the number of dex_indeces that follows.
291 * Classes are grouped per their dex files and the line
292 * `dex_profile_index,class_id1,class_id2...,dex_profile_index2,...` encodes the
293 * mapping from `dex_profile_index` to the set of classes `class_id1,class_id2...`
Calin Juravle589e71e2017-03-03 16:05:05 -0800294 * M stands for megamorphic or missing types and it's encoded as either
295 * the byte kIsMegamorphicEncoding or kIsMissingTypesEncoding.
Calin Juravle940eb0c2017-01-30 19:30:44 -0800296 * When present, there will be no class ids following.
Calin Juravle31f2c152015-10-23 17:56:15 +0100297 **/
Calin Juravle2e2db782016-02-23 12:00:03 +0000298bool ProfileCompilationInfo::Save(int fd) {
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000299 uint64_t start = NanoTime();
Mathieu Chartier32ce2ad2016-03-04 14:58:03 -0800300 ScopedTrace trace(__PRETTY_FUNCTION__);
Calin Juravle2e2db782016-02-23 12:00:03 +0000301 DCHECK_GE(fd, 0);
Calin Juravle64142952016-03-21 14:37:55 +0000302
Calin Juravle64142952016-03-21 14:37:55 +0000303 // Use a vector wrapper to avoid keeping track of offsets when we add elements.
304 std::vector<uint8_t> buffer;
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000305 if (!WriteBuffer(fd, kProfileMagic, sizeof(kProfileMagic))) {
306 return false;
307 }
308 if (!WriteBuffer(fd, kProfileVersion, sizeof(kProfileVersion))) {
309 return false;
310 }
Calin Juravle940eb0c2017-01-30 19:30:44 -0800311 DCHECK_LE(info_.size(), std::numeric_limits<uint8_t>::max());
312 AddUintToBuffer(&buffer, static_cast<uint8_t>(info_.size()));
Calin Juravle64142952016-03-21 14:37:55 +0000313
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000314 uint32_t required_capacity = 0;
315 for (const DexFileData* dex_data_ptr : info_) {
316 const DexFileData& dex_data = *dex_data_ptr;
317 uint32_t methods_region_size = GetMethodsRegionSize(dex_data);
318 required_capacity += kLineHeaderSize +
319 dex_data.profile_key.size() +
320 sizeof(uint16_t) * dex_data.class_set.size() +
Mathieu Chartierea650f32017-05-24 12:04:13 -0700321 methods_region_size +
322 dex_data.bitmap_storage.size();
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000323 }
324 if (required_capacity > kProfileSizeErrorThresholdInBytes) {
325 LOG(ERROR) << "Profile data size exceeds "
326 << std::to_string(kProfileSizeErrorThresholdInBytes)
327 << " bytes. Profile will not be written to disk.";
328 return false;
329 }
330 if (required_capacity > kProfileSizeWarningThresholdInBytes) {
331 LOG(WARNING) << "Profile data size exceeds "
332 << std::to_string(kProfileSizeWarningThresholdInBytes);
333 }
334 AddUintToBuffer(&buffer, required_capacity);
335 if (!WriteBuffer(fd, buffer.data(), buffer.size())) {
336 return false;
337 }
338 // Make sure that the buffer has enough capacity to avoid repeated resizings
339 // while we add data.
340 buffer.reserve(required_capacity);
341 buffer.clear();
342
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700343 // Dex files must be written in the order of their profile index. This
Calin Juravlee0ac1152017-02-13 19:03:47 -0800344 // avoids writing the index in the output file and simplifies the parsing logic.
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700345 for (const DexFileData* dex_data_ptr : info_) {
346 const DexFileData& dex_data = *dex_data_ptr;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800347
348 // Note that we allow dex files without any methods or classes, so that
349 // inline caches can refer valid dex files.
Calin Juravle31f2c152015-10-23 17:56:15 +0100350
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700351 if (dex_data.profile_key.size() >= kMaxDexFileKeyLength) {
Calin Juravle64142952016-03-21 14:37:55 +0000352 LOG(WARNING) << "DexFileKey exceeds allocated limit";
353 return false;
354 }
355
Calin Juravle940eb0c2017-01-30 19:30:44 -0800356 uint32_t methods_region_size = GetMethodsRegionSize(dex_data);
Calin Juravle64142952016-03-21 14:37:55 +0000357
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700358 DCHECK_LE(dex_data.profile_key.size(), std::numeric_limits<uint16_t>::max());
Calin Juravle64142952016-03-21 14:37:55 +0000359 DCHECK_LE(dex_data.class_set.size(), std::numeric_limits<uint16_t>::max());
Mathieu Chartierea650f32017-05-24 12:04:13 -0700360 // Write profile line header.
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700361 AddUintToBuffer(&buffer, static_cast<uint16_t>(dex_data.profile_key.size()));
Calin Juravle64142952016-03-21 14:37:55 +0000362 AddUintToBuffer(&buffer, static_cast<uint16_t>(dex_data.class_set.size()));
Calin Juravle940eb0c2017-01-30 19:30:44 -0800363 AddUintToBuffer(&buffer, methods_region_size); // uint32_t
Calin Juravle64142952016-03-21 14:37:55 +0000364 AddUintToBuffer(&buffer, dex_data.checksum); // uint32_t
Mathieu Chartierea650f32017-05-24 12:04:13 -0700365 AddUintToBuffer(&buffer, dex_data.num_method_ids); // uint32_t
Calin Juravle64142952016-03-21 14:37:55 +0000366
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700367 AddStringToBuffer(&buffer, dex_data.profile_key);
Calin Juravle64142952016-03-21 14:37:55 +0000368
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000369 uint16_t last_method_index = 0;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800370 for (const auto& method_it : dex_data.method_map) {
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000371 // Store the difference between the method indices. The SafeMap is ordered by
372 // method_id, so the difference will always be non negative.
373 DCHECK_GE(method_it.first, last_method_index);
374 uint16_t diff_with_last_method_index = method_it.first - last_method_index;
375 last_method_index = method_it.first;
376 AddUintToBuffer(&buffer, diff_with_last_method_index);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800377 AddInlineCacheToBuffer(&buffer, method_it.second);
Calin Juravle31f2c152015-10-23 17:56:15 +0100378 }
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000379
380 uint16_t last_class_index = 0;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800381 for (const auto& class_id : dex_data.class_set) {
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000382 // Store the difference between the class indices. The set is ordered by
383 // class_id, so the difference will always be non negative.
384 DCHECK_GE(class_id.index_, last_class_index);
385 uint16_t diff_with_last_class_index = class_id.index_ - last_class_index;
386 last_class_index = class_id.index_;
387 AddUintToBuffer(&buffer, diff_with_last_class_index);
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800388 }
Mathieu Chartierea650f32017-05-24 12:04:13 -0700389
390 buffer.insert(buffer.end(),
391 dex_data.bitmap_storage.begin(),
392 dex_data.bitmap_storage.end());
Calin Juravle31f2c152015-10-23 17:56:15 +0100393 }
394
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000395 uint32_t output_size = 0;
396 std::unique_ptr<uint8_t[]> compressed_buffer = DeflateBuffer(buffer.data(),
397 required_capacity,
398 &output_size);
399
400 buffer.clear();
401 AddUintToBuffer(&buffer, output_size);
402
403 if (!WriteBuffer(fd, buffer.data(), buffer.size())) {
404 return false;
405 }
406 if (!WriteBuffer(fd, compressed_buffer.get(), output_size)) {
407 return false;
408 }
409 uint64_t total_time = NanoTime() - start;
410 VLOG(profiler) << "Compressed from "
411 << std::to_string(required_capacity)
412 << " to "
413 << std::to_string(output_size);
414 VLOG(profiler) << "Time to save profile: " << std::to_string(total_time);
415 return true;
Calin Juravle226501b2015-12-11 14:41:31 +0000416}
417
Calin Juravle940eb0c2017-01-30 19:30:44 -0800418void ProfileCompilationInfo::AddInlineCacheToBuffer(std::vector<uint8_t>* buffer,
419 const InlineCacheMap& inline_cache_map) {
420 // Add inline cache map size.
421 AddUintToBuffer(buffer, static_cast<uint16_t>(inline_cache_map.size()));
422 if (inline_cache_map.size() == 0) {
423 return;
424 }
425 for (const auto& inline_cache_it : inline_cache_map) {
426 uint16_t dex_pc = inline_cache_it.first;
427 const DexPcData dex_pc_data = inline_cache_it.second;
428 const ClassSet& classes = dex_pc_data.classes;
429
430 // Add the dex pc.
431 AddUintToBuffer(buffer, dex_pc);
432
Calin Juravle589e71e2017-03-03 16:05:05 -0800433 // Add the megamorphic/missing_types encoding if needed and continue.
434 // In either cases we don't add any classes to the profiles and so there's
435 // no point to continue.
436 // TODO(calin): in case we miss types there is still value to add the
437 // rest of the classes. They can be added without bumping the profile version.
438 if (dex_pc_data.is_missing_types) {
439 DCHECK(!dex_pc_data.is_megamorphic); // at this point the megamorphic flag should not be set.
440 DCHECK_EQ(classes.size(), 0u);
441 AddUintToBuffer(buffer, kIsMissingTypesEncoding);
442 continue;
443 } else if (dex_pc_data.is_megamorphic) {
444 DCHECK_EQ(classes.size(), 0u);
445 AddUintToBuffer(buffer, kIsMegamorphicEncoding);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800446 continue;
447 }
448
449 DCHECK_LT(classes.size(), InlineCache::kIndividualCacheSize);
450 DCHECK_NE(classes.size(), 0u) << "InlineCache contains a dex_pc with 0 classes";
451
452 SafeMap<uint8_t, std::vector<dex::TypeIndex>> dex_to_classes_map;
453 // Group the classes by dex. We expect that most of the classes will come from
454 // the same dex, so this will be more efficient than encoding the dex index
455 // for each class reference.
456 GroupClassesByDex(classes, &dex_to_classes_map);
457 // Add the dex map size.
458 AddUintToBuffer(buffer, static_cast<uint8_t>(dex_to_classes_map.size()));
459 for (const auto& dex_it : dex_to_classes_map) {
460 uint8_t dex_profile_index = dex_it.first;
461 const std::vector<dex::TypeIndex>& dex_classes = dex_it.second;
462 // Add the dex profile index.
463 AddUintToBuffer(buffer, dex_profile_index);
464 // Add the the number of classes for each dex profile index.
465 AddUintToBuffer(buffer, static_cast<uint8_t>(dex_classes.size()));
466 for (size_t i = 0; i < dex_classes.size(); i++) {
467 // Add the type index of the classes.
468 AddUintToBuffer(buffer, dex_classes[i].index_);
469 }
470 }
471 }
472}
473
474uint32_t ProfileCompilationInfo::GetMethodsRegionSize(const DexFileData& dex_data) {
475 // ((uint16_t)method index + (uint16_t)inline cache size) * number of methods
476 uint32_t size = 2 * sizeof(uint16_t) * dex_data.method_map.size();
477 for (const auto& method_it : dex_data.method_map) {
478 const InlineCacheMap& inline_cache = method_it.second;
479 size += sizeof(uint16_t) * inline_cache.size(); // dex_pc
480 for (const auto& inline_cache_it : inline_cache) {
481 const ClassSet& classes = inline_cache_it.second.classes;
482 SafeMap<uint8_t, std::vector<dex::TypeIndex>> dex_to_classes_map;
483 GroupClassesByDex(classes, &dex_to_classes_map);
484 size += sizeof(uint8_t); // dex_to_classes_map size
485 for (const auto& dex_it : dex_to_classes_map) {
486 size += sizeof(uint8_t); // dex profile index
487 size += sizeof(uint8_t); // number of classes
488 const std::vector<dex::TypeIndex>& dex_classes = dex_it.second;
489 size += sizeof(uint16_t) * dex_classes.size(); // the actual classes
490 }
491 }
492 }
493 return size;
494}
495
496void ProfileCompilationInfo::GroupClassesByDex(
497 const ClassSet& classes,
498 /*out*/SafeMap<uint8_t, std::vector<dex::TypeIndex>>* dex_to_classes_map) {
499 for (const auto& classes_it : classes) {
500 auto dex_it = dex_to_classes_map->FindOrAdd(classes_it.dex_profile_index);
501 dex_it->second.push_back(classes_it.type_index);
502 }
503}
504
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800505ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::GetOrAddDexFileData(
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700506 const std::string& profile_key,
Mathieu Chartierea650f32017-05-24 12:04:13 -0700507 uint32_t checksum,
508 uint32_t num_method_ids) {
Vladimir Marko3bada4b2017-05-19 12:32:47 +0100509 const auto profile_index_it = profile_key_map_.FindOrAdd(profile_key, profile_key_map_.size());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700510 if (profile_key_map_.size() > std::numeric_limits<uint8_t>::max()) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800511 // Allow only 255 dex files to be profiled. This allows us to save bytes
512 // when encoding. The number is well above what we expect for normal applications.
513 if (kIsDebugBuild) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700514 LOG(ERROR) << "Exceeded the maximum number of dex files (255). Something went wrong";
Calin Juravle940eb0c2017-01-30 19:30:44 -0800515 }
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700516 profile_key_map_.erase(profile_key);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800517 return nullptr;
Calin Juravle998c2162015-12-21 15:39:33 +0200518 }
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700519
520 uint8_t profile_index = profile_index_it->second;
521 if (info_.size() <= profile_index) {
522 // This is a new addition. Add it to the info_ array.
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700523 DexFileData* dex_file_data = new (&arena_) DexFileData(
Mathieu Chartierea650f32017-05-24 12:04:13 -0700524 &arena_,
525 profile_key,
526 checksum,
527 profile_index,
528 num_method_ids);
Calin Juravlecc3171a2017-05-19 16:47:53 -0700529 info_.push_back(dex_file_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700530 }
531 DexFileData* result = info_[profile_index];
532 // DCHECK that profile info map key is consistent with the one stored in the dex file data.
533 // This should always be the case since since the cache map is managed by ProfileCompilationInfo.
534 DCHECK_EQ(profile_key, result->profile_key);
535 DCHECK_EQ(profile_index, result->profile_index);
Mathieu Chartierea650f32017-05-24 12:04:13 -0700536 DCHECK_EQ(num_method_ids, result->num_method_ids);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700537
538 // Check that the checksum matches.
539 // This may different if for example the dex file was updated and
540 // we had a record of the old one.
541 if (result->checksum != checksum) {
542 LOG(WARNING) << "Checksum mismatch for dex " << profile_key;
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800543 return nullptr;
544 }
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700545 return result;
546}
547
548const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexData(
549 const std::string& profile_key) const {
Vladimir Marko3bada4b2017-05-19 12:32:47 +0100550 const auto profile_index_it = profile_key_map_.find(profile_key);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700551 if (profile_index_it == profile_key_map_.end()) {
552 return nullptr;
553 }
554
555 uint8_t profile_index = profile_index_it->second;
556 const DexFileData* result = info_[profile_index];
557 DCHECK_EQ(profile_key, result->profile_key);
558 DCHECK_EQ(profile_index, result->profile_index);
559 return result;
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800560}
561
562bool ProfileCompilationInfo::AddResolvedClasses(const DexCacheResolvedClasses& classes) {
563 const std::string dex_location = GetProfileDexFileKey(classes.GetDexLocation());
564 const uint32_t checksum = classes.GetLocationChecksum();
Mathieu Chartierea650f32017-05-24 12:04:13 -0700565 DexFileData* const data = GetOrAddDexFileData(dex_location, checksum, classes.NumMethodIds());
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800566 if (data == nullptr) {
Calin Juravle998c2162015-12-21 15:39:33 +0200567 return false;
568 }
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800569 data->class_set.insert(classes.GetClasses().begin(), classes.GetClasses().end());
570 return true;
571}
572
573bool ProfileCompilationInfo::AddMethodIndex(const std::string& dex_location,
Calin Juravle940eb0c2017-01-30 19:30:44 -0800574 uint32_t dex_checksum,
Mathieu Chartierea650f32017-05-24 12:04:13 -0700575 uint16_t method_index,
576 uint32_t num_method_ids) {
577 return AddMethod(dex_location,
578 dex_checksum,
579 method_index,
580 num_method_ids,
581 OfflineProfileMethodInfo(nullptr));
Calin Juravle940eb0c2017-01-30 19:30:44 -0800582}
583
584bool ProfileCompilationInfo::AddMethod(const std::string& dex_location,
585 uint32_t dex_checksum,
586 uint16_t method_index,
Mathieu Chartierea650f32017-05-24 12:04:13 -0700587 uint32_t num_method_ids,
Calin Juravle940eb0c2017-01-30 19:30:44 -0800588 const OfflineProfileMethodInfo& pmi) {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700589 DexFileData* const data = GetOrAddDexFileData(GetProfileDexFileKey(dex_location),
590 dex_checksum,
591 num_method_ids);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800592 if (data == nullptr) { // checksum mismatch
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800593 return false;
594 }
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700595 // Add the method.
Calin Juravlecc3171a2017-05-19 16:47:53 -0700596 InlineCacheMap* inline_cache = data->FindOrAddMethod(method_index);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700597
598 if (pmi.inline_caches == nullptr) {
599 // If we don't have inline caches return success right away.
600 return true;
601 }
602 for (const auto& pmi_inline_cache_it : *pmi.inline_caches) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800603 uint16_t pmi_ic_dex_pc = pmi_inline_cache_it.first;
604 const DexPcData& pmi_ic_dex_pc_data = pmi_inline_cache_it.second;
Calin Juravlecc3171a2017-05-19 16:47:53 -0700605 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, pmi_ic_dex_pc);
606 if (dex_pc_data->is_missing_types || dex_pc_data->is_megamorphic) {
Calin Juravle589e71e2017-03-03 16:05:05 -0800607 // We are already megamorphic or we are missing types; no point in going forward.
Calin Juravle940eb0c2017-01-30 19:30:44 -0800608 continue;
609 }
Calin Juravle589e71e2017-03-03 16:05:05 -0800610
611 if (pmi_ic_dex_pc_data.is_missing_types) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700612 dex_pc_data->SetIsMissingTypes();
Calin Juravle589e71e2017-03-03 16:05:05 -0800613 continue;
614 }
615 if (pmi_ic_dex_pc_data.is_megamorphic) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700616 dex_pc_data->SetIsMegamorphic();
Calin Juravle589e71e2017-03-03 16:05:05 -0800617 continue;
618 }
619
Calin Juravle940eb0c2017-01-30 19:30:44 -0800620 for (const ClassReference& class_ref : pmi_ic_dex_pc_data.classes) {
621 const DexReference& dex_ref = pmi.dex_references[class_ref.dex_profile_index];
622 DexFileData* class_dex_data = GetOrAddDexFileData(
623 GetProfileDexFileKey(dex_ref.dex_location),
Mathieu Chartierea650f32017-05-24 12:04:13 -0700624 dex_ref.dex_checksum,
625 dex_ref.num_method_ids);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800626 if (class_dex_data == nullptr) { // checksum mismatch
627 return false;
628 }
Calin Juravlecc3171a2017-05-19 16:47:53 -0700629 dex_pc_data->AddClass(class_dex_data->profile_index, class_ref.type_index);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800630 }
631 }
632 return true;
633}
634
635bool ProfileCompilationInfo::AddMethod(const ProfileMethodInfo& pmi) {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700636 DexFileData* const data = GetOrAddDexFileData(pmi.dex_file);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800637 if (data == nullptr) { // checksum mismatch
638 return false;
639 }
Calin Juravlecc3171a2017-05-19 16:47:53 -0700640 InlineCacheMap* inline_cache = data->FindOrAddMethod(pmi.dex_method_index);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800641
642 for (const ProfileMethodInfo::ProfileInlineCache& cache : pmi.inline_caches) {
Calin Juravle589e71e2017-03-03 16:05:05 -0800643 if (cache.is_missing_types) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700644 FindOrAddDexPc(inline_cache, cache.dex_pc)->SetIsMissingTypes();
Calin Juravle589e71e2017-03-03 16:05:05 -0800645 continue;
646 }
Mathieu Chartierdbddc222017-05-24 12:04:13 -0700647 for (const TypeReference& class_ref : cache.classes) {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700648 DexFileData* class_dex_data = GetOrAddDexFileData(class_ref.dex_file);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800649 if (class_dex_data == nullptr) { // checksum mismatch
650 return false;
651 }
Calin Juravlecc3171a2017-05-19 16:47:53 -0700652 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, cache.dex_pc);
653 if (dex_pc_data->is_missing_types) {
Calin Juravle589e71e2017-03-03 16:05:05 -0800654 // Don't bother adding classes if we are missing types.
655 break;
656 }
Calin Juravlecc3171a2017-05-19 16:47:53 -0700657 dex_pc_data->AddClass(class_dex_data->profile_index, class_ref.type_index);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800658 }
659 }
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800660 return true;
661}
662
663bool ProfileCompilationInfo::AddClassIndex(const std::string& dex_location,
664 uint32_t checksum,
Mathieu Chartierea650f32017-05-24 12:04:13 -0700665 dex::TypeIndex type_idx,
666 uint32_t num_method_ids) {
667 DexFileData* const data = GetOrAddDexFileData(dex_location, checksum, num_method_ids);
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800668 if (data == nullptr) {
669 return false;
670 }
Jeff Hao54b58552016-11-16 15:15:04 -0800671 data->class_set.insert(type_idx);
Calin Juravle998c2162015-12-21 15:39:33 +0200672 return true;
673}
674
Andreas Gampe37c58462017-03-27 15:14:27 -0700675#define READ_UINT(type, buffer, dest, error) \
676 do { \
677 if (!(buffer).ReadUintAndAdvance<type>(&(dest))) { \
678 *(error) = "Could not read "#dest; \
679 return false; \
680 } \
681 } \
Calin Juravle940eb0c2017-01-30 19:30:44 -0800682 while (false)
683
684bool ProfileCompilationInfo::ReadInlineCache(SafeBuffer& buffer,
685 uint8_t number_of_dex_files,
686 /*out*/ InlineCacheMap* inline_cache,
687 /*out*/ std::string* error) {
688 uint16_t inline_cache_size;
689 READ_UINT(uint16_t, buffer, inline_cache_size, error);
690 for (; inline_cache_size > 0; inline_cache_size--) {
691 uint16_t dex_pc;
692 uint8_t dex_to_classes_map_size;
693 READ_UINT(uint16_t, buffer, dex_pc, error);
694 READ_UINT(uint8_t, buffer, dex_to_classes_map_size, error);
Calin Juravlecc3171a2017-05-19 16:47:53 -0700695 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, dex_pc);
Calin Juravle589e71e2017-03-03 16:05:05 -0800696 if (dex_to_classes_map_size == kIsMissingTypesEncoding) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700697 dex_pc_data->SetIsMissingTypes();
Calin Juravle589e71e2017-03-03 16:05:05 -0800698 continue;
699 }
700 if (dex_to_classes_map_size == kIsMegamorphicEncoding) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700701 dex_pc_data->SetIsMegamorphic();
Calin Juravle940eb0c2017-01-30 19:30:44 -0800702 continue;
703 }
704 for (; dex_to_classes_map_size > 0; dex_to_classes_map_size--) {
705 uint8_t dex_profile_index;
706 uint8_t dex_classes_size;
707 READ_UINT(uint8_t, buffer, dex_profile_index, error);
708 READ_UINT(uint8_t, buffer, dex_classes_size, error);
709 if (dex_profile_index >= number_of_dex_files) {
710 *error = "dex_profile_index out of bounds ";
711 *error += std::to_string(dex_profile_index) + " " + std::to_string(number_of_dex_files);
712 return false;
713 }
714 for (; dex_classes_size > 0; dex_classes_size--) {
715 uint16_t type_index;
716 READ_UINT(uint16_t, buffer, type_index, error);
Calin Juravlecc3171a2017-05-19 16:47:53 -0700717 dex_pc_data->AddClass(dex_profile_index, dex::TypeIndex(type_index));
Calin Juravle940eb0c2017-01-30 19:30:44 -0800718 }
719 }
720 }
721 return true;
722}
723
724bool ProfileCompilationInfo::ReadMethods(SafeBuffer& buffer,
725 uint8_t number_of_dex_files,
726 const ProfileLineHeader& line_header,
727 /*out*/std::string* error) {
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000728 uint32_t unread_bytes_before_operation = buffer.CountUnreadBytes();
729 if (unread_bytes_before_operation < line_header.method_region_size_bytes) {
730 *error += "Profile EOF reached prematurely for ReadMethod";
731 return kProfileLoadBadData;
732 }
733 size_t expected_unread_bytes_after_operation = buffer.CountUnreadBytes()
734 - line_header.method_region_size_bytes;
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000735 uint16_t last_method_index = 0;
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000736 while (buffer.CountUnreadBytes() > expected_unread_bytes_after_operation) {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700737 DexFileData* const data = GetOrAddDexFileData(line_header.dex_location,
738 line_header.checksum,
739 line_header.num_method_ids);
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000740 uint16_t diff_with_last_method_index;
741 READ_UINT(uint16_t, buffer, diff_with_last_method_index, error);
742 uint16_t method_index = last_method_index + diff_with_last_method_index;
743 last_method_index = method_index;
Calin Juravlecc3171a2017-05-19 16:47:53 -0700744 InlineCacheMap* inline_cache = data->FindOrAddMethod(method_index);
745 if (!ReadInlineCache(buffer, number_of_dex_files, inline_cache, error)) {
Calin Juravle877fd962016-01-05 14:29:29 +0000746 return false;
747 }
Calin Juravle226501b2015-12-11 14:41:31 +0000748 }
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000749 uint32_t total_bytes_read = unread_bytes_before_operation - buffer.CountUnreadBytes();
750 if (total_bytes_read != line_header.method_region_size_bytes) {
751 *error += "Profile data inconsistent for ReadMethods";
752 return false;
753 }
Calin Juravle940eb0c2017-01-30 19:30:44 -0800754 return true;
755}
756
757bool ProfileCompilationInfo::ReadClasses(SafeBuffer& buffer,
Calin Juravle940eb0c2017-01-30 19:30:44 -0800758 const ProfileLineHeader& line_header,
759 /*out*/std::string* error) {
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000760 size_t unread_bytes_before_op = buffer.CountUnreadBytes();
761 if (unread_bytes_before_op < line_header.class_set_size) {
762 *error += "Profile EOF reached prematurely for ReadClasses";
763 return kProfileLoadBadData;
764 }
765
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000766 uint16_t last_class_index = 0;
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000767 for (uint16_t i = 0; i < line_header.class_set_size; i++) {
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000768 uint16_t diff_with_last_class_index;
769 READ_UINT(uint16_t, buffer, diff_with_last_class_index, error);
770 uint16_t type_index = last_class_index + diff_with_last_class_index;
771 last_class_index = type_index;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800772 if (!AddClassIndex(line_header.dex_location,
773 line_header.checksum,
Mathieu Chartierea650f32017-05-24 12:04:13 -0700774 dex::TypeIndex(type_index),
775 line_header.num_method_ids)) {
Calin Juravle64142952016-03-21 14:37:55 +0000776 return false;
777 }
778 }
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000779 size_t total_bytes_read = unread_bytes_before_op - buffer.CountUnreadBytes();
780 uint32_t expected_bytes_read = line_header.class_set_size * sizeof(uint16_t);
781 if (total_bytes_read != expected_bytes_read) {
782 *error += "Profile data inconsistent for ReadClasses";
783 return false;
784 }
Calin Juravle226501b2015-12-11 14:41:31 +0000785 return true;
786}
787
Calin Juravle64142952016-03-21 14:37:55 +0000788// Tests for EOF by trying to read 1 byte from the descriptor.
789// Returns:
790// 0 if the descriptor is at the EOF,
791// -1 if there was an IO error
792// 1 if the descriptor has more content to read
793static int testEOF(int fd) {
794 uint8_t buffer[1];
795 return TEMP_FAILURE_RETRY(read(fd, buffer, 1));
796}
797
798// Reads an uint value previously written with AddUintToBuffer.
799template <typename T>
Calin Juravle940eb0c2017-01-30 19:30:44 -0800800bool ProfileCompilationInfo::SafeBuffer::ReadUintAndAdvance(/*out*/T* value) {
Calin Juravle64142952016-03-21 14:37:55 +0000801 static_assert(std::is_unsigned<T>::value, "Type is not unsigned");
Calin Juravle940eb0c2017-01-30 19:30:44 -0800802 if (ptr_current_ + sizeof(T) > ptr_end_) {
803 return false;
804 }
805 *value = 0;
Calin Juravle64142952016-03-21 14:37:55 +0000806 for (size_t i = 0; i < sizeof(T); i++) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800807 *value += ptr_current_[i] << (i * kBitsPerByte);
Calin Juravle226501b2015-12-11 14:41:31 +0000808 }
Calin Juravle64142952016-03-21 14:37:55 +0000809 ptr_current_ += sizeof(T);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800810 return true;
Calin Juravle64142952016-03-21 14:37:55 +0000811}
812
813bool ProfileCompilationInfo::SafeBuffer::CompareAndAdvance(const uint8_t* data, size_t data_size) {
814 if (ptr_current_ + data_size > ptr_end_) {
815 return false;
816 }
817 if (memcmp(ptr_current_, data, data_size) == 0) {
818 ptr_current_ += data_size;
819 return true;
820 }
821 return false;
822}
823
824ProfileCompilationInfo::ProfileLoadSatus ProfileCompilationInfo::SafeBuffer::FillFromFd(
825 int fd,
826 const std::string& source,
827 /*out*/std::string* error) {
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000828 size_t byte_count = (ptr_end_ - ptr_current_) * sizeof(*ptr_current_);
Calin Juravle64142952016-03-21 14:37:55 +0000829 uint8_t* buffer = ptr_current_;
830 while (byte_count > 0) {
831 int bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, byte_count));
832 if (bytes_read == 0) {
833 *error += "Profile EOF reached prematurely for " + source;
834 return kProfileLoadBadData;
835 } else if (bytes_read < 0) {
836 *error += "Profile IO error for " + source + strerror(errno);
837 return kProfileLoadIOError;
Calin Juravle226501b2015-12-11 14:41:31 +0000838 }
Calin Juravle64142952016-03-21 14:37:55 +0000839 byte_count -= bytes_read;
840 buffer += bytes_read;
Calin Juravle226501b2015-12-11 14:41:31 +0000841 }
Calin Juravle64142952016-03-21 14:37:55 +0000842 return kProfileLoadSuccess;
843}
844
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000845size_t ProfileCompilationInfo::SafeBuffer::CountUnreadBytes() {
846 return (ptr_end_ - ptr_current_) * sizeof(*ptr_current_);
847}
848
849const uint8_t* ProfileCompilationInfo::SafeBuffer::GetCurrentPtr() {
850 return ptr_current_;
851}
852
853void ProfileCompilationInfo::SafeBuffer::Advance(size_t data_size) {
854 ptr_current_ += data_size;
855}
856
Calin Juravle64142952016-03-21 14:37:55 +0000857ProfileCompilationInfo::ProfileLoadSatus ProfileCompilationInfo::ReadProfileHeader(
858 int fd,
Calin Juravle940eb0c2017-01-30 19:30:44 -0800859 /*out*/uint8_t* number_of_dex_files,
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000860 /*out*/uint32_t* uncompressed_data_size,
861 /*out*/uint32_t* compressed_data_size,
Calin Juravle64142952016-03-21 14:37:55 +0000862 /*out*/std::string* error) {
863 // Read magic and version
864 const size_t kMagicVersionSize =
865 sizeof(kProfileMagic) +
866 sizeof(kProfileVersion) +
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000867 sizeof(uint8_t) + // number of dex files
868 sizeof(uint32_t) + // size of uncompressed profile data
869 sizeof(uint32_t); // size of compressed profile data
Calin Juravle64142952016-03-21 14:37:55 +0000870
871 SafeBuffer safe_buffer(kMagicVersionSize);
872
873 ProfileLoadSatus status = safe_buffer.FillFromFd(fd, "ReadProfileHeader", error);
874 if (status != kProfileLoadSuccess) {
875 return status;
876 }
877
878 if (!safe_buffer.CompareAndAdvance(kProfileMagic, sizeof(kProfileMagic))) {
879 *error = "Profile missing magic";
880 return kProfileLoadVersionMismatch;
881 }
882 if (!safe_buffer.CompareAndAdvance(kProfileVersion, sizeof(kProfileVersion))) {
883 *error = "Profile version mismatch";
884 return kProfileLoadVersionMismatch;
885 }
Calin Juravle940eb0c2017-01-30 19:30:44 -0800886 if (!safe_buffer.ReadUintAndAdvance<uint8_t>(number_of_dex_files)) {
887 *error = "Cannot read the number of dex files";
888 return kProfileLoadBadData;
889 }
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000890 if (!safe_buffer.ReadUintAndAdvance<uint32_t>(uncompressed_data_size)) {
891 *error = "Cannot read the size of uncompressed data";
892 return kProfileLoadBadData;
893 }
894 if (!safe_buffer.ReadUintAndAdvance<uint32_t>(compressed_data_size)) {
895 *error = "Cannot read the size of compressed data";
896 return kProfileLoadBadData;
897 }
Calin Juravle64142952016-03-21 14:37:55 +0000898 return kProfileLoadSuccess;
899}
900
Calin Juravle940eb0c2017-01-30 19:30:44 -0800901bool ProfileCompilationInfo::ReadProfileLineHeaderElements(SafeBuffer& buffer,
902 /*out*/uint16_t* dex_location_size,
903 /*out*/ProfileLineHeader* line_header,
904 /*out*/std::string* error) {
905 READ_UINT(uint16_t, buffer, *dex_location_size, error);
906 READ_UINT(uint16_t, buffer, line_header->class_set_size, error);
907 READ_UINT(uint32_t, buffer, line_header->method_region_size_bytes, error);
908 READ_UINT(uint32_t, buffer, line_header->checksum, error);
Mathieu Chartierea650f32017-05-24 12:04:13 -0700909 READ_UINT(uint32_t, buffer, line_header->num_method_ids, error);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800910 return true;
911}
912
Calin Juravle64142952016-03-21 14:37:55 +0000913ProfileCompilationInfo::ProfileLoadSatus ProfileCompilationInfo::ReadProfileLineHeader(
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000914 SafeBuffer& buffer,
915 /*out*/ProfileLineHeader* line_header,
916 /*out*/std::string* error) {
917 if (buffer.CountUnreadBytes() < kLineHeaderSize) {
918 *error += "Profile EOF reached prematurely for ReadProfileLineHeader";
919 return kProfileLoadBadData;
Calin Juravle64142952016-03-21 14:37:55 +0000920 }
921
Calin Juravle940eb0c2017-01-30 19:30:44 -0800922 uint16_t dex_location_size;
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000923 if (!ReadProfileLineHeaderElements(buffer, &dex_location_size, line_header, error)) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800924 return kProfileLoadBadData;
925 }
Calin Juravle64142952016-03-21 14:37:55 +0000926
927 if (dex_location_size == 0 || dex_location_size > kMaxDexFileKeyLength) {
Goran Jakovljevic4eb6fbf2016-04-25 19:14:17 +0200928 *error = "DexFileKey has an invalid size: " +
929 std::to_string(static_cast<uint32_t>(dex_location_size));
Calin Juravle64142952016-03-21 14:37:55 +0000930 return kProfileLoadBadData;
931 }
932
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000933 if (buffer.CountUnreadBytes() < dex_location_size) {
934 *error += "Profile EOF reached prematurely for ReadProfileHeaderDexLocation";
935 return kProfileLoadBadData;
Calin Juravle64142952016-03-21 14:37:55 +0000936 }
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000937 const uint8_t* base_ptr = buffer.GetCurrentPtr();
Calin Juravle64142952016-03-21 14:37:55 +0000938 line_header->dex_location.assign(
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000939 reinterpret_cast<const char*>(base_ptr), dex_location_size);
940 buffer.Advance(dex_location_size);
Calin Juravle64142952016-03-21 14:37:55 +0000941 return kProfileLoadSuccess;
942}
943
944ProfileCompilationInfo::ProfileLoadSatus ProfileCompilationInfo::ReadProfileLine(
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000945 SafeBuffer& buffer,
Calin Juravle940eb0c2017-01-30 19:30:44 -0800946 uint8_t number_of_dex_files,
Calin Juravle64142952016-03-21 14:37:55 +0000947 const ProfileLineHeader& line_header,
948 /*out*/std::string* error) {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700949 DexFileData* data = GetOrAddDexFileData(line_header.dex_location,
950 line_header.checksum,
951 line_header.num_method_ids);
952 if (data == nullptr) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800953 *error = "Error when reading profile file line header: checksum mismatch for "
954 + line_header.dex_location;
955 return kProfileLoadBadData;
956 }
Calin Juravle64142952016-03-21 14:37:55 +0000957
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000958 if (!ReadMethods(buffer, number_of_dex_files, line_header, error)) {
959 return kProfileLoadBadData;
Calin Juravle64142952016-03-21 14:37:55 +0000960 }
Calin Juravle940eb0c2017-01-30 19:30:44 -0800961
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000962 if (!ReadClasses(buffer, line_header, error)) {
963 return kProfileLoadBadData;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800964 }
Mathieu Chartierea650f32017-05-24 12:04:13 -0700965
966 const size_t bytes = data->bitmap_storage.size();
967 if (buffer.CountUnreadBytes() < bytes) {
968 *error += "Profile EOF reached prematurely for ReadProfileHeaderDexLocation";
969 return kProfileLoadBadData;
970 }
971 const uint8_t* base_ptr = buffer.GetCurrentPtr();
972 std::copy_n(base_ptr, bytes, &data->bitmap_storage[0]);
973 buffer.Advance(bytes);
974 // Read method bitmap.
Calin Juravle64142952016-03-21 14:37:55 +0000975 return kProfileLoadSuccess;
Calin Juravle226501b2015-12-11 14:41:31 +0000976}
977
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700978// TODO(calin): Fix this API. ProfileCompilationInfo::Load should be static and
979// return a unique pointer to a ProfileCompilationInfo upon success.
Calin Juravle2e2db782016-02-23 12:00:03 +0000980bool ProfileCompilationInfo::Load(int fd) {
Calin Juravle64142952016-03-21 14:37:55 +0000981 std::string error;
982 ProfileLoadSatus status = LoadInternal(fd, &error);
983
984 if (status == kProfileLoadSuccess) {
985 return true;
986 } else {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800987 LOG(WARNING) << "Error when reading profile: " << error;
Calin Juravle64142952016-03-21 14:37:55 +0000988 return false;
989 }
990}
991
Calin Juravledcab1902017-05-12 19:18:47 -0700992// TODO(calin): fail fast if the dex checksums don't match.
Calin Juravle64142952016-03-21 14:37:55 +0000993ProfileCompilationInfo::ProfileLoadSatus ProfileCompilationInfo::LoadInternal(
994 int fd, std::string* error) {
Mathieu Chartier32ce2ad2016-03-04 14:58:03 -0800995 ScopedTrace trace(__PRETTY_FUNCTION__);
Calin Juravle2e2db782016-02-23 12:00:03 +0000996 DCHECK_GE(fd, 0);
Calin Juravle226501b2015-12-11 14:41:31 +0000997
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700998 if (!IsEmpty()) {
999 return kProfileLoadWouldOverwiteData;
1000 }
1001
Calin Juravle64142952016-03-21 14:37:55 +00001002 struct stat stat_buffer;
1003 if (fstat(fd, &stat_buffer) != 0) {
1004 return kProfileLoadIOError;
Calin Juravle226501b2015-12-11 14:41:31 +00001005 }
Calin Juravle64142952016-03-21 14:37:55 +00001006 // We allow empty profile files.
1007 // Profiles may be created by ActivityManager or installd before we manage to
1008 // process them in the runtime or profman.
1009 if (stat_buffer.st_size == 0) {
1010 return kProfileLoadSuccess;
1011 }
Calin Juravle940eb0c2017-01-30 19:30:44 -08001012 // Read profile header: magic + version + number_of_dex_files.
1013 uint8_t number_of_dex_files;
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001014 uint32_t uncompressed_data_size;
1015 uint32_t compressed_data_size;
1016 ProfileLoadSatus status = ReadProfileHeader(fd,
1017 &number_of_dex_files,
1018 &uncompressed_data_size,
1019 &compressed_data_size,
1020 error);
1021
Calin Juravle64142952016-03-21 14:37:55 +00001022 if (status != kProfileLoadSuccess) {
1023 return status;
1024 }
1025
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001026 if (uncompressed_data_size > kProfileSizeErrorThresholdInBytes) {
1027 LOG(ERROR) << "Profile data size exceeds "
1028 << std::to_string(kProfileSizeErrorThresholdInBytes)
1029 << " bytes";
1030 return kProfileLoadBadData;
1031 }
1032 if (uncompressed_data_size > kProfileSizeWarningThresholdInBytes) {
1033 LOG(WARNING) << "Profile data size exceeds "
1034 << std::to_string(kProfileSizeWarningThresholdInBytes)
1035 << " bytes";
1036 }
1037
1038 std::unique_ptr<uint8_t[]> compressed_data(new uint8_t[compressed_data_size]);
1039 bool bytes_read_success =
1040 android::base::ReadFully(fd, compressed_data.get(), compressed_data_size);
1041
1042 if (testEOF(fd) != 0) {
1043 *error += "Unexpected data in the profile file.";
1044 return kProfileLoadBadData;
1045 }
1046
1047 if (!bytes_read_success) {
1048 *error += "Unable to read compressed profile data";
1049 return kProfileLoadBadData;
1050 }
1051
1052 SafeBuffer uncompressed_data(uncompressed_data_size);
1053
1054 int ret = InflateBuffer(compressed_data.get(),
1055 compressed_data_size,
1056 uncompressed_data_size,
1057 uncompressed_data.Get());
1058
1059 if (ret != Z_STREAM_END) {
1060 *error += "Error reading uncompressed profile data";
1061 return kProfileLoadBadData;
1062 }
1063
Calin Juravle940eb0c2017-01-30 19:30:44 -08001064 for (uint8_t k = 0; k < number_of_dex_files; k++) {
Calin Juravle64142952016-03-21 14:37:55 +00001065 ProfileLineHeader line_header;
Calin Juravle940eb0c2017-01-30 19:30:44 -08001066
Calin Juravle64142952016-03-21 14:37:55 +00001067 // First, read the line header to get the amount of data we need to read.
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001068 status = ReadProfileLineHeader(uncompressed_data, &line_header, error);
Calin Juravle64142952016-03-21 14:37:55 +00001069 if (status != kProfileLoadSuccess) {
1070 return status;
1071 }
1072
1073 // Now read the actual profile line.
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001074 status = ReadProfileLine(uncompressed_data, number_of_dex_files, line_header, error);
Calin Juravle64142952016-03-21 14:37:55 +00001075 if (status != kProfileLoadSuccess) {
1076 return status;
1077 }
Calin Juravle64142952016-03-21 14:37:55 +00001078 }
1079
1080 // Check that we read everything and that profiles don't contain junk data.
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001081 if (uncompressed_data.CountUnreadBytes() > 0) {
Calin Juravle64142952016-03-21 14:37:55 +00001082 *error = "Unexpected content in the profile file";
1083 return kProfileLoadBadData;
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001084 } else {
1085 return kProfileLoadSuccess;
Calin Juravle64142952016-03-21 14:37:55 +00001086 }
Calin Juravle998c2162015-12-21 15:39:33 +02001087}
1088
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001089std::unique_ptr<uint8_t[]> ProfileCompilationInfo::DeflateBuffer(const uint8_t* in_buffer,
1090 uint32_t in_size,
1091 uint32_t* compressed_data_size) {
1092 z_stream strm;
1093 strm.zalloc = Z_NULL;
1094 strm.zfree = Z_NULL;
1095 strm.opaque = Z_NULL;
1096 int ret = deflateInit(&strm, 1);
1097 if (ret != Z_OK) {
1098 return nullptr;
1099 }
1100
1101 uint32_t out_size = deflateBound(&strm, in_size);
1102
1103 std::unique_ptr<uint8_t[]> compressed_buffer(new uint8_t[out_size]);
1104 strm.avail_in = in_size;
1105 strm.next_in = const_cast<uint8_t*>(in_buffer);
1106 strm.avail_out = out_size;
1107 strm.next_out = &compressed_buffer[0];
1108 ret = deflate(&strm, Z_FINISH);
1109 if (ret == Z_STREAM_ERROR) {
1110 return nullptr;
1111 }
1112 *compressed_data_size = out_size - strm.avail_out;
1113 deflateEnd(&strm);
1114 return compressed_buffer;
1115}
1116
1117int ProfileCompilationInfo::InflateBuffer(const uint8_t* in_buffer,
1118 uint32_t in_size,
1119 uint32_t expected_uncompressed_data_size,
1120 uint8_t* out_buffer) {
1121 z_stream strm;
1122
1123 /* allocate inflate state */
1124 strm.zalloc = Z_NULL;
1125 strm.zfree = Z_NULL;
1126 strm.opaque = Z_NULL;
1127 strm.avail_in = in_size;
1128 strm.next_in = const_cast<uint8_t*>(in_buffer);
1129 strm.avail_out = expected_uncompressed_data_size;
1130 strm.next_out = out_buffer;
1131
1132 int ret;
1133 inflateInit(&strm);
1134 ret = inflate(&strm, Z_NO_FLUSH);
1135
1136 if (strm.avail_in != 0 || strm.avail_out != 0) {
1137 return Z_DATA_ERROR;
1138 }
1139 inflateEnd(&strm);
1140 return ret;
1141}
1142
Calin Juravle67265462016-03-18 16:23:40 +00001143bool ProfileCompilationInfo::MergeWith(const ProfileCompilationInfo& other) {
Calin Juravle5d1bd0a2016-03-24 20:33:22 +00001144 // First verify that all checksums match. This will avoid adding garbage to
1145 // the current profile info.
1146 // Note that the number of elements should be very small, so this should not
1147 // be a performance issue.
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001148 for (const DexFileData* other_dex_data : other.info_) {
1149 const DexFileData* dex_data = FindDexData(other_dex_data->profile_key);
1150 if ((dex_data != nullptr) && (dex_data->checksum != other_dex_data->checksum)) {
1151 LOG(WARNING) << "Checksum mismatch for dex " << other_dex_data->profile_key;
Calin Juravle5d1bd0a2016-03-24 20:33:22 +00001152 return false;
1153 }
1154 }
1155 // All checksums match. Import the data.
Calin Juravle940eb0c2017-01-30 19:30:44 -08001156
1157 // The other profile might have a different indexing of dex files.
1158 // That is because each dex files gets a 'dex_profile_index' on a first come first served basis.
1159 // That means that the order in with the methods are added to the profile matters for the
1160 // actual indices.
1161 // The reason we cannot rely on the actual multidex index is that a single profile may store
1162 // data from multiple splits. This means that a profile may contain a classes2.dex from split-A
1163 // and one from split-B.
1164
1165 // First, build a mapping from other_dex_profile_index to this_dex_profile_index.
1166 // This will make sure that the ClassReferences will point to the correct dex file.
1167 SafeMap<uint8_t, uint8_t> dex_profile_index_remap;
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001168 for (const DexFileData* other_dex_data : other.info_) {
1169 const DexFileData* dex_data = GetOrAddDexFileData(other_dex_data->profile_key,
Mathieu Chartierea650f32017-05-24 12:04:13 -07001170 other_dex_data->checksum,
1171 other_dex_data->num_method_ids);
Calin Juravlee0ac1152017-02-13 19:03:47 -08001172 if (dex_data == nullptr) {
1173 return false; // Could happen if we exceed the number of allowed dex files.
1174 }
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001175 dex_profile_index_remap.Put(other_dex_data->profile_index, dex_data->profile_index);
Calin Juravle940eb0c2017-01-30 19:30:44 -08001176 }
1177
1178 // Merge the actual profile data.
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001179 for (const DexFileData* other_dex_data : other.info_) {
1180 DexFileData* dex_data = const_cast<DexFileData*>(FindDexData(other_dex_data->profile_key));
1181 DCHECK(dex_data != nullptr);
Calin Juravle940eb0c2017-01-30 19:30:44 -08001182
1183 // Merge the classes.
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001184 dex_data->class_set.insert(other_dex_data->class_set.begin(),
1185 other_dex_data->class_set.end());
Calin Juravle940eb0c2017-01-30 19:30:44 -08001186
1187 // Merge the methods and the inline caches.
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001188 for (const auto& other_method_it : other_dex_data->method_map) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001189 uint16_t other_method_index = other_method_it.first;
Calin Juravlecc3171a2017-05-19 16:47:53 -07001190 InlineCacheMap* inline_cache = dex_data->FindOrAddMethod(other_method_index);
Calin Juravle940eb0c2017-01-30 19:30:44 -08001191 const auto& other_inline_cache = other_method_it.second;
1192 for (const auto& other_ic_it : other_inline_cache) {
1193 uint16_t other_dex_pc = other_ic_it.first;
1194 const ClassSet& other_class_set = other_ic_it.second.classes;
Calin Juravlecc3171a2017-05-19 16:47:53 -07001195 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, other_dex_pc);
Calin Juravle589e71e2017-03-03 16:05:05 -08001196 if (other_ic_it.second.is_missing_types) {
Calin Juravlecc3171a2017-05-19 16:47:53 -07001197 dex_pc_data->SetIsMissingTypes();
Calin Juravle589e71e2017-03-03 16:05:05 -08001198 } else if (other_ic_it.second.is_megamorphic) {
Calin Juravlecc3171a2017-05-19 16:47:53 -07001199 dex_pc_data->SetIsMegamorphic();
Calin Juravle0def68d2017-02-21 19:00:33 -08001200 } else {
1201 for (const auto& class_it : other_class_set) {
Calin Juravlecc3171a2017-05-19 16:47:53 -07001202 dex_pc_data->AddClass(dex_profile_index_remap.Get(
Calin Juravle0def68d2017-02-21 19:00:33 -08001203 class_it.dex_profile_index), class_it.type_index);
1204 }
Calin Juravle940eb0c2017-01-30 19:30:44 -08001205 }
1206 }
1207 }
Mathieu Chartierea650f32017-05-24 12:04:13 -07001208
1209 // Merge the bitmaps.
1210 dex_data->MergeBitmap(*other_dex_data);
Calin Juravle998c2162015-12-21 15:39:33 +02001211 }
1212 return true;
Calin Juravle226501b2015-12-11 14:41:31 +00001213}
1214
Calin Juravle940eb0c2017-01-30 19:30:44 -08001215static bool ChecksumMatch(uint32_t dex_file_checksum, uint32_t checksum) {
1216 return kDebugIgnoreChecksum || dex_file_checksum == checksum;
1217}
1218
Calin Juravlec4588572016-06-08 14:24:13 +01001219static bool ChecksumMatch(const DexFile& dex_file, uint32_t checksum) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001220 return ChecksumMatch(dex_file.GetLocationChecksum(), checksum);
Calin Juravlec4588572016-06-08 14:24:13 +01001221}
1222
Mathieu Chartierea650f32017-05-24 12:04:13 -07001223bool ProfileCompilationInfo::IsStartupOrHotMethod(const MethodReference& method_ref) const {
1224 return IsStartupOrHotMethod(method_ref.dex_file->GetLocation(),
1225 method_ref.dex_file->GetLocationChecksum(),
1226 method_ref.dex_method_index);
1227}
1228
Mathieu Chartierdb40eac2017-06-09 18:34:11 -07001229const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexData(
1230 const DexFile* dex_file) const {
1231 const DexFileData* dex_data = FindDexData(GetProfileDexFileKey(dex_file->GetLocation()));
1232 if (dex_data == nullptr || !ChecksumMatch(*dex_file, dex_data->checksum)) {
1233 return nullptr;
1234 }
1235 return dex_data;
1236}
1237
Mathieu Chartierea650f32017-05-24 12:04:13 -07001238bool ProfileCompilationInfo::IsStartupOrHotMethod(const std::string& dex_location,
1239 uint32_t dex_checksum,
1240 uint16_t dex_method_index) const {
1241 const DexFileData* dex_data = FindDexData(GetProfileDexFileKey(dex_location));
1242 if (dex_data == nullptr || !ChecksumMatch(dex_checksum, dex_data->checksum)) {
1243 return false;
1244 }
1245 if (dex_data->HasSampledMethod(/*startup*/ true, dex_method_index)) {
1246 return true;
1247 }
1248 const MethodMap& methods = dex_data->method_map;
1249 const auto method_it = methods.find(dex_method_index);
1250 return method_it != methods.end();
1251}
1252
Mathieu Chartierdb40eac2017-06-09 18:34:11 -07001253bool ProfileCompilationInfo::ContainsSampledMethod(bool startup,
1254 const MethodReference& method_ref) const {
1255 const DexFileData* dex_data = FindDexData(method_ref.dex_file);
1256 if (dex_data == nullptr) {
1257 return false;
1258 }
1259 return dex_data->HasSampledMethod(startup, method_ref.dex_method_index);
1260}
1261
Mathieu Chartier7b135c82017-06-05 12:54:01 -07001262bool ProfileCompilationInfo::ContainsHotMethod(const MethodReference& method_ref) const {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001263 return FindMethod(method_ref.dex_file->GetLocation(),
1264 method_ref.dex_file->GetLocationChecksum(),
1265 method_ref.dex_method_index) != nullptr;
Calin Juravle226501b2015-12-11 14:41:31 +00001266}
1267
Calin Juravle940eb0c2017-01-30 19:30:44 -08001268const ProfileCompilationInfo::InlineCacheMap*
1269ProfileCompilationInfo::FindMethod(const std::string& dex_location,
1270 uint32_t dex_checksum,
1271 uint16_t dex_method_index) const {
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001272 const DexFileData* dex_data = FindDexData(GetProfileDexFileKey(dex_location));
1273 if (dex_data != nullptr) {
1274 if (!ChecksumMatch(dex_checksum, dex_data->checksum)) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001275 return nullptr;
1276 }
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001277 const MethodMap& methods = dex_data->method_map;
Calin Juravle940eb0c2017-01-30 19:30:44 -08001278 const auto method_it = methods.find(dex_method_index);
1279 return method_it == methods.end() ? nullptr : &(method_it->second);
1280 }
1281 return nullptr;
1282}
1283
Calin Juravlecc3171a2017-05-19 16:47:53 -07001284std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> ProfileCompilationInfo::GetMethod(
1285 const std::string& dex_location,
1286 uint32_t dex_checksum,
1287 uint16_t dex_method_index) const {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001288 const InlineCacheMap* inline_caches = FindMethod(dex_location, dex_checksum, dex_method_index);
1289 if (inline_caches == nullptr) {
Calin Juravlecc3171a2017-05-19 16:47:53 -07001290 return nullptr;
Calin Juravle940eb0c2017-01-30 19:30:44 -08001291 }
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001292
1293 std::unique_ptr<OfflineProfileMethodInfo> pmi(new OfflineProfileMethodInfo(inline_caches));
Calin Juravle940eb0c2017-01-30 19:30:44 -08001294
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001295 pmi->dex_references.resize(info_.size());
1296 for (const DexFileData* dex_data : info_) {
1297 pmi->dex_references[dex_data->profile_index].dex_location = dex_data->profile_key;
1298 pmi->dex_references[dex_data->profile_index].dex_checksum = dex_data->checksum;
Mathieu Chartierea650f32017-05-24 12:04:13 -07001299 pmi->dex_references[dex_data->profile_index].num_method_ids = dex_data->num_method_ids;
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001300 }
1301
Calin Juravlecc3171a2017-05-19 16:47:53 -07001302 return pmi;
Calin Juravle940eb0c2017-01-30 19:30:44 -08001303}
1304
1305
Andreas Gampea5b09a62016-11-17 15:21:22 -08001306bool ProfileCompilationInfo::ContainsClass(const DexFile& dex_file, dex::TypeIndex type_idx) const {
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001307 const DexFileData* dex_data = FindDexData(GetProfileDexFileKey(dex_file.GetLocation()));
1308 if (dex_data != nullptr) {
1309 if (!ChecksumMatch(dex_file, dex_data->checksum)) {
Mathieu Chartiera8077802016-03-16 19:08:31 -07001310 return false;
1311 }
Calin Juravlecc3171a2017-05-19 16:47:53 -07001312 const ArenaSet<dex::TypeIndex>& classes = dex_data->class_set;
Jeff Hao54b58552016-11-16 15:15:04 -08001313 return classes.find(type_idx) != classes.end();
Mathieu Chartiera8077802016-03-16 19:08:31 -07001314 }
1315 return false;
1316}
1317
Calin Juravle998c2162015-12-21 15:39:33 +02001318uint32_t ProfileCompilationInfo::GetNumberOfMethods() const {
1319 uint32_t total = 0;
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001320 for (const DexFileData* dex_data : info_) {
1321 total += dex_data->method_map.size();
Calin Juravle998c2162015-12-21 15:39:33 +02001322 }
1323 return total;
1324}
1325
Calin Juravle67265462016-03-18 16:23:40 +00001326uint32_t ProfileCompilationInfo::GetNumberOfResolvedClasses() const {
1327 uint32_t total = 0;
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001328 for (const DexFileData* dex_data : info_) {
1329 total += dex_data->class_set.size();
Calin Juravle67265462016-03-18 16:23:40 +00001330 }
1331 return total;
1332}
1333
David Sehrb18991b2017-02-08 20:58:10 -08001334// Produce a non-owning vector from a vector.
1335template<typename T>
1336const std::vector<T*>* MakeNonOwningVector(const std::vector<std::unique_ptr<T>>* owning_vector) {
1337 auto non_owning_vector = new std::vector<T*>();
1338 for (auto& element : *owning_vector) {
1339 non_owning_vector->push_back(element.get());
1340 }
1341 return non_owning_vector;
1342}
1343
1344std::string ProfileCompilationInfo::DumpInfo(
1345 const std::vector<std::unique_ptr<const DexFile>>* dex_files,
1346 bool print_full_dex_location) const {
1347 std::unique_ptr<const std::vector<const DexFile*>> non_owning_dex_files(
1348 MakeNonOwningVector(dex_files));
1349 return DumpInfo(non_owning_dex_files.get(), print_full_dex_location);
1350}
1351
Calin Juravle998c2162015-12-21 15:39:33 +02001352std::string ProfileCompilationInfo::DumpInfo(const std::vector<const DexFile*>* dex_files,
1353 bool print_full_dex_location) const {
Calin Juravle226501b2015-12-11 14:41:31 +00001354 std::ostringstream os;
1355 if (info_.empty()) {
1356 return "ProfileInfo: empty";
1357 }
1358
1359 os << "ProfileInfo:";
1360
Calin Juravle226501b2015-12-11 14:41:31 +00001361 const std::string kFirstDexFileKeySubstitute = ":classes.dex";
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001362
1363 for (const DexFileData* dex_data : info_) {
Calin Juravle226501b2015-12-11 14:41:31 +00001364 os << "\n";
Calin Juravle226501b2015-12-11 14:41:31 +00001365 if (print_full_dex_location) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001366 os << dex_data->profile_key;
Calin Juravle226501b2015-12-11 14:41:31 +00001367 } else {
1368 // Replace the (empty) multidex suffix of the first key with a substitute for easier reading.
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001369 std::string multidex_suffix = DexFile::GetMultiDexSuffix(dex_data->profile_key);
Calin Juravle226501b2015-12-11 14:41:31 +00001370 os << (multidex_suffix.empty() ? kFirstDexFileKeySubstitute : multidex_suffix);
1371 }
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001372 os << " [index=" << static_cast<uint32_t>(dex_data->profile_index) << "]";
Calin Juravle876f3502016-03-24 16:16:34 +00001373 const DexFile* dex_file = nullptr;
1374 if (dex_files != nullptr) {
1375 for (size_t i = 0; i < dex_files->size(); i++) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001376 if (dex_data->profile_key == (*dex_files)[i]->GetLocation()) {
Calin Juravle876f3502016-03-24 16:16:34 +00001377 dex_file = (*dex_files)[i];
Calin Juravle998c2162015-12-21 15:39:33 +02001378 }
Calin Juravle226501b2015-12-11 14:41:31 +00001379 }
Calin Juravle876f3502016-03-24 16:16:34 +00001380 }
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001381 os << "\n\thot methods: ";
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001382 for (const auto& method_it : dex_data->method_map) {
Calin Juravle876f3502016-03-24 16:16:34 +00001383 if (dex_file != nullptr) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001384 os << "\n\t\t" << dex_file->PrettyMethod(method_it.first, true);
Calin Juravle876f3502016-03-24 16:16:34 +00001385 } else {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001386 os << method_it.first;
Calin Juravle876f3502016-03-24 16:16:34 +00001387 }
Calin Juravle940eb0c2017-01-30 19:30:44 -08001388
1389 os << "[";
1390 for (const auto& inline_cache_it : method_it.second) {
1391 os << "{" << std::hex << inline_cache_it.first << std::dec << ":";
Calin Juravle589e71e2017-03-03 16:05:05 -08001392 if (inline_cache_it.second.is_missing_types) {
1393 os << "MT";
1394 } else if (inline_cache_it.second.is_megamorphic) {
1395 os << "MM";
Calin Juravle940eb0c2017-01-30 19:30:44 -08001396 } else {
1397 for (const ClassReference& class_ref : inline_cache_it.second.classes) {
1398 os << "(" << static_cast<uint32_t>(class_ref.dex_profile_index)
1399 << "," << class_ref.type_index.index_ << ")";
1400 }
1401 }
1402 os << "}";
1403 }
1404 os << "], ";
Calin Juravle876f3502016-03-24 16:16:34 +00001405 }
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001406 bool startup = true;
1407 while (true) {
1408 os << "\n\t" << (startup ? "startup methods: " : "post startup methods: ");
1409 for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
1410 if (dex_data->HasSampledMethod(startup, method_idx)) {
1411 os << method_idx << ", ";
1412 }
1413 }
1414 if (startup == false) {
1415 break;
1416 }
1417 startup = false;
1418 }
Calin Juravle876f3502016-03-24 16:16:34 +00001419 os << "\n\tclasses: ";
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001420 for (const auto class_it : dex_data->class_set) {
Calin Juravle876f3502016-03-24 16:16:34 +00001421 if (dex_file != nullptr) {
Jeff Hao54b58552016-11-16 15:15:04 -08001422 os << "\n\t\t" << dex_file->PrettyType(class_it);
Calin Juravle876f3502016-03-24 16:16:34 +00001423 } else {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001424 os << class_it.index_ << ",";
Calin Juravle876f3502016-03-24 16:16:34 +00001425 }
Calin Juravle226501b2015-12-11 14:41:31 +00001426 }
1427 }
1428 return os.str();
1429}
1430
Mathieu Chartierea650f32017-05-24 12:04:13 -07001431bool ProfileCompilationInfo::GetClassesAndMethods(
1432 const DexFile& dex_file,
1433 /*out*/std::set<dex::TypeIndex>* class_set,
1434 /*out*/std::set<uint16_t>* hot_method_set,
1435 /*out*/std::set<uint16_t>* startup_method_set,
1436 /*out*/std::set<uint16_t>* post_startup_method_method_set) const {
Mathieu Chartier34067262017-04-06 13:55:46 -07001437 std::set<std::string> ret;
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001438 std::string profile_key = GetProfileDexFileKey(dex_file.GetLocation());
Mathieu Chartier34067262017-04-06 13:55:46 -07001439 const DexFileData* dex_data = FindDexData(profile_key);
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001440 if (dex_data == nullptr || dex_data->checksum != dex_file.GetLocationChecksum()) {
Mathieu Chartier34067262017-04-06 13:55:46 -07001441 return false;
David Sehr7c80f2d2017-02-07 16:47:58 -08001442 }
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001443 for (const auto& it : dex_data->method_map) {
Mathieu Chartierea650f32017-05-24 12:04:13 -07001444 hot_method_set->insert(it.first);
1445 }
1446 for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
1447 if (dex_data->HasSampledMethod(/*startup*/ true, method_idx)) {
1448 startup_method_set->insert(method_idx);
1449 }
1450 if (dex_data->HasSampledMethod(/*startup*/ false, method_idx)) {
1451 post_startup_method_method_set->insert(method_idx);
1452 }
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001453 }
Calin Juravlecc3171a2017-05-19 16:47:53 -07001454 for (const dex::TypeIndex& type_index : dex_data->class_set) {
1455 class_set->insert(type_index);
1456 }
Mathieu Chartier34067262017-04-06 13:55:46 -07001457 return true;
David Sehr7c80f2d2017-02-07 16:47:58 -08001458}
1459
Calin Juravle2e2db782016-02-23 12:00:03 +00001460bool ProfileCompilationInfo::Equals(const ProfileCompilationInfo& other) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001461 // No need to compare profile_key_map_. That's only a cache for fast search.
1462 // All the information is already in the info_ vector.
1463 if (info_.size() != other.info_.size()) {
1464 return false;
1465 }
1466 for (size_t i = 0; i < info_.size(); i++) {
1467 const DexFileData& dex_data = *info_[i];
1468 const DexFileData& other_dex_data = *other.info_[i];
1469 if (!(dex_data == other_dex_data)) {
1470 return false;
1471 }
1472 }
1473 return true;
Calin Juravle877fd962016-01-05 14:29:29 +00001474}
1475
Mathieu Chartier046854b2017-03-01 17:16:22 -08001476std::set<DexCacheResolvedClasses> ProfileCompilationInfo::GetResolvedClasses(
Calin Juravle08556882017-05-26 16:40:45 -07001477 const std::vector<const DexFile*>& dex_files) const {
1478 std::unordered_map<std::string, const DexFile* > key_to_dex_file;
1479 for (const DexFile* dex_file : dex_files) {
1480 key_to_dex_file.emplace(GetProfileDexFileKey(dex_file->GetLocation()), dex_file);
Mathieu Chartier046854b2017-03-01 17:16:22 -08001481 }
Mathieu Chartierc5dd3192015-12-09 16:38:30 -08001482 std::set<DexCacheResolvedClasses> ret;
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001483 for (const DexFileData* dex_data : info_) {
Calin Juravle08556882017-05-26 16:40:45 -07001484 const auto it = key_to_dex_file.find(dex_data->profile_key);
1485 if (it != key_to_dex_file.end()) {
1486 const DexFile* dex_file = it->second;
1487 const std::string& dex_location = dex_file->GetLocation();
1488 if (dex_data->checksum != it->second->GetLocationChecksum()) {
1489 LOG(ERROR) << "Dex checksum mismatch when getting resolved classes from profile for "
1490 << "location " << dex_location << " (checksum=" << dex_file->GetLocationChecksum()
1491 << ", profile checksum=" << dex_data->checksum;
1492 return std::set<DexCacheResolvedClasses>();
1493 }
Mathieu Chartierea650f32017-05-24 12:04:13 -07001494 DexCacheResolvedClasses classes(dex_location,
1495 dex_location,
1496 dex_data->checksum,
1497 dex_data->num_method_ids);
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001498 classes.AddClasses(dex_data->class_set.begin(), dex_data->class_set.end());
Mathieu Chartier046854b2017-03-01 17:16:22 -08001499 ret.insert(classes);
1500 }
Mathieu Chartierc5dd3192015-12-09 16:38:30 -08001501 }
1502 return ret;
1503}
1504
Calin Juravle7bcdb532016-06-07 16:14:47 +01001505// Naive implementation to generate a random profile file suitable for testing.
1506bool ProfileCompilationInfo::GenerateTestProfile(int fd,
1507 uint16_t number_of_dex_files,
1508 uint16_t method_ratio,
Jeff Haof0a31f82017-03-27 15:50:37 -07001509 uint16_t class_ratio,
1510 uint32_t random_seed) {
Calin Juravle7bcdb532016-06-07 16:14:47 +01001511 const std::string base_dex_location = "base.apk";
1512 ProfileCompilationInfo info;
1513 // The limits are defined by the dex specification.
Mathieu Chartierea650f32017-05-24 12:04:13 -07001514 const uint16_t max_method = std::numeric_limits<uint16_t>::max();
1515 const uint16_t max_classes = std::numeric_limits<uint16_t>::max();
Calin Juravle7bcdb532016-06-07 16:14:47 +01001516 uint16_t number_of_methods = max_method * method_ratio / 100;
1517 uint16_t number_of_classes = max_classes * class_ratio / 100;
1518
Jeff Haof0a31f82017-03-27 15:50:37 -07001519 std::srand(random_seed);
Calin Juravle7bcdb532016-06-07 16:14:47 +01001520
1521 // Make sure we generate more samples with a low index value.
1522 // This makes it more likely to hit valid method/class indices in small apps.
1523 const uint16_t kFavorFirstN = 10000;
1524 const uint16_t kFavorSplit = 2;
1525
1526 for (uint16_t i = 0; i < number_of_dex_files; i++) {
1527 std::string dex_location = DexFile::GetMultiDexLocation(i, base_dex_location.c_str());
1528 std::string profile_key = GetProfileDexFileKey(dex_location);
1529
1530 for (uint16_t m = 0; m < number_of_methods; m++) {
1531 uint16_t method_idx = rand() % max_method;
1532 if (m < (number_of_methods / kFavorSplit)) {
1533 method_idx %= kFavorFirstN;
1534 }
Mathieu Chartierea650f32017-05-24 12:04:13 -07001535 info.AddMethodIndex(profile_key, 0, method_idx, max_method);
Calin Juravle7bcdb532016-06-07 16:14:47 +01001536 }
1537
1538 for (uint16_t c = 0; c < number_of_classes; c++) {
Jeff Hao54b58552016-11-16 15:15:04 -08001539 uint16_t type_idx = rand() % max_classes;
Calin Juravle7bcdb532016-06-07 16:14:47 +01001540 if (c < (number_of_classes / kFavorSplit)) {
Jeff Hao54b58552016-11-16 15:15:04 -08001541 type_idx %= kFavorFirstN;
Calin Juravle7bcdb532016-06-07 16:14:47 +01001542 }
Mathieu Chartierea650f32017-05-24 12:04:13 -07001543 info.AddClassIndex(profile_key, 0, dex::TypeIndex(type_idx), max_method);
Calin Juravle7bcdb532016-06-07 16:14:47 +01001544 }
1545 }
1546 return info.Save(fd);
1547}
1548
Jeff Haof0a31f82017-03-27 15:50:37 -07001549// Naive implementation to generate a random profile file suitable for testing.
1550bool ProfileCompilationInfo::GenerateTestProfile(
1551 int fd,
1552 std::vector<std::unique_ptr<const DexFile>>& dex_files,
1553 uint32_t random_seed) {
1554 std::srand(random_seed);
1555 ProfileCompilationInfo info;
1556 for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
1557 const std::string& location = dex_file->GetLocation();
1558 uint32_t checksum = dex_file->GetLocationChecksum();
1559 for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
1560 // Randomly add a class from the dex file (with 50% chance).
1561 if (std::rand() % 2 != 0) {
Mathieu Chartierea650f32017-05-24 12:04:13 -07001562 info.AddClassIndex(location,
1563 checksum,
1564 dex::TypeIndex(dex_file->GetClassDef(i).class_idx_),
1565 dex_file->NumMethodIds());
Jeff Haof0a31f82017-03-27 15:50:37 -07001566 }
1567 }
1568 for (uint32_t i = 0; i < dex_file->NumMethodIds(); ++i) {
1569 // Randomly add a method from the dex file (with 50% chance).
1570 if (std::rand() % 2 != 0) {
Mathieu Chartierea650f32017-05-24 12:04:13 -07001571 info.AddMethodIndex(location, checksum, i, dex_file->NumMethodIds());
Jeff Haof0a31f82017-03-27 15:50:37 -07001572 }
1573 }
1574 }
1575 return info.Save(fd);
1576}
1577
Calin Juravle940eb0c2017-01-30 19:30:44 -08001578bool ProfileCompilationInfo::OfflineProfileMethodInfo::operator==(
1579 const OfflineProfileMethodInfo& other) const {
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001580 if (inline_caches->size() != other.inline_caches->size()) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001581 return false;
1582 }
1583
1584 // We can't use a simple equality test because we need to match the dex files
Calin Juravle589e71e2017-03-03 16:05:05 -08001585 // of the inline caches which might have different profile indexes.
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001586 for (const auto& inline_cache_it : *inline_caches) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001587 uint16_t dex_pc = inline_cache_it.first;
1588 const DexPcData dex_pc_data = inline_cache_it.second;
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001589 const auto& other_it = other.inline_caches->find(dex_pc);
1590 if (other_it == other.inline_caches->end()) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001591 return false;
1592 }
1593 const DexPcData& other_dex_pc_data = other_it->second;
Calin Juravle589e71e2017-03-03 16:05:05 -08001594 if (dex_pc_data.is_megamorphic != other_dex_pc_data.is_megamorphic ||
1595 dex_pc_data.is_missing_types != other_dex_pc_data.is_missing_types) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001596 return false;
1597 }
1598 for (const ClassReference& class_ref : dex_pc_data.classes) {
1599 bool found = false;
1600 for (const ClassReference& other_class_ref : other_dex_pc_data.classes) {
1601 CHECK_LE(class_ref.dex_profile_index, dex_references.size());
1602 CHECK_LE(other_class_ref.dex_profile_index, other.dex_references.size());
1603 const DexReference& dex_ref = dex_references[class_ref.dex_profile_index];
1604 const DexReference& other_dex_ref = other.dex_references[other_class_ref.dex_profile_index];
1605 if (class_ref.type_index == other_class_ref.type_index &&
1606 dex_ref == other_dex_ref) {
1607 found = true;
1608 break;
1609 }
1610 }
1611 if (!found) {
1612 return false;
1613 }
1614 }
1615 }
1616 return true;
1617}
1618
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001619bool ProfileCompilationInfo::IsEmpty() const {
1620 DCHECK_EQ(info_.empty(), profile_key_map_.empty());
1621 return info_.empty();
1622}
1623
Calin Juravlecc3171a2017-05-19 16:47:53 -07001624ProfileCompilationInfo::InlineCacheMap*
1625ProfileCompilationInfo::DexFileData::FindOrAddMethod(uint16_t method_index) {
1626 return &(method_map.FindOrAdd(
1627 method_index,
1628 InlineCacheMap(std::less<uint16_t>(), arena_->Adapter(kArenaAllocProfile)))->second);
1629}
1630
1631ProfileCompilationInfo::DexPcData*
1632ProfileCompilationInfo::FindOrAddDexPc(InlineCacheMap* inline_cache, uint32_t dex_pc) {
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001633 return &(inline_cache->FindOrAdd(dex_pc, DexPcData(&arena_))->second);
Calin Juravlecc3171a2017-05-19 16:47:53 -07001634}
1635
Calin Juravle31f2c152015-10-23 17:56:15 +01001636} // namespace art