blob: 2ebde5e06d2e08279f8d0ecf1f7f52ecc7d4d819 [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
Andreas Gampe81ccda62018-09-20 11:59:12 -070026#include <algorithm>
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070027#include <cerrno>
28#include <climits>
29#include <cstdlib>
Andreas Gampe81ccda62018-09-20 11:59:12 -070030#include <iostream>
31#include <numeric>
32#include <random>
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070033#include <string>
34#include <vector>
35
36#include "android-base/file.h"
Calin Juravle31f2c152015-10-23 17:56:15 +010037
Calin Juravlecc3171a2017-05-19 16:47:53 -070038#include "base/arena_allocator.h"
39#include "base/dumpable.h"
Josh Gao675e0a52018-08-30 17:29:00 -070040#include "base/file_utils.h"
Andreas Gampe57943812017-12-06 21:39:13 -080041#include "base/logging.h" // For VLOG.
David Sehr3215fff2018-04-03 17:10:12 -070042#include "base/malloc_arena_pool.h"
David Sehrc431b9d2018-03-02 12:01:51 -080043#include "base/os.h"
David Sehr67bf42e2018-02-26 16:43:04 -080044#include "base/safe_map.h"
Calin Juravle877fd962016-01-05 14:29:29 +000045#include "base/scoped_flock.h"
Calin Juravle66f55232015-12-08 15:09:10 +000046#include "base/stl_util.h"
Mathieu Chartier32ce2ad2016-03-04 14:58:03 -080047#include "base/systrace.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070048#include "base/time_utils.h"
Calin Juravle877fd962016-01-05 14:29:29 +000049#include "base/unix_file/fd_file.h"
David Sehrc431b9d2018-03-02 12:01:51 -080050#include "base/utils.h"
David Sehr79e26072018-04-06 17:58:50 -070051#include "base/zip_archive.h"
David Sehr9e734c72018-01-04 17:56:19 -080052#include "dex/dex_file_loader.h"
Calin Juravle31f2c152015-10-23 17:56:15 +010053
54namespace art {
55
Calin Juravle64142952016-03-21 14:37:55 +000056const uint8_t ProfileCompilationInfo::kProfileMagic[] = { 'p', 'r', 'o', '\0' };
Shubham Ajmeraafbbf182017-08-04 14:33:34 -070057// Last profile version: merge profiles directly from the file without creating
58// profile_compilation_info object. All the profile line headers are now placed together
59// before corresponding method_encodings and class_ids.
60const uint8_t ProfileCompilationInfo::kProfileVersion[] = { '0', '1', '0', '\0' };
Calin Juravle64142952016-03-21 14:37:55 +000061
Calin Juravle1e2de642018-01-18 01:08:23 -080062// The name of the profile entry in the dex metadata file.
63// DO NOT CHANGE THIS! (it's similar to classes.dex in the apk files).
Vladimir Marko54159c62018-06-20 14:30:08 +010064const char ProfileCompilationInfo::kDexMetadataProfileEntry[] = "primary.prof";
Calin Juravle1e2de642018-01-18 01:08:23 -080065
Calin Juravle64142952016-03-21 14:37:55 +000066static constexpr uint16_t kMaxDexFileKeyLength = PATH_MAX;
67
Calin Juravlec4588572016-06-08 14:24:13 +010068// 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 +010069// Used to facilitate testing profile guided compilation across a large number of apps
Calin Juravlec4588572016-06-08 14:24:13 +010070// using the same test profile.
71static constexpr bool kDebugIgnoreChecksum = false;
72
Calin Juravle589e71e2017-03-03 16:05:05 -080073static constexpr uint8_t kIsMissingTypesEncoding = 6;
74static constexpr uint8_t kIsMegamorphicEncoding = 7;
Calin Juravle940eb0c2017-01-30 19:30:44 -080075
David Sehr82d046e2018-04-23 08:14:19 -070076static_assert(sizeof(ProfileCompilationInfo::kIndividualInlineCacheSize) == sizeof(uint8_t),
77 "InlineCache::kIndividualInlineCacheSize does not have the expect type size");
78static_assert(ProfileCompilationInfo::kIndividualInlineCacheSize < kIsMegamorphicEncoding,
79 "InlineCache::kIndividualInlineCacheSize is larger than expected");
80static_assert(ProfileCompilationInfo::kIndividualInlineCacheSize < kIsMissingTypesEncoding,
81 "InlineCache::kIndividualInlineCacheSize is larger than expected");
Calin Juravle940eb0c2017-01-30 19:30:44 -080082
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -070083static bool ChecksumMatch(uint32_t dex_file_checksum, uint32_t checksum) {
84 return kDebugIgnoreChecksum || dex_file_checksum == checksum;
85}
86
Calin Juravlecc3171a2017-05-19 16:47:53 -070087ProfileCompilationInfo::ProfileCompilationInfo(ArenaPool* custom_arena_pool)
Calin Juravlee6f87cc2017-05-24 17:41:05 -070088 : default_arena_pool_(),
Vladimir Markoca6fff82017-10-03 14:49:14 +010089 allocator_(custom_arena_pool),
90 info_(allocator_.Adapter(kArenaAllocProfile)),
91 profile_key_map_(std::less<const std::string>(), allocator_.Adapter(kArenaAllocProfile)) {
Calin Juravlecc3171a2017-05-19 16:47:53 -070092}
93
94ProfileCompilationInfo::ProfileCompilationInfo()
David Sehr3215fff2018-04-03 17:10:12 -070095 : default_arena_pool_(),
Vladimir Markoca6fff82017-10-03 14:49:14 +010096 allocator_(&default_arena_pool_),
97 info_(allocator_.Adapter(kArenaAllocProfile)),
98 profile_key_map_(std::less<const std::string>(), allocator_.Adapter(kArenaAllocProfile)) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -070099}
100
101ProfileCompilationInfo::~ProfileCompilationInfo() {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100102 VLOG(profiler) << Dumpable<MemStats>(allocator_.GetMemStats());
Calin Juravled5aeade2018-05-08 18:23:24 -0700103 ClearData();
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.
David Sehr82d046e2018-04-23 08:14:19 -0700124 if (classes.size() + 1 >= ProfileCompilationInfo::kIndividualInlineCacheSize) {
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
Calin Juravleee9cb412018-02-13 20:32:35 -0800171bool ProfileCompilationInfo::AddMethods(const std::vector<ProfileMethodInfo>& methods,
172 MethodHotness::Flag flags) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800173 for (const ProfileMethodInfo& method : methods) {
Calin Juravleee9cb412018-02-13 20:32:35 -0800174 if (!AddMethod(method, flags)) {
Calin Juravle67265462016-03-18 16:23:40 +0000175 return false;
176 }
177 }
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700178 return true;
179}
180
181bool ProfileCompilationInfo::AddClasses(const std::set<DexCacheResolvedClasses>& resolved_classes) {
Calin Juravle67265462016-03-18 16:23:40 +0000182 for (const DexCacheResolvedClasses& dex_cache : resolved_classes) {
183 if (!AddResolvedClasses(dex_cache)) {
184 return false;
185 }
186 }
187 return true;
188}
189
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700190bool ProfileCompilationInfo::MergeWith(const std::string& filename) {
191 std::string error;
192 int flags = O_RDONLY | O_NOFOLLOW | O_CLOEXEC;
193 ScopedFlock profile_file = LockedFile::Open(filename.c_str(), flags,
194 /*block*/false, &error);
195
196 if (profile_file.get() == nullptr) {
197 LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
198 return false;
199 }
200
201 int fd = profile_file->Fd();
202
Calin Juravle36060d12018-01-19 16:28:38 -0800203 ProfileLoadStatus status = LoadInternal(fd, &error);
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700204 if (status == kProfileLoadSuccess) {
205 return true;
206 }
207
208 LOG(WARNING) << "Could not load profile data from file " << filename << ": " << error;
209 return false;
210}
211
Calin Juravledcab1902017-05-12 19:18:47 -0700212bool ProfileCompilationInfo::Load(const std::string& filename, bool clear_if_invalid) {
Calin Juravle67265462016-03-18 16:23:40 +0000213 ScopedTrace trace(__PRETTY_FUNCTION__);
Calin Juravle67265462016-03-18 16:23:40 +0000214 std::string error;
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700215
216 if (!IsEmpty()) {
217 return kProfileLoadWouldOverwiteData;
218 }
219
Calin Juravledf674c42017-04-27 19:30:16 -0700220 int flags = O_RDWR | O_NOFOLLOW | O_CLOEXEC;
221 // There's no need to fsync profile data right away. We get many chances
222 // to write it again in case something goes wrong. We can rely on a simple
223 // close(), no sync, and let to the kernel decide when to write to disk.
Narayan Kamatha3d27eb2017-05-11 13:50:59 +0100224 ScopedFlock profile_file = LockedFile::Open(filename.c_str(), flags,
225 /*block*/false, &error);
226
227 if (profile_file.get() == nullptr) {
Calin Juravle67265462016-03-18 16:23:40 +0000228 LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
229 return false;
230 }
231
Narayan Kamatha3d27eb2017-05-11 13:50:59 +0100232 int fd = profile_file->Fd();
Calin Juravle67265462016-03-18 16:23:40 +0000233
Calin Juravle36060d12018-01-19 16:28:38 -0800234 ProfileLoadStatus status = LoadInternal(fd, &error);
Calin Juravle5d1bd0a2016-03-24 20:33:22 +0000235 if (status == kProfileLoadSuccess) {
Calin Juravledcab1902017-05-12 19:18:47 -0700236 return true;
237 }
238
239 if (clear_if_invalid &&
240 ((status == kProfileLoadVersionMismatch) || (status == kProfileLoadBadData))) {
241 LOG(WARNING) << "Clearing bad or obsolete profile data from file "
242 << filename << ": " << error;
Narayan Kamatha3d27eb2017-05-11 13:50:59 +0100243 if (profile_file->ClearContent()) {
Calin Juravledcab1902017-05-12 19:18:47 -0700244 return true;
Calin Juravle5d1bd0a2016-03-24 20:33:22 +0000245 } else {
Calin Juravledcab1902017-05-12 19:18:47 -0700246 PLOG(WARNING) << "Could not clear profile file: " << filename;
247 return false;
Calin Juravle5d1bd0a2016-03-24 20:33:22 +0000248 }
Calin Juravledcab1902017-05-12 19:18:47 -0700249 }
250
251 LOG(WARNING) << "Could not load profile data from file " << filename << ": " << error;
252 return false;
253}
254
255bool ProfileCompilationInfo::Save(const std::string& filename, uint64_t* bytes_written) {
256 ScopedTrace trace(__PRETTY_FUNCTION__);
Calin Juravledcab1902017-05-12 19:18:47 -0700257 std::string error;
258 int flags = O_WRONLY | O_NOFOLLOW | O_CLOEXEC;
259 // There's no need to fsync profile data right away. We get many chances
260 // to write it again in case something goes wrong. We can rely on a simple
261 // close(), no sync, and let to the kernel decide when to write to disk.
Narayan Kamatha3d27eb2017-05-11 13:50:59 +0100262 ScopedFlock profile_file = LockedFile::Open(filename.c_str(), flags,
263 /*block*/false, &error);
264 if (profile_file.get() == nullptr) {
Calin Juravledcab1902017-05-12 19:18:47 -0700265 LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
Calin Juravle67265462016-03-18 16:23:40 +0000266 return false;
267 }
268
Narayan Kamatha3d27eb2017-05-11 13:50:59 +0100269 int fd = profile_file->Fd();
Calin Juravledcab1902017-05-12 19:18:47 -0700270
Calin Juravle5d1bd0a2016-03-24 20:33:22 +0000271 // We need to clear the data because we don't support appending to the profiles yet.
Narayan Kamatha3d27eb2017-05-11 13:50:59 +0100272 if (!profile_file->ClearContent()) {
Calin Juravle67265462016-03-18 16:23:40 +0000273 PLOG(WARNING) << "Could not clear profile file: " << filename;
274 return false;
275 }
276
277 // This doesn't need locking because we are trying to lock the file for exclusive
278 // access and fail immediately if we can't.
279 bool result = Save(fd);
280 if (result) {
David Sehrc431b9d2018-03-02 12:01:51 -0800281 int64_t size = OS::GetFileSizeBytes(filename.c_str());
Calin Juravledcab1902017-05-12 19:18:47 -0700282 if (size != -1) {
283 VLOG(profiler)
284 << "Successfully saved profile info to " << filename << " Size: "
285 << size;
286 if (bytes_written != nullptr) {
287 *bytes_written = static_cast<uint64_t>(size);
288 }
Calin Juravle67265462016-03-18 16:23:40 +0000289 }
290 } else {
291 VLOG(profiler) << "Failed to save profile info to " << filename;
292 }
293 return result;
294}
295
Calin Juravle64142952016-03-21 14:37:55 +0000296// Returns true if all the bytes were successfully written to the file descriptor.
297static bool WriteBuffer(int fd, const uint8_t* buffer, size_t byte_count) {
298 while (byte_count > 0) {
299 int bytes_written = TEMP_FAILURE_RETRY(write(fd, buffer, byte_count));
300 if (bytes_written == -1) {
Calin Juravle877fd962016-01-05 14:29:29 +0000301 return false;
302 }
Calin Juravle64142952016-03-21 14:37:55 +0000303 byte_count -= bytes_written; // Reduce the number of remaining bytes.
304 buffer += bytes_written; // Move the buffer forward.
305 }
Calin Juravle877fd962016-01-05 14:29:29 +0000306 return true;
Calin Juravle31f2c152015-10-23 17:56:15 +0100307}
308
Calin Juravle64142952016-03-21 14:37:55 +0000309// Add the string bytes to the buffer.
310static void AddStringToBuffer(std::vector<uint8_t>* buffer, const std::string& value) {
311 buffer->insert(buffer->end(), value.begin(), value.end());
312}
313
314// Insert each byte, from low to high into the buffer.
315template <typename T>
316static void AddUintToBuffer(std::vector<uint8_t>* buffer, T value) {
317 for (size_t i = 0; i < sizeof(T); i++) {
318 buffer->push_back((value >> (i * kBitsPerByte)) & 0xff);
319 }
320}
321
322static constexpr size_t kLineHeaderSize =
Calin Juravle940eb0c2017-01-30 19:30:44 -0800323 2 * sizeof(uint16_t) + // class_set.size + dex_location.size
Mathieu Chartierea650f32017-05-24 12:04:13 -0700324 3 * sizeof(uint32_t); // method_map.size + checksum + num_method_ids
Calin Juravle31f2c152015-10-23 17:56:15 +0100325
326/**
327 * Serialization format:
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700328 * [profile_header, zipped[[profile_line_header1, profile_line_header2...],[profile_line_data1,
329 * profile_line_data2...]]]
330 * profile_header:
331 * magic,version,number_of_dex_files,uncompressed_size_of_zipped_data,compressed_data_size
332 * profile_line_header:
333 * dex_location,number_of_classes,methods_region_size,dex_location_checksum,num_method_ids
334 * profile_line_data:
335 * method_encoding_1,method_encoding_2...,class_id1,class_id2...,startup/post startup bitmap
Calin Juravle940eb0c2017-01-30 19:30:44 -0800336 * The method_encoding is:
337 * method_id,number_of_inline_caches,inline_cache1,inline_cache2...
338 * The inline_cache is:
339 * dex_pc,[M|dex_map_size], dex_profile_index,class_id1,class_id2...,dex_profile_index2,...
340 * dex_map_size is the number of dex_indeces that follows.
341 * Classes are grouped per their dex files and the line
342 * `dex_profile_index,class_id1,class_id2...,dex_profile_index2,...` encodes the
343 * mapping from `dex_profile_index` to the set of classes `class_id1,class_id2...`
Calin Juravle589e71e2017-03-03 16:05:05 -0800344 * M stands for megamorphic or missing types and it's encoded as either
345 * the byte kIsMegamorphicEncoding or kIsMissingTypesEncoding.
Calin Juravle940eb0c2017-01-30 19:30:44 -0800346 * When present, there will be no class ids following.
Calin Juravle31f2c152015-10-23 17:56:15 +0100347 **/
Calin Juravle2e2db782016-02-23 12:00:03 +0000348bool ProfileCompilationInfo::Save(int fd) {
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000349 uint64_t start = NanoTime();
Mathieu Chartier32ce2ad2016-03-04 14:58:03 -0800350 ScopedTrace trace(__PRETTY_FUNCTION__);
Calin Juravle2e2db782016-02-23 12:00:03 +0000351 DCHECK_GE(fd, 0);
Calin Juravle64142952016-03-21 14:37:55 +0000352
Calin Juravle64142952016-03-21 14:37:55 +0000353 // Use a vector wrapper to avoid keeping track of offsets when we add elements.
354 std::vector<uint8_t> buffer;
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000355 if (!WriteBuffer(fd, kProfileMagic, sizeof(kProfileMagic))) {
356 return false;
357 }
358 if (!WriteBuffer(fd, kProfileVersion, sizeof(kProfileVersion))) {
359 return false;
360 }
Calin Juravle940eb0c2017-01-30 19:30:44 -0800361 DCHECK_LE(info_.size(), std::numeric_limits<uint8_t>::max());
362 AddUintToBuffer(&buffer, static_cast<uint8_t>(info_.size()));
Calin Juravle64142952016-03-21 14:37:55 +0000363
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000364 uint32_t required_capacity = 0;
365 for (const DexFileData* dex_data_ptr : info_) {
366 const DexFileData& dex_data = *dex_data_ptr;
367 uint32_t methods_region_size = GetMethodsRegionSize(dex_data);
368 required_capacity += kLineHeaderSize +
369 dex_data.profile_key.size() +
370 sizeof(uint16_t) * dex_data.class_set.size() +
Mathieu Chartierea650f32017-05-24 12:04:13 -0700371 methods_region_size +
372 dex_data.bitmap_storage.size();
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000373 }
Mathieu Chartierf2e2af82017-07-12 21:09:57 -0700374 // Allow large profiles for non target builds for the case where we are merging many profiles
375 // to generate a boot image profile.
376 if (kIsTargetBuild && required_capacity > kProfileSizeErrorThresholdInBytes) {
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000377 LOG(ERROR) << "Profile data size exceeds "
378 << std::to_string(kProfileSizeErrorThresholdInBytes)
379 << " bytes. Profile will not be written to disk.";
380 return false;
381 }
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000382 AddUintToBuffer(&buffer, required_capacity);
383 if (!WriteBuffer(fd, buffer.data(), buffer.size())) {
384 return false;
385 }
386 // Make sure that the buffer has enough capacity to avoid repeated resizings
387 // while we add data.
388 buffer.reserve(required_capacity);
389 buffer.clear();
390
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700391 // Dex files must be written in the order of their profile index. This
Calin Juravlee0ac1152017-02-13 19:03:47 -0800392 // avoids writing the index in the output file and simplifies the parsing logic.
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700393 // Write profile line headers.
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700394 for (const DexFileData* dex_data_ptr : info_) {
395 const DexFileData& dex_data = *dex_data_ptr;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800396
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700397 if (dex_data.profile_key.size() >= kMaxDexFileKeyLength) {
Calin Juravle64142952016-03-21 14:37:55 +0000398 LOG(WARNING) << "DexFileKey exceeds allocated limit";
399 return false;
400 }
401
Calin Juravle940eb0c2017-01-30 19:30:44 -0800402 uint32_t methods_region_size = GetMethodsRegionSize(dex_data);
Calin Juravle64142952016-03-21 14:37:55 +0000403
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700404 DCHECK_LE(dex_data.profile_key.size(), std::numeric_limits<uint16_t>::max());
Calin Juravle64142952016-03-21 14:37:55 +0000405 DCHECK_LE(dex_data.class_set.size(), std::numeric_limits<uint16_t>::max());
Mathieu Chartierea650f32017-05-24 12:04:13 -0700406 // Write profile line header.
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700407 AddUintToBuffer(&buffer, static_cast<uint16_t>(dex_data.profile_key.size()));
Calin Juravle64142952016-03-21 14:37:55 +0000408 AddUintToBuffer(&buffer, static_cast<uint16_t>(dex_data.class_set.size()));
Calin Juravle940eb0c2017-01-30 19:30:44 -0800409 AddUintToBuffer(&buffer, methods_region_size); // uint32_t
Calin Juravle64142952016-03-21 14:37:55 +0000410 AddUintToBuffer(&buffer, dex_data.checksum); // uint32_t
Mathieu Chartierea650f32017-05-24 12:04:13 -0700411 AddUintToBuffer(&buffer, dex_data.num_method_ids); // uint32_t
Calin Juravle64142952016-03-21 14:37:55 +0000412
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700413 AddStringToBuffer(&buffer, dex_data.profile_key);
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700414 }
415
416 for (const DexFileData* dex_data_ptr : info_) {
417 const DexFileData& dex_data = *dex_data_ptr;
418
419 // Note that we allow dex files without any methods or classes, so that
420 // inline caches can refer valid dex files.
Calin Juravle64142952016-03-21 14:37:55 +0000421
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000422 uint16_t last_method_index = 0;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800423 for (const auto& method_it : dex_data.method_map) {
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000424 // Store the difference between the method indices. The SafeMap is ordered by
425 // method_id, so the difference will always be non negative.
426 DCHECK_GE(method_it.first, last_method_index);
427 uint16_t diff_with_last_method_index = method_it.first - last_method_index;
428 last_method_index = method_it.first;
429 AddUintToBuffer(&buffer, diff_with_last_method_index);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800430 AddInlineCacheToBuffer(&buffer, method_it.second);
Calin Juravle31f2c152015-10-23 17:56:15 +0100431 }
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000432
433 uint16_t last_class_index = 0;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800434 for (const auto& class_id : dex_data.class_set) {
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000435 // Store the difference between the class indices. The set is ordered by
436 // class_id, so the difference will always be non negative.
437 DCHECK_GE(class_id.index_, last_class_index);
438 uint16_t diff_with_last_class_index = class_id.index_ - last_class_index;
439 last_class_index = class_id.index_;
440 AddUintToBuffer(&buffer, diff_with_last_class_index);
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800441 }
Mathieu Chartierea650f32017-05-24 12:04:13 -0700442
443 buffer.insert(buffer.end(),
444 dex_data.bitmap_storage.begin(),
445 dex_data.bitmap_storage.end());
Calin Juravle31f2c152015-10-23 17:56:15 +0100446 }
447
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000448 uint32_t output_size = 0;
449 std::unique_ptr<uint8_t[]> compressed_buffer = DeflateBuffer(buffer.data(),
450 required_capacity,
451 &output_size);
452
Shubham Ajmerad704f0b2017-07-26 16:33:35 -0700453 if (output_size > kProfileSizeWarningThresholdInBytes) {
454 LOG(WARNING) << "Profile data size exceeds "
455 << std::to_string(kProfileSizeWarningThresholdInBytes);
456 }
457
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000458 buffer.clear();
459 AddUintToBuffer(&buffer, output_size);
460
461 if (!WriteBuffer(fd, buffer.data(), buffer.size())) {
462 return false;
463 }
464 if (!WriteBuffer(fd, compressed_buffer.get(), output_size)) {
465 return false;
466 }
467 uint64_t total_time = NanoTime() - start;
468 VLOG(profiler) << "Compressed from "
469 << std::to_string(required_capacity)
470 << " to "
471 << std::to_string(output_size);
472 VLOG(profiler) << "Time to save profile: " << std::to_string(total_time);
473 return true;
Calin Juravle226501b2015-12-11 14:41:31 +0000474}
475
Calin Juravle940eb0c2017-01-30 19:30:44 -0800476void ProfileCompilationInfo::AddInlineCacheToBuffer(std::vector<uint8_t>* buffer,
477 const InlineCacheMap& inline_cache_map) {
478 // Add inline cache map size.
479 AddUintToBuffer(buffer, static_cast<uint16_t>(inline_cache_map.size()));
480 if (inline_cache_map.size() == 0) {
481 return;
482 }
483 for (const auto& inline_cache_it : inline_cache_map) {
484 uint16_t dex_pc = inline_cache_it.first;
485 const DexPcData dex_pc_data = inline_cache_it.second;
486 const ClassSet& classes = dex_pc_data.classes;
487
488 // Add the dex pc.
489 AddUintToBuffer(buffer, dex_pc);
490
Calin Juravle589e71e2017-03-03 16:05:05 -0800491 // Add the megamorphic/missing_types encoding if needed and continue.
492 // In either cases we don't add any classes to the profiles and so there's
493 // no point to continue.
494 // TODO(calin): in case we miss types there is still value to add the
495 // rest of the classes. They can be added without bumping the profile version.
496 if (dex_pc_data.is_missing_types) {
497 DCHECK(!dex_pc_data.is_megamorphic); // at this point the megamorphic flag should not be set.
498 DCHECK_EQ(classes.size(), 0u);
499 AddUintToBuffer(buffer, kIsMissingTypesEncoding);
500 continue;
501 } else if (dex_pc_data.is_megamorphic) {
502 DCHECK_EQ(classes.size(), 0u);
503 AddUintToBuffer(buffer, kIsMegamorphicEncoding);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800504 continue;
505 }
506
David Sehr82d046e2018-04-23 08:14:19 -0700507 DCHECK_LT(classes.size(), ProfileCompilationInfo::kIndividualInlineCacheSize);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800508 DCHECK_NE(classes.size(), 0u) << "InlineCache contains a dex_pc with 0 classes";
509
510 SafeMap<uint8_t, std::vector<dex::TypeIndex>> dex_to_classes_map;
511 // Group the classes by dex. We expect that most of the classes will come from
512 // the same dex, so this will be more efficient than encoding the dex index
513 // for each class reference.
514 GroupClassesByDex(classes, &dex_to_classes_map);
515 // Add the dex map size.
516 AddUintToBuffer(buffer, static_cast<uint8_t>(dex_to_classes_map.size()));
517 for (const auto& dex_it : dex_to_classes_map) {
518 uint8_t dex_profile_index = dex_it.first;
519 const std::vector<dex::TypeIndex>& dex_classes = dex_it.second;
520 // Add the dex profile index.
521 AddUintToBuffer(buffer, dex_profile_index);
522 // Add the the number of classes for each dex profile index.
523 AddUintToBuffer(buffer, static_cast<uint8_t>(dex_classes.size()));
524 for (size_t i = 0; i < dex_classes.size(); i++) {
525 // Add the type index of the classes.
526 AddUintToBuffer(buffer, dex_classes[i].index_);
527 }
528 }
529 }
530}
531
532uint32_t ProfileCompilationInfo::GetMethodsRegionSize(const DexFileData& dex_data) {
533 // ((uint16_t)method index + (uint16_t)inline cache size) * number of methods
534 uint32_t size = 2 * sizeof(uint16_t) * dex_data.method_map.size();
535 for (const auto& method_it : dex_data.method_map) {
536 const InlineCacheMap& inline_cache = method_it.second;
537 size += sizeof(uint16_t) * inline_cache.size(); // dex_pc
538 for (const auto& inline_cache_it : inline_cache) {
539 const ClassSet& classes = inline_cache_it.second.classes;
540 SafeMap<uint8_t, std::vector<dex::TypeIndex>> dex_to_classes_map;
541 GroupClassesByDex(classes, &dex_to_classes_map);
542 size += sizeof(uint8_t); // dex_to_classes_map size
543 for (const auto& dex_it : dex_to_classes_map) {
544 size += sizeof(uint8_t); // dex profile index
545 size += sizeof(uint8_t); // number of classes
546 const std::vector<dex::TypeIndex>& dex_classes = dex_it.second;
547 size += sizeof(uint16_t) * dex_classes.size(); // the actual classes
548 }
549 }
550 }
551 return size;
552}
553
554void ProfileCompilationInfo::GroupClassesByDex(
555 const ClassSet& classes,
556 /*out*/SafeMap<uint8_t, std::vector<dex::TypeIndex>>* dex_to_classes_map) {
557 for (const auto& classes_it : classes) {
558 auto dex_it = dex_to_classes_map->FindOrAdd(classes_it.dex_profile_index);
559 dex_it->second.push_back(classes_it.type_index);
560 }
561}
562
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800563ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::GetOrAddDexFileData(
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700564 const std::string& profile_key,
Mathieu Chartierea650f32017-05-24 12:04:13 -0700565 uint32_t checksum,
566 uint32_t num_method_ids) {
Vladimir Marko3bada4b2017-05-19 12:32:47 +0100567 const auto profile_index_it = profile_key_map_.FindOrAdd(profile_key, profile_key_map_.size());
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700568 if (profile_key_map_.size() > std::numeric_limits<uint8_t>::max()) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800569 // Allow only 255 dex files to be profiled. This allows us to save bytes
570 // when encoding. The number is well above what we expect for normal applications.
571 if (kIsDebugBuild) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700572 LOG(ERROR) << "Exceeded the maximum number of dex files (255). Something went wrong";
Calin Juravle940eb0c2017-01-30 19:30:44 -0800573 }
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700574 profile_key_map_.erase(profile_key);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800575 return nullptr;
Calin Juravle998c2162015-12-21 15:39:33 +0200576 }
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700577
578 uint8_t profile_index = profile_index_it->second;
579 if (info_.size() <= profile_index) {
580 // This is a new addition. Add it to the info_ array.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100581 DexFileData* dex_file_data = new (&allocator_) DexFileData(
582 &allocator_,
Mathieu Chartierea650f32017-05-24 12:04:13 -0700583 profile_key,
584 checksum,
585 profile_index,
586 num_method_ids);
Calin Juravlecc3171a2017-05-19 16:47:53 -0700587 info_.push_back(dex_file_data);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700588 }
589 DexFileData* result = info_[profile_index];
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700590
591 // Check that the checksum matches.
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700592 // 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 -0700593 if (result->checksum != checksum) {
594 LOG(WARNING) << "Checksum mismatch for dex " << profile_key;
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800595 return nullptr;
596 }
Shubham Ajmera61200a02017-08-30 16:29:41 -0700597
598 // DCHECK that profile info map key is consistent with the one stored in the dex file data.
599 // This should always be the case since since the cache map is managed by ProfileCompilationInfo.
600 DCHECK_EQ(profile_key, result->profile_key);
601 DCHECK_EQ(profile_index, result->profile_index);
Calin Juravle1ad1e3f2017-09-19 18:20:37 -0700602
603 if (num_method_ids != result->num_method_ids) {
604 // This should not happen... added to help investigating b/65812889.
605 LOG(ERROR) << "num_method_ids mismatch for dex " << profile_key
606 << ", expected=" << num_method_ids
607 << ", actual=" << result->num_method_ids;
608 return nullptr;
609 }
Shubham Ajmera61200a02017-08-30 16:29:41 -0700610
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700611 return result;
612}
613
614const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexData(
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700615 const std::string& profile_key,
616 uint32_t checksum,
617 bool verify_checksum) const {
Vladimir Marko3bada4b2017-05-19 12:32:47 +0100618 const auto profile_index_it = profile_key_map_.find(profile_key);
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700619 if (profile_index_it == profile_key_map_.end()) {
620 return nullptr;
621 }
622
623 uint8_t profile_index = profile_index_it->second;
624 const DexFileData* result = info_[profile_index];
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700625 if (verify_checksum && !ChecksumMatch(result->checksum, checksum)) {
626 return nullptr;
627 }
Calin Juravlecea9e9d2017-03-23 19:04:59 -0700628 DCHECK_EQ(profile_key, result->profile_key);
629 DCHECK_EQ(profile_index, result->profile_index);
630 return result;
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800631}
632
633bool ProfileCompilationInfo::AddResolvedClasses(const DexCacheResolvedClasses& classes) {
634 const std::string dex_location = GetProfileDexFileKey(classes.GetDexLocation());
635 const uint32_t checksum = classes.GetLocationChecksum();
Mathieu Chartierea650f32017-05-24 12:04:13 -0700636 DexFileData* const data = GetOrAddDexFileData(dex_location, checksum, classes.NumMethodIds());
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800637 if (data == nullptr) {
Calin Juravle998c2162015-12-21 15:39:33 +0200638 return false;
639 }
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800640 data->class_set.insert(classes.GetClasses().begin(), classes.GetClasses().end());
641 return true;
642}
643
Calin Juravle940eb0c2017-01-30 19:30:44 -0800644bool ProfileCompilationInfo::AddMethod(const std::string& dex_location,
645 uint32_t dex_checksum,
646 uint16_t method_index,
Mathieu Chartierea650f32017-05-24 12:04:13 -0700647 uint32_t num_method_ids,
Calin Juravleee9cb412018-02-13 20:32:35 -0800648 const OfflineProfileMethodInfo& pmi,
649 MethodHotness::Flag flags) {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700650 DexFileData* const data = GetOrAddDexFileData(GetProfileDexFileKey(dex_location),
651 dex_checksum,
652 num_method_ids);
Calin Juravleee9cb412018-02-13 20:32:35 -0800653 if (data == nullptr) {
654 // The data is null if there is a mismatch in the checksum or number of method ids.
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800655 return false;
656 }
Calin Juravleee9cb412018-02-13 20:32:35 -0800657
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700658 // Add the method.
Calin Juravlecc3171a2017-05-19 16:47:53 -0700659 InlineCacheMap* inline_cache = data->FindOrAddMethod(method_index);
Calin Juravleee9cb412018-02-13 20:32:35 -0800660 if (inline_cache == nullptr) {
661 // Happens if the method index is outside the range (i.e. is greater then the number
662 // of methods in the dex file). This should not happen during normal execution,
663 // But tools (e.g. boot image aggregation tools) and tests stress this behaviour.
664 return false;
665 }
666
667 data->SetMethodHotness(method_index, flags);
Calin Juravlee6f87cc2017-05-24 17:41:05 -0700668
669 if (pmi.inline_caches == nullptr) {
670 // If we don't have inline caches return success right away.
671 return true;
672 }
673 for (const auto& pmi_inline_cache_it : *pmi.inline_caches) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800674 uint16_t pmi_ic_dex_pc = pmi_inline_cache_it.first;
675 const DexPcData& pmi_ic_dex_pc_data = pmi_inline_cache_it.second;
Calin Juravlecc3171a2017-05-19 16:47:53 -0700676 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, pmi_ic_dex_pc);
677 if (dex_pc_data->is_missing_types || dex_pc_data->is_megamorphic) {
Calin Juravle589e71e2017-03-03 16:05:05 -0800678 // We are already megamorphic or we are missing types; no point in going forward.
Calin Juravle940eb0c2017-01-30 19:30:44 -0800679 continue;
680 }
Calin Juravle589e71e2017-03-03 16:05:05 -0800681
682 if (pmi_ic_dex_pc_data.is_missing_types) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700683 dex_pc_data->SetIsMissingTypes();
Calin Juravle589e71e2017-03-03 16:05:05 -0800684 continue;
685 }
686 if (pmi_ic_dex_pc_data.is_megamorphic) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700687 dex_pc_data->SetIsMegamorphic();
Calin Juravle589e71e2017-03-03 16:05:05 -0800688 continue;
689 }
690
Calin Juravle940eb0c2017-01-30 19:30:44 -0800691 for (const ClassReference& class_ref : pmi_ic_dex_pc_data.classes) {
692 const DexReference& dex_ref = pmi.dex_references[class_ref.dex_profile_index];
693 DexFileData* class_dex_data = GetOrAddDexFileData(
694 GetProfileDexFileKey(dex_ref.dex_location),
Mathieu Chartierea650f32017-05-24 12:04:13 -0700695 dex_ref.dex_checksum,
696 dex_ref.num_method_ids);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800697 if (class_dex_data == nullptr) { // checksum mismatch
698 return false;
699 }
Calin Juravlecc3171a2017-05-19 16:47:53 -0700700 dex_pc_data->AddClass(class_dex_data->profile_index, class_ref.type_index);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800701 }
702 }
703 return true;
704}
705
Calin Juravleee9cb412018-02-13 20:32:35 -0800706bool ProfileCompilationInfo::AddMethod(const ProfileMethodInfo& pmi, MethodHotness::Flag flags) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -0700707 DexFileData* const data = GetOrAddDexFileData(pmi.ref.dex_file);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800708 if (data == nullptr) { // checksum mismatch
709 return false;
710 }
Mathieu Chartierfc8b4222017-09-17 13:44:24 -0700711 InlineCacheMap* inline_cache = data->FindOrAddMethod(pmi.ref.index);
Calin Juravleee9cb412018-02-13 20:32:35 -0800712 if (inline_cache == nullptr) {
713 return false;
714 }
715 data->SetMethodHotness(pmi.ref.index, flags);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800716
717 for (const ProfileMethodInfo::ProfileInlineCache& cache : pmi.inline_caches) {
Calin Juravle589e71e2017-03-03 16:05:05 -0800718 if (cache.is_missing_types) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700719 FindOrAddDexPc(inline_cache, cache.dex_pc)->SetIsMissingTypes();
Calin Juravle589e71e2017-03-03 16:05:05 -0800720 continue;
721 }
Mathieu Chartierdbddc222017-05-24 12:04:13 -0700722 for (const TypeReference& class_ref : cache.classes) {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700723 DexFileData* class_dex_data = GetOrAddDexFileData(class_ref.dex_file);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800724 if (class_dex_data == nullptr) { // checksum mismatch
725 return false;
726 }
Calin Juravlecc3171a2017-05-19 16:47:53 -0700727 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, cache.dex_pc);
728 if (dex_pc_data->is_missing_types) {
Calin Juravle589e71e2017-03-03 16:05:05 -0800729 // Don't bother adding classes if we are missing types.
730 break;
731 }
Mathieu Chartierfc8b4222017-09-17 13:44:24 -0700732 dex_pc_data->AddClass(class_dex_data->profile_index, class_ref.TypeIndex());
Calin Juravle940eb0c2017-01-30 19:30:44 -0800733 }
734 }
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800735 return true;
736}
737
738bool ProfileCompilationInfo::AddClassIndex(const std::string& dex_location,
739 uint32_t checksum,
Mathieu Chartierea650f32017-05-24 12:04:13 -0700740 dex::TypeIndex type_idx,
741 uint32_t num_method_ids) {
742 DexFileData* const data = GetOrAddDexFileData(dex_location, checksum, num_method_ids);
Mathieu Chartierc5dd3192015-12-09 16:38:30 -0800743 if (data == nullptr) {
744 return false;
745 }
Jeff Hao54b58552016-11-16 15:15:04 -0800746 data->class_set.insert(type_idx);
Calin Juravle998c2162015-12-21 15:39:33 +0200747 return true;
748}
749
Andreas Gampe37c58462017-03-27 15:14:27 -0700750#define READ_UINT(type, buffer, dest, error) \
751 do { \
752 if (!(buffer).ReadUintAndAdvance<type>(&(dest))) { \
753 *(error) = "Could not read "#dest; \
754 return false; \
755 } \
756 } \
Calin Juravle940eb0c2017-01-30 19:30:44 -0800757 while (false)
758
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700759bool ProfileCompilationInfo::ReadInlineCache(
760 SafeBuffer& buffer,
761 uint8_t number_of_dex_files,
762 const SafeMap<uint8_t, uint8_t>& dex_profile_index_remap,
763 /*out*/ InlineCacheMap* inline_cache,
764 /*out*/ std::string* error) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800765 uint16_t inline_cache_size;
766 READ_UINT(uint16_t, buffer, inline_cache_size, error);
767 for (; inline_cache_size > 0; inline_cache_size--) {
768 uint16_t dex_pc;
769 uint8_t dex_to_classes_map_size;
770 READ_UINT(uint16_t, buffer, dex_pc, error);
771 READ_UINT(uint8_t, buffer, dex_to_classes_map_size, error);
Calin Juravlecc3171a2017-05-19 16:47:53 -0700772 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, dex_pc);
Calin Juravle589e71e2017-03-03 16:05:05 -0800773 if (dex_to_classes_map_size == kIsMissingTypesEncoding) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700774 dex_pc_data->SetIsMissingTypes();
Calin Juravle589e71e2017-03-03 16:05:05 -0800775 continue;
776 }
777 if (dex_to_classes_map_size == kIsMegamorphicEncoding) {
Calin Juravlecc3171a2017-05-19 16:47:53 -0700778 dex_pc_data->SetIsMegamorphic();
Calin Juravle940eb0c2017-01-30 19:30:44 -0800779 continue;
780 }
781 for (; dex_to_classes_map_size > 0; dex_to_classes_map_size--) {
782 uint8_t dex_profile_index;
783 uint8_t dex_classes_size;
784 READ_UINT(uint8_t, buffer, dex_profile_index, error);
785 READ_UINT(uint8_t, buffer, dex_classes_size, error);
786 if (dex_profile_index >= number_of_dex_files) {
787 *error = "dex_profile_index out of bounds ";
788 *error += std::to_string(dex_profile_index) + " " + std::to_string(number_of_dex_files);
789 return false;
790 }
791 for (; dex_classes_size > 0; dex_classes_size--) {
792 uint16_t type_index;
793 READ_UINT(uint16_t, buffer, type_index, error);
Calin Juravled9f4d642018-01-24 20:33:00 -0800794 auto it = dex_profile_index_remap.find(dex_profile_index);
795 if (it == dex_profile_index_remap.end()) {
796 // If we don't have an index that's because the dex file was filtered out when loading.
797 // Set missing types on the dex pc data.
798 dex_pc_data->SetIsMissingTypes();
799 } else {
800 dex_pc_data->AddClass(it->second, dex::TypeIndex(type_index));
801 }
Calin Juravle940eb0c2017-01-30 19:30:44 -0800802 }
803 }
804 }
805 return true;
806}
807
808bool ProfileCompilationInfo::ReadMethods(SafeBuffer& buffer,
809 uint8_t number_of_dex_files,
810 const ProfileLineHeader& line_header,
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700811 const SafeMap<uint8_t, uint8_t>& dex_profile_index_remap,
Calin Juravle940eb0c2017-01-30 19:30:44 -0800812 /*out*/std::string* error) {
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000813 uint32_t unread_bytes_before_operation = buffer.CountUnreadBytes();
814 if (unread_bytes_before_operation < line_header.method_region_size_bytes) {
815 *error += "Profile EOF reached prematurely for ReadMethod";
816 return kProfileLoadBadData;
817 }
818 size_t expected_unread_bytes_after_operation = buffer.CountUnreadBytes()
819 - line_header.method_region_size_bytes;
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000820 uint16_t last_method_index = 0;
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000821 while (buffer.CountUnreadBytes() > expected_unread_bytes_after_operation) {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700822 DexFileData* const data = GetOrAddDexFileData(line_header.dex_location,
823 line_header.checksum,
824 line_header.num_method_ids);
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000825 uint16_t diff_with_last_method_index;
826 READ_UINT(uint16_t, buffer, diff_with_last_method_index, error);
827 uint16_t method_index = last_method_index + diff_with_last_method_index;
828 last_method_index = method_index;
Calin Juravlecc3171a2017-05-19 16:47:53 -0700829 InlineCacheMap* inline_cache = data->FindOrAddMethod(method_index);
Calin Juravleee9cb412018-02-13 20:32:35 -0800830 if (inline_cache == nullptr) {
831 return false;
832 }
Shubham Ajmeraafbbf182017-08-04 14:33:34 -0700833 if (!ReadInlineCache(buffer,
834 number_of_dex_files,
835 dex_profile_index_remap,
836 inline_cache,
837 error)) {
Calin Juravle877fd962016-01-05 14:29:29 +0000838 return false;
839 }
Calin Juravle226501b2015-12-11 14:41:31 +0000840 }
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000841 uint32_t total_bytes_read = unread_bytes_before_operation - buffer.CountUnreadBytes();
842 if (total_bytes_read != line_header.method_region_size_bytes) {
843 *error += "Profile data inconsistent for ReadMethods";
844 return false;
845 }
Calin Juravle940eb0c2017-01-30 19:30:44 -0800846 return true;
847}
848
849bool ProfileCompilationInfo::ReadClasses(SafeBuffer& buffer,
Calin Juravle940eb0c2017-01-30 19:30:44 -0800850 const ProfileLineHeader& line_header,
851 /*out*/std::string* error) {
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000852 size_t unread_bytes_before_op = buffer.CountUnreadBytes();
853 if (unread_bytes_before_op < line_header.class_set_size) {
854 *error += "Profile EOF reached prematurely for ReadClasses";
855 return kProfileLoadBadData;
856 }
857
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000858 uint16_t last_class_index = 0;
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000859 for (uint16_t i = 0; i < line_header.class_set_size; i++) {
Shubham Ajmera4b8a96b2017-05-12 18:00:14 +0000860 uint16_t diff_with_last_class_index;
861 READ_UINT(uint16_t, buffer, diff_with_last_class_index, error);
862 uint16_t type_index = last_class_index + diff_with_last_class_index;
863 last_class_index = type_index;
Calin Juravle940eb0c2017-01-30 19:30:44 -0800864 if (!AddClassIndex(line_header.dex_location,
865 line_header.checksum,
Mathieu Chartierea650f32017-05-24 12:04:13 -0700866 dex::TypeIndex(type_index),
867 line_header.num_method_ids)) {
Calin Juravle64142952016-03-21 14:37:55 +0000868 return false;
869 }
870 }
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000871 size_t total_bytes_read = unread_bytes_before_op - buffer.CountUnreadBytes();
872 uint32_t expected_bytes_read = line_header.class_set_size * sizeof(uint16_t);
873 if (total_bytes_read != expected_bytes_read) {
874 *error += "Profile data inconsistent for ReadClasses";
875 return false;
876 }
Calin Juravle226501b2015-12-11 14:41:31 +0000877 return true;
878}
879
Calin Juravle64142952016-03-21 14:37:55 +0000880// Tests for EOF by trying to read 1 byte from the descriptor.
881// Returns:
882// 0 if the descriptor is at the EOF,
883// -1 if there was an IO error
884// 1 if the descriptor has more content to read
885static int testEOF(int fd) {
886 uint8_t buffer[1];
887 return TEMP_FAILURE_RETRY(read(fd, buffer, 1));
888}
889
890// Reads an uint value previously written with AddUintToBuffer.
891template <typename T>
Calin Juravle940eb0c2017-01-30 19:30:44 -0800892bool ProfileCompilationInfo::SafeBuffer::ReadUintAndAdvance(/*out*/T* value) {
Calin Juravle64142952016-03-21 14:37:55 +0000893 static_assert(std::is_unsigned<T>::value, "Type is not unsigned");
Calin Juravle940eb0c2017-01-30 19:30:44 -0800894 if (ptr_current_ + sizeof(T) > ptr_end_) {
895 return false;
896 }
897 *value = 0;
Calin Juravle64142952016-03-21 14:37:55 +0000898 for (size_t i = 0; i < sizeof(T); i++) {
Calin Juravle940eb0c2017-01-30 19:30:44 -0800899 *value += ptr_current_[i] << (i * kBitsPerByte);
Calin Juravle226501b2015-12-11 14:41:31 +0000900 }
Calin Juravle64142952016-03-21 14:37:55 +0000901 ptr_current_ += sizeof(T);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800902 return true;
Calin Juravle64142952016-03-21 14:37:55 +0000903}
904
905bool ProfileCompilationInfo::SafeBuffer::CompareAndAdvance(const uint8_t* data, size_t data_size) {
906 if (ptr_current_ + data_size > ptr_end_) {
907 return false;
908 }
909 if (memcmp(ptr_current_, data, data_size) == 0) {
910 ptr_current_ += data_size;
911 return true;
912 }
913 return false;
914}
915
Calin Juravle36060d12018-01-19 16:28:38 -0800916ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::SafeBuffer::Fill(
Calin Juravle1e2de642018-01-18 01:08:23 -0800917 ProfileSource& source,
918 const std::string& debug_stage,
919 /*out*/ std::string* error) {
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000920 size_t byte_count = (ptr_end_ - ptr_current_) * sizeof(*ptr_current_);
Calin Juravle64142952016-03-21 14:37:55 +0000921 uint8_t* buffer = ptr_current_;
Calin Juravle1e2de642018-01-18 01:08:23 -0800922 return source.Read(buffer, byte_count, debug_stage, error);
Calin Juravle64142952016-03-21 14:37:55 +0000923}
924
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000925size_t ProfileCompilationInfo::SafeBuffer::CountUnreadBytes() {
926 return (ptr_end_ - ptr_current_) * sizeof(*ptr_current_);
927}
928
929const uint8_t* ProfileCompilationInfo::SafeBuffer::GetCurrentPtr() {
930 return ptr_current_;
931}
932
933void ProfileCompilationInfo::SafeBuffer::Advance(size_t data_size) {
934 ptr_current_ += data_size;
935}
936
Calin Juravle36060d12018-01-19 16:28:38 -0800937ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadProfileHeader(
Calin Juravle1e2de642018-01-18 01:08:23 -0800938 ProfileSource& source,
Calin Juravle940eb0c2017-01-30 19:30:44 -0800939 /*out*/uint8_t* number_of_dex_files,
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000940 /*out*/uint32_t* uncompressed_data_size,
941 /*out*/uint32_t* compressed_data_size,
Calin Juravle64142952016-03-21 14:37:55 +0000942 /*out*/std::string* error) {
943 // Read magic and version
944 const size_t kMagicVersionSize =
945 sizeof(kProfileMagic) +
946 sizeof(kProfileVersion) +
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000947 sizeof(uint8_t) + // number of dex files
948 sizeof(uint32_t) + // size of uncompressed profile data
949 sizeof(uint32_t); // size of compressed profile data
Calin Juravle64142952016-03-21 14:37:55 +0000950
951 SafeBuffer safe_buffer(kMagicVersionSize);
952
Calin Juravle36060d12018-01-19 16:28:38 -0800953 ProfileLoadStatus status = safe_buffer.Fill(source, "ReadProfileHeader", error);
Calin Juravle64142952016-03-21 14:37:55 +0000954 if (status != kProfileLoadSuccess) {
955 return status;
956 }
957
958 if (!safe_buffer.CompareAndAdvance(kProfileMagic, sizeof(kProfileMagic))) {
959 *error = "Profile missing magic";
960 return kProfileLoadVersionMismatch;
961 }
962 if (!safe_buffer.CompareAndAdvance(kProfileVersion, sizeof(kProfileVersion))) {
963 *error = "Profile version mismatch";
964 return kProfileLoadVersionMismatch;
965 }
Calin Juravle940eb0c2017-01-30 19:30:44 -0800966 if (!safe_buffer.ReadUintAndAdvance<uint8_t>(number_of_dex_files)) {
967 *error = "Cannot read the number of dex files";
968 return kProfileLoadBadData;
969 }
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000970 if (!safe_buffer.ReadUintAndAdvance<uint32_t>(uncompressed_data_size)) {
971 *error = "Cannot read the size of uncompressed data";
972 return kProfileLoadBadData;
973 }
974 if (!safe_buffer.ReadUintAndAdvance<uint32_t>(compressed_data_size)) {
975 *error = "Cannot read the size of compressed data";
976 return kProfileLoadBadData;
977 }
Calin Juravle64142952016-03-21 14:37:55 +0000978 return kProfileLoadSuccess;
979}
980
Calin Juravle940eb0c2017-01-30 19:30:44 -0800981bool ProfileCompilationInfo::ReadProfileLineHeaderElements(SafeBuffer& buffer,
982 /*out*/uint16_t* dex_location_size,
983 /*out*/ProfileLineHeader* line_header,
984 /*out*/std::string* error) {
985 READ_UINT(uint16_t, buffer, *dex_location_size, error);
986 READ_UINT(uint16_t, buffer, line_header->class_set_size, error);
987 READ_UINT(uint32_t, buffer, line_header->method_region_size_bytes, error);
988 READ_UINT(uint32_t, buffer, line_header->checksum, error);
Mathieu Chartierea650f32017-05-24 12:04:13 -0700989 READ_UINT(uint32_t, buffer, line_header->num_method_ids, error);
Calin Juravle940eb0c2017-01-30 19:30:44 -0800990 return true;
991}
992
Calin Juravle36060d12018-01-19 16:28:38 -0800993ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadProfileLineHeader(
Shubham Ajmera4d198e02017-05-12 17:45:29 +0000994 SafeBuffer& buffer,
995 /*out*/ProfileLineHeader* line_header,
996 /*out*/std::string* error) {
997 if (buffer.CountUnreadBytes() < kLineHeaderSize) {
998 *error += "Profile EOF reached prematurely for ReadProfileLineHeader";
999 return kProfileLoadBadData;
Calin Juravle64142952016-03-21 14:37:55 +00001000 }
1001
Calin Juravle940eb0c2017-01-30 19:30:44 -08001002 uint16_t dex_location_size;
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001003 if (!ReadProfileLineHeaderElements(buffer, &dex_location_size, line_header, error)) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001004 return kProfileLoadBadData;
1005 }
Calin Juravle64142952016-03-21 14:37:55 +00001006
1007 if (dex_location_size == 0 || dex_location_size > kMaxDexFileKeyLength) {
Goran Jakovljevic4eb6fbf2016-04-25 19:14:17 +02001008 *error = "DexFileKey has an invalid size: " +
1009 std::to_string(static_cast<uint32_t>(dex_location_size));
Calin Juravle64142952016-03-21 14:37:55 +00001010 return kProfileLoadBadData;
1011 }
1012
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001013 if (buffer.CountUnreadBytes() < dex_location_size) {
1014 *error += "Profile EOF reached prematurely for ReadProfileHeaderDexLocation";
1015 return kProfileLoadBadData;
Calin Juravle64142952016-03-21 14:37:55 +00001016 }
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001017 const uint8_t* base_ptr = buffer.GetCurrentPtr();
Calin Juravle64142952016-03-21 14:37:55 +00001018 line_header->dex_location.assign(
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001019 reinterpret_cast<const char*>(base_ptr), dex_location_size);
1020 buffer.Advance(dex_location_size);
Calin Juravle64142952016-03-21 14:37:55 +00001021 return kProfileLoadSuccess;
1022}
1023
Calin Juravle36060d12018-01-19 16:28:38 -08001024ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadProfileLine(
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001025 SafeBuffer& buffer,
Calin Juravle940eb0c2017-01-30 19:30:44 -08001026 uint8_t number_of_dex_files,
Calin Juravle64142952016-03-21 14:37:55 +00001027 const ProfileLineHeader& line_header,
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001028 const SafeMap<uint8_t, uint8_t>& dex_profile_index_remap,
1029 bool merge_classes,
Calin Juravle64142952016-03-21 14:37:55 +00001030 /*out*/std::string* error) {
Mathieu Chartierea650f32017-05-24 12:04:13 -07001031 DexFileData* data = GetOrAddDexFileData(line_header.dex_location,
1032 line_header.checksum,
1033 line_header.num_method_ids);
1034 if (data == nullptr) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001035 *error = "Error when reading profile file line header: checksum mismatch for "
1036 + line_header.dex_location;
1037 return kProfileLoadBadData;
1038 }
Calin Juravle64142952016-03-21 14:37:55 +00001039
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001040 if (!ReadMethods(buffer, number_of_dex_files, line_header, dex_profile_index_remap, error)) {
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001041 return kProfileLoadBadData;
Calin Juravle64142952016-03-21 14:37:55 +00001042 }
Calin Juravle940eb0c2017-01-30 19:30:44 -08001043
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001044 if (merge_classes) {
1045 if (!ReadClasses(buffer, line_header, error)) {
1046 return kProfileLoadBadData;
1047 }
Calin Juravle940eb0c2017-01-30 19:30:44 -08001048 }
Mathieu Chartierea650f32017-05-24 12:04:13 -07001049
1050 const size_t bytes = data->bitmap_storage.size();
1051 if (buffer.CountUnreadBytes() < bytes) {
1052 *error += "Profile EOF reached prematurely for ReadProfileHeaderDexLocation";
1053 return kProfileLoadBadData;
1054 }
1055 const uint8_t* base_ptr = buffer.GetCurrentPtr();
Andreas Gampe693bfbf2017-11-10 12:23:31 -08001056 std::copy_n(base_ptr, bytes, data->bitmap_storage.data());
Mathieu Chartierea650f32017-05-24 12:04:13 -07001057 buffer.Advance(bytes);
1058 // Read method bitmap.
Calin Juravle64142952016-03-21 14:37:55 +00001059 return kProfileLoadSuccess;
Calin Juravle226501b2015-12-11 14:41:31 +00001060}
1061
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001062// TODO(calin): Fix this API. ProfileCompilationInfo::Load should be static and
1063// return a unique pointer to a ProfileCompilationInfo upon success.
Calin Juravled9f4d642018-01-24 20:33:00 -08001064bool ProfileCompilationInfo::Load(
1065 int fd, bool merge_classes, const ProfileLoadFilterFn& filter_fn) {
Calin Juravle64142952016-03-21 14:37:55 +00001066 std::string error;
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001067
Calin Juravled9f4d642018-01-24 20:33:00 -08001068 ProfileLoadStatus status = LoadInternal(fd, &error, merge_classes, filter_fn);
Calin Juravle64142952016-03-21 14:37:55 +00001069
1070 if (status == kProfileLoadSuccess) {
1071 return true;
1072 } else {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001073 LOG(WARNING) << "Error when reading profile: " << error;
Calin Juravle64142952016-03-21 14:37:55 +00001074 return false;
1075 }
1076}
1077
Shubham Ajmera188b2bf2017-09-20 15:53:35 -07001078bool ProfileCompilationInfo::VerifyProfileData(const std::vector<const DexFile*>& dex_files) {
1079 std::unordered_map<std::string, const DexFile*> key_to_dex_file;
1080 for (const DexFile* dex_file : dex_files) {
1081 key_to_dex_file.emplace(GetProfileDexFileKey(dex_file->GetLocation()), dex_file);
1082 }
1083 for (const DexFileData* dex_data : info_) {
1084 const auto it = key_to_dex_file.find(dex_data->profile_key);
1085 if (it == key_to_dex_file.end()) {
1086 // It is okay if profile contains data for additional dex files.
1087 continue;
1088 }
1089 const DexFile* dex_file = it->second;
1090 const std::string& dex_location = dex_file->GetLocation();
1091 if (!ChecksumMatch(dex_data->checksum, dex_file->GetLocationChecksum())) {
1092 LOG(ERROR) << "Dex checksum mismatch while verifying profile "
1093 << "dex location " << dex_location << " (checksum="
1094 << dex_file->GetLocationChecksum() << ", profile checksum="
1095 << dex_data->checksum;
1096 return false;
1097 }
Shubham Ajmera460ab792017-09-21 13:44:07 -07001098
1099 if (dex_data->num_method_ids != dex_file->NumMethodIds()) {
1100 LOG(ERROR) << "Number of method ids in dex file and profile don't match."
1101 << "dex location " << dex_location << " NumMethodId in DexFile"
1102 << dex_file->NumMethodIds() << ", NumMethodId in profile"
1103 << dex_data->num_method_ids;
1104 return false;
1105 }
1106
Shubham Ajmera188b2bf2017-09-20 15:53:35 -07001107 // Verify method_encoding.
1108 for (const auto& method_it : dex_data->method_map) {
1109 size_t method_id = (size_t)(method_it.first);
1110 if (method_id >= dex_file->NumMethodIds()) {
1111 LOG(ERROR) << "Invalid method id in profile file. dex location="
1112 << dex_location << " method_id=" << method_id << " NumMethodIds="
1113 << dex_file->NumMethodIds();
1114 return false;
1115 }
1116
1117 // Verify class indices of inline caches.
1118 const InlineCacheMap &inline_cache_map = method_it.second;
1119 for (const auto& inline_cache_it : inline_cache_map) {
1120 const DexPcData dex_pc_data = inline_cache_it.second;
1121 if (dex_pc_data.is_missing_types || dex_pc_data.is_megamorphic) {
1122 // No class indices to verify.
1123 continue;
1124 }
1125
1126 const ClassSet &classes = dex_pc_data.classes;
1127 SafeMap<uint8_t, std::vector<dex::TypeIndex>> dex_to_classes_map;
1128 // Group the classes by dex. We expect that most of the classes will come from
1129 // the same dex, so this will be more efficient than encoding the dex index
1130 // for each class reference.
1131 GroupClassesByDex(classes, &dex_to_classes_map);
1132 for (const auto &dex_it : dex_to_classes_map) {
1133 uint8_t dex_profile_index = dex_it.first;
1134 const auto dex_file_inline_cache_it = key_to_dex_file.find(
1135 info_[dex_profile_index]->profile_key);
1136 if (dex_file_inline_cache_it == key_to_dex_file.end()) {
1137 // It is okay if profile contains data for additional dex files.
1138 continue;
1139 }
1140 const DexFile *dex_file_for_inline_cache_check = dex_file_inline_cache_it->second;
1141 const std::vector<dex::TypeIndex> &dex_classes = dex_it.second;
1142 for (size_t i = 0; i < dex_classes.size(); i++) {
1143 if (dex_classes[i].index_ >= dex_file_for_inline_cache_check->NumTypeIds()) {
1144 LOG(ERROR) << "Invalid inline cache in profile file. dex location="
1145 << dex_location << " method_id=" << method_id
1146 << " dex_profile_index="
1147 << static_cast<uint16_t >(dex_profile_index) << " type_index="
1148 << dex_classes[i].index_
1149 << " NumTypeIds="
1150 << dex_file_for_inline_cache_check->NumTypeIds();
1151 return false;
1152 }
1153 }
1154 }
1155 }
1156 }
1157 // Verify class_ids.
1158 for (const auto& class_id : dex_data->class_set) {
1159 if (class_id.index_ >= dex_file->NumTypeIds()) {
1160 LOG(ERROR) << "Invalid class id in profile file. dex_file location "
1161 << dex_location << " class_id=" << class_id.index_ << " NumClassIds="
1162 << dex_file->NumClassDefs();
1163 return false;
1164 }
1165 }
1166 }
1167 return true;
1168}
1169
Calin Juravle36060d12018-01-19 16:28:38 -08001170ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::OpenSource(
Calin Juravle1e2de642018-01-18 01:08:23 -08001171 int32_t fd,
1172 /*out*/ std::unique_ptr<ProfileSource>* source,
1173 /*out*/ std::string* error) {
1174 if (IsProfileFile(fd)) {
1175 source->reset(ProfileSource::Create(fd));
1176 return kProfileLoadSuccess;
1177 } else {
Josh Gao675e0a52018-08-30 17:29:00 -07001178 std::unique_ptr<ZipArchive> zip_archive(
1179 ZipArchive::OpenFromFd(DupCloexec(fd), "profile", error));
Calin Juravle1e2de642018-01-18 01:08:23 -08001180 if (zip_archive.get() == nullptr) {
1181 *error = "Could not open the profile zip archive";
1182 return kProfileLoadBadData;
1183 }
1184 std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(kDexMetadataProfileEntry, error));
1185 if (zip_entry == nullptr) {
1186 // Allow archives without the profile entry. In this case, create an empty profile.
1187 // This gives more flexible when ure-using archives that may miss the entry.
1188 // (e.g. dex metadata files)
Vladimir Marko54159c62018-06-20 14:30:08 +01001189 LOG(WARNING) << "Could not find entry " << kDexMetadataProfileEntry
1190 << " in the zip archive. Creating an empty profile.";
Vladimir Markoc34bebf2018-08-16 16:12:49 +01001191 source->reset(ProfileSource::Create(MemMap::Invalid()));
Calin Juravle1e2de642018-01-18 01:08:23 -08001192 return kProfileLoadSuccess;
1193 }
1194 if (zip_entry->GetUncompressedLength() == 0) {
1195 *error = "Empty profile entry in the zip archive.";
1196 return kProfileLoadBadData;
1197 }
1198
Mathieu Chartier792111c2018-02-15 13:02:15 -08001199 // TODO(calin) pass along file names to assist with debugging.
Vladimir Markoc34bebf2018-08-16 16:12:49 +01001200 MemMap map = zip_entry->MapDirectlyOrExtract(kDexMetadataProfileEntry, "profile file", error);
Calin Juravle1e2de642018-01-18 01:08:23 -08001201
Vladimir Markoc34bebf2018-08-16 16:12:49 +01001202 if (map.IsValid()) {
Calin Juravle1e2de642018-01-18 01:08:23 -08001203 source->reset(ProfileSource::Create(std::move(map)));
1204 return kProfileLoadSuccess;
1205 } else {
1206 return kProfileLoadBadData;
1207 }
1208 }
1209}
1210
Calin Juravle36060d12018-01-19 16:28:38 -08001211ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ProfileSource::Read(
Calin Juravle1e2de642018-01-18 01:08:23 -08001212 uint8_t* buffer,
1213 size_t byte_count,
1214 const std::string& debug_stage,
1215 std::string* error) {
1216 if (IsMemMap()) {
Vladimir Markoc34bebf2018-08-16 16:12:49 +01001217 if (mem_map_cur_ + byte_count > mem_map_.Size()) {
Calin Juravle1e2de642018-01-18 01:08:23 -08001218 return kProfileLoadBadData;
1219 }
1220 for (size_t i = 0; i < byte_count; i++) {
Vladimir Markoc34bebf2018-08-16 16:12:49 +01001221 buffer[i] = *(mem_map_.Begin() + mem_map_cur_);
Calin Juravle1e2de642018-01-18 01:08:23 -08001222 mem_map_cur_++;
1223 }
1224 } else {
1225 while (byte_count > 0) {
1226 int bytes_read = TEMP_FAILURE_RETRY(read(fd_, buffer, byte_count));;
1227 if (bytes_read == 0) {
1228 *error += "Profile EOF reached prematurely for " + debug_stage;
1229 return kProfileLoadBadData;
1230 } else if (bytes_read < 0) {
1231 *error += "Profile IO error for " + debug_stage + strerror(errno);
1232 return kProfileLoadIOError;
1233 }
1234 byte_count -= bytes_read;
1235 buffer += bytes_read;
1236 }
1237 }
1238 return kProfileLoadSuccess;
1239}
1240
1241bool ProfileCompilationInfo::ProfileSource::HasConsumedAllData() const {
1242 return IsMemMap()
Vladimir Markoc34bebf2018-08-16 16:12:49 +01001243 ? (!mem_map_.IsValid() || mem_map_cur_ == mem_map_.Size())
Calin Juravle1e2de642018-01-18 01:08:23 -08001244 : (testEOF(fd_) == 0);
1245}
1246
1247bool ProfileCompilationInfo::ProfileSource::HasEmptyContent() const {
1248 if (IsMemMap()) {
Vladimir Markoc34bebf2018-08-16 16:12:49 +01001249 return !mem_map_.IsValid() || mem_map_.Size() == 0;
Calin Juravle1e2de642018-01-18 01:08:23 -08001250 } else {
1251 struct stat stat_buffer;
1252 if (fstat(fd_, &stat_buffer) != 0) {
1253 return false;
1254 }
1255 return stat_buffer.st_size == 0;
1256 }
1257}
1258
Calin Juravledcab1902017-05-12 19:18:47 -07001259// TODO(calin): fail fast if the dex checksums don't match.
Calin Juravle36060d12018-01-19 16:28:38 -08001260ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::LoadInternal(
Calin Juravled9f4d642018-01-24 20:33:00 -08001261 int32_t fd,
1262 std::string* error,
1263 bool merge_classes,
1264 const ProfileLoadFilterFn& filter_fn) {
Mathieu Chartier32ce2ad2016-03-04 14:58:03 -08001265 ScopedTrace trace(__PRETTY_FUNCTION__);
Calin Juravle2e2db782016-02-23 12:00:03 +00001266 DCHECK_GE(fd, 0);
Calin Juravle226501b2015-12-11 14:41:31 +00001267
Calin Juravle1e2de642018-01-18 01:08:23 -08001268 std::unique_ptr<ProfileSource> source;
Calin Juravle36060d12018-01-19 16:28:38 -08001269 ProfileLoadStatus status = OpenSource(fd, &source, error);
Calin Juravle1e2de642018-01-18 01:08:23 -08001270 if (status != kProfileLoadSuccess) {
1271 return status;
Calin Juravle226501b2015-12-11 14:41:31 +00001272 }
Calin Juravle1e2de642018-01-18 01:08:23 -08001273
Calin Juravle64142952016-03-21 14:37:55 +00001274 // We allow empty profile files.
1275 // Profiles may be created by ActivityManager or installd before we manage to
1276 // process them in the runtime or profman.
Calin Juravle1e2de642018-01-18 01:08:23 -08001277 if (source->HasEmptyContent()) {
Calin Juravle64142952016-03-21 14:37:55 +00001278 return kProfileLoadSuccess;
1279 }
Calin Juravle1e2de642018-01-18 01:08:23 -08001280
Calin Juravle940eb0c2017-01-30 19:30:44 -08001281 // Read profile header: magic + version + number_of_dex_files.
1282 uint8_t number_of_dex_files;
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001283 uint32_t uncompressed_data_size;
1284 uint32_t compressed_data_size;
Calin Juravle1e2de642018-01-18 01:08:23 -08001285 status = ReadProfileHeader(*source,
1286 &number_of_dex_files,
1287 &uncompressed_data_size,
1288 &compressed_data_size,
1289 error);
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001290
Calin Juravle64142952016-03-21 14:37:55 +00001291 if (status != kProfileLoadSuccess) {
1292 return status;
1293 }
Mathieu Chartierf2e2af82017-07-12 21:09:57 -07001294 // Allow large profiles for non target builds for the case where we are merging many profiles
1295 // to generate a boot image profile.
1296 if (kIsTargetBuild && uncompressed_data_size > kProfileSizeErrorThresholdInBytes) {
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001297 LOG(ERROR) << "Profile data size exceeds "
1298 << std::to_string(kProfileSizeErrorThresholdInBytes)
1299 << " bytes";
1300 return kProfileLoadBadData;
1301 }
1302 if (uncompressed_data_size > kProfileSizeWarningThresholdInBytes) {
1303 LOG(WARNING) << "Profile data size exceeds "
1304 << std::to_string(kProfileSizeWarningThresholdInBytes)
1305 << " bytes";
1306 }
1307
1308 std::unique_ptr<uint8_t[]> compressed_data(new uint8_t[compressed_data_size]);
Calin Juravle1e2de642018-01-18 01:08:23 -08001309 status = source->Read(compressed_data.get(), compressed_data_size, "ReadContent", error);
1310 if (status != kProfileLoadSuccess) {
1311 *error += "Unable to read compressed profile data";
1312 return status;
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001313 }
1314
Calin Juravle1e2de642018-01-18 01:08:23 -08001315 if (!source->HasConsumedAllData()) {
1316 *error += "Unexpected data in the profile file.";
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001317 return kProfileLoadBadData;
1318 }
1319
1320 SafeBuffer uncompressed_data(uncompressed_data_size);
1321
1322 int ret = InflateBuffer(compressed_data.get(),
1323 compressed_data_size,
1324 uncompressed_data_size,
1325 uncompressed_data.Get());
1326
1327 if (ret != Z_STREAM_END) {
1328 *error += "Error reading uncompressed profile data";
1329 return kProfileLoadBadData;
1330 }
1331
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001332 std::vector<ProfileLineHeader> profile_line_headers;
1333 // Read profile line headers.
Calin Juravle940eb0c2017-01-30 19:30:44 -08001334 for (uint8_t k = 0; k < number_of_dex_files; k++) {
Calin Juravle64142952016-03-21 14:37:55 +00001335 ProfileLineHeader line_header;
Calin Juravle940eb0c2017-01-30 19:30:44 -08001336
Calin Juravle64142952016-03-21 14:37:55 +00001337 // First, read the line header to get the amount of data we need to read.
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001338 status = ReadProfileLineHeader(uncompressed_data, &line_header, error);
Calin Juravle64142952016-03-21 14:37:55 +00001339 if (status != kProfileLoadSuccess) {
1340 return status;
1341 }
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001342 profile_line_headers.push_back(line_header);
1343 }
Calin Juravle64142952016-03-21 14:37:55 +00001344
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001345 SafeMap<uint8_t, uint8_t> dex_profile_index_remap;
Calin Juravled9f4d642018-01-24 20:33:00 -08001346 if (!RemapProfileIndex(profile_line_headers, filter_fn, &dex_profile_index_remap)) {
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001347 return kProfileLoadBadData;
1348 }
1349
1350 for (uint8_t k = 0; k < number_of_dex_files; k++) {
Calin Juravled9f4d642018-01-24 20:33:00 -08001351 if (!filter_fn(profile_line_headers[k].dex_location, profile_line_headers[k].checksum)) {
1352 // We have to skip the line. Advanced the current pointer of the buffer.
1353 size_t profile_line_size =
Calin Juravlef0cf86f2018-04-25 16:47:25 -07001354 profile_line_headers[k].class_set_size * sizeof(uint16_t) +
Calin Juravled9f4d642018-01-24 20:33:00 -08001355 profile_line_headers[k].method_region_size_bytes +
1356 DexFileData::ComputeBitmapStorage(profile_line_headers[k].num_method_ids);
1357 uncompressed_data.Advance(profile_line_size);
1358 } else {
1359 // Now read the actual profile line.
1360 status = ReadProfileLine(uncompressed_data,
1361 number_of_dex_files,
1362 profile_line_headers[k],
1363 dex_profile_index_remap,
1364 merge_classes,
1365 error);
1366 if (status != kProfileLoadSuccess) {
1367 return status;
1368 }
Calin Juravle64142952016-03-21 14:37:55 +00001369 }
Calin Juravle64142952016-03-21 14:37:55 +00001370 }
1371
1372 // Check that we read everything and that profiles don't contain junk data.
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001373 if (uncompressed_data.CountUnreadBytes() > 0) {
Calin Juravle64142952016-03-21 14:37:55 +00001374 *error = "Unexpected content in the profile file";
1375 return kProfileLoadBadData;
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001376 } else {
1377 return kProfileLoadSuccess;
Calin Juravle64142952016-03-21 14:37:55 +00001378 }
Calin Juravle998c2162015-12-21 15:39:33 +02001379}
1380
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001381bool ProfileCompilationInfo::RemapProfileIndex(
1382 const std::vector<ProfileLineHeader>& profile_line_headers,
Calin Juravled9f4d642018-01-24 20:33:00 -08001383 const ProfileLoadFilterFn& filter_fn,
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001384 /*out*/SafeMap<uint8_t, uint8_t>* dex_profile_index_remap) {
1385 // First verify that all checksums match. This will avoid adding garbage to
1386 // the current profile info.
1387 // Note that the number of elements should be very small, so this should not
1388 // be a performance issue.
Andreas Gampebc802de2018-06-20 17:24:11 -07001389 for (const ProfileLineHeader& other_profile_line_header : profile_line_headers) {
Calin Juravled9f4d642018-01-24 20:33:00 -08001390 if (!filter_fn(other_profile_line_header.dex_location, other_profile_line_header.checksum)) {
1391 continue;
1392 }
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001393 // verify_checksum is false because we want to differentiate between a missing dex data and
1394 // a mismatched checksum.
1395 const DexFileData* dex_data = FindDexData(other_profile_line_header.dex_location,
1396 0u,
1397 false /* verify_checksum */);
1398 if ((dex_data != nullptr) && (dex_data->checksum != other_profile_line_header.checksum)) {
1399 LOG(WARNING) << "Checksum mismatch for dex " << other_profile_line_header.dex_location;
1400 return false;
1401 }
1402 }
1403 // All checksums match. Import the data.
1404 uint32_t num_dex_files = static_cast<uint32_t>(profile_line_headers.size());
1405 for (uint32_t i = 0; i < num_dex_files; i++) {
Calin Juravled9f4d642018-01-24 20:33:00 -08001406 if (!filter_fn(profile_line_headers[i].dex_location, profile_line_headers[i].checksum)) {
1407 continue;
1408 }
Shubham Ajmeraafbbf182017-08-04 14:33:34 -07001409 const DexFileData* dex_data = GetOrAddDexFileData(profile_line_headers[i].dex_location,
1410 profile_line_headers[i].checksum,
1411 profile_line_headers[i].num_method_ids);
1412 if (dex_data == nullptr) {
1413 return false; // Could happen if we exceed the number of allowed dex files.
1414 }
1415 dex_profile_index_remap->Put(i, dex_data->profile_index);
1416 }
1417 return true;
1418}
Shubham Ajmera61200a02017-08-30 16:29:41 -07001419
Shubham Ajmera4d198e02017-05-12 17:45:29 +00001420std::unique_ptr<uint8_t[]> ProfileCompilationInfo::DeflateBuffer(const uint8_t* in_buffer,
1421 uint32_t in_size,
1422 uint32_t* compressed_data_size) {
1423 z_stream strm;
1424 strm.zalloc = Z_NULL;
1425 strm.zfree = Z_NULL;
1426 strm.opaque = Z_NULL;
1427 int ret = deflateInit(&strm, 1);
1428 if (ret != Z_OK) {
1429 return nullptr;
1430 }
1431
1432 uint32_t out_size = deflateBound(&strm, in_size);
1433
1434 std::unique_ptr<uint8_t[]> compressed_buffer(new uint8_t[out_size]);
1435 strm.avail_in = in_size;
1436 strm.next_in = const_cast<uint8_t*>(in_buffer);
1437 strm.avail_out = out_size;
1438 strm.next_out = &compressed_buffer[0];
1439 ret = deflate(&strm, Z_FINISH);
1440 if (ret == Z_STREAM_ERROR) {
1441 return nullptr;
1442 }
1443 *compressed_data_size = out_size - strm.avail_out;
1444 deflateEnd(&strm);
1445 return compressed_buffer;
1446}
1447
1448int ProfileCompilationInfo::InflateBuffer(const uint8_t* in_buffer,
1449 uint32_t in_size,
1450 uint32_t expected_uncompressed_data_size,
1451 uint8_t* out_buffer) {
1452 z_stream strm;
1453
1454 /* allocate inflate state */
1455 strm.zalloc = Z_NULL;
1456 strm.zfree = Z_NULL;
1457 strm.opaque = Z_NULL;
1458 strm.avail_in = in_size;
1459 strm.next_in = const_cast<uint8_t*>(in_buffer);
1460 strm.avail_out = expected_uncompressed_data_size;
1461 strm.next_out = out_buffer;
1462
1463 int ret;
1464 inflateInit(&strm);
1465 ret = inflate(&strm, Z_NO_FLUSH);
1466
1467 if (strm.avail_in != 0 || strm.avail_out != 0) {
1468 return Z_DATA_ERROR;
1469 }
1470 inflateEnd(&strm);
1471 return ret;
1472}
1473
Mathieu Chartier2f794552017-06-19 10:58:08 -07001474bool ProfileCompilationInfo::MergeWith(const ProfileCompilationInfo& other,
1475 bool merge_classes) {
Calin Juravle5d1bd0a2016-03-24 20:33:22 +00001476 // First verify that all checksums match. This will avoid adding garbage to
1477 // the current profile info.
1478 // Note that the number of elements should be very small, so this should not
1479 // be a performance issue.
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001480 for (const DexFileData* other_dex_data : other.info_) {
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001481 // verify_checksum is false because we want to differentiate between a missing dex data and
1482 // a mismatched checksum.
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001483 const DexFileData* dex_data = FindDexData(other_dex_data->profile_key,
1484 0u,
1485 /* verify_checksum */ false);
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001486 if ((dex_data != nullptr) && (dex_data->checksum != other_dex_data->checksum)) {
1487 LOG(WARNING) << "Checksum mismatch for dex " << other_dex_data->profile_key;
Calin Juravle5d1bd0a2016-03-24 20:33:22 +00001488 return false;
1489 }
1490 }
1491 // All checksums match. Import the data.
Calin Juravle940eb0c2017-01-30 19:30:44 -08001492
1493 // The other profile might have a different indexing of dex files.
1494 // That is because each dex files gets a 'dex_profile_index' on a first come first served basis.
1495 // That means that the order in with the methods are added to the profile matters for the
1496 // actual indices.
1497 // The reason we cannot rely on the actual multidex index is that a single profile may store
1498 // data from multiple splits. This means that a profile may contain a classes2.dex from split-A
1499 // and one from split-B.
1500
1501 // First, build a mapping from other_dex_profile_index to this_dex_profile_index.
1502 // This will make sure that the ClassReferences will point to the correct dex file.
1503 SafeMap<uint8_t, uint8_t> dex_profile_index_remap;
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001504 for (const DexFileData* other_dex_data : other.info_) {
1505 const DexFileData* dex_data = GetOrAddDexFileData(other_dex_data->profile_key,
Mathieu Chartierea650f32017-05-24 12:04:13 -07001506 other_dex_data->checksum,
1507 other_dex_data->num_method_ids);
Calin Juravlee0ac1152017-02-13 19:03:47 -08001508 if (dex_data == nullptr) {
1509 return false; // Could happen if we exceed the number of allowed dex files.
1510 }
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001511 dex_profile_index_remap.Put(other_dex_data->profile_index, dex_data->profile_index);
Calin Juravle940eb0c2017-01-30 19:30:44 -08001512 }
1513
1514 // Merge the actual profile data.
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001515 for (const DexFileData* other_dex_data : other.info_) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001516 DexFileData* dex_data = const_cast<DexFileData*>(FindDexData(other_dex_data->profile_key,
1517 other_dex_data->checksum));
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001518 DCHECK(dex_data != nullptr);
Calin Juravle940eb0c2017-01-30 19:30:44 -08001519
1520 // Merge the classes.
Mathieu Chartier2f794552017-06-19 10:58:08 -07001521 if (merge_classes) {
1522 dex_data->class_set.insert(other_dex_data->class_set.begin(),
1523 other_dex_data->class_set.end());
1524 }
Calin Juravle940eb0c2017-01-30 19:30:44 -08001525
1526 // Merge the methods and the inline caches.
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001527 for (const auto& other_method_it : other_dex_data->method_map) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001528 uint16_t other_method_index = other_method_it.first;
Calin Juravlecc3171a2017-05-19 16:47:53 -07001529 InlineCacheMap* inline_cache = dex_data->FindOrAddMethod(other_method_index);
Calin Juravleee9cb412018-02-13 20:32:35 -08001530 if (inline_cache == nullptr) {
1531 return false;
1532 }
Calin Juravle940eb0c2017-01-30 19:30:44 -08001533 const auto& other_inline_cache = other_method_it.second;
1534 for (const auto& other_ic_it : other_inline_cache) {
1535 uint16_t other_dex_pc = other_ic_it.first;
1536 const ClassSet& other_class_set = other_ic_it.second.classes;
Calin Juravlecc3171a2017-05-19 16:47:53 -07001537 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, other_dex_pc);
Calin Juravle589e71e2017-03-03 16:05:05 -08001538 if (other_ic_it.second.is_missing_types) {
Calin Juravlecc3171a2017-05-19 16:47:53 -07001539 dex_pc_data->SetIsMissingTypes();
Calin Juravle589e71e2017-03-03 16:05:05 -08001540 } else if (other_ic_it.second.is_megamorphic) {
Calin Juravlecc3171a2017-05-19 16:47:53 -07001541 dex_pc_data->SetIsMegamorphic();
Calin Juravle0def68d2017-02-21 19:00:33 -08001542 } else {
1543 for (const auto& class_it : other_class_set) {
Calin Juravlecc3171a2017-05-19 16:47:53 -07001544 dex_pc_data->AddClass(dex_profile_index_remap.Get(
Calin Juravle0def68d2017-02-21 19:00:33 -08001545 class_it.dex_profile_index), class_it.type_index);
1546 }
Calin Juravle940eb0c2017-01-30 19:30:44 -08001547 }
1548 }
1549 }
Mathieu Chartierea650f32017-05-24 12:04:13 -07001550
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001551 // Merge the method bitmaps.
Mathieu Chartierea650f32017-05-24 12:04:13 -07001552 dex_data->MergeBitmap(*other_dex_data);
Calin Juravle998c2162015-12-21 15:39:33 +02001553 }
1554 return true;
Calin Juravle226501b2015-12-11 14:41:31 +00001555}
1556
Mathieu Chartierdb40eac2017-06-09 18:34:11 -07001557const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexData(
1558 const DexFile* dex_file) const {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001559 return FindDexData(GetProfileDexFileKey(dex_file->GetLocation()),
1560 dex_file->GetLocationChecksum());
Mathieu Chartierdb40eac2017-06-09 18:34:11 -07001561}
1562
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001563ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::GetMethodHotness(
1564 const MethodReference& method_ref) const {
Mathieu Chartierdb40eac2017-06-09 18:34:11 -07001565 const DexFileData* dex_data = FindDexData(method_ref.dex_file);
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001566 return dex_data != nullptr
Mathieu Chartierfc8b4222017-09-17 13:44:24 -07001567 ? dex_data->GetHotnessInfo(method_ref.index)
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001568 : MethodHotness();
Mathieu Chartierdb40eac2017-06-09 18:34:11 -07001569}
1570
Mathieu Chartier2f794552017-06-19 10:58:08 -07001571bool ProfileCompilationInfo::AddMethodHotness(const MethodReference& method_ref,
1572 const MethodHotness& hotness) {
1573 DexFileData* dex_data = GetOrAddDexFileData(method_ref.dex_file);
1574 if (dex_data != nullptr) {
1575 // TODO: Add inline caches.
Calin Juravle1ad1e3f2017-09-19 18:20:37 -07001576 return dex_data->AddMethod(
1577 static_cast<MethodHotness::Flag>(hotness.GetFlags()), method_ref.index);
Mathieu Chartier2f794552017-06-19 10:58:08 -07001578 }
1579 return false;
1580}
1581
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001582ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::GetMethodHotness(
1583 const std::string& dex_location,
1584 uint32_t dex_checksum,
1585 uint16_t dex_method_index) const {
1586 const DexFileData* dex_data = FindDexData(GetProfileDexFileKey(dex_location), dex_checksum);
1587 return dex_data != nullptr ? dex_data->GetHotnessInfo(dex_method_index) : MethodHotness();
Calin Juravle226501b2015-12-11 14:41:31 +00001588}
1589
Calin Juravle940eb0c2017-01-30 19:30:44 -08001590
Calin Juravlecc3171a2017-05-19 16:47:53 -07001591std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> ProfileCompilationInfo::GetMethod(
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001592 const std::string& dex_location,
1593 uint32_t dex_checksum,
1594 uint16_t dex_method_index) const {
1595 MethodHotness hotness(GetMethodHotness(dex_location, dex_checksum, dex_method_index));
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001596 if (!hotness.IsHot()) {
Calin Juravlecc3171a2017-05-19 16:47:53 -07001597 return nullptr;
Calin Juravle940eb0c2017-01-30 19:30:44 -08001598 }
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001599 const InlineCacheMap* inline_caches = hotness.GetInlineCacheMap();
1600 DCHECK(inline_caches != nullptr);
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001601 std::unique_ptr<OfflineProfileMethodInfo> pmi(new OfflineProfileMethodInfo(inline_caches));
Calin Juravle940eb0c2017-01-30 19:30:44 -08001602
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001603 pmi->dex_references.resize(info_.size());
1604 for (const DexFileData* dex_data : info_) {
1605 pmi->dex_references[dex_data->profile_index].dex_location = dex_data->profile_key;
1606 pmi->dex_references[dex_data->profile_index].dex_checksum = dex_data->checksum;
Mathieu Chartierea650f32017-05-24 12:04:13 -07001607 pmi->dex_references[dex_data->profile_index].num_method_ids = dex_data->num_method_ids;
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001608 }
1609
Calin Juravlecc3171a2017-05-19 16:47:53 -07001610 return pmi;
Calin Juravle940eb0c2017-01-30 19:30:44 -08001611}
1612
1613
Andreas Gampea5b09a62016-11-17 15:21:22 -08001614bool ProfileCompilationInfo::ContainsClass(const DexFile& dex_file, dex::TypeIndex type_idx) const {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001615 const DexFileData* dex_data = FindDexData(&dex_file);
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001616 if (dex_data != nullptr) {
Calin Juravlecc3171a2017-05-19 16:47:53 -07001617 const ArenaSet<dex::TypeIndex>& classes = dex_data->class_set;
Jeff Hao54b58552016-11-16 15:15:04 -08001618 return classes.find(type_idx) != classes.end();
Mathieu Chartiera8077802016-03-16 19:08:31 -07001619 }
1620 return false;
1621}
1622
Calin Juravle998c2162015-12-21 15:39:33 +02001623uint32_t ProfileCompilationInfo::GetNumberOfMethods() const {
1624 uint32_t total = 0;
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001625 for (const DexFileData* dex_data : info_) {
1626 total += dex_data->method_map.size();
Calin Juravle998c2162015-12-21 15:39:33 +02001627 }
1628 return total;
1629}
1630
Calin Juravle67265462016-03-18 16:23:40 +00001631uint32_t ProfileCompilationInfo::GetNumberOfResolvedClasses() const {
1632 uint32_t total = 0;
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001633 for (const DexFileData* dex_data : info_) {
1634 total += dex_data->class_set.size();
Calin Juravle67265462016-03-18 16:23:40 +00001635 }
1636 return total;
1637}
1638
Mathieu Chartier0573f852018-10-01 13:52:12 -07001639std::string ProfileCompilationInfo::DumpInfo(const std::vector<const DexFile*>& dex_files,
Calin Juravle998c2162015-12-21 15:39:33 +02001640 bool print_full_dex_location) const {
Calin Juravle226501b2015-12-11 14:41:31 +00001641 std::ostringstream os;
1642 if (info_.empty()) {
1643 return "ProfileInfo: empty";
1644 }
1645
1646 os << "ProfileInfo:";
1647
Calin Juravlea308a322017-07-18 16:51:51 -07001648 const std::string kFirstDexFileKeySubstitute = "!classes.dex";
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001649
1650 for (const DexFileData* dex_data : info_) {
Calin Juravle226501b2015-12-11 14:41:31 +00001651 os << "\n";
Calin Juravle226501b2015-12-11 14:41:31 +00001652 if (print_full_dex_location) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001653 os << dex_data->profile_key;
Calin Juravle226501b2015-12-11 14:41:31 +00001654 } else {
1655 // Replace the (empty) multidex suffix of the first key with a substitute for easier reading.
Mathieu Chartier79c87da2017-10-10 11:54:29 -07001656 std::string multidex_suffix = DexFileLoader::GetMultiDexSuffix(dex_data->profile_key);
Calin Juravle226501b2015-12-11 14:41:31 +00001657 os << (multidex_suffix.empty() ? kFirstDexFileKeySubstitute : multidex_suffix);
1658 }
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001659 os << " [index=" << static_cast<uint32_t>(dex_data->profile_index) << "]";
Mathieu Chartierf120ffc2018-04-23 11:27:31 -07001660 os << " [checksum=" << std::hex << dex_data->checksum << "]" << std::dec;
Calin Juravle876f3502016-03-24 16:16:34 +00001661 const DexFile* dex_file = nullptr;
Mathieu Chartier0573f852018-10-01 13:52:12 -07001662 for (const DexFile* current : dex_files) {
1663 if (dex_data->profile_key == current->GetLocation() &&
1664 dex_data->checksum == current->GetLocationChecksum()) {
1665 dex_file = current;
Calin Juravle226501b2015-12-11 14:41:31 +00001666 }
Calin Juravle876f3502016-03-24 16:16:34 +00001667 }
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001668 os << "\n\thot methods: ";
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001669 for (const auto& method_it : dex_data->method_map) {
Calin Juravle876f3502016-03-24 16:16:34 +00001670 if (dex_file != nullptr) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001671 os << "\n\t\t" << dex_file->PrettyMethod(method_it.first, true);
Calin Juravle876f3502016-03-24 16:16:34 +00001672 } else {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001673 os << method_it.first;
Calin Juravle876f3502016-03-24 16:16:34 +00001674 }
Calin Juravle940eb0c2017-01-30 19:30:44 -08001675
1676 os << "[";
1677 for (const auto& inline_cache_it : method_it.second) {
1678 os << "{" << std::hex << inline_cache_it.first << std::dec << ":";
Calin Juravle589e71e2017-03-03 16:05:05 -08001679 if (inline_cache_it.second.is_missing_types) {
1680 os << "MT";
1681 } else if (inline_cache_it.second.is_megamorphic) {
1682 os << "MM";
Calin Juravle940eb0c2017-01-30 19:30:44 -08001683 } else {
1684 for (const ClassReference& class_ref : inline_cache_it.second.classes) {
1685 os << "(" << static_cast<uint32_t>(class_ref.dex_profile_index)
1686 << "," << class_ref.type_index.index_ << ")";
1687 }
1688 }
1689 os << "}";
1690 }
1691 os << "], ";
Calin Juravle876f3502016-03-24 16:16:34 +00001692 }
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001693 bool startup = true;
1694 while (true) {
1695 os << "\n\t" << (startup ? "startup methods: " : "post startup methods: ");
1696 for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001697 MethodHotness hotness_info(dex_data->GetHotnessInfo(method_idx));
1698 if (startup ? hotness_info.IsStartup() : hotness_info.IsPostStartup()) {
Calin Juravle0545d4a2017-12-01 13:36:26 -08001699 if (dex_file != nullptr) {
1700 os << "\n\t\t" << dex_file->PrettyMethod(method_idx, true);
1701 } else {
1702 os << method_idx << ", ";
1703 }
Mathieu Chartier28b5c582017-06-06 14:12:50 -07001704 }
1705 }
1706 if (startup == false) {
1707 break;
1708 }
1709 startup = false;
1710 }
Calin Juravle876f3502016-03-24 16:16:34 +00001711 os << "\n\tclasses: ";
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001712 for (const auto class_it : dex_data->class_set) {
Calin Juravle876f3502016-03-24 16:16:34 +00001713 if (dex_file != nullptr) {
Jeff Hao54b58552016-11-16 15:15:04 -08001714 os << "\n\t\t" << dex_file->PrettyType(class_it);
Calin Juravle876f3502016-03-24 16:16:34 +00001715 } else {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001716 os << class_it.index_ << ",";
Calin Juravle876f3502016-03-24 16:16:34 +00001717 }
Calin Juravle226501b2015-12-11 14:41:31 +00001718 }
1719 }
1720 return os.str();
1721}
1722
Mathieu Chartierea650f32017-05-24 12:04:13 -07001723bool ProfileCompilationInfo::GetClassesAndMethods(
1724 const DexFile& dex_file,
1725 /*out*/std::set<dex::TypeIndex>* class_set,
1726 /*out*/std::set<uint16_t>* hot_method_set,
1727 /*out*/std::set<uint16_t>* startup_method_set,
1728 /*out*/std::set<uint16_t>* post_startup_method_method_set) const {
Mathieu Chartier34067262017-04-06 13:55:46 -07001729 std::set<std::string> ret;
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001730 const DexFileData* dex_data = FindDexData(&dex_file);
1731 if (dex_data == nullptr) {
Mathieu Chartier34067262017-04-06 13:55:46 -07001732 return false;
David Sehr7c80f2d2017-02-07 16:47:58 -08001733 }
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001734 for (const auto& it : dex_data->method_map) {
Mathieu Chartierea650f32017-05-24 12:04:13 -07001735 hot_method_set->insert(it.first);
1736 }
1737 for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001738 MethodHotness hotness = dex_data->GetHotnessInfo(method_idx);
1739 if (hotness.IsStartup()) {
Mathieu Chartierea650f32017-05-24 12:04:13 -07001740 startup_method_set->insert(method_idx);
1741 }
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001742 if (hotness.IsPostStartup()) {
Mathieu Chartierea650f32017-05-24 12:04:13 -07001743 post_startup_method_method_set->insert(method_idx);
1744 }
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001745 }
Calin Juravlecc3171a2017-05-19 16:47:53 -07001746 for (const dex::TypeIndex& type_index : dex_data->class_set) {
1747 class_set->insert(type_index);
1748 }
Mathieu Chartier34067262017-04-06 13:55:46 -07001749 return true;
David Sehr7c80f2d2017-02-07 16:47:58 -08001750}
1751
Calin Juravle2e2db782016-02-23 12:00:03 +00001752bool ProfileCompilationInfo::Equals(const ProfileCompilationInfo& other) {
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001753 // No need to compare profile_key_map_. That's only a cache for fast search.
1754 // All the information is already in the info_ vector.
1755 if (info_.size() != other.info_.size()) {
1756 return false;
1757 }
1758 for (size_t i = 0; i < info_.size(); i++) {
1759 const DexFileData& dex_data = *info_[i];
1760 const DexFileData& other_dex_data = *other.info_[i];
1761 if (!(dex_data == other_dex_data)) {
1762 return false;
1763 }
1764 }
1765 return true;
Calin Juravle877fd962016-01-05 14:29:29 +00001766}
1767
Mathieu Chartier046854b2017-03-01 17:16:22 -08001768std::set<DexCacheResolvedClasses> ProfileCompilationInfo::GetResolvedClasses(
Calin Juravle08556882017-05-26 16:40:45 -07001769 const std::vector<const DexFile*>& dex_files) const {
1770 std::unordered_map<std::string, const DexFile* > key_to_dex_file;
1771 for (const DexFile* dex_file : dex_files) {
1772 key_to_dex_file.emplace(GetProfileDexFileKey(dex_file->GetLocation()), dex_file);
Mathieu Chartier046854b2017-03-01 17:16:22 -08001773 }
Mathieu Chartierc5dd3192015-12-09 16:38:30 -08001774 std::set<DexCacheResolvedClasses> ret;
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001775 for (const DexFileData* dex_data : info_) {
Calin Juravle08556882017-05-26 16:40:45 -07001776 const auto it = key_to_dex_file.find(dex_data->profile_key);
1777 if (it != key_to_dex_file.end()) {
1778 const DexFile* dex_file = it->second;
1779 const std::string& dex_location = dex_file->GetLocation();
1780 if (dex_data->checksum != it->second->GetLocationChecksum()) {
1781 LOG(ERROR) << "Dex checksum mismatch when getting resolved classes from profile for "
1782 << "location " << dex_location << " (checksum=" << dex_file->GetLocationChecksum()
1783 << ", profile checksum=" << dex_data->checksum;
1784 return std::set<DexCacheResolvedClasses>();
1785 }
Mathieu Chartierea650f32017-05-24 12:04:13 -07001786 DexCacheResolvedClasses classes(dex_location,
1787 dex_location,
1788 dex_data->checksum,
1789 dex_data->num_method_ids);
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001790 classes.AddClasses(dex_data->class_set.begin(), dex_data->class_set.end());
Mathieu Chartier046854b2017-03-01 17:16:22 -08001791 ret.insert(classes);
1792 }
Mathieu Chartierc5dd3192015-12-09 16:38:30 -08001793 }
1794 return ret;
1795}
1796
Calin Juravle7bcdb532016-06-07 16:14:47 +01001797// Naive implementation to generate a random profile file suitable for testing.
1798bool ProfileCompilationInfo::GenerateTestProfile(int fd,
1799 uint16_t number_of_dex_files,
Shubham Ajmerad704f0b2017-07-26 16:33:35 -07001800 uint16_t method_percentage,
1801 uint16_t class_percentage,
Jeff Haof0a31f82017-03-27 15:50:37 -07001802 uint32_t random_seed) {
Calin Juravle7bcdb532016-06-07 16:14:47 +01001803 const std::string base_dex_location = "base.apk";
1804 ProfileCompilationInfo info;
1805 // The limits are defined by the dex specification.
Mathieu Chartierea650f32017-05-24 12:04:13 -07001806 const uint16_t max_method = std::numeric_limits<uint16_t>::max();
1807 const uint16_t max_classes = std::numeric_limits<uint16_t>::max();
Shubham Ajmerad704f0b2017-07-26 16:33:35 -07001808 uint16_t number_of_methods = max_method * method_percentage / 100;
1809 uint16_t number_of_classes = max_classes * class_percentage / 100;
Calin Juravle7bcdb532016-06-07 16:14:47 +01001810
Jeff Haof0a31f82017-03-27 15:50:37 -07001811 std::srand(random_seed);
Calin Juravle7bcdb532016-06-07 16:14:47 +01001812
1813 // Make sure we generate more samples with a low index value.
1814 // This makes it more likely to hit valid method/class indices in small apps.
1815 const uint16_t kFavorFirstN = 10000;
1816 const uint16_t kFavorSplit = 2;
1817
1818 for (uint16_t i = 0; i < number_of_dex_files; i++) {
Mathieu Chartier79c87da2017-10-10 11:54:29 -07001819 std::string dex_location = DexFileLoader::GetMultiDexLocation(i, base_dex_location.c_str());
Calin Juravle7bcdb532016-06-07 16:14:47 +01001820 std::string profile_key = GetProfileDexFileKey(dex_location);
1821
1822 for (uint16_t m = 0; m < number_of_methods; m++) {
1823 uint16_t method_idx = rand() % max_method;
1824 if (m < (number_of_methods / kFavorSplit)) {
1825 method_idx %= kFavorFirstN;
1826 }
Mathieu Chartierc46cf802017-09-28 11:52:19 -07001827 // Alternate between startup and post startup.
1828 uint32_t flags = MethodHotness::kFlagHot;
1829 flags |= ((m & 1) != 0) ? MethodHotness::kFlagPostStartup : MethodHotness::kFlagStartup;
1830 info.AddMethodIndex(static_cast<MethodHotness::Flag>(flags),
Mathieu Chartierbbe3a5e2017-06-13 16:36:17 -07001831 profile_key,
1832 /*method_idx*/ 0,
1833 method_idx,
1834 max_method);
Calin Juravle7bcdb532016-06-07 16:14:47 +01001835 }
1836
1837 for (uint16_t c = 0; c < number_of_classes; c++) {
Jeff Hao54b58552016-11-16 15:15:04 -08001838 uint16_t type_idx = rand() % max_classes;
Calin Juravle7bcdb532016-06-07 16:14:47 +01001839 if (c < (number_of_classes / kFavorSplit)) {
Jeff Hao54b58552016-11-16 15:15:04 -08001840 type_idx %= kFavorFirstN;
Calin Juravle7bcdb532016-06-07 16:14:47 +01001841 }
Mathieu Chartierea650f32017-05-24 12:04:13 -07001842 info.AddClassIndex(profile_key, 0, dex::TypeIndex(type_idx), max_method);
Calin Juravle7bcdb532016-06-07 16:14:47 +01001843 }
1844 }
1845 return info.Save(fd);
1846}
1847
Jeff Haof0a31f82017-03-27 15:50:37 -07001848// Naive implementation to generate a random profile file suitable for testing.
Shubham Ajmerad704f0b2017-07-26 16:33:35 -07001849// Description of random selection:
1850// * Select a random starting point S.
1851// * For every index i, add (S+i) % (N - total number of methods/classes) to profile with the
1852// probably of 1/(N - i - number of methods/classes needed to add in profile).
Jeff Haof0a31f82017-03-27 15:50:37 -07001853bool ProfileCompilationInfo::GenerateTestProfile(
1854 int fd,
1855 std::vector<std::unique_ptr<const DexFile>>& dex_files,
Shubham Ajmerad704f0b2017-07-26 16:33:35 -07001856 uint16_t method_percentage,
1857 uint16_t class_percentage,
Jeff Haof0a31f82017-03-27 15:50:37 -07001858 uint32_t random_seed) {
Jeff Haof0a31f82017-03-27 15:50:37 -07001859 ProfileCompilationInfo info;
Andreas Gampe81ccda62018-09-20 11:59:12 -07001860 std::default_random_engine rng(random_seed);
1861 auto create_shuffled_range = [&rng](uint32_t take, uint32_t out_of) {
1862 CHECK_LE(take, out_of);
1863 std::vector<uint32_t> vec(out_of);
1864 std::iota(vec.begin(), vec.end(), 0u);
1865 std::shuffle(vec.begin(), vec.end(), rng);
1866 vec.erase(vec.begin() + take, vec.end());
1867 std::sort(vec.begin(), vec.end());
1868 return vec;
1869 };
Jeff Haof0a31f82017-03-27 15:50:37 -07001870 for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
1871 const std::string& location = dex_file->GetLocation();
1872 uint32_t checksum = dex_file->GetLocationChecksum();
Shubham Ajmerad704f0b2017-07-26 16:33:35 -07001873
1874 uint32_t number_of_classes = dex_file->NumClassDefs();
1875 uint32_t classes_required_in_profile = (number_of_classes * class_percentage) / 100;
Andreas Gampe81ccda62018-09-20 11:59:12 -07001876 for (uint32_t class_index : create_shuffled_range(classes_required_in_profile,
1877 number_of_classes)) {
1878 info.AddClassIndex(location,
1879 checksum,
1880 dex_file->GetClassDef(class_index).class_idx_,
1881 dex_file->NumMethodIds());
Jeff Haof0a31f82017-03-27 15:50:37 -07001882 }
Shubham Ajmerad704f0b2017-07-26 16:33:35 -07001883
1884 uint32_t number_of_methods = dex_file->NumMethodIds();
1885 uint32_t methods_required_in_profile = (number_of_methods * method_percentage) / 100;
Andreas Gampe81ccda62018-09-20 11:59:12 -07001886 for (uint32_t method_index : create_shuffled_range(methods_required_in_profile,
1887 number_of_methods)) {
1888 // Alternate between startup and post startup.
1889 uint32_t flags = MethodHotness::kFlagHot;
1890 flags |= ((method_index & 1) != 0)
1891 ? MethodHotness::kFlagPostStartup
1892 : MethodHotness::kFlagStartup;
1893 info.AddMethodIndex(static_cast<MethodHotness::Flag>(flags),
1894 MethodReference(dex_file.get(), method_index));
Jeff Haof0a31f82017-03-27 15:50:37 -07001895 }
1896 }
1897 return info.Save(fd);
1898}
1899
Calin Juravle940eb0c2017-01-30 19:30:44 -08001900bool ProfileCompilationInfo::OfflineProfileMethodInfo::operator==(
1901 const OfflineProfileMethodInfo& other) const {
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001902 if (inline_caches->size() != other.inline_caches->size()) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001903 return false;
1904 }
1905
1906 // We can't use a simple equality test because we need to match the dex files
Calin Juravle589e71e2017-03-03 16:05:05 -08001907 // of the inline caches which might have different profile indexes.
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001908 for (const auto& inline_cache_it : *inline_caches) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001909 uint16_t dex_pc = inline_cache_it.first;
1910 const DexPcData dex_pc_data = inline_cache_it.second;
Calin Juravlee6f87cc2017-05-24 17:41:05 -07001911 const auto& other_it = other.inline_caches->find(dex_pc);
1912 if (other_it == other.inline_caches->end()) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001913 return false;
1914 }
1915 const DexPcData& other_dex_pc_data = other_it->second;
Calin Juravle589e71e2017-03-03 16:05:05 -08001916 if (dex_pc_data.is_megamorphic != other_dex_pc_data.is_megamorphic ||
1917 dex_pc_data.is_missing_types != other_dex_pc_data.is_missing_types) {
Calin Juravle940eb0c2017-01-30 19:30:44 -08001918 return false;
1919 }
1920 for (const ClassReference& class_ref : dex_pc_data.classes) {
1921 bool found = false;
1922 for (const ClassReference& other_class_ref : other_dex_pc_data.classes) {
1923 CHECK_LE(class_ref.dex_profile_index, dex_references.size());
1924 CHECK_LE(other_class_ref.dex_profile_index, other.dex_references.size());
1925 const DexReference& dex_ref = dex_references[class_ref.dex_profile_index];
1926 const DexReference& other_dex_ref = other.dex_references[other_class_ref.dex_profile_index];
1927 if (class_ref.type_index == other_class_ref.type_index &&
1928 dex_ref == other_dex_ref) {
1929 found = true;
1930 break;
1931 }
1932 }
1933 if (!found) {
1934 return false;
1935 }
1936 }
1937 }
1938 return true;
1939}
1940
Calin Juravlecea9e9d2017-03-23 19:04:59 -07001941bool ProfileCompilationInfo::IsEmpty() const {
1942 DCHECK_EQ(info_.empty(), profile_key_map_.empty());
1943 return info_.empty();
1944}
1945
Calin Juravlecc3171a2017-05-19 16:47:53 -07001946ProfileCompilationInfo::InlineCacheMap*
1947ProfileCompilationInfo::DexFileData::FindOrAddMethod(uint16_t method_index) {
Calin Juravleee9cb412018-02-13 20:32:35 -08001948 if (method_index >= num_method_ids) {
1949 LOG(ERROR) << "Invalid method index " << method_index << ". num_method_ids=" << num_method_ids;
1950 return nullptr;
1951 }
Calin Juravlecc3171a2017-05-19 16:47:53 -07001952 return &(method_map.FindOrAdd(
1953 method_index,
Vladimir Marko69d310e2017-10-09 14:12:23 +01001954 InlineCacheMap(std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)))->second);
Calin Juravlecc3171a2017-05-19 16:47:53 -07001955}
1956
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001957// Mark a method as executed at least once.
Calin Juravle1ad1e3f2017-09-19 18:20:37 -07001958bool ProfileCompilationInfo::DexFileData::AddMethod(MethodHotness::Flag flags, size_t index) {
1959 if (index >= num_method_ids) {
1960 LOG(ERROR) << "Invalid method index " << index << ". num_method_ids=" << num_method_ids;
1961 return false;
1962 }
1963
Calin Juravleee9cb412018-02-13 20:32:35 -08001964 SetMethodHotness(index, flags);
1965
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001966 if ((flags & MethodHotness::kFlagHot) != 0) {
1967 method_map.FindOrAdd(
1968 index,
Vladimir Marko69d310e2017-10-09 14:12:23 +01001969 InlineCacheMap(std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)));
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001970 }
Calin Juravle1ad1e3f2017-09-19 18:20:37 -07001971 return true;
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001972}
1973
Calin Juravleee9cb412018-02-13 20:32:35 -08001974void ProfileCompilationInfo::DexFileData::SetMethodHotness(size_t index,
1975 MethodHotness::Flag flags) {
1976 DCHECK_LT(index, num_method_ids);
1977 if ((flags & MethodHotness::kFlagStartup) != 0) {
1978 method_bitmap.StoreBit(MethodBitIndex(/*startup*/ true, index), /*value*/ true);
1979 }
1980 if ((flags & MethodHotness::kFlagPostStartup) != 0) {
1981 method_bitmap.StoreBit(MethodBitIndex(/*startup*/ false, index), /*value*/ true);
1982 }
1983}
1984
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001985ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::DexFileData::GetHotnessInfo(
1986 uint32_t dex_method_index) const {
1987 MethodHotness ret;
1988 if (method_bitmap.LoadBit(MethodBitIndex(/*startup*/ true, dex_method_index))) {
1989 ret.AddFlag(MethodHotness::kFlagStartup);
1990 }
1991 if (method_bitmap.LoadBit(MethodBitIndex(/*startup*/ false, dex_method_index))) {
1992 ret.AddFlag(MethodHotness::kFlagPostStartup);
1993 }
1994 auto it = method_map.find(dex_method_index);
1995 if (it != method_map.end()) {
1996 ret.SetInlineCacheMap(&it->second);
1997 ret.AddFlag(MethodHotness::kFlagHot);
1998 }
1999 return ret;
2000}
2001
Calin Juravlecc3171a2017-05-19 16:47:53 -07002002ProfileCompilationInfo::DexPcData*
2003ProfileCompilationInfo::FindOrAddDexPc(InlineCacheMap* inline_cache, uint32_t dex_pc) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002004 return &(inline_cache->FindOrAdd(dex_pc, DexPcData(&allocator_))->second);
Calin Juravlecc3171a2017-05-19 16:47:53 -07002005}
2006
Vladimir Marko54159c62018-06-20 14:30:08 +01002007HashSet<std::string> ProfileCompilationInfo::GetClassDescriptors(
Mathieu Chartier4f342b02017-07-21 17:12:39 -07002008 const std::vector<const DexFile*>& dex_files) {
Vladimir Marko54159c62018-06-20 14:30:08 +01002009 HashSet<std::string> ret;
Mathieu Chartier4f342b02017-07-21 17:12:39 -07002010 for (const DexFile* dex_file : dex_files) {
2011 const DexFileData* data = FindDexData(dex_file);
2012 if (data != nullptr) {
2013 for (dex::TypeIndex type_idx : data->class_set) {
2014 if (!dex_file->IsTypeIndexValid(type_idx)) {
2015 // Something went bad. The profile is probably corrupted. Abort and return an emtpy set.
2016 LOG(WARNING) << "Corrupted profile: invalid type index "
2017 << type_idx.index_ << " in dex " << dex_file->GetLocation();
Vladimir Marko54159c62018-06-20 14:30:08 +01002018 return HashSet<std::string>();
Mathieu Chartier4f342b02017-07-21 17:12:39 -07002019 }
2020 const DexFile::TypeId& type_id = dex_file->GetTypeId(type_idx);
2021 ret.insert(dex_file->GetTypeDescriptor(type_id));
2022 }
2023 } else {
2024 VLOG(compiler) << "Failed to find profile data for " << dex_file->GetLocation();
2025 }
2026 }
2027 return ret;
2028}
2029
Calin Juravle1e2de642018-01-18 01:08:23 -08002030bool ProfileCompilationInfo::IsProfileFile(int fd) {
2031 // First check if it's an empty file as we allow empty profile files.
2032 // Profiles may be created by ActivityManager or installd before we manage to
2033 // process them in the runtime or profman.
2034 struct stat stat_buffer;
2035 if (fstat(fd, &stat_buffer) != 0) {
2036 return false;
2037 }
2038
2039 if (stat_buffer.st_size == 0) {
2040 return true;
2041 }
2042
2043 // The files is not empty. Check if it contains the profile magic.
2044 size_t byte_count = sizeof(kProfileMagic);
2045 uint8_t buffer[sizeof(kProfileMagic)];
2046 if (!android::base::ReadFully(fd, buffer, byte_count)) {
2047 return false;
2048 }
2049
2050 // Reset the offset to prepare the file for reading.
2051 off_t rc = TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET));
2052 if (rc == static_cast<off_t>(-1)) {
2053 PLOG(ERROR) << "Failed to reset the offset";
2054 return false;
2055 }
2056
2057 return memcmp(buffer, kProfileMagic, byte_count) == 0;
2058}
2059
Calin Juravle2dba0ab2018-01-22 19:22:24 -08002060bool ProfileCompilationInfo::UpdateProfileKeys(
2061 const std::vector<std::unique_ptr<const DexFile>>& dex_files) {
2062 for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
2063 for (DexFileData* dex_data : info_) {
2064 if (dex_data->checksum == dex_file->GetLocationChecksum()
2065 && dex_data->num_method_ids == dex_file->NumMethodIds()) {
2066 std::string new_profile_key = GetProfileDexFileKey(dex_file->GetLocation());
2067 if (dex_data->profile_key != new_profile_key) {
2068 if (profile_key_map_.find(new_profile_key) != profile_key_map_.end()) {
2069 // We can't update the key if the new key belongs to a different dex file.
2070 LOG(ERROR) << "Cannot update profile key to " << new_profile_key
2071 << " because the new key belongs to another dex file.";
2072 return false;
2073 }
2074 profile_key_map_.erase(dex_data->profile_key);
2075 profile_key_map_.Put(new_profile_key, dex_data->profile_index);
2076 dex_data->profile_key = new_profile_key;
2077 }
2078 }
2079 }
2080 }
2081 return true;
2082}
2083
Calin Juravled9f4d642018-01-24 20:33:00 -08002084bool ProfileCompilationInfo::ProfileFilterFnAcceptAll(
2085 const std::string& dex_location ATTRIBUTE_UNUSED,
2086 uint32_t checksum ATTRIBUTE_UNUSED) {
2087 return true;
2088}
2089
Calin Juravled5aeade2018-05-08 18:23:24 -07002090void ProfileCompilationInfo::ClearData() {
2091 for (DexFileData* data : info_) {
2092 delete data;
2093 }
2094 info_.clear();
2095 profile_key_map_.clear();
2096}
2097
Calin Juravle31f2c152015-10-23 17:56:15 +01002098} // namespace art