blob: 33fa0d6a2666726fb4b72f3559a9debf8e0b11ee [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 Juravle31f2c152015-10-23 17:56:15 +010019#include <sys/file.h>
20#include <sys/stat.h>
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070021#include <sys/types.h>
Calin Juravle31f2c152015-10-23 17:56:15 +010022#include <sys/uio.h>
Shubham Ajmera4d198e02017-05-12 17:45:29 +000023#include <unistd.h>
24#include <zlib.h>
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070025
26#include <cerrno>
27#include <climits>
28#include <cstdlib>
29#include <string>
30#include <vector>
Shubham Ajmeraafbbf182017-08-04 14:33:34 -070031#include <iostream>
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070032
33#include "android-base/file.h"
Calin Juravle31f2c152015-10-23 17:56:15 +010034
Calin Juravlecc3171a2017-05-19 16:47:53 -070035#include "base/arena_allocator.h"
36#include "base/dumpable.h"
David Sehr891a50e2017-10-27 17:01:07 -070037#include "base/file_utils.h"
Andreas Gampe57943812017-12-06 21:39:13 -080038#include "base/logging.h" // For VLOG.
Calin Juravle31f2c152015-10-23 17:56:15 +010039#include "base/mutex.h"
Calin Juravle877fd962016-01-05 14:29:29 +000040#include "base/scoped_flock.h"
Calin Juravle66f55232015-12-08 15:09:10 +000041#include "base/stl_util.h"
Mathieu Chartier32ce2ad2016-03-04 14:58:03 -080042#include "base/systrace.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070043#include "base/time_utils.h"
Calin Juravle877fd962016-01-05 14:29:29 +000044#include "base/unix_file/fd_file.h"
David Sehr9e734c72018-01-04 17:56:19 -080045#include "dex/dex_file_loader.h"
Calin Juravle31f2c152015-10-23 17:56:15 +010046#include "jit/profiling_info.h"
Calin Juravle877fd962016-01-05 14:29:29 +000047#include "os.h"
Calin Juravle31f2c152015-10-23 17:56:15 +010048#include "safe_map.h"
Andreas Gampec6ea7d02017-02-01 16:46:28 -080049#include "utils.h"
Calin Juravle1e2de642018-01-18 01:08:23 -080050#include "zip_archive.h"
Calin Juravle31f2c152015-10-23 17:56:15 +010051
52namespace art {
53
Calin Juravle64142952016-03-21 14:37:55 +000054const uint8_t ProfileCompilationInfo::kProfileMagic[] = { 'p', 'r', 'o', '\0' };
Shubham Ajmeraafbbf182017-08-04 14:33:34 -070055// Last profile version: merge profiles directly from the file without creating
56// profile_compilation_info object. All the profile line headers are now placed together
57// before corresponding method_encodings and class_ids.
58const uint8_t ProfileCompilationInfo::kProfileVersion[] = { '0', '1', '0', '\0' };
Calin Juravle64142952016-03-21 14:37:55 +000059
Calin Juravle1e2de642018-01-18 01:08:23 -080060// The name of the profile entry in the dex metadata file.
61// DO NOT CHANGE THIS! (it's similar to classes.dex in the apk files).
62const char* ProfileCompilationInfo::kDexMetadataProfileEntry = "primary.prof";
63
Calin Juravle64142952016-03-21 14:37:55 +000064static constexpr uint16_t kMaxDexFileKeyLength = PATH_MAX;
65
Calin Juravlec4588572016-06-08 14:24:13 +010066// 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 +010067// Used to facilitate testing profile guided compilation across a large number of apps
Calin Juravlec4588572016-06-08 14:24:13 +010068// using the same test profile.
69static constexpr bool kDebugIgnoreChecksum = false;
70
Calin Juravle589e71e2017-03-03 16:05:05 -080071static constexpr uint8_t kIsMissingTypesEncoding = 6;
72static constexpr uint8_t kIsMegamorphicEncoding = 7;
Calin Juravle940eb0c2017-01-30 19:30:44 -080073
74static_assert(sizeof(InlineCache::kIndividualCacheSize) == sizeof(uint8_t),
75 "InlineCache::kIndividualCacheSize does not have the expect type size");
Calin Juravle589e71e2017-03-03 16:05:05 -080076static_assert(InlineCache::kIndividualCacheSize < kIsMegamorphicEncoding,
77 "InlineCache::kIndividualCacheSize is larger than expected");
78static_assert(InlineCache::kIndividualCacheSize < kIsMissingTypesEncoding,
Calin Juravle940eb0c2017-01-30 19:30:44 -080079 "InlineCache::kIndividualCacheSize is larger than expected");
80
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -070081static bool ChecksumMatch(uint32_t dex_file_checksum, uint32_t checksum) {
82 return kDebugIgnoreChecksum || dex_file_checksum == checksum;
83}
84
Calin Juravlecc3171a2017-05-19 16:47:53 -070085ProfileCompilationInfo::ProfileCompilationInfo(ArenaPool* custom_arena_pool)
Calin Juravlee6f87cc2017-05-24 17:41:05 -070086 : default_arena_pool_(),
Vladimir Markoca6fff82017-10-03 14:49:14 +010087 allocator_(custom_arena_pool),
88 info_(allocator_.Adapter(kArenaAllocProfile)),
89 profile_key_map_(std::less<const std::string>(), allocator_.Adapter(kArenaAllocProfile)) {
Calin Juravlecc3171a2017-05-19 16:47:53 -070090}
91
92ProfileCompilationInfo::ProfileCompilationInfo()
Calin Juravlee6f87cc2017-05-24 17:41:05 -070093 : default_arena_pool_(/*use_malloc*/true, /*low_4gb*/false, "ProfileCompilationInfo"),
Vladimir Markoca6fff82017-10-03 14:49:14 +010094 allocator_(&default_arena_pool_),
95 info_(allocator_.Adapter(kArenaAllocProfile)),
96 profile_key_map_(std::less<const std::string>(), allocator_.Adapter(kArenaAllocProfile)) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -070097}
98
99ProfileCompilationInfo::~ProfileCompilationInfo() {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100100 VLOG(profiler) << Dumpable<MemStats>(allocator_.GetMemStats());
Calin Juravle798ba162017-05-23 23:01:53 -0700101 for (DexFileData* data : info_) {
102 delete data;
103 }
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700104}
105
Calin Juravle940eb0c2017-01-30 19:30:44 -0800106void ProfileCompilationInfo::DexPcData::AddClass(uint16_t dex_profile_idx,
107 const dex::TypeIndex& type_idx) {
Calin Juravle589e71e2017-03-03 16:05:05 -0800108 if (is_megamorphic || is_missing_types) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800109 return;
110 }
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700111
112 // Perform an explicit lookup for the type instead of directly emplacing the
113 // element. We do this because emplace() allocates the node before doing the
114 // lookup and if it then finds an identical element, it shall deallocate the
115 // node. For Arena allocations, that's essentially a leak.
116 ClassReference ref(dex_profile_idx, type_idx);
117 auto it = classes.find(ref);
118 if (it != classes.end()) {
119 // The type index exists.
120 return;
121 }
122
123 // Check if the adding the type will cause the cache to become megamorphic.
124 if (classes.size() + 1 >= InlineCache::kIndividualCacheSize) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800125 is_megamorphic = true;
126 classes.clear();
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700127 return;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800128 }
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700129
130 // The type does not exist and the inline cache will not be megamorphic.
131 classes.insert(ref);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800132}
133
Calin Juravle34900cc2016-02-05 16:19:19 +0000134// Transform the actual dex location into relative paths.
135// Note: this is OK because we don't store profiles of different apps into the same file.
136// Apps with split apks don't cause trouble because each split has a different name and will not
137// collide with other entries.
Calin Juravle31708b72016-02-05 19:44:05 +0000138std::string ProfileCompilationInfo::GetProfileDexFileKey(const std::string& dex_location) {
Calin Juravle34900cc2016-02-05 16:19:19 +0000139 DCHECK(!dex_location.empty());
140 size_t last_sep_index = dex_location.find_last_of('/');
141 if (last_sep_index == std::string::npos) {
142 return dex_location;
143 } else {
Calin Juravle31708b72016-02-05 19:44:05 +0000144 DCHECK(last_sep_index < dex_location.size());
145 return dex_location.substr(last_sep_index + 1);
Calin Juravle34900cc2016-02-05 16:19:19 +0000146 }
147}
148
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700149bool ProfileCompilationInfo::AddMethodIndex(MethodHotness::Flag flags, const MethodReference& ref) {
150 DexFileData* data = GetOrAddDexFileData(ref.dex_file);
151 if (data == nullptr) {
152 return false;
153 }
Calin Juravle1ad1e3f2017-09-19 18:20:37 -0700154 return data->AddMethod(flags, ref.index);
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700155}
156
157bool ProfileCompilationInfo::AddMethodIndex(MethodHotness::Flag flags,
158 const std::string& dex_location,
159 uint32_t checksum,
160 uint16_t method_idx,
161 uint32_t num_method_ids) {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700162 DexFileData* data = GetOrAddDexFileData(GetProfileDexFileKey(dex_location),
163 checksum,
164 num_method_ids);
165 if (data == nullptr) {
166 return false;
167 }
Calin Juravle1ad1e3f2017-09-19 18:20:37 -0700168 return data->AddMethod(flags, method_idx);
Mathieu Chartierea650f32017-05-24 12:04:13 -0700169}
170
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700171bool ProfileCompilationInfo::AddMethods(const std::vector<ProfileMethodInfo>& methods) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800172 for (const ProfileMethodInfo& method : methods) {
173 if (!AddMethod(method)) {
Calin Juravle67265462016-03-18 16:23:40 +0000174 return false;
175 }
176 }
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700177 return true;
178}
179
180bool ProfileCompilationInfo::AddClasses(const std::set<DexCacheResolvedClasses>& resolved_classes) {
Calin Juravle67265462016-03-18 16:23:40 +0000181 for (const DexCacheResolvedClasses& dex_cache : resolved_classes) {
182 if (!AddResolvedClasses(dex_cache)) {
183 return false;
184 }
185 }
186 return true;
187}
188
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700189bool ProfileCompilationInfo::MergeWith(const std::string& filename) {
190 std::string error;
191 int flags = O_RDONLY | O_NOFOLLOW | O_CLOEXEC;
192 ScopedFlock profile_file = LockedFile::Open(filename.c_str(), flags,
193 /*block*/false, &error);
194
195 if (profile_file.get() == nullptr) {
196 LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
197 return false;
198 }
199
200 int fd = profile_file->Fd();
201
Calin Juravle36060d12018-01-19 16:28:38 -0800202 ProfileLoadStatus status = LoadInternal(fd, &error);
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700203 if (status == kProfileLoadSuccess) {
204 return true;
205 }
206
207 LOG(WARNING) << "Could not load profile data from file " << filename << ": " << error;
208 return false;
209}
210
Calin Juravledcab1902017-05-12 19:18:47 -0700211bool ProfileCompilationInfo::Load(const std::string& filename, bool clear_if_invalid) {
Calin Juravle67265462016-03-18 16:23:40 +0000212 ScopedTrace trace(__PRETTY_FUNCTION__);
Calin Juravle67265462016-03-18 16:23:40 +0000213 std::string error;
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700214
215 if (!IsEmpty()) {
216 return kProfileLoadWouldOverwiteData;
217 }
218
Calin Juravledf674c42017-04-27 19:30:16 -0700219 int flags = O_RDWR | O_NOFOLLOW | O_CLOEXEC;
220 // There's no need to fsync profile data right away. We get many chances
221 // to write it again in case something goes wrong. We can rely on a simple
222 // close(), no sync, and let to the kernel decide when to write to disk.
Narayan Kamatha3d27eb2017-05-11 13:50:59 +0100223 ScopedFlock profile_file = LockedFile::Open(filename.c_str(), flags,
224 /*block*/false, &error);
225
226 if (profile_file.get() == nullptr) {
Calin Juravle67265462016-03-18 16:23:40 +0000227 LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
228 return false;
229 }
230
Narayan Kamatha3d27eb2017-05-11 13:50:59 +0100231 int fd = profile_file->Fd();
Calin Juravle67265462016-03-18 16:23:40 +0000232
Calin Juravle36060d12018-01-19 16:28:38 -0800233 ProfileLoadStatus status = LoadInternal(fd, &error);
Calin Juravle5d1bd0a2016-03-24 20:33:22 +0000234 if (status == kProfileLoadSuccess) {
Calin Juravledcab1902017-05-12 19:18:47 -0700235 return true;
236 }
237
238 if (clear_if_invalid &&
239 ((status == kProfileLoadVersionMismatch) || (status == kProfileLoadBadData))) {
240 LOG(WARNING) << "Clearing bad or obsolete profile data from file "
241 << filename << ": " << error;
Narayan Kamatha3d27eb2017-05-11 13:50:59 +0100242 if (profile_file->ClearContent()) {
Calin Juravledcab1902017-05-12 19:18:47 -0700243 return true;
Calin Juravle5d1bd0a2016-03-24 20:33:22 +0000244 } else {
Calin Juravledcab1902017-05-12 19:18:47 -0700245 PLOG(WARNING) << "Could not clear profile file: " << filename;
246 return false;
Calin Juravle5d1bd0a2016-03-24 20:33:22 +0000247 }
Calin Juravledcab1902017-05-12 19:18:47 -0700248 }
249
250 LOG(WARNING) << "Could not load profile data from file " << filename << ": " << error;
251 return false;
252}
253
254bool ProfileCompilationInfo::Save(const std::string& filename, uint64_t* bytes_written) {
255 ScopedTrace trace(__PRETTY_FUNCTION__);
Calin Juravledcab1902017-05-12 19:18:47 -0700256 std::string error;
257 int flags = O_WRONLY | O_NOFOLLOW | O_CLOEXEC;
258 // There's no need to fsync profile data right away. We get many chances
259 // to write it again in case something goes wrong. We can rely on a simple
260 // close(), no sync, and let to the kernel decide when to write to disk.
Narayan Kamatha3d27eb2017-05-11 13:50:59 +0100261 ScopedFlock profile_file = LockedFile::Open(filename.c_str(), flags,
262 /*block*/false, &error);
263 if (profile_file.get() == nullptr) {
Calin Juravledcab1902017-05-12 19:18:47 -0700264 LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
Calin Juravle67265462016-03-18 16:23:40 +0000265 return false;
266 }
267
Narayan Kamatha3d27eb2017-05-11 13:50:59 +0100268 int fd = profile_file->Fd();
Calin Juravledcab1902017-05-12 19:18:47 -0700269
Calin Juravle5d1bd0a2016-03-24 20:33:22 +0000270 // We need to clear the data because we don't support appending to the profiles yet.
Narayan Kamatha3d27eb2017-05-11 13:50:59 +0100271 if (!profile_file->ClearContent()) {
Calin Juravle67265462016-03-18 16:23:40 +0000272 PLOG(WARNING) << "Could not clear profile file: " << filename;
273 return false;
274 }
275
276 // This doesn't need locking because we are trying to lock the file for exclusive
277 // access and fail immediately if we can't.
278 bool result = Save(fd);
279 if (result) {
Calin Juravledcab1902017-05-12 19:18:47 -0700280 int64_t size = GetFileSizeBytes(filename);
281 if (size != -1) {
282 VLOG(profiler)
283 << "Successfully saved profile info to " << filename << " Size: "
284 << size;
285 if (bytes_written != nullptr) {
286 *bytes_written = static_cast<uint64_t>(size);
287 }
Calin Juravle67265462016-03-18 16:23:40 +0000288 }
289 } else {
290 VLOG(profiler) << "Failed to save profile info to " << filename;
291 }
292 return result;
293}
294
Calin Juravle64142952016-03-21 14:37:55 +0000295// Returns true if all the bytes were successfully written to the file descriptor.
296static bool WriteBuffer(int fd, const uint8_t* buffer, size_t byte_count) {
297 while (byte_count > 0) {
298 int bytes_written = TEMP_FAILURE_RETRY(write(fd, buffer, byte_count));
299 if (bytes_written == -1) {
Calin Juravle877fd962016-01-05 14:29:29 +0000300 return false;
301 }
Calin Juravle64142952016-03-21 14:37:55 +0000302 byte_count -= bytes_written; // Reduce the number of remaining bytes.
303 buffer += bytes_written; // Move the buffer forward.
304 }
Calin Juravle877fd962016-01-05 14:29:29 +0000305 return true;
Calin Juravle31f2c152015-10-23 17:56:15 +0100306}
307
Calin Juravle64142952016-03-21 14:37:55 +0000308// Add the string bytes to the buffer.
309static void AddStringToBuffer(std::vector<uint8_t>* buffer, const std::string& value) {
310 buffer->insert(buffer->end(), value.begin(), value.end());
311}
312
313// Insert each byte, from low to high into the buffer.
314template <typename T>
315static void AddUintToBuffer(std::vector<uint8_t>* buffer, T value) {
316 for (size_t i = 0; i < sizeof(T); i++) {
317 buffer->push_back((value >> (i * kBitsPerByte)) & 0xff);
318 }
319}
320
321static constexpr size_t kLineHeaderSize =
Calin Juravle940eb0c2017-01-30 19:30:44 -0800322 2 * sizeof(uint16_t) + // class_set.size + dex_location.size
Mathieu Chartierea650f32017-05-24 12:04:13 -0700323 3 * sizeof(uint32_t); // method_map.size + checksum + num_method_ids
Calin Juravle31f2c152015-10-23 17:56:15 +0100324
325/**
326 * Serialization format:
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700327 * [profile_header, zipped[[profile_line_header1, profile_line_header2...],[profile_line_data1,
328 * profile_line_data2...]]]
329 * profile_header:
330 * magic,version,number_of_dex_files,uncompressed_size_of_zipped_data,compressed_data_size
331 * profile_line_header:
332 * dex_location,number_of_classes,methods_region_size,dex_location_checksum,num_method_ids
333 * profile_line_data:
334 * method_encoding_1,method_encoding_2...,class_id1,class_id2...,startup/post startup bitmap
Calin Juravle940eb0c2017-01-30 19:30:44 -0800335 * The method_encoding is:
336 * method_id,number_of_inline_caches,inline_cache1,inline_cache2...
337 * The inline_cache is:
338 * dex_pc,[M|dex_map_size], dex_profile_index,class_id1,class_id2...,dex_profile_index2,...
339 * dex_map_size is the number of dex_indeces that follows.
340 * Classes are grouped per their dex files and the line
341 * `dex_profile_index,class_id1,class_id2...,dex_profile_index2,...` encodes the
342 * mapping from `dex_profile_index` to the set of classes `class_id1,class_id2...`
Calin Juravle589e71e2017-03-03 16:05:05 -0800343 * M stands for megamorphic or missing types and it's encoded as either
344 * the byte kIsMegamorphicEncoding or kIsMissingTypesEncoding.
Calin Juravle940eb0c2017-01-30 19:30:44 -0800345 * When present, there will be no class ids following.
Calin Juravle31f2c152015-10-23 17:56:15 +0100346 **/
Calin Juravle2e2db782016-02-23 12:00:03 +0000347bool ProfileCompilationInfo::Save(int fd) {
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000348 uint64_t start = NanoTime();
Mathieu Chartier32ce2ad2016-03-04 14:58:03 -0800349 ScopedTrace trace(__PRETTY_FUNCTION__);
Calin Juravle2e2db782016-02-23 12:00:03 +0000350 DCHECK_GE(fd, 0);
Calin Juravle64142952016-03-21 14:37:55 +0000351
Calin Juravle64142952016-03-21 14:37:55 +0000352 // Use a vector wrapper to avoid keeping track of offsets when we add elements.
353 std::vector<uint8_t> buffer;
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000354 if (!WriteBuffer(fd, kProfileMagic, sizeof(kProfileMagic))) {
355 return false;
356 }
357 if (!WriteBuffer(fd, kProfileVersion, sizeof(kProfileVersion))) {
358 return false;
359 }
Calin Juravle940eb0c2017-01-30 19:30:44 -0800360 DCHECK_LE(info_.size(), std::numeric_limits<uint8_t>::max());
361 AddUintToBuffer(&buffer, static_cast<uint8_t>(info_.size()));
Calin Juravle64142952016-03-21 14:37:55 +0000362
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000363 uint32_t required_capacity = 0;
364 for (const DexFileData* dex_data_ptr : info_) {
365 const DexFileData& dex_data = *dex_data_ptr;
366 uint32_t methods_region_size = GetMethodsRegionSize(dex_data);
367 required_capacity += kLineHeaderSize +
368 dex_data.profile_key.size() +
369 sizeof(uint16_t) * dex_data.class_set.size() +
Mathieu Chartierea650f32017-05-24 12:04:13 -0700370 methods_region_size +
371 dex_data.bitmap_storage.size();
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000372 }
Mathieu Chartierf2e2af82017-07-12 21:09:57 -0700373 // Allow large profiles for non target builds for the case where we are merging many profiles
374 // to generate a boot image profile.
375 if (kIsTargetBuild && required_capacity > kProfileSizeErrorThresholdInBytes) {
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000376 LOG(ERROR) << "Profile data size exceeds "
377 << std::to_string(kProfileSizeErrorThresholdInBytes)
378 << " bytes. Profile will not be written to disk.";
379 return false;
380 }
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000381 AddUintToBuffer(&buffer, required_capacity);
382 if (!WriteBuffer(fd, buffer.data(), buffer.size())) {
383 return false;
384 }
385 // Make sure that the buffer has enough capacity to avoid repeated resizings
386 // while we add data.
387 buffer.reserve(required_capacity);
388 buffer.clear();
389
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700390 // Dex files must be written in the order of their profile index. This
Calin Juravlee0ac1152017-02-13 19:03:47 -0800391 // avoids writing the index in the output file and simplifies the parsing logic.
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700392 // Write profile line headers.
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700393 for (const DexFileData* dex_data_ptr : info_) {
394 const DexFileData& dex_data = *dex_data_ptr;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800395
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700396 if (dex_data.profile_key.size() >= kMaxDexFileKeyLength) {
Calin Juravle64142952016-03-21 14:37:55 +0000397 LOG(WARNING) << "DexFileKey exceeds allocated limit";
398 return false;
399 }
400
Calin Juravle940eb0c2017-01-30 19:30:44 -0800401 uint32_t methods_region_size = GetMethodsRegionSize(dex_data);
Calin Juravle64142952016-03-21 14:37:55 +0000402
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700403 DCHECK_LE(dex_data.profile_key.size(), std::numeric_limits<uint16_t>::max());
Calin Juravle64142952016-03-21 14:37:55 +0000404 DCHECK_LE(dex_data.class_set.size(), std::numeric_limits<uint16_t>::max());
Mathieu Chartierea650f32017-05-24 12:04:13 -0700405 // Write profile line header.
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700406 AddUintToBuffer(&buffer, static_cast<uint16_t>(dex_data.profile_key.size()));
Calin Juravle64142952016-03-21 14:37:55 +0000407 AddUintToBuffer(&buffer, static_cast<uint16_t>(dex_data.class_set.size()));
Calin Juravle940eb0c2017-01-30 19:30:44 -0800408 AddUintToBuffer(&buffer, methods_region_size); // uint32_t
Calin Juravle64142952016-03-21 14:37:55 +0000409 AddUintToBuffer(&buffer, dex_data.checksum); // uint32_t
Mathieu Chartierea650f32017-05-24 12:04:13 -0700410 AddUintToBuffer(&buffer, dex_data.num_method_ids); // uint32_t
Calin Juravle64142952016-03-21 14:37:55 +0000411
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700412 AddStringToBuffer(&buffer, dex_data.profile_key);
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700413 }
414
415 for (const DexFileData* dex_data_ptr : info_) {
416 const DexFileData& dex_data = *dex_data_ptr;
417
418 // Note that we allow dex files without any methods or classes, so that
419 // inline caches can refer valid dex files.
Calin Juravle64142952016-03-21 14:37:55 +0000420
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000421 uint16_t last_method_index = 0;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800422 for (const auto& method_it : dex_data.method_map) {
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000423 // Store the difference between the method indices. The SafeMap is ordered by
424 // method_id, so the difference will always be non negative.
425 DCHECK_GE(method_it.first, last_method_index);
426 uint16_t diff_with_last_method_index = method_it.first - last_method_index;
427 last_method_index = method_it.first;
428 AddUintToBuffer(&buffer, diff_with_last_method_index);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800429 AddInlineCacheToBuffer(&buffer, method_it.second);
Calin Juravle31f2c152015-10-23 17:56:15 +0100430 }
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000431
432 uint16_t last_class_index = 0;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800433 for (const auto& class_id : dex_data.class_set) {
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000434 // Store the difference between the class indices. The set is ordered by
435 // class_id, so the difference will always be non negative.
436 DCHECK_GE(class_id.index_, last_class_index);
437 uint16_t diff_with_last_class_index = class_id.index_ - last_class_index;
438 last_class_index = class_id.index_;
439 AddUintToBuffer(&buffer, diff_with_last_class_index);
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800440 }
Mathieu Chartierea650f32017-05-24 12:04:13 -0700441
442 buffer.insert(buffer.end(),
443 dex_data.bitmap_storage.begin(),
444 dex_data.bitmap_storage.end());
Calin Juravle31f2c152015-10-23 17:56:15 +0100445 }
446
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000447 uint32_t output_size = 0;
448 std::unique_ptr<uint8_t[]> compressed_buffer = DeflateBuffer(buffer.data(),
449 required_capacity,
450 &output_size);
451
Shubham Ajmerad704f0b2017-07-26 16:33:35 -0700452 if (output_size > kProfileSizeWarningThresholdInBytes) {
453 LOG(WARNING) << "Profile data size exceeds "
454 << std::to_string(kProfileSizeWarningThresholdInBytes);
455 }
456
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000457 buffer.clear();
458 AddUintToBuffer(&buffer, output_size);
459
460 if (!WriteBuffer(fd, buffer.data(), buffer.size())) {
461 return false;
462 }
463 if (!WriteBuffer(fd, compressed_buffer.get(), output_size)) {
464 return false;
465 }
466 uint64_t total_time = NanoTime() - start;
467 VLOG(profiler) << "Compressed from "
468 << std::to_string(required_capacity)
469 << " to "
470 << std::to_string(output_size);
471 VLOG(profiler) << "Time to save profile: " << std::to_string(total_time);
472 return true;
Calin Juravle226501b2015-12-11 14:41:31 +0000473}
474
Calin Juravle940eb0c2017-01-30 19:30:44 -0800475void ProfileCompilationInfo::AddInlineCacheToBuffer(std::vector<uint8_t>* buffer,
476 const InlineCacheMap& inline_cache_map) {
477 // Add inline cache map size.
478 AddUintToBuffer(buffer, static_cast<uint16_t>(inline_cache_map.size()));
479 if (inline_cache_map.size() == 0) {
480 return;
481 }
482 for (const auto& inline_cache_it : inline_cache_map) {
483 uint16_t dex_pc = inline_cache_it.first;
484 const DexPcData dex_pc_data = inline_cache_it.second;
485 const ClassSet& classes = dex_pc_data.classes;
486
487 // Add the dex pc.
488 AddUintToBuffer(buffer, dex_pc);
489
Calin Juravle589e71e2017-03-03 16:05:05 -0800490 // Add the megamorphic/missing_types encoding if needed and continue.
491 // In either cases we don't add any classes to the profiles and so there's
492 // no point to continue.
493 // TODO(calin): in case we miss types there is still value to add the
494 // rest of the classes. They can be added without bumping the profile version.
495 if (dex_pc_data.is_missing_types) {
496 DCHECK(!dex_pc_data.is_megamorphic); // at this point the megamorphic flag should not be set.
497 DCHECK_EQ(classes.size(), 0u);
498 AddUintToBuffer(buffer, kIsMissingTypesEncoding);
499 continue;
500 } else if (dex_pc_data.is_megamorphic) {
501 DCHECK_EQ(classes.size(), 0u);
502 AddUintToBuffer(buffer, kIsMegamorphicEncoding);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800503 continue;
504 }
505
506 DCHECK_LT(classes.size(), InlineCache::kIndividualCacheSize);
507 DCHECK_NE(classes.size(), 0u) << "InlineCache contains a dex_pc with 0 classes";
508
509 SafeMap<uint8_t, std::vector<dex::TypeIndex>> dex_to_classes_map;
510 // Group the classes by dex. We expect that most of the classes will come from
511 // the same dex, so this will be more efficient than encoding the dex index
512 // for each class reference.
513 GroupClassesByDex(classes, &dex_to_classes_map);
514 // Add the dex map size.
515 AddUintToBuffer(buffer, static_cast<uint8_t>(dex_to_classes_map.size()));
516 for (const auto& dex_it : dex_to_classes_map) {
517 uint8_t dex_profile_index = dex_it.first;
518 const std::vector<dex::TypeIndex>& dex_classes = dex_it.second;
519 // Add the dex profile index.
520 AddUintToBuffer(buffer, dex_profile_index);
521 // Add the the number of classes for each dex profile index.
522 AddUintToBuffer(buffer, static_cast<uint8_t>(dex_classes.size()));
523 for (size_t i = 0; i < dex_classes.size(); i++) {
524 // Add the type index of the classes.
525 AddUintToBuffer(buffer, dex_classes[i].index_);
526 }
527 }
528 }
529}
530
531uint32_t ProfileCompilationInfo::GetMethodsRegionSize(const DexFileData& dex_data) {
532 // ((uint16_t)method index + (uint16_t)inline cache size) * number of methods
533 uint32_t size = 2 * sizeof(uint16_t) * dex_data.method_map.size();
534 for (const auto& method_it : dex_data.method_map) {
535 const InlineCacheMap& inline_cache = method_it.second;
536 size += sizeof(uint16_t) * inline_cache.size(); // dex_pc
537 for (const auto& inline_cache_it : inline_cache) {
538 const ClassSet& classes = inline_cache_it.second.classes;
539 SafeMap<uint8_t, std::vector<dex::TypeIndex>> dex_to_classes_map;
540 GroupClassesByDex(classes, &dex_to_classes_map);
541 size += sizeof(uint8_t); // dex_to_classes_map size
542 for (const auto& dex_it : dex_to_classes_map) {
543 size += sizeof(uint8_t); // dex profile index
544 size += sizeof(uint8_t); // number of classes
545 const std::vector<dex::TypeIndex>& dex_classes = dex_it.second;
546 size += sizeof(uint16_t) * dex_classes.size(); // the actual classes
547 }
548 }
549 }
550 return size;
551}
552
553void ProfileCompilationInfo::GroupClassesByDex(
554 const ClassSet& classes,
555 /*out*/SafeMap<uint8_t, std::vector<dex::TypeIndex>>* dex_to_classes_map) {
556 for (const auto& classes_it : classes) {
557 auto dex_it = dex_to_classes_map->FindOrAdd(classes_it.dex_profile_index);
558 dex_it->second.push_back(classes_it.type_index);
559 }
560}
561
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800562ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::GetOrAddDexFileData(
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700563 const std::string& profile_key,
Mathieu Chartierea650f32017-05-24 12:04:13 -0700564 uint32_t checksum,
565 uint32_t num_method_ids) {
Vladimir Marko3bada4b2017-05-19 12:32:47 +0100566 const auto profile_index_it = profile_key_map_.FindOrAdd(profile_key, profile_key_map_.size());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700567 if (profile_key_map_.size() > std::numeric_limits<uint8_t>::max()) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800568 // Allow only 255 dex files to be profiled. This allows us to save bytes
569 // when encoding. The number is well above what we expect for normal applications.
570 if (kIsDebugBuild) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700571 LOG(ERROR) << "Exceeded the maximum number of dex files (255). Something went wrong";
Calin Juravle940eb0c2017-01-30 19:30:44 -0800572 }
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700573 profile_key_map_.erase(profile_key);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800574 return nullptr;
Calin Juravle998c2162015-12-21 15:39:33 +0200575 }
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700576
577 uint8_t profile_index = profile_index_it->second;
578 if (info_.size() <= profile_index) {
579 // This is a new addition. Add it to the info_ array.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100580 DexFileData* dex_file_data = new (&allocator_) DexFileData(
581 &allocator_,
Mathieu Chartierea650f32017-05-24 12:04:13 -0700582 profile_key,
583 checksum,
584 profile_index,
585 num_method_ids);
Calin Juravlecc3171a2017-05-19 16:47:53 -0700586 info_.push_back(dex_file_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700587 }
588 DexFileData* result = info_[profile_index];
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700589
590 // Check that the checksum matches.
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700591 // This may different if for example the dex file was updated and we had a record of the old one.
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700592 if (result->checksum != checksum) {
593 LOG(WARNING) << "Checksum mismatch for dex " << profile_key;
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800594 return nullptr;
595 }
Shubham Ajmera61200a02017-08-30 16:29:41 -0700596
597 // DCHECK that profile info map key is consistent with the one stored in the dex file data.
598 // This should always be the case since since the cache map is managed by ProfileCompilationInfo.
599 DCHECK_EQ(profile_key, result->profile_key);
600 DCHECK_EQ(profile_index, result->profile_index);
Calin Juravle1ad1e3f2017-09-19 18:20:37 -0700601
602 if (num_method_ids != result->num_method_ids) {
603 // This should not happen... added to help investigating b/65812889.
604 LOG(ERROR) << "num_method_ids mismatch for dex " << profile_key
605 << ", expected=" << num_method_ids
606 << ", actual=" << result->num_method_ids;
607 return nullptr;
608 }
Shubham Ajmera61200a02017-08-30 16:29:41 -0700609
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700610 return result;
611}
612
613const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexData(
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700614 const std::string& profile_key,
615 uint32_t checksum,
616 bool verify_checksum) const {
Vladimir Marko3bada4b2017-05-19 12:32:47 +0100617 const auto profile_index_it = profile_key_map_.find(profile_key);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700618 if (profile_index_it == profile_key_map_.end()) {
619 return nullptr;
620 }
621
622 uint8_t profile_index = profile_index_it->second;
623 const DexFileData* result = info_[profile_index];
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700624 if (verify_checksum && !ChecksumMatch(result->checksum, checksum)) {
625 return nullptr;
626 }
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700627 DCHECK_EQ(profile_key, result->profile_key);
628 DCHECK_EQ(profile_index, result->profile_index);
629 return result;
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800630}
631
632bool ProfileCompilationInfo::AddResolvedClasses(const DexCacheResolvedClasses& classes) {
633 const std::string dex_location = GetProfileDexFileKey(classes.GetDexLocation());
634 const uint32_t checksum = classes.GetLocationChecksum();
Mathieu Chartierea650f32017-05-24 12:04:13 -0700635 DexFileData* const data = GetOrAddDexFileData(dex_location, checksum, classes.NumMethodIds());
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800636 if (data == nullptr) {
Calin Juravle998c2162015-12-21 15:39:33 +0200637 return false;
638 }
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800639 data->class_set.insert(classes.GetClasses().begin(), classes.GetClasses().end());
640 return true;
641}
642
Calin Juravle940eb0c2017-01-30 19:30:44 -0800643bool ProfileCompilationInfo::AddMethod(const std::string& dex_location,
644 uint32_t dex_checksum,
645 uint16_t method_index,
Mathieu Chartierea650f32017-05-24 12:04:13 -0700646 uint32_t num_method_ids,
Calin Juravle940eb0c2017-01-30 19:30:44 -0800647 const OfflineProfileMethodInfo& pmi) {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700648 DexFileData* const data = GetOrAddDexFileData(GetProfileDexFileKey(dex_location),
649 dex_checksum,
650 num_method_ids);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800651 if (data == nullptr) { // checksum mismatch
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800652 return false;
653 }
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700654 // Add the method.
Calin Juravlecc3171a2017-05-19 16:47:53 -0700655 InlineCacheMap* inline_cache = data->FindOrAddMethod(method_index);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700656
657 if (pmi.inline_caches == nullptr) {
658 // If we don't have inline caches return success right away.
659 return true;
660 }
661 for (const auto& pmi_inline_cache_it : *pmi.inline_caches) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800662 uint16_t pmi_ic_dex_pc = pmi_inline_cache_it.first;
663 const DexPcData& pmi_ic_dex_pc_data = pmi_inline_cache_it.second;
Calin Juravlecc3171a2017-05-19 16:47:53 -0700664 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, pmi_ic_dex_pc);
665 if (dex_pc_data->is_missing_types || dex_pc_data->is_megamorphic) {
Calin Juravle589e71e2017-03-03 16:05:05 -0800666 // We are already megamorphic or we are missing types; no point in going forward.
Calin Juravle940eb0c2017-01-30 19:30:44 -0800667 continue;
668 }
Calin Juravle589e71e2017-03-03 16:05:05 -0800669
670 if (pmi_ic_dex_pc_data.is_missing_types) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700671 dex_pc_data->SetIsMissingTypes();
Calin Juravle589e71e2017-03-03 16:05:05 -0800672 continue;
673 }
674 if (pmi_ic_dex_pc_data.is_megamorphic) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700675 dex_pc_data->SetIsMegamorphic();
Calin Juravle589e71e2017-03-03 16:05:05 -0800676 continue;
677 }
678
Calin Juravle940eb0c2017-01-30 19:30:44 -0800679 for (const ClassReference& class_ref : pmi_ic_dex_pc_data.classes) {
680 const DexReference& dex_ref = pmi.dex_references[class_ref.dex_profile_index];
681 DexFileData* class_dex_data = GetOrAddDexFileData(
682 GetProfileDexFileKey(dex_ref.dex_location),
Mathieu Chartierea650f32017-05-24 12:04:13 -0700683 dex_ref.dex_checksum,
684 dex_ref.num_method_ids);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800685 if (class_dex_data == nullptr) { // checksum mismatch
686 return false;
687 }
Calin Juravlecc3171a2017-05-19 16:47:53 -0700688 dex_pc_data->AddClass(class_dex_data->profile_index, class_ref.type_index);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800689 }
690 }
691 return true;
692}
693
694bool ProfileCompilationInfo::AddMethod(const ProfileMethodInfo& pmi) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700695 DexFileData* const data = GetOrAddDexFileData(pmi.ref.dex_file);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800696 if (data == nullptr) { // checksum mismatch
697 return false;
698 }
Mathieu Chartierfc8b4222017-09-17 13:44:24 -0700699 InlineCacheMap* inline_cache = data->FindOrAddMethod(pmi.ref.index);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800700
701 for (const ProfileMethodInfo::ProfileInlineCache& cache : pmi.inline_caches) {
Calin Juravle589e71e2017-03-03 16:05:05 -0800702 if (cache.is_missing_types) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700703 FindOrAddDexPc(inline_cache, cache.dex_pc)->SetIsMissingTypes();
Calin Juravle589e71e2017-03-03 16:05:05 -0800704 continue;
705 }
Mathieu Chartierdbddc222017-05-24 12:04:13 -0700706 for (const TypeReference& class_ref : cache.classes) {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700707 DexFileData* class_dex_data = GetOrAddDexFileData(class_ref.dex_file);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800708 if (class_dex_data == nullptr) { // checksum mismatch
709 return false;
710 }
Calin Juravlecc3171a2017-05-19 16:47:53 -0700711 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, cache.dex_pc);
712 if (dex_pc_data->is_missing_types) {
Calin Juravle589e71e2017-03-03 16:05:05 -0800713 // Don't bother adding classes if we are missing types.
714 break;
715 }
Mathieu Chartierfc8b4222017-09-17 13:44:24 -0700716 dex_pc_data->AddClass(class_dex_data->profile_index, class_ref.TypeIndex());
Calin Juravle940eb0c2017-01-30 19:30:44 -0800717 }
718 }
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800719 return true;
720}
721
722bool ProfileCompilationInfo::AddClassIndex(const std::string& dex_location,
723 uint32_t checksum,
Mathieu Chartierea650f32017-05-24 12:04:13 -0700724 dex::TypeIndex type_idx,
725 uint32_t num_method_ids) {
726 DexFileData* const data = GetOrAddDexFileData(dex_location, checksum, num_method_ids);
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800727 if (data == nullptr) {
728 return false;
729 }
Jeff Hao54b58552016-11-16 15:15:04 -0800730 data->class_set.insert(type_idx);
Calin Juravle998c2162015-12-21 15:39:33 +0200731 return true;
732}
733
Andreas Gampe37c58462017-03-27 15:14:27 -0700734#define READ_UINT(type, buffer, dest, error) \
735 do { \
736 if (!(buffer).ReadUintAndAdvance<type>(&(dest))) { \
737 *(error) = "Could not read "#dest; \
738 return false; \
739 } \
740 } \
Calin Juravle940eb0c2017-01-30 19:30:44 -0800741 while (false)
742
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700743bool ProfileCompilationInfo::ReadInlineCache(
744 SafeBuffer& buffer,
745 uint8_t number_of_dex_files,
746 const SafeMap<uint8_t, uint8_t>& dex_profile_index_remap,
747 /*out*/ InlineCacheMap* inline_cache,
748 /*out*/ std::string* error) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800749 uint16_t inline_cache_size;
750 READ_UINT(uint16_t, buffer, inline_cache_size, error);
751 for (; inline_cache_size > 0; inline_cache_size--) {
752 uint16_t dex_pc;
753 uint8_t dex_to_classes_map_size;
754 READ_UINT(uint16_t, buffer, dex_pc, error);
755 READ_UINT(uint8_t, buffer, dex_to_classes_map_size, error);
Calin Juravlecc3171a2017-05-19 16:47:53 -0700756 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, dex_pc);
Calin Juravle589e71e2017-03-03 16:05:05 -0800757 if (dex_to_classes_map_size == kIsMissingTypesEncoding) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700758 dex_pc_data->SetIsMissingTypes();
Calin Juravle589e71e2017-03-03 16:05:05 -0800759 continue;
760 }
761 if (dex_to_classes_map_size == kIsMegamorphicEncoding) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700762 dex_pc_data->SetIsMegamorphic();
Calin Juravle940eb0c2017-01-30 19:30:44 -0800763 continue;
764 }
765 for (; dex_to_classes_map_size > 0; dex_to_classes_map_size--) {
766 uint8_t dex_profile_index;
767 uint8_t dex_classes_size;
768 READ_UINT(uint8_t, buffer, dex_profile_index, error);
769 READ_UINT(uint8_t, buffer, dex_classes_size, error);
770 if (dex_profile_index >= number_of_dex_files) {
771 *error = "dex_profile_index out of bounds ";
772 *error += std::to_string(dex_profile_index) + " " + std::to_string(number_of_dex_files);
773 return false;
774 }
775 for (; dex_classes_size > 0; dex_classes_size--) {
776 uint16_t type_index;
777 READ_UINT(uint16_t, buffer, type_index, error);
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700778 dex_pc_data->AddClass(dex_profile_index_remap.Get(dex_profile_index),
779 dex::TypeIndex(type_index));
Calin Juravle940eb0c2017-01-30 19:30:44 -0800780 }
781 }
782 }
783 return true;
784}
785
786bool ProfileCompilationInfo::ReadMethods(SafeBuffer& buffer,
787 uint8_t number_of_dex_files,
788 const ProfileLineHeader& line_header,
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700789 const SafeMap<uint8_t, uint8_t>& dex_profile_index_remap,
Calin Juravle940eb0c2017-01-30 19:30:44 -0800790 /*out*/std::string* error) {
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000791 uint32_t unread_bytes_before_operation = buffer.CountUnreadBytes();
792 if (unread_bytes_before_operation < line_header.method_region_size_bytes) {
793 *error += "Profile EOF reached prematurely for ReadMethod";
794 return kProfileLoadBadData;
795 }
796 size_t expected_unread_bytes_after_operation = buffer.CountUnreadBytes()
797 - line_header.method_region_size_bytes;
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000798 uint16_t last_method_index = 0;
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000799 while (buffer.CountUnreadBytes() > expected_unread_bytes_after_operation) {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700800 DexFileData* const data = GetOrAddDexFileData(line_header.dex_location,
801 line_header.checksum,
802 line_header.num_method_ids);
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000803 uint16_t diff_with_last_method_index;
804 READ_UINT(uint16_t, buffer, diff_with_last_method_index, error);
805 uint16_t method_index = last_method_index + diff_with_last_method_index;
806 last_method_index = method_index;
Calin Juravlecc3171a2017-05-19 16:47:53 -0700807 InlineCacheMap* inline_cache = data->FindOrAddMethod(method_index);
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700808 if (!ReadInlineCache(buffer,
809 number_of_dex_files,
810 dex_profile_index_remap,
811 inline_cache,
812 error)) {
Calin Juravle877fd962016-01-05 14:29:29 +0000813 return false;
814 }
Calin Juravle226501b2015-12-11 14:41:31 +0000815 }
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000816 uint32_t total_bytes_read = unread_bytes_before_operation - buffer.CountUnreadBytes();
817 if (total_bytes_read != line_header.method_region_size_bytes) {
818 *error += "Profile data inconsistent for ReadMethods";
819 return false;
820 }
Calin Juravle940eb0c2017-01-30 19:30:44 -0800821 return true;
822}
823
824bool ProfileCompilationInfo::ReadClasses(SafeBuffer& buffer,
Calin Juravle940eb0c2017-01-30 19:30:44 -0800825 const ProfileLineHeader& line_header,
826 /*out*/std::string* error) {
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000827 size_t unread_bytes_before_op = buffer.CountUnreadBytes();
828 if (unread_bytes_before_op < line_header.class_set_size) {
829 *error += "Profile EOF reached prematurely for ReadClasses";
830 return kProfileLoadBadData;
831 }
832
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000833 uint16_t last_class_index = 0;
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000834 for (uint16_t i = 0; i < line_header.class_set_size; i++) {
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000835 uint16_t diff_with_last_class_index;
836 READ_UINT(uint16_t, buffer, diff_with_last_class_index, error);
837 uint16_t type_index = last_class_index + diff_with_last_class_index;
838 last_class_index = type_index;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800839 if (!AddClassIndex(line_header.dex_location,
840 line_header.checksum,
Mathieu Chartierea650f32017-05-24 12:04:13 -0700841 dex::TypeIndex(type_index),
842 line_header.num_method_ids)) {
Calin Juravle64142952016-03-21 14:37:55 +0000843 return false;
844 }
845 }
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000846 size_t total_bytes_read = unread_bytes_before_op - buffer.CountUnreadBytes();
847 uint32_t expected_bytes_read = line_header.class_set_size * sizeof(uint16_t);
848 if (total_bytes_read != expected_bytes_read) {
849 *error += "Profile data inconsistent for ReadClasses";
850 return false;
851 }
Calin Juravle226501b2015-12-11 14:41:31 +0000852 return true;
853}
854
Calin Juravle64142952016-03-21 14:37:55 +0000855// Tests for EOF by trying to read 1 byte from the descriptor.
856// Returns:
857// 0 if the descriptor is at the EOF,
858// -1 if there was an IO error
859// 1 if the descriptor has more content to read
860static int testEOF(int fd) {
861 uint8_t buffer[1];
862 return TEMP_FAILURE_RETRY(read(fd, buffer, 1));
863}
864
865// Reads an uint value previously written with AddUintToBuffer.
866template <typename T>
Calin Juravle940eb0c2017-01-30 19:30:44 -0800867bool ProfileCompilationInfo::SafeBuffer::ReadUintAndAdvance(/*out*/T* value) {
Calin Juravle64142952016-03-21 14:37:55 +0000868 static_assert(std::is_unsigned<T>::value, "Type is not unsigned");
Calin Juravle940eb0c2017-01-30 19:30:44 -0800869 if (ptr_current_ + sizeof(T) > ptr_end_) {
870 return false;
871 }
872 *value = 0;
Calin Juravle64142952016-03-21 14:37:55 +0000873 for (size_t i = 0; i < sizeof(T); i++) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800874 *value += ptr_current_[i] << (i * kBitsPerByte);
Calin Juravle226501b2015-12-11 14:41:31 +0000875 }
Calin Juravle64142952016-03-21 14:37:55 +0000876 ptr_current_ += sizeof(T);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800877 return true;
Calin Juravle64142952016-03-21 14:37:55 +0000878}
879
880bool ProfileCompilationInfo::SafeBuffer::CompareAndAdvance(const uint8_t* data, size_t data_size) {
881 if (ptr_current_ + data_size > ptr_end_) {
882 return false;
883 }
884 if (memcmp(ptr_current_, data, data_size) == 0) {
885 ptr_current_ += data_size;
886 return true;
887 }
888 return false;
889}
890
Calin Juravle36060d12018-01-19 16:28:38 -0800891ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::SafeBuffer::Fill(
Calin Juravle1e2de642018-01-18 01:08:23 -0800892 ProfileSource& source,
893 const std::string& debug_stage,
894 /*out*/ std::string* error) {
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000895 size_t byte_count = (ptr_end_ - ptr_current_) * sizeof(*ptr_current_);
Calin Juravle64142952016-03-21 14:37:55 +0000896 uint8_t* buffer = ptr_current_;
Calin Juravle1e2de642018-01-18 01:08:23 -0800897 return source.Read(buffer, byte_count, debug_stage, error);
Calin Juravle64142952016-03-21 14:37:55 +0000898}
899
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000900size_t ProfileCompilationInfo::SafeBuffer::CountUnreadBytes() {
901 return (ptr_end_ - ptr_current_) * sizeof(*ptr_current_);
902}
903
904const uint8_t* ProfileCompilationInfo::SafeBuffer::GetCurrentPtr() {
905 return ptr_current_;
906}
907
908void ProfileCompilationInfo::SafeBuffer::Advance(size_t data_size) {
909 ptr_current_ += data_size;
910}
911
Calin Juravle36060d12018-01-19 16:28:38 -0800912ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadProfileHeader(
Calin Juravle1e2de642018-01-18 01:08:23 -0800913 ProfileSource& source,
Calin Juravle940eb0c2017-01-30 19:30:44 -0800914 /*out*/uint8_t* number_of_dex_files,
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000915 /*out*/uint32_t* uncompressed_data_size,
916 /*out*/uint32_t* compressed_data_size,
Calin Juravle64142952016-03-21 14:37:55 +0000917 /*out*/std::string* error) {
918 // Read magic and version
919 const size_t kMagicVersionSize =
920 sizeof(kProfileMagic) +
921 sizeof(kProfileVersion) +
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000922 sizeof(uint8_t) + // number of dex files
923 sizeof(uint32_t) + // size of uncompressed profile data
924 sizeof(uint32_t); // size of compressed profile data
Calin Juravle64142952016-03-21 14:37:55 +0000925
926 SafeBuffer safe_buffer(kMagicVersionSize);
927
Calin Juravle36060d12018-01-19 16:28:38 -0800928 ProfileLoadStatus status = safe_buffer.Fill(source, "ReadProfileHeader", error);
Calin Juravle64142952016-03-21 14:37:55 +0000929 if (status != kProfileLoadSuccess) {
930 return status;
931 }
932
933 if (!safe_buffer.CompareAndAdvance(kProfileMagic, sizeof(kProfileMagic))) {
934 *error = "Profile missing magic";
935 return kProfileLoadVersionMismatch;
936 }
937 if (!safe_buffer.CompareAndAdvance(kProfileVersion, sizeof(kProfileVersion))) {
938 *error = "Profile version mismatch";
939 return kProfileLoadVersionMismatch;
940 }
Calin Juravle940eb0c2017-01-30 19:30:44 -0800941 if (!safe_buffer.ReadUintAndAdvance<uint8_t>(number_of_dex_files)) {
942 *error = "Cannot read the number of dex files";
943 return kProfileLoadBadData;
944 }
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000945 if (!safe_buffer.ReadUintAndAdvance<uint32_t>(uncompressed_data_size)) {
946 *error = "Cannot read the size of uncompressed data";
947 return kProfileLoadBadData;
948 }
949 if (!safe_buffer.ReadUintAndAdvance<uint32_t>(compressed_data_size)) {
950 *error = "Cannot read the size of compressed data";
951 return kProfileLoadBadData;
952 }
Calin Juravle64142952016-03-21 14:37:55 +0000953 return kProfileLoadSuccess;
954}
955
Calin Juravle940eb0c2017-01-30 19:30:44 -0800956bool ProfileCompilationInfo::ReadProfileLineHeaderElements(SafeBuffer& buffer,
957 /*out*/uint16_t* dex_location_size,
958 /*out*/ProfileLineHeader* line_header,
959 /*out*/std::string* error) {
960 READ_UINT(uint16_t, buffer, *dex_location_size, error);
961 READ_UINT(uint16_t, buffer, line_header->class_set_size, error);
962 READ_UINT(uint32_t, buffer, line_header->method_region_size_bytes, error);
963 READ_UINT(uint32_t, buffer, line_header->checksum, error);
Mathieu Chartierea650f32017-05-24 12:04:13 -0700964 READ_UINT(uint32_t, buffer, line_header->num_method_ids, error);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800965 return true;
966}
967
Calin Juravle36060d12018-01-19 16:28:38 -0800968ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadProfileLineHeader(
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000969 SafeBuffer& buffer,
970 /*out*/ProfileLineHeader* line_header,
971 /*out*/std::string* error) {
972 if (buffer.CountUnreadBytes() < kLineHeaderSize) {
973 *error += "Profile EOF reached prematurely for ReadProfileLineHeader";
974 return kProfileLoadBadData;
Calin Juravle64142952016-03-21 14:37:55 +0000975 }
976
Calin Juravle940eb0c2017-01-30 19:30:44 -0800977 uint16_t dex_location_size;
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000978 if (!ReadProfileLineHeaderElements(buffer, &dex_location_size, line_header, error)) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800979 return kProfileLoadBadData;
980 }
Calin Juravle64142952016-03-21 14:37:55 +0000981
982 if (dex_location_size == 0 || dex_location_size > kMaxDexFileKeyLength) {
Goran Jakovljevic4eb6fbf2016-04-25 19:14:17 +0200983 *error = "DexFileKey has an invalid size: " +
984 std::to_string(static_cast<uint32_t>(dex_location_size));
Calin Juravle64142952016-03-21 14:37:55 +0000985 return kProfileLoadBadData;
986 }
987
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000988 if (buffer.CountUnreadBytes() < dex_location_size) {
989 *error += "Profile EOF reached prematurely for ReadProfileHeaderDexLocation";
990 return kProfileLoadBadData;
Calin Juravle64142952016-03-21 14:37:55 +0000991 }
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000992 const uint8_t* base_ptr = buffer.GetCurrentPtr();
Calin Juravle64142952016-03-21 14:37:55 +0000993 line_header->dex_location.assign(
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000994 reinterpret_cast<const char*>(base_ptr), dex_location_size);
995 buffer.Advance(dex_location_size);
Calin Juravle64142952016-03-21 14:37:55 +0000996 return kProfileLoadSuccess;
997}
998
Calin Juravle36060d12018-01-19 16:28:38 -0800999ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadProfileLine(
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001000 SafeBuffer& buffer,
Calin Juravle940eb0c2017-01-30 19:30:44 -08001001 uint8_t number_of_dex_files,
Calin Juravle64142952016-03-21 14:37:55 +00001002 const ProfileLineHeader& line_header,
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001003 const SafeMap<uint8_t, uint8_t>& dex_profile_index_remap,
1004 bool merge_classes,
Calin Juravle64142952016-03-21 14:37:55 +00001005 /*out*/std::string* error) {
Mathieu Chartierea650f32017-05-24 12:04:13 -07001006 DexFileData* data = GetOrAddDexFileData(line_header.dex_location,
1007 line_header.checksum,
1008 line_header.num_method_ids);
1009 if (data == nullptr) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001010 *error = "Error when reading profile file line header: checksum mismatch for "
1011 + line_header.dex_location;
1012 return kProfileLoadBadData;
1013 }
Calin Juravle64142952016-03-21 14:37:55 +00001014
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001015 if (!ReadMethods(buffer, number_of_dex_files, line_header, dex_profile_index_remap, error)) {
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001016 return kProfileLoadBadData;
Calin Juravle64142952016-03-21 14:37:55 +00001017 }
Calin Juravle940eb0c2017-01-30 19:30:44 -08001018
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001019 if (merge_classes) {
1020 if (!ReadClasses(buffer, line_header, error)) {
1021 return kProfileLoadBadData;
1022 }
Calin Juravle940eb0c2017-01-30 19:30:44 -08001023 }
Mathieu Chartierea650f32017-05-24 12:04:13 -07001024
1025 const size_t bytes = data->bitmap_storage.size();
1026 if (buffer.CountUnreadBytes() < bytes) {
1027 *error += "Profile EOF reached prematurely for ReadProfileHeaderDexLocation";
1028 return kProfileLoadBadData;
1029 }
1030 const uint8_t* base_ptr = buffer.GetCurrentPtr();
Andreas Gampe693bfbf2017-11-10 12:23:31 -08001031 std::copy_n(base_ptr, bytes, data->bitmap_storage.data());
Mathieu Chartierea650f32017-05-24 12:04:13 -07001032 buffer.Advance(bytes);
1033 // Read method bitmap.
Calin Juravle64142952016-03-21 14:37:55 +00001034 return kProfileLoadSuccess;
Calin Juravle226501b2015-12-11 14:41:31 +00001035}
1036
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001037// TODO(calin): Fix this API. ProfileCompilationInfo::Load should be static and
1038// return a unique pointer to a ProfileCompilationInfo upon success.
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001039bool ProfileCompilationInfo::Load(int fd, bool merge_classes) {
Calin Juravle64142952016-03-21 14:37:55 +00001040 std::string error;
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001041
Calin Juravle36060d12018-01-19 16:28:38 -08001042 ProfileLoadStatus status = LoadInternal(fd, &error, merge_classes);
Calin Juravle64142952016-03-21 14:37:55 +00001043
1044 if (status == kProfileLoadSuccess) {
1045 return true;
1046 } else {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001047 LOG(WARNING) << "Error when reading profile: " << error;
Calin Juravle64142952016-03-21 14:37:55 +00001048 return false;
1049 }
1050}
1051
Shubham Ajmera188b2bf2017-09-20 15:53:35 -07001052bool ProfileCompilationInfo::VerifyProfileData(const std::vector<const DexFile*>& dex_files) {
1053 std::unordered_map<std::string, const DexFile*> key_to_dex_file;
1054 for (const DexFile* dex_file : dex_files) {
1055 key_to_dex_file.emplace(GetProfileDexFileKey(dex_file->GetLocation()), dex_file);
1056 }
1057 for (const DexFileData* dex_data : info_) {
1058 const auto it = key_to_dex_file.find(dex_data->profile_key);
1059 if (it == key_to_dex_file.end()) {
1060 // It is okay if profile contains data for additional dex files.
1061 continue;
1062 }
1063 const DexFile* dex_file = it->second;
1064 const std::string& dex_location = dex_file->GetLocation();
1065 if (!ChecksumMatch(dex_data->checksum, dex_file->GetLocationChecksum())) {
1066 LOG(ERROR) << "Dex checksum mismatch while verifying profile "
1067 << "dex location " << dex_location << " (checksum="
1068 << dex_file->GetLocationChecksum() << ", profile checksum="
1069 << dex_data->checksum;
1070 return false;
1071 }
Shubham Ajmera460ab792017-09-21 13:44:07 -07001072
1073 if (dex_data->num_method_ids != dex_file->NumMethodIds()) {
1074 LOG(ERROR) << "Number of method ids in dex file and profile don't match."
1075 << "dex location " << dex_location << " NumMethodId in DexFile"
1076 << dex_file->NumMethodIds() << ", NumMethodId in profile"
1077 << dex_data->num_method_ids;
1078 return false;
1079 }
1080
Shubham Ajmera188b2bf2017-09-20 15:53:35 -07001081 // Verify method_encoding.
1082 for (const auto& method_it : dex_data->method_map) {
1083 size_t method_id = (size_t)(method_it.first);
1084 if (method_id >= dex_file->NumMethodIds()) {
1085 LOG(ERROR) << "Invalid method id in profile file. dex location="
1086 << dex_location << " method_id=" << method_id << " NumMethodIds="
1087 << dex_file->NumMethodIds();
1088 return false;
1089 }
1090
1091 // Verify class indices of inline caches.
1092 const InlineCacheMap &inline_cache_map = method_it.second;
1093 for (const auto& inline_cache_it : inline_cache_map) {
1094 const DexPcData dex_pc_data = inline_cache_it.second;
1095 if (dex_pc_data.is_missing_types || dex_pc_data.is_megamorphic) {
1096 // No class indices to verify.
1097 continue;
1098 }
1099
1100 const ClassSet &classes = dex_pc_data.classes;
1101 SafeMap<uint8_t, std::vector<dex::TypeIndex>> dex_to_classes_map;
1102 // Group the classes by dex. We expect that most of the classes will come from
1103 // the same dex, so this will be more efficient than encoding the dex index
1104 // for each class reference.
1105 GroupClassesByDex(classes, &dex_to_classes_map);
1106 for (const auto &dex_it : dex_to_classes_map) {
1107 uint8_t dex_profile_index = dex_it.first;
1108 const auto dex_file_inline_cache_it = key_to_dex_file.find(
1109 info_[dex_profile_index]->profile_key);
1110 if (dex_file_inline_cache_it == key_to_dex_file.end()) {
1111 // It is okay if profile contains data for additional dex files.
1112 continue;
1113 }
1114 const DexFile *dex_file_for_inline_cache_check = dex_file_inline_cache_it->second;
1115 const std::vector<dex::TypeIndex> &dex_classes = dex_it.second;
1116 for (size_t i = 0; i < dex_classes.size(); i++) {
1117 if (dex_classes[i].index_ >= dex_file_for_inline_cache_check->NumTypeIds()) {
1118 LOG(ERROR) << "Invalid inline cache in profile file. dex location="
1119 << dex_location << " method_id=" << method_id
1120 << " dex_profile_index="
1121 << static_cast<uint16_t >(dex_profile_index) << " type_index="
1122 << dex_classes[i].index_
1123 << " NumTypeIds="
1124 << dex_file_for_inline_cache_check->NumTypeIds();
1125 return false;
1126 }
1127 }
1128 }
1129 }
1130 }
1131 // Verify class_ids.
1132 for (const auto& class_id : dex_data->class_set) {
1133 if (class_id.index_ >= dex_file->NumTypeIds()) {
1134 LOG(ERROR) << "Invalid class id in profile file. dex_file location "
1135 << dex_location << " class_id=" << class_id.index_ << " NumClassIds="
1136 << dex_file->NumClassDefs();
1137 return false;
1138 }
1139 }
1140 }
1141 return true;
1142}
1143
Calin Juravle36060d12018-01-19 16:28:38 -08001144ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::OpenSource(
Calin Juravle1e2de642018-01-18 01:08:23 -08001145 int32_t fd,
1146 /*out*/ std::unique_ptr<ProfileSource>* source,
1147 /*out*/ std::string* error) {
1148 if (IsProfileFile(fd)) {
1149 source->reset(ProfileSource::Create(fd));
1150 return kProfileLoadSuccess;
1151 } else {
1152 std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, "profile", error));
1153 if (zip_archive.get() == nullptr) {
1154 *error = "Could not open the profile zip archive";
1155 return kProfileLoadBadData;
1156 }
1157 std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(kDexMetadataProfileEntry, error));
1158 if (zip_entry == nullptr) {
1159 // Allow archives without the profile entry. In this case, create an empty profile.
1160 // This gives more flexible when ure-using archives that may miss the entry.
1161 // (e.g. dex metadata files)
1162 LOG(WARNING) << std::string("Could not find entry ") + kDexMetadataProfileEntry +
1163 " in the zip archive. Creating an empty profile.";
1164 source->reset(ProfileSource::Create(nullptr));
1165 return kProfileLoadSuccess;
1166 }
1167 if (zip_entry->GetUncompressedLength() == 0) {
1168 *error = "Empty profile entry in the zip archive.";
1169 return kProfileLoadBadData;
1170 }
1171
1172 std::unique_ptr<MemMap> map;
1173 if (zip_entry->IsUncompressed()) {
1174 // Map uncompressed files within zip as file-backed to avoid a dirty copy.
1175 map.reset(zip_entry->MapDirectlyFromFile(kDexMetadataProfileEntry, error));
1176 if (map == nullptr) {
1177 LOG(WARNING) << "Can't mmap profile directly; "
1178 << "is your ZIP file corrupted? Falling back to extraction.";
1179 // Try again with Extraction which still has a chance of recovery.
1180 }
1181 }
1182
1183 if (map == nullptr) {
1184 // Default path for compressed ZIP entries, and fallback for stored ZIP entries.
1185 // TODO(calin) pass along file names to assist with debugging.
1186 map.reset(zip_entry->ExtractToMemMap("profile file", kDexMetadataProfileEntry, error));
1187 }
1188
1189 if (map != nullptr) {
1190 source->reset(ProfileSource::Create(std::move(map)));
1191 return kProfileLoadSuccess;
1192 } else {
1193 return kProfileLoadBadData;
1194 }
1195 }
1196}
1197
Calin Juravle36060d12018-01-19 16:28:38 -08001198ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ProfileSource::Read(
Calin Juravle1e2de642018-01-18 01:08:23 -08001199 uint8_t* buffer,
1200 size_t byte_count,
1201 const std::string& debug_stage,
1202 std::string* error) {
1203 if (IsMemMap()) {
1204 if (mem_map_cur_ + byte_count > mem_map_->Size()) {
1205 return kProfileLoadBadData;
1206 }
1207 for (size_t i = 0; i < byte_count; i++) {
1208 buffer[i] = *(mem_map_->Begin() + mem_map_cur_);
1209 mem_map_cur_++;
1210 }
1211 } else {
1212 while (byte_count > 0) {
1213 int bytes_read = TEMP_FAILURE_RETRY(read(fd_, buffer, byte_count));;
1214 if (bytes_read == 0) {
1215 *error += "Profile EOF reached prematurely for " + debug_stage;
1216 return kProfileLoadBadData;
1217 } else if (bytes_read < 0) {
1218 *error += "Profile IO error for " + debug_stage + strerror(errno);
1219 return kProfileLoadIOError;
1220 }
1221 byte_count -= bytes_read;
1222 buffer += bytes_read;
1223 }
1224 }
1225 return kProfileLoadSuccess;
1226}
1227
1228bool ProfileCompilationInfo::ProfileSource::HasConsumedAllData() const {
1229 return IsMemMap()
1230 ? (mem_map_ == nullptr || mem_map_cur_ == mem_map_->Size())
1231 : (testEOF(fd_) == 0);
1232}
1233
1234bool ProfileCompilationInfo::ProfileSource::HasEmptyContent() const {
1235 if (IsMemMap()) {
1236 return mem_map_ == nullptr || mem_map_->Size() == 0;
1237 } else {
1238 struct stat stat_buffer;
1239 if (fstat(fd_, &stat_buffer) != 0) {
1240 return false;
1241 }
1242 return stat_buffer.st_size == 0;
1243 }
1244}
1245
Calin Juravledcab1902017-05-12 19:18:47 -07001246// TODO(calin): fail fast if the dex checksums don't match.
Calin Juravle36060d12018-01-19 16:28:38 -08001247ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::LoadInternal(
Calin Juravle1e2de642018-01-18 01:08:23 -08001248 int32_t fd, std::string* error, bool merge_classes) {
Mathieu Chartier32ce2ad2016-03-04 14:58:03 -08001249 ScopedTrace trace(__PRETTY_FUNCTION__);
Calin Juravle2e2db782016-02-23 12:00:03 +00001250 DCHECK_GE(fd, 0);
Calin Juravle226501b2015-12-11 14:41:31 +00001251
Calin Juravle1e2de642018-01-18 01:08:23 -08001252 std::unique_ptr<ProfileSource> source;
Calin Juravle36060d12018-01-19 16:28:38 -08001253 ProfileLoadStatus status = OpenSource(fd, &source, error);
Calin Juravle1e2de642018-01-18 01:08:23 -08001254 if (status != kProfileLoadSuccess) {
1255 return status;
Calin Juravle226501b2015-12-11 14:41:31 +00001256 }
Calin Juravle1e2de642018-01-18 01:08:23 -08001257
Calin Juravle64142952016-03-21 14:37:55 +00001258 // We allow empty profile files.
1259 // Profiles may be created by ActivityManager or installd before we manage to
1260 // process them in the runtime or profman.
Calin Juravle1e2de642018-01-18 01:08:23 -08001261 if (source->HasEmptyContent()) {
Calin Juravle64142952016-03-21 14:37:55 +00001262 return kProfileLoadSuccess;
1263 }
Calin Juravle1e2de642018-01-18 01:08:23 -08001264
Calin Juravle940eb0c2017-01-30 19:30:44 -08001265 // Read profile header: magic + version + number_of_dex_files.
1266 uint8_t number_of_dex_files;
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001267 uint32_t uncompressed_data_size;
1268 uint32_t compressed_data_size;
Calin Juravle1e2de642018-01-18 01:08:23 -08001269 status = ReadProfileHeader(*source,
1270 &number_of_dex_files,
1271 &uncompressed_data_size,
1272 &compressed_data_size,
1273 error);
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001274
Calin Juravle64142952016-03-21 14:37:55 +00001275 if (status != kProfileLoadSuccess) {
1276 return status;
1277 }
Mathieu Chartierf2e2af82017-07-12 21:09:57 -07001278 // Allow large profiles for non target builds for the case where we are merging many profiles
1279 // to generate a boot image profile.
1280 if (kIsTargetBuild && uncompressed_data_size > kProfileSizeErrorThresholdInBytes) {
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001281 LOG(ERROR) << "Profile data size exceeds "
1282 << std::to_string(kProfileSizeErrorThresholdInBytes)
1283 << " bytes";
1284 return kProfileLoadBadData;
1285 }
1286 if (uncompressed_data_size > kProfileSizeWarningThresholdInBytes) {
1287 LOG(WARNING) << "Profile data size exceeds "
1288 << std::to_string(kProfileSizeWarningThresholdInBytes)
1289 << " bytes";
1290 }
1291
1292 std::unique_ptr<uint8_t[]> compressed_data(new uint8_t[compressed_data_size]);
Calin Juravle1e2de642018-01-18 01:08:23 -08001293 status = source->Read(compressed_data.get(), compressed_data_size, "ReadContent", error);
1294 if (status != kProfileLoadSuccess) {
1295 *error += "Unable to read compressed profile data";
1296 return status;
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001297 }
1298
Calin Juravle1e2de642018-01-18 01:08:23 -08001299 if (!source->HasConsumedAllData()) {
1300 *error += "Unexpected data in the profile file.";
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001301 return kProfileLoadBadData;
1302 }
1303
1304 SafeBuffer uncompressed_data(uncompressed_data_size);
1305
1306 int ret = InflateBuffer(compressed_data.get(),
1307 compressed_data_size,
1308 uncompressed_data_size,
1309 uncompressed_data.Get());
1310
1311 if (ret != Z_STREAM_END) {
1312 *error += "Error reading uncompressed profile data";
1313 return kProfileLoadBadData;
1314 }
1315
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001316 std::vector<ProfileLineHeader> profile_line_headers;
1317 // Read profile line headers.
Calin Juravle940eb0c2017-01-30 19:30:44 -08001318 for (uint8_t k = 0; k < number_of_dex_files; k++) {
Calin Juravle64142952016-03-21 14:37:55 +00001319 ProfileLineHeader line_header;
Calin Juravle940eb0c2017-01-30 19:30:44 -08001320
Calin Juravle64142952016-03-21 14:37:55 +00001321 // First, read the line header to get the amount of data we need to read.
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001322 status = ReadProfileLineHeader(uncompressed_data, &line_header, error);
Calin Juravle64142952016-03-21 14:37:55 +00001323 if (status != kProfileLoadSuccess) {
1324 return status;
1325 }
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001326 profile_line_headers.push_back(line_header);
1327 }
Calin Juravle64142952016-03-21 14:37:55 +00001328
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001329 SafeMap<uint8_t, uint8_t> dex_profile_index_remap;
1330 if (!RemapProfileIndex(profile_line_headers, &dex_profile_index_remap)) {
1331 return kProfileLoadBadData;
1332 }
1333
1334 for (uint8_t k = 0; k < number_of_dex_files; k++) {
Calin Juravle64142952016-03-21 14:37:55 +00001335 // Now read the actual profile line.
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001336 status = ReadProfileLine(uncompressed_data,
1337 number_of_dex_files,
1338 profile_line_headers[k],
1339 dex_profile_index_remap,
1340 merge_classes,
1341 error);
Calin Juravle64142952016-03-21 14:37:55 +00001342 if (status != kProfileLoadSuccess) {
1343 return status;
1344 }
Calin Juravle64142952016-03-21 14:37:55 +00001345 }
1346
1347 // Check that we read everything and that profiles don't contain junk data.
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001348 if (uncompressed_data.CountUnreadBytes() > 0) {
Calin Juravle64142952016-03-21 14:37:55 +00001349 *error = "Unexpected content in the profile file";
1350 return kProfileLoadBadData;
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001351 } else {
1352 return kProfileLoadSuccess;
Calin Juravle64142952016-03-21 14:37:55 +00001353 }
Calin Juravle998c2162015-12-21 15:39:33 +02001354}
1355
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001356bool ProfileCompilationInfo::RemapProfileIndex(
1357 const std::vector<ProfileLineHeader>& profile_line_headers,
1358 /*out*/SafeMap<uint8_t, uint8_t>* dex_profile_index_remap) {
1359 // First verify that all checksums match. This will avoid adding garbage to
1360 // the current profile info.
1361 // Note that the number of elements should be very small, so this should not
1362 // be a performance issue.
1363 for (const ProfileLineHeader other_profile_line_header : profile_line_headers) {
1364 // verify_checksum is false because we want to differentiate between a missing dex data and
1365 // a mismatched checksum.
1366 const DexFileData* dex_data = FindDexData(other_profile_line_header.dex_location,
1367 0u,
1368 false /* verify_checksum */);
1369 if ((dex_data != nullptr) && (dex_data->checksum != other_profile_line_header.checksum)) {
1370 LOG(WARNING) << "Checksum mismatch for dex " << other_profile_line_header.dex_location;
1371 return false;
1372 }
1373 }
1374 // All checksums match. Import the data.
1375 uint32_t num_dex_files = static_cast<uint32_t>(profile_line_headers.size());
1376 for (uint32_t i = 0; i < num_dex_files; i++) {
1377 const DexFileData* dex_data = GetOrAddDexFileData(profile_line_headers[i].dex_location,
1378 profile_line_headers[i].checksum,
1379 profile_line_headers[i].num_method_ids);
1380 if (dex_data == nullptr) {
1381 return false; // Could happen if we exceed the number of allowed dex files.
1382 }
1383 dex_profile_index_remap->Put(i, dex_data->profile_index);
1384 }
1385 return true;
1386}
Shubham Ajmera61200a02017-08-30 16:29:41 -07001387
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001388std::unique_ptr<uint8_t[]> ProfileCompilationInfo::DeflateBuffer(const uint8_t* in_buffer,
1389 uint32_t in_size,
1390 uint32_t* compressed_data_size) {
1391 z_stream strm;
1392 strm.zalloc = Z_NULL;
1393 strm.zfree = Z_NULL;
1394 strm.opaque = Z_NULL;
1395 int ret = deflateInit(&strm, 1);
1396 if (ret != Z_OK) {
1397 return nullptr;
1398 }
1399
1400 uint32_t out_size = deflateBound(&strm, in_size);
1401
1402 std::unique_ptr<uint8_t[]> compressed_buffer(new uint8_t[out_size]);
1403 strm.avail_in = in_size;
1404 strm.next_in = const_cast<uint8_t*>(in_buffer);
1405 strm.avail_out = out_size;
1406 strm.next_out = &compressed_buffer[0];
1407 ret = deflate(&strm, Z_FINISH);
1408 if (ret == Z_STREAM_ERROR) {
1409 return nullptr;
1410 }
1411 *compressed_data_size = out_size - strm.avail_out;
1412 deflateEnd(&strm);
1413 return compressed_buffer;
1414}
1415
1416int ProfileCompilationInfo::InflateBuffer(const uint8_t* in_buffer,
1417 uint32_t in_size,
1418 uint32_t expected_uncompressed_data_size,
1419 uint8_t* out_buffer) {
1420 z_stream strm;
1421
1422 /* allocate inflate state */
1423 strm.zalloc = Z_NULL;
1424 strm.zfree = Z_NULL;
1425 strm.opaque = Z_NULL;
1426 strm.avail_in = in_size;
1427 strm.next_in = const_cast<uint8_t*>(in_buffer);
1428 strm.avail_out = expected_uncompressed_data_size;
1429 strm.next_out = out_buffer;
1430
1431 int ret;
1432 inflateInit(&strm);
1433 ret = inflate(&strm, Z_NO_FLUSH);
1434
1435 if (strm.avail_in != 0 || strm.avail_out != 0) {
1436 return Z_DATA_ERROR;
1437 }
1438 inflateEnd(&strm);
1439 return ret;
1440}
1441
Mathieu Chartier2f794552017-06-19 10:58:08 -07001442bool ProfileCompilationInfo::MergeWith(const ProfileCompilationInfo& other,
1443 bool merge_classes) {
Calin Juravle5d1bd0a2016-03-24 20:33:22 +00001444 // First verify that all checksums match. This will avoid adding garbage to
1445 // the current profile info.
1446 // Note that the number of elements should be very small, so this should not
1447 // be a performance issue.
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001448 for (const DexFileData* other_dex_data : other.info_) {
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001449 // verify_checksum is false because we want to differentiate between a missing dex data and
1450 // a mismatched checksum.
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001451 const DexFileData* dex_data = FindDexData(other_dex_data->profile_key,
1452 0u,
1453 /* verify_checksum */ false);
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001454 if ((dex_data != nullptr) && (dex_data->checksum != other_dex_data->checksum)) {
1455 LOG(WARNING) << "Checksum mismatch for dex " << other_dex_data->profile_key;
Calin Juravle5d1bd0a2016-03-24 20:33:22 +00001456 return false;
1457 }
1458 }
1459 // All checksums match. Import the data.
Calin Juravle940eb0c2017-01-30 19:30:44 -08001460
1461 // The other profile might have a different indexing of dex files.
1462 // That is because each dex files gets a 'dex_profile_index' on a first come first served basis.
1463 // That means that the order in with the methods are added to the profile matters for the
1464 // actual indices.
1465 // The reason we cannot rely on the actual multidex index is that a single profile may store
1466 // data from multiple splits. This means that a profile may contain a classes2.dex from split-A
1467 // and one from split-B.
1468
1469 // First, build a mapping from other_dex_profile_index to this_dex_profile_index.
1470 // This will make sure that the ClassReferences will point to the correct dex file.
1471 SafeMap<uint8_t, uint8_t> dex_profile_index_remap;
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001472 for (const DexFileData* other_dex_data : other.info_) {
1473 const DexFileData* dex_data = GetOrAddDexFileData(other_dex_data->profile_key,
Mathieu Chartierea650f32017-05-24 12:04:13 -07001474 other_dex_data->checksum,
1475 other_dex_data->num_method_ids);
Calin Juravlee0ac1152017-02-13 19:03:47 -08001476 if (dex_data == nullptr) {
1477 return false; // Could happen if we exceed the number of allowed dex files.
1478 }
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001479 dex_profile_index_remap.Put(other_dex_data->profile_index, dex_data->profile_index);
Calin Juravle940eb0c2017-01-30 19:30:44 -08001480 }
1481
1482 // Merge the actual profile data.
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001483 for (const DexFileData* other_dex_data : other.info_) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001484 DexFileData* dex_data = const_cast<DexFileData*>(FindDexData(other_dex_data->profile_key,
1485 other_dex_data->checksum));
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001486 DCHECK(dex_data != nullptr);
Calin Juravle940eb0c2017-01-30 19:30:44 -08001487
1488 // Merge the classes.
Mathieu Chartier2f794552017-06-19 10:58:08 -07001489 if (merge_classes) {
1490 dex_data->class_set.insert(other_dex_data->class_set.begin(),
1491 other_dex_data->class_set.end());
1492 }
Calin Juravle940eb0c2017-01-30 19:30:44 -08001493
1494 // Merge the methods and the inline caches.
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001495 for (const auto& other_method_it : other_dex_data->method_map) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001496 uint16_t other_method_index = other_method_it.first;
Calin Juravlecc3171a2017-05-19 16:47:53 -07001497 InlineCacheMap* inline_cache = dex_data->FindOrAddMethod(other_method_index);
Calin Juravle940eb0c2017-01-30 19:30:44 -08001498 const auto& other_inline_cache = other_method_it.second;
1499 for (const auto& other_ic_it : other_inline_cache) {
1500 uint16_t other_dex_pc = other_ic_it.first;
1501 const ClassSet& other_class_set = other_ic_it.second.classes;
Calin Juravlecc3171a2017-05-19 16:47:53 -07001502 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, other_dex_pc);
Calin Juravle589e71e2017-03-03 16:05:05 -08001503 if (other_ic_it.second.is_missing_types) {
Calin Juravlecc3171a2017-05-19 16:47:53 -07001504 dex_pc_data->SetIsMissingTypes();
Calin Juravle589e71e2017-03-03 16:05:05 -08001505 } else if (other_ic_it.second.is_megamorphic) {
Calin Juravlecc3171a2017-05-19 16:47:53 -07001506 dex_pc_data->SetIsMegamorphic();
Calin Juravle0def68d2017-02-21 19:00:33 -08001507 } else {
1508 for (const auto& class_it : other_class_set) {
Calin Juravlecc3171a2017-05-19 16:47:53 -07001509 dex_pc_data->AddClass(dex_profile_index_remap.Get(
Calin Juravle0def68d2017-02-21 19:00:33 -08001510 class_it.dex_profile_index), class_it.type_index);
1511 }
Calin Juravle940eb0c2017-01-30 19:30:44 -08001512 }
1513 }
1514 }
Mathieu Chartierea650f32017-05-24 12:04:13 -07001515
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001516 // Merge the method bitmaps.
Mathieu Chartierea650f32017-05-24 12:04:13 -07001517 dex_data->MergeBitmap(*other_dex_data);
Calin Juravle998c2162015-12-21 15:39:33 +02001518 }
1519 return true;
Calin Juravle226501b2015-12-11 14:41:31 +00001520}
1521
Mathieu Chartierdb40eac2017-06-09 18:34:11 -07001522const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexData(
1523 const DexFile* dex_file) const {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001524 return FindDexData(GetProfileDexFileKey(dex_file->GetLocation()),
1525 dex_file->GetLocationChecksum());
Mathieu Chartierdb40eac2017-06-09 18:34:11 -07001526}
1527
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001528ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::GetMethodHotness(
1529 const MethodReference& method_ref) const {
Mathieu Chartierdb40eac2017-06-09 18:34:11 -07001530 const DexFileData* dex_data = FindDexData(method_ref.dex_file);
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001531 return dex_data != nullptr
Mathieu Chartierfc8b4222017-09-17 13:44:24 -07001532 ? dex_data->GetHotnessInfo(method_ref.index)
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001533 : MethodHotness();
Mathieu Chartierdb40eac2017-06-09 18:34:11 -07001534}
1535
Mathieu Chartier2f794552017-06-19 10:58:08 -07001536bool ProfileCompilationInfo::AddMethodHotness(const MethodReference& method_ref,
1537 const MethodHotness& hotness) {
1538 DexFileData* dex_data = GetOrAddDexFileData(method_ref.dex_file);
1539 if (dex_data != nullptr) {
1540 // TODO: Add inline caches.
Calin Juravle1ad1e3f2017-09-19 18:20:37 -07001541 return dex_data->AddMethod(
1542 static_cast<MethodHotness::Flag>(hotness.GetFlags()), method_ref.index);
Mathieu Chartier2f794552017-06-19 10:58:08 -07001543 }
1544 return false;
1545}
1546
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001547ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::GetMethodHotness(
1548 const std::string& dex_location,
1549 uint32_t dex_checksum,
1550 uint16_t dex_method_index) const {
1551 const DexFileData* dex_data = FindDexData(GetProfileDexFileKey(dex_location), dex_checksum);
1552 return dex_data != nullptr ? dex_data->GetHotnessInfo(dex_method_index) : MethodHotness();
Calin Juravle226501b2015-12-11 14:41:31 +00001553}
1554
Calin Juravle940eb0c2017-01-30 19:30:44 -08001555
Calin Juravlecc3171a2017-05-19 16:47:53 -07001556std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> ProfileCompilationInfo::GetMethod(
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001557 const std::string& dex_location,
1558 uint32_t dex_checksum,
1559 uint16_t dex_method_index) const {
1560 MethodHotness hotness(GetMethodHotness(dex_location, dex_checksum, dex_method_index));
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001561 if (!hotness.IsHot()) {
Calin Juravlecc3171a2017-05-19 16:47:53 -07001562 return nullptr;
Calin Juravle940eb0c2017-01-30 19:30:44 -08001563 }
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001564 const InlineCacheMap* inline_caches = hotness.GetInlineCacheMap();
1565 DCHECK(inline_caches != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001566 std::unique_ptr<OfflineProfileMethodInfo> pmi(new OfflineProfileMethodInfo(inline_caches));
Calin Juravle940eb0c2017-01-30 19:30:44 -08001567
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001568 pmi->dex_references.resize(info_.size());
1569 for (const DexFileData* dex_data : info_) {
1570 pmi->dex_references[dex_data->profile_index].dex_location = dex_data->profile_key;
1571 pmi->dex_references[dex_data->profile_index].dex_checksum = dex_data->checksum;
Mathieu Chartierea650f32017-05-24 12:04:13 -07001572 pmi->dex_references[dex_data->profile_index].num_method_ids = dex_data->num_method_ids;
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001573 }
1574
Calin Juravlecc3171a2017-05-19 16:47:53 -07001575 return pmi;
Calin Juravle940eb0c2017-01-30 19:30:44 -08001576}
1577
1578
Andreas Gampea5b09a62016-11-17 15:21:22 -08001579bool ProfileCompilationInfo::ContainsClass(const DexFile& dex_file, dex::TypeIndex type_idx) const {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001580 const DexFileData* dex_data = FindDexData(&dex_file);
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001581 if (dex_data != nullptr) {
Calin Juravlecc3171a2017-05-19 16:47:53 -07001582 const ArenaSet<dex::TypeIndex>& classes = dex_data->class_set;
Jeff Hao54b58552016-11-16 15:15:04 -08001583 return classes.find(type_idx) != classes.end();
Mathieu Chartiera8077802016-03-16 19:08:31 -07001584 }
1585 return false;
1586}
1587
Calin Juravle998c2162015-12-21 15:39:33 +02001588uint32_t ProfileCompilationInfo::GetNumberOfMethods() const {
1589 uint32_t total = 0;
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001590 for (const DexFileData* dex_data : info_) {
1591 total += dex_data->method_map.size();
Calin Juravle998c2162015-12-21 15:39:33 +02001592 }
1593 return total;
1594}
1595
Calin Juravle67265462016-03-18 16:23:40 +00001596uint32_t ProfileCompilationInfo::GetNumberOfResolvedClasses() const {
1597 uint32_t total = 0;
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001598 for (const DexFileData* dex_data : info_) {
1599 total += dex_data->class_set.size();
Calin Juravle67265462016-03-18 16:23:40 +00001600 }
1601 return total;
1602}
1603
David Sehrb18991b2017-02-08 20:58:10 -08001604// Produce a non-owning vector from a vector.
1605template<typename T>
1606const std::vector<T*>* MakeNonOwningVector(const std::vector<std::unique_ptr<T>>* owning_vector) {
1607 auto non_owning_vector = new std::vector<T*>();
1608 for (auto& element : *owning_vector) {
1609 non_owning_vector->push_back(element.get());
1610 }
1611 return non_owning_vector;
1612}
1613
1614std::string ProfileCompilationInfo::DumpInfo(
1615 const std::vector<std::unique_ptr<const DexFile>>* dex_files,
1616 bool print_full_dex_location) const {
1617 std::unique_ptr<const std::vector<const DexFile*>> non_owning_dex_files(
1618 MakeNonOwningVector(dex_files));
1619 return DumpInfo(non_owning_dex_files.get(), print_full_dex_location);
1620}
1621
Calin Juravle998c2162015-12-21 15:39:33 +02001622std::string ProfileCompilationInfo::DumpInfo(const std::vector<const DexFile*>* dex_files,
1623 bool print_full_dex_location) const {
Calin Juravle226501b2015-12-11 14:41:31 +00001624 std::ostringstream os;
1625 if (info_.empty()) {
1626 return "ProfileInfo: empty";
1627 }
1628
1629 os << "ProfileInfo:";
1630
Calin Juravlea308a322017-07-18 16:51:51 -07001631 const std::string kFirstDexFileKeySubstitute = "!classes.dex";
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001632
1633 for (const DexFileData* dex_data : info_) {
Calin Juravle226501b2015-12-11 14:41:31 +00001634 os << "\n";
Calin Juravle226501b2015-12-11 14:41:31 +00001635 if (print_full_dex_location) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001636 os << dex_data->profile_key;
Calin Juravle226501b2015-12-11 14:41:31 +00001637 } else {
1638 // Replace the (empty) multidex suffix of the first key with a substitute for easier reading.
Mathieu Chartier79c87da2017-10-10 11:54:29 -07001639 std::string multidex_suffix = DexFileLoader::GetMultiDexSuffix(dex_data->profile_key);
Calin Juravle226501b2015-12-11 14:41:31 +00001640 os << (multidex_suffix.empty() ? kFirstDexFileKeySubstitute : multidex_suffix);
1641 }
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001642 os << " [index=" << static_cast<uint32_t>(dex_data->profile_index) << "]";
Calin Juravle876f3502016-03-24 16:16:34 +00001643 const DexFile* dex_file = nullptr;
1644 if (dex_files != nullptr) {
1645 for (size_t i = 0; i < dex_files->size(); i++) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001646 if (dex_data->profile_key == (*dex_files)[i]->GetLocation()) {
Calin Juravle876f3502016-03-24 16:16:34 +00001647 dex_file = (*dex_files)[i];
Calin Juravle998c2162015-12-21 15:39:33 +02001648 }
Calin Juravle226501b2015-12-11 14:41:31 +00001649 }
Calin Juravle876f3502016-03-24 16:16:34 +00001650 }
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001651 os << "\n\thot methods: ";
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001652 for (const auto& method_it : dex_data->method_map) {
Calin Juravle876f3502016-03-24 16:16:34 +00001653 if (dex_file != nullptr) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001654 os << "\n\t\t" << dex_file->PrettyMethod(method_it.first, true);
Calin Juravle876f3502016-03-24 16:16:34 +00001655 } else {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001656 os << method_it.first;
Calin Juravle876f3502016-03-24 16:16:34 +00001657 }
Calin Juravle940eb0c2017-01-30 19:30:44 -08001658
1659 os << "[";
1660 for (const auto& inline_cache_it : method_it.second) {
1661 os << "{" << std::hex << inline_cache_it.first << std::dec << ":";
Calin Juravle589e71e2017-03-03 16:05:05 -08001662 if (inline_cache_it.second.is_missing_types) {
1663 os << "MT";
1664 } else if (inline_cache_it.second.is_megamorphic) {
1665 os << "MM";
Calin Juravle940eb0c2017-01-30 19:30:44 -08001666 } else {
1667 for (const ClassReference& class_ref : inline_cache_it.second.classes) {
1668 os << "(" << static_cast<uint32_t>(class_ref.dex_profile_index)
1669 << "," << class_ref.type_index.index_ << ")";
1670 }
1671 }
1672 os << "}";
1673 }
1674 os << "], ";
Calin Juravle876f3502016-03-24 16:16:34 +00001675 }
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001676 bool startup = true;
1677 while (true) {
1678 os << "\n\t" << (startup ? "startup methods: " : "post startup methods: ");
1679 for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001680 MethodHotness hotness_info(dex_data->GetHotnessInfo(method_idx));
1681 if (startup ? hotness_info.IsStartup() : hotness_info.IsPostStartup()) {
Calin Juravle0545d4a2017-12-01 13:36:26 -08001682 if (dex_file != nullptr) {
1683 os << "\n\t\t" << dex_file->PrettyMethod(method_idx, true);
1684 } else {
1685 os << method_idx << ", ";
1686 }
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001687 }
1688 }
1689 if (startup == false) {
1690 break;
1691 }
1692 startup = false;
1693 }
Calin Juravle876f3502016-03-24 16:16:34 +00001694 os << "\n\tclasses: ";
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001695 for (const auto class_it : dex_data->class_set) {
Calin Juravle876f3502016-03-24 16:16:34 +00001696 if (dex_file != nullptr) {
Jeff Hao54b58552016-11-16 15:15:04 -08001697 os << "\n\t\t" << dex_file->PrettyType(class_it);
Calin Juravle876f3502016-03-24 16:16:34 +00001698 } else {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001699 os << class_it.index_ << ",";
Calin Juravle876f3502016-03-24 16:16:34 +00001700 }
Calin Juravle226501b2015-12-11 14:41:31 +00001701 }
1702 }
1703 return os.str();
1704}
1705
Mathieu Chartierea650f32017-05-24 12:04:13 -07001706bool ProfileCompilationInfo::GetClassesAndMethods(
1707 const DexFile& dex_file,
1708 /*out*/std::set<dex::TypeIndex>* class_set,
1709 /*out*/std::set<uint16_t>* hot_method_set,
1710 /*out*/std::set<uint16_t>* startup_method_set,
1711 /*out*/std::set<uint16_t>* post_startup_method_method_set) const {
Mathieu Chartier34067262017-04-06 13:55:46 -07001712 std::set<std::string> ret;
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001713 const DexFileData* dex_data = FindDexData(&dex_file);
1714 if (dex_data == nullptr) {
Mathieu Chartier34067262017-04-06 13:55:46 -07001715 return false;
David Sehr7c80f2d2017-02-07 16:47:58 -08001716 }
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001717 for (const auto& it : dex_data->method_map) {
Mathieu Chartierea650f32017-05-24 12:04:13 -07001718 hot_method_set->insert(it.first);
1719 }
1720 for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001721 MethodHotness hotness = dex_data->GetHotnessInfo(method_idx);
1722 if (hotness.IsStartup()) {
Mathieu Chartierea650f32017-05-24 12:04:13 -07001723 startup_method_set->insert(method_idx);
1724 }
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001725 if (hotness.IsPostStartup()) {
Mathieu Chartierea650f32017-05-24 12:04:13 -07001726 post_startup_method_method_set->insert(method_idx);
1727 }
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001728 }
Calin Juravlecc3171a2017-05-19 16:47:53 -07001729 for (const dex::TypeIndex& type_index : dex_data->class_set) {
1730 class_set->insert(type_index);
1731 }
Mathieu Chartier34067262017-04-06 13:55:46 -07001732 return true;
David Sehr7c80f2d2017-02-07 16:47:58 -08001733}
1734
Calin Juravle2e2db782016-02-23 12:00:03 +00001735bool ProfileCompilationInfo::Equals(const ProfileCompilationInfo& other) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001736 // No need to compare profile_key_map_. That's only a cache for fast search.
1737 // All the information is already in the info_ vector.
1738 if (info_.size() != other.info_.size()) {
1739 return false;
1740 }
1741 for (size_t i = 0; i < info_.size(); i++) {
1742 const DexFileData& dex_data = *info_[i];
1743 const DexFileData& other_dex_data = *other.info_[i];
1744 if (!(dex_data == other_dex_data)) {
1745 return false;
1746 }
1747 }
1748 return true;
Calin Juravle877fd962016-01-05 14:29:29 +00001749}
1750
Mathieu Chartier046854b2017-03-01 17:16:22 -08001751std::set<DexCacheResolvedClasses> ProfileCompilationInfo::GetResolvedClasses(
Calin Juravle08556882017-05-26 16:40:45 -07001752 const std::vector<const DexFile*>& dex_files) const {
1753 std::unordered_map<std::string, const DexFile* > key_to_dex_file;
1754 for (const DexFile* dex_file : dex_files) {
1755 key_to_dex_file.emplace(GetProfileDexFileKey(dex_file->GetLocation()), dex_file);
Mathieu Chartier046854b2017-03-01 17:16:22 -08001756 }
Mathieu Chartierc5dd3192015-12-09 16:38:30 -08001757 std::set<DexCacheResolvedClasses> ret;
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001758 for (const DexFileData* dex_data : info_) {
Calin Juravle08556882017-05-26 16:40:45 -07001759 const auto it = key_to_dex_file.find(dex_data->profile_key);
1760 if (it != key_to_dex_file.end()) {
1761 const DexFile* dex_file = it->second;
1762 const std::string& dex_location = dex_file->GetLocation();
1763 if (dex_data->checksum != it->second->GetLocationChecksum()) {
1764 LOG(ERROR) << "Dex checksum mismatch when getting resolved classes from profile for "
1765 << "location " << dex_location << " (checksum=" << dex_file->GetLocationChecksum()
1766 << ", profile checksum=" << dex_data->checksum;
1767 return std::set<DexCacheResolvedClasses>();
1768 }
Mathieu Chartierea650f32017-05-24 12:04:13 -07001769 DexCacheResolvedClasses classes(dex_location,
1770 dex_location,
1771 dex_data->checksum,
1772 dex_data->num_method_ids);
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001773 classes.AddClasses(dex_data->class_set.begin(), dex_data->class_set.end());
Mathieu Chartier046854b2017-03-01 17:16:22 -08001774 ret.insert(classes);
1775 }
Mathieu Chartierc5dd3192015-12-09 16:38:30 -08001776 }
1777 return ret;
1778}
1779
Calin Juravle7bcdb532016-06-07 16:14:47 +01001780// Naive implementation to generate a random profile file suitable for testing.
1781bool ProfileCompilationInfo::GenerateTestProfile(int fd,
1782 uint16_t number_of_dex_files,
Shubham Ajmerad704f0b2017-07-26 16:33:35 -07001783 uint16_t method_percentage,
1784 uint16_t class_percentage,
Jeff Haof0a31f82017-03-27 15:50:37 -07001785 uint32_t random_seed) {
Calin Juravle7bcdb532016-06-07 16:14:47 +01001786 const std::string base_dex_location = "base.apk";
1787 ProfileCompilationInfo info;
1788 // The limits are defined by the dex specification.
Mathieu Chartierea650f32017-05-24 12:04:13 -07001789 const uint16_t max_method = std::numeric_limits<uint16_t>::max();
1790 const uint16_t max_classes = std::numeric_limits<uint16_t>::max();
Shubham Ajmerad704f0b2017-07-26 16:33:35 -07001791 uint16_t number_of_methods = max_method * method_percentage / 100;
1792 uint16_t number_of_classes = max_classes * class_percentage / 100;
Calin Juravle7bcdb532016-06-07 16:14:47 +01001793
Jeff Haof0a31f82017-03-27 15:50:37 -07001794 std::srand(random_seed);
Calin Juravle7bcdb532016-06-07 16:14:47 +01001795
1796 // Make sure we generate more samples with a low index value.
1797 // This makes it more likely to hit valid method/class indices in small apps.
1798 const uint16_t kFavorFirstN = 10000;
1799 const uint16_t kFavorSplit = 2;
1800
1801 for (uint16_t i = 0; i < number_of_dex_files; i++) {
Mathieu Chartier79c87da2017-10-10 11:54:29 -07001802 std::string dex_location = DexFileLoader::GetMultiDexLocation(i, base_dex_location.c_str());
Calin Juravle7bcdb532016-06-07 16:14:47 +01001803 std::string profile_key = GetProfileDexFileKey(dex_location);
1804
1805 for (uint16_t m = 0; m < number_of_methods; m++) {
1806 uint16_t method_idx = rand() % max_method;
1807 if (m < (number_of_methods / kFavorSplit)) {
1808 method_idx %= kFavorFirstN;
1809 }
Mathieu Chartierc46cf802017-09-28 11:52:19 -07001810 // Alternate between startup and post startup.
1811 uint32_t flags = MethodHotness::kFlagHot;
1812 flags |= ((m & 1) != 0) ? MethodHotness::kFlagPostStartup : MethodHotness::kFlagStartup;
1813 info.AddMethodIndex(static_cast<MethodHotness::Flag>(flags),
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001814 profile_key,
1815 /*method_idx*/ 0,
1816 method_idx,
1817 max_method);
Calin Juravle7bcdb532016-06-07 16:14:47 +01001818 }
1819
1820 for (uint16_t c = 0; c < number_of_classes; c++) {
Jeff Hao54b58552016-11-16 15:15:04 -08001821 uint16_t type_idx = rand() % max_classes;
Calin Juravle7bcdb532016-06-07 16:14:47 +01001822 if (c < (number_of_classes / kFavorSplit)) {
Jeff Hao54b58552016-11-16 15:15:04 -08001823 type_idx %= kFavorFirstN;
Calin Juravle7bcdb532016-06-07 16:14:47 +01001824 }
Mathieu Chartierea650f32017-05-24 12:04:13 -07001825 info.AddClassIndex(profile_key, 0, dex::TypeIndex(type_idx), max_method);
Calin Juravle7bcdb532016-06-07 16:14:47 +01001826 }
1827 }
1828 return info.Save(fd);
1829}
1830
Jeff Haof0a31f82017-03-27 15:50:37 -07001831// Naive implementation to generate a random profile file suitable for testing.
Shubham Ajmerad704f0b2017-07-26 16:33:35 -07001832// Description of random selection:
1833// * Select a random starting point S.
1834// * For every index i, add (S+i) % (N - total number of methods/classes) to profile with the
1835// probably of 1/(N - i - number of methods/classes needed to add in profile).
Jeff Haof0a31f82017-03-27 15:50:37 -07001836bool ProfileCompilationInfo::GenerateTestProfile(
1837 int fd,
1838 std::vector<std::unique_ptr<const DexFile>>& dex_files,
Shubham Ajmerad704f0b2017-07-26 16:33:35 -07001839 uint16_t method_percentage,
1840 uint16_t class_percentage,
Jeff Haof0a31f82017-03-27 15:50:37 -07001841 uint32_t random_seed) {
1842 std::srand(random_seed);
1843 ProfileCompilationInfo info;
1844 for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
1845 const std::string& location = dex_file->GetLocation();
1846 uint32_t checksum = dex_file->GetLocationChecksum();
Shubham Ajmerad704f0b2017-07-26 16:33:35 -07001847
1848 uint32_t number_of_classes = dex_file->NumClassDefs();
1849 uint32_t classes_required_in_profile = (number_of_classes * class_percentage) / 100;
1850 uint32_t class_start_index = rand() % number_of_classes;
1851 for (uint32_t i = 0; i < number_of_classes && classes_required_in_profile; ++i) {
1852 if (number_of_classes - i == classes_required_in_profile ||
1853 std::rand() % (number_of_classes - i - classes_required_in_profile) == 0) {
1854 uint32_t class_index = (i + class_start_index) % number_of_classes;
Mathieu Chartierea650f32017-05-24 12:04:13 -07001855 info.AddClassIndex(location,
1856 checksum,
Shubham Ajmerad704f0b2017-07-26 16:33:35 -07001857 dex_file->GetClassDef(class_index).class_idx_,
Mathieu Chartierea650f32017-05-24 12:04:13 -07001858 dex_file->NumMethodIds());
Shubham Ajmerad704f0b2017-07-26 16:33:35 -07001859 classes_required_in_profile--;
Jeff Haof0a31f82017-03-27 15:50:37 -07001860 }
1861 }
Shubham Ajmerad704f0b2017-07-26 16:33:35 -07001862
1863 uint32_t number_of_methods = dex_file->NumMethodIds();
1864 uint32_t methods_required_in_profile = (number_of_methods * method_percentage) / 100;
1865 uint32_t method_start_index = rand() % number_of_methods;
1866 for (uint32_t i = 0; i < number_of_methods && methods_required_in_profile; ++i) {
1867 if (number_of_methods - i == methods_required_in_profile ||
1868 std::rand() % (number_of_methods - i - methods_required_in_profile) == 0) {
1869 uint32_t method_index = (method_start_index + i) % number_of_methods;
Mathieu Chartierc46cf802017-09-28 11:52:19 -07001870 // Alternate between startup and post startup.
1871 uint32_t flags = MethodHotness::kFlagHot;
1872 flags |= ((method_index & 1) != 0)
1873 ? MethodHotness::kFlagPostStartup
1874 : MethodHotness::kFlagStartup;
1875 info.AddMethodIndex(static_cast<MethodHotness::Flag>(flags),
1876 MethodReference(dex_file.get(), method_index));
Shubham Ajmerad704f0b2017-07-26 16:33:35 -07001877 methods_required_in_profile--;
Jeff Haof0a31f82017-03-27 15:50:37 -07001878 }
1879 }
1880 }
1881 return info.Save(fd);
1882}
1883
Calin Juravle940eb0c2017-01-30 19:30:44 -08001884bool ProfileCompilationInfo::OfflineProfileMethodInfo::operator==(
1885 const OfflineProfileMethodInfo& other) const {
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001886 if (inline_caches->size() != other.inline_caches->size()) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001887 return false;
1888 }
1889
1890 // We can't use a simple equality test because we need to match the dex files
Calin Juravle589e71e2017-03-03 16:05:05 -08001891 // of the inline caches which might have different profile indexes.
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001892 for (const auto& inline_cache_it : *inline_caches) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001893 uint16_t dex_pc = inline_cache_it.first;
1894 const DexPcData dex_pc_data = inline_cache_it.second;
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001895 const auto& other_it = other.inline_caches->find(dex_pc);
1896 if (other_it == other.inline_caches->end()) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001897 return false;
1898 }
1899 const DexPcData& other_dex_pc_data = other_it->second;
Calin Juravle589e71e2017-03-03 16:05:05 -08001900 if (dex_pc_data.is_megamorphic != other_dex_pc_data.is_megamorphic ||
1901 dex_pc_data.is_missing_types != other_dex_pc_data.is_missing_types) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001902 return false;
1903 }
1904 for (const ClassReference& class_ref : dex_pc_data.classes) {
1905 bool found = false;
1906 for (const ClassReference& other_class_ref : other_dex_pc_data.classes) {
1907 CHECK_LE(class_ref.dex_profile_index, dex_references.size());
1908 CHECK_LE(other_class_ref.dex_profile_index, other.dex_references.size());
1909 const DexReference& dex_ref = dex_references[class_ref.dex_profile_index];
1910 const DexReference& other_dex_ref = other.dex_references[other_class_ref.dex_profile_index];
1911 if (class_ref.type_index == other_class_ref.type_index &&
1912 dex_ref == other_dex_ref) {
1913 found = true;
1914 break;
1915 }
1916 }
1917 if (!found) {
1918 return false;
1919 }
1920 }
1921 }
1922 return true;
1923}
1924
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001925bool ProfileCompilationInfo::IsEmpty() const {
1926 DCHECK_EQ(info_.empty(), profile_key_map_.empty());
1927 return info_.empty();
1928}
1929
Calin Juravlecc3171a2017-05-19 16:47:53 -07001930ProfileCompilationInfo::InlineCacheMap*
1931ProfileCompilationInfo::DexFileData::FindOrAddMethod(uint16_t method_index) {
1932 return &(method_map.FindOrAdd(
1933 method_index,
Vladimir Marko69d310e2017-10-09 14:12:23 +01001934 InlineCacheMap(std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)))->second);
Calin Juravlecc3171a2017-05-19 16:47:53 -07001935}
1936
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001937// Mark a method as executed at least once.
Calin Juravle1ad1e3f2017-09-19 18:20:37 -07001938bool ProfileCompilationInfo::DexFileData::AddMethod(MethodHotness::Flag flags, size_t index) {
1939 if (index >= num_method_ids) {
1940 LOG(ERROR) << "Invalid method index " << index << ". num_method_ids=" << num_method_ids;
1941 return false;
1942 }
1943
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001944 if ((flags & MethodHotness::kFlagStartup) != 0) {
1945 method_bitmap.StoreBit(MethodBitIndex(/*startup*/ true, index), /*value*/ true);
1946 }
1947 if ((flags & MethodHotness::kFlagPostStartup) != 0) {
1948 method_bitmap.StoreBit(MethodBitIndex(/*startup*/ false, index), /*value*/ true);
1949 }
1950 if ((flags & MethodHotness::kFlagHot) != 0) {
1951 method_map.FindOrAdd(
1952 index,
Vladimir Marko69d310e2017-10-09 14:12:23 +01001953 InlineCacheMap(std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)));
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001954 }
Calin Juravle1ad1e3f2017-09-19 18:20:37 -07001955 return true;
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001956}
1957
1958ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::DexFileData::GetHotnessInfo(
1959 uint32_t dex_method_index) const {
1960 MethodHotness ret;
1961 if (method_bitmap.LoadBit(MethodBitIndex(/*startup*/ true, dex_method_index))) {
1962 ret.AddFlag(MethodHotness::kFlagStartup);
1963 }
1964 if (method_bitmap.LoadBit(MethodBitIndex(/*startup*/ false, dex_method_index))) {
1965 ret.AddFlag(MethodHotness::kFlagPostStartup);
1966 }
1967 auto it = method_map.find(dex_method_index);
1968 if (it != method_map.end()) {
1969 ret.SetInlineCacheMap(&it->second);
1970 ret.AddFlag(MethodHotness::kFlagHot);
1971 }
1972 return ret;
1973}
1974
Calin Juravlecc3171a2017-05-19 16:47:53 -07001975ProfileCompilationInfo::DexPcData*
1976ProfileCompilationInfo::FindOrAddDexPc(InlineCacheMap* inline_cache, uint32_t dex_pc) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001977 return &(inline_cache->FindOrAdd(dex_pc, DexPcData(&allocator_))->second);
Calin Juravlecc3171a2017-05-19 16:47:53 -07001978}
1979
Mathieu Chartier4f342b02017-07-21 17:12:39 -07001980std::unordered_set<std::string> ProfileCompilationInfo::GetClassDescriptors(
1981 const std::vector<const DexFile*>& dex_files) {
1982 std::unordered_set<std::string> ret;
1983 for (const DexFile* dex_file : dex_files) {
1984 const DexFileData* data = FindDexData(dex_file);
1985 if (data != nullptr) {
1986 for (dex::TypeIndex type_idx : data->class_set) {
1987 if (!dex_file->IsTypeIndexValid(type_idx)) {
1988 // Something went bad. The profile is probably corrupted. Abort and return an emtpy set.
1989 LOG(WARNING) << "Corrupted profile: invalid type index "
1990 << type_idx.index_ << " in dex " << dex_file->GetLocation();
1991 return std::unordered_set<std::string>();
1992 }
1993 const DexFile::TypeId& type_id = dex_file->GetTypeId(type_idx);
1994 ret.insert(dex_file->GetTypeDescriptor(type_id));
1995 }
1996 } else {
1997 VLOG(compiler) << "Failed to find profile data for " << dex_file->GetLocation();
1998 }
1999 }
2000 return ret;
2001}
2002
Calin Juravle1e2de642018-01-18 01:08:23 -08002003bool ProfileCompilationInfo::IsProfileFile(int fd) {
2004 // First check if it's an empty file as we allow empty profile files.
2005 // Profiles may be created by ActivityManager or installd before we manage to
2006 // process them in the runtime or profman.
2007 struct stat stat_buffer;
2008 if (fstat(fd, &stat_buffer) != 0) {
2009 return false;
2010 }
2011
2012 if (stat_buffer.st_size == 0) {
2013 return true;
2014 }
2015
2016 // The files is not empty. Check if it contains the profile magic.
2017 size_t byte_count = sizeof(kProfileMagic);
2018 uint8_t buffer[sizeof(kProfileMagic)];
2019 if (!android::base::ReadFully(fd, buffer, byte_count)) {
2020 return false;
2021 }
2022
2023 // Reset the offset to prepare the file for reading.
2024 off_t rc = TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET));
2025 if (rc == static_cast<off_t>(-1)) {
2026 PLOG(ERROR) << "Failed to reset the offset";
2027 return false;
2028 }
2029
2030 return memcmp(buffer, kProfileMagic, byte_count) == 0;
2031}
2032
Calin Juravle31f2c152015-10-23 17:56:15 +01002033} // namespace art