1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "profile_compilation_info.h"
18
19 #include <sys/file.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 #include <zlib.h>
24
25 #include <algorithm>
26 #include <cerrno>
27 #include <climits>
28 #include <cstdlib>
29 #include <iostream>
30 #include <numeric>
31 #include <random>
32 #include <string>
33 #include <vector>
34
35 #include "android-base/file.h"
36
37 #include "base/arena_allocator.h"
38 #include "base/bit_utils.h"
39 #include "base/dumpable.h"
40 #include "base/file_utils.h"
41 #include "base/logging.h" // For VLOG.
42 #include "base/malloc_arena_pool.h"
43 #include "base/os.h"
44 #include "base/safe_map.h"
45 #include "base/scoped_flock.h"
46 #include "base/stl_util.h"
47 #include "base/systrace.h"
48 #include "base/time_utils.h"
49 #include "base/unix_file/fd_file.h"
50 #include "base/utils.h"
51 #include "base/zip_archive.h"
52 #include "dex/descriptors_names.h"
53 #include "dex/dex_file_loader.h"
54
55 namespace art {
56
57 const uint8_t ProfileCompilationInfo::kProfileMagic[] = { 'p', 'r', 'o', '\0' };
58 // Last profile version: New extensible profile format.
59 const uint8_t ProfileCompilationInfo::kProfileVersion[] = { '0', '1', '5', '\0' };
60 const uint8_t ProfileCompilationInfo::kProfileVersionForBootImage[] = { '0', '1', '6', '\0' };
61
62 static_assert(sizeof(ProfileCompilationInfo::kProfileVersion) == 4,
63 "Invalid profile version size");
64 static_assert(sizeof(ProfileCompilationInfo::kProfileVersionForBootImage) == 4,
65 "Invalid profile version size");
66
67 // The name of the profile entry in the dex metadata file.
68 // DO NOT CHANGE THIS! (it's similar to classes.dex in the apk files).
69 const char ProfileCompilationInfo::kDexMetadataProfileEntry[] = "primary.prof";
70
71 // A synthetic annotations that can be used to denote that no annotation should
72 // be associated with the profile samples. We use the empty string for the package name
73 // because that's an invalid package name and should never occur in practice.
74 const ProfileCompilationInfo::ProfileSampleAnnotation
75 ProfileCompilationInfo::ProfileSampleAnnotation::kNone =
76 ProfileCompilationInfo::ProfileSampleAnnotation("");
77
78 static constexpr char kSampleMetadataSeparator = ':';
79
80 // Note: This used to be PATH_MAX (usually 4096) but that seems excessive
81 // and we do not want to rely on that external constant anyway.
82 static constexpr uint16_t kMaxDexFileKeyLength = 1024;
83
84 // Extra descriptors are serialized with a `uint16_t` prefix. This defines the length limit.
85 static constexpr size_t kMaxExtraDescriptorLength = std::numeric_limits<uint16_t>::max();
86
87 // According to dex file specification, there can be more than 2^16 valid method indexes
88 // but bytecode uses only 16 bits, so higher method indexes are not very useful (though
89 // such methods could be reached through virtual or interface dispatch). Consequently,
90 // dex files with more than 2^16 method indexes are not really used and the profile file
91 // format does not support higher method indexes.
92 static constexpr uint32_t kMaxSupportedMethodIndex = 0xffffu;
93
94 // Debug flag to ignore checksums when testing if a method or a class is present in the profile.
95 // Used to facilitate testing profile guided compilation across a large number of apps
96 // using the same test profile.
97 static constexpr bool kDebugIgnoreChecksum = false;
98
99 static constexpr uint8_t kIsMissingTypesEncoding = 6;
100 static constexpr uint8_t kIsMegamorphicEncoding = 7;
101
102 static_assert(sizeof(ProfileCompilationInfo::kIndividualInlineCacheSize) == sizeof(uint8_t),
103 "InlineCache::kIndividualInlineCacheSize does not have the expect type size");
104 static_assert(ProfileCompilationInfo::kIndividualInlineCacheSize < kIsMegamorphicEncoding,
105 "InlineCache::kIndividualInlineCacheSize is larger than expected");
106 static_assert(ProfileCompilationInfo::kIndividualInlineCacheSize < kIsMissingTypesEncoding,
107 "InlineCache::kIndividualInlineCacheSize is larger than expected");
108
109 static constexpr uint32_t kSizeWarningThresholdBytes = 500000U;
110 static constexpr uint32_t kSizeErrorThresholdBytes = 1500000U;
111
112 static constexpr uint32_t kSizeWarningThresholdBootBytes = 25000000U;
113 static constexpr uint32_t kSizeErrorThresholdBootBytes = 100000000U;
114
ChecksumMatch(uint32_t dex_file_checksum,uint32_t checksum)115 static bool ChecksumMatch(uint32_t dex_file_checksum, uint32_t checksum) {
116 return kDebugIgnoreChecksum || dex_file_checksum == checksum;
117 }
118
119 namespace {
120
121 // Deflate the input buffer `in_buffer`. It returns a buffer of
122 // compressed data for the input buffer of `*compressed_data_size` size.
DeflateBuffer(ArrayRef<const uint8_t> in_buffer,uint32_t * compressed_data_size)123 std::unique_ptr<uint8_t[]> DeflateBuffer(ArrayRef<const uint8_t> in_buffer,
124 /*out*/ uint32_t* compressed_data_size) {
125 z_stream strm;
126 strm.zalloc = Z_NULL;
127 strm.zfree = Z_NULL;
128 strm.opaque = Z_NULL;
129 int init_ret = deflateInit(&strm, 1);
130 if (init_ret != Z_OK) {
131 return nullptr;
132 }
133
134 uint32_t out_size = dchecked_integral_cast<uint32_t>(deflateBound(&strm, in_buffer.size()));
135
136 std::unique_ptr<uint8_t[]> compressed_buffer(new uint8_t[out_size]);
137 strm.avail_in = in_buffer.size();
138 strm.next_in = const_cast<uint8_t*>(in_buffer.data());
139 strm.avail_out = out_size;
140 strm.next_out = &compressed_buffer[0];
141 int ret = deflate(&strm, Z_FINISH);
142 if (ret == Z_STREAM_ERROR) {
143 return nullptr;
144 }
145 *compressed_data_size = out_size - strm.avail_out;
146
147 int end_ret = deflateEnd(&strm);
148 if (end_ret != Z_OK) {
149 return nullptr;
150 }
151
152 return compressed_buffer;
153 }
154
155 // Inflate the data from `in_buffer` into `out_buffer`. The `out_buffer.size()`
156 // is the expected output size of the buffer. It returns Z_STREAM_END on success.
157 // On error, it returns Z_STREAM_ERROR if the compressed data is inconsistent
158 // and Z_DATA_ERROR if the stream ended prematurely or the stream has extra data.
InflateBuffer(ArrayRef<const uint8_t> in_buffer,ArrayRef<uint8_t> out_buffer)159 int InflateBuffer(ArrayRef<const uint8_t> in_buffer, /*out*/ ArrayRef<uint8_t> out_buffer) {
160 /* allocate inflate state */
161 z_stream strm;
162 strm.zalloc = Z_NULL;
163 strm.zfree = Z_NULL;
164 strm.opaque = Z_NULL;
165 strm.avail_in = in_buffer.size();
166 strm.next_in = const_cast<uint8_t*>(in_buffer.data());
167 strm.avail_out = out_buffer.size();
168 strm.next_out = out_buffer.data();
169
170 int init_ret = inflateInit(&strm);
171 if (init_ret != Z_OK) {
172 return init_ret;
173 }
174
175 int ret = inflate(&strm, Z_NO_FLUSH);
176 if (strm.avail_in != 0 || strm.avail_out != 0) {
177 return Z_DATA_ERROR;
178 }
179
180 int end_ret = inflateEnd(&strm);
181 if (end_ret != Z_OK) {
182 return end_ret;
183 }
184
185 return ret;
186 }
187
188 } // anonymous namespace
189
190 enum class ProfileCompilationInfo::ProfileLoadStatus : uint32_t {
191 kSuccess,
192 kIOError,
193 kBadMagic,
194 kVersionMismatch,
195 kBadData,
196 kMergeError, // Merging failed. There are too many extra descriptors
197 // or classes without TypeId referenced by a dex file.
198 };
199
200 enum class ProfileCompilationInfo::FileSectionType : uint32_t {
201 // The values of section enumerators and data format for individual sections
202 // must not be changed without changing the profile file version. New sections
203 // can be added at the end and they shall be ignored by old versions of ART.
204
205 // The list of the dex files included in the profile.
206 // There must be exactly one dex file section and it must be first.
207 kDexFiles = 0,
208
209 // Extra descriptors for referencing classes that do not have a `dex::TypeId`
210 // in the referencing dex file, such as classes from a different dex file
211 // (even outside of the dex files in the profile) or array classes that were
212 // used from other dex files or created through reflection.
213 kExtraDescriptors = 1,
214
215 // Classes included in the profile.
216 kClasses = 2,
217
218 // Methods included in the profile, their hotness flags and inline caches.
219 kMethods = 3,
220
221 // The number of known sections.
222 kNumberOfSections = 4
223 };
224
225 class ProfileCompilationInfo::FileSectionInfo {
226 public:
227 // Constructor for reading from a `ProfileSource`. Data shall be filled from the source.
FileSectionInfo()228 FileSectionInfo() {}
229
230 // Constructor for writing to a file.
FileSectionInfo(FileSectionType type,uint32_t file_offset,uint32_t file_size,uint32_t inflated_size)231 FileSectionInfo(FileSectionType type,
232 uint32_t file_offset,
233 uint32_t file_size,
234 uint32_t inflated_size)
235 : type_(type),
236 file_offset_(file_offset),
237 file_size_(file_size),
238 inflated_size_(inflated_size) {}
239
SetFileOffset(uint32_t file_offset)240 void SetFileOffset(uint32_t file_offset) {
241 DCHECK_EQ(file_offset_, 0u);
242 DCHECK_NE(file_offset, 0u);
243 file_offset_ = file_offset;
244 }
245
GetType() const246 FileSectionType GetType() const {
247 return type_;
248 }
249
GetFileOffset() const250 uint32_t GetFileOffset() const {
251 return file_offset_;
252 }
253
GetFileSize() const254 uint32_t GetFileSize() const {
255 return file_size_;
256 }
257
GetInflatedSize() const258 uint32_t GetInflatedSize() const {
259 return inflated_size_;
260 }
261
GetMemSize() const262 uint32_t GetMemSize() const {
263 return inflated_size_ != 0u ? inflated_size_ : file_size_;
264 }
265
266 private:
267 FileSectionType type_;
268 uint32_t file_offset_;
269 uint32_t file_size_;
270 uint32_t inflated_size_; // If 0, do not inflate and use data from file directly.
271 };
272
273 // The file header.
274 class ProfileCompilationInfo::FileHeader {
275 public:
276 // Constructor for reading from a `ProfileSource`. Data shall be filled from the source.
FileHeader()277 FileHeader() {
278 DCHECK(!IsValid());
279 }
280
281 // Constructor for writing to a file.
FileHeader(const uint8_t * version,uint32_t file_section_count)282 FileHeader(const uint8_t* version, uint32_t file_section_count)
283 : file_section_count_(file_section_count) {
284 static_assert(sizeof(magic_) == sizeof(kProfileMagic));
285 static_assert(sizeof(version_) == sizeof(kProfileVersion));
286 static_assert(sizeof(version_) == sizeof(kProfileVersionForBootImage));
287 memcpy(magic_, kProfileMagic, sizeof(kProfileMagic));
288 memcpy(version_, version, sizeof(version_));
289 DCHECK_LE(file_section_count, kMaxFileSectionCount);
290 DCHECK(IsValid());
291 }
292
IsValid() const293 bool IsValid() const {
294 return memcmp(magic_, kProfileMagic, sizeof(kProfileMagic)) == 0 &&
295 (memcmp(version_, kProfileVersion, kProfileVersionSize) == 0 ||
296 memcmp(version_, kProfileVersionForBootImage, kProfileVersionSize) == 0) &&
297 file_section_count_ != 0u && // The dex files section is mandatory.
298 file_section_count_ <= kMaxFileSectionCount;
299 }
300
GetVersion() const301 const uint8_t* GetVersion() const {
302 DCHECK(IsValid());
303 return version_;
304 }
305
306 ProfileLoadStatus InvalidHeaderMessage(/*out*/ std::string* error_msg) const;
307
GetFileSectionCount() const308 uint32_t GetFileSectionCount() const {
309 DCHECK(IsValid());
310 return file_section_count_;
311 }
312
313 private:
314 // The upper bound for file section count is used to ensure that there
315 // shall be no arithmetic overflow when calculating size of the header
316 // with section information.
317 static const uint32_t kMaxFileSectionCount;
318
319 uint8_t magic_[4] = {0, 0, 0, 0};
320 uint8_t version_[4] = {0, 0, 0, 0};
321 uint32_t file_section_count_ = 0u;
322 };
323
324 const uint32_t ProfileCompilationInfo::FileHeader::kMaxFileSectionCount =
325 (std::numeric_limits<uint32_t>::max() - sizeof(FileHeader)) / sizeof(FileSectionInfo);
326
327 ProfileCompilationInfo::ProfileLoadStatus
InvalidHeaderMessage(std::string * error_msg) const328 ProfileCompilationInfo::FileHeader::InvalidHeaderMessage(/*out*/ std::string* error_msg) const {
329 if (memcmp(magic_, kProfileMagic, sizeof(kProfileMagic)) != 0) {
330 *error_msg = "Profile missing magic.";
331 return ProfileLoadStatus::kBadMagic;
332 }
333 if (memcmp(version_, kProfileVersion, sizeof(kProfileVersion)) != 0 &&
334 memcmp(version_, kProfileVersion, sizeof(kProfileVersionForBootImage)) != 0) {
335 *error_msg = "Profile version mismatch.";
336 return ProfileLoadStatus::kVersionMismatch;
337 }
338 if (file_section_count_ == 0u) {
339 *error_msg = "Missing mandatory dex files section.";
340 return ProfileLoadStatus::kBadData;
341 }
342 DCHECK_GT(file_section_count_, kMaxFileSectionCount);
343 *error_msg ="Too many sections.";
344 return ProfileLoadStatus::kBadData;
345 }
346
347 /**
348 * Encapsulate the source of profile data for loading.
349 * The source can be either a plain file or a zip file.
350 * For zip files, the profile entry will be extracted to
351 * the memory map.
352 */
353 class ProfileCompilationInfo::ProfileSource {
354 public:
355 /**
356 * Create a profile source for the given fd. The ownership of the fd
357 * remains to the caller; as this class will not attempt to close it at any
358 * point.
359 */
Create(int32_t fd)360 static ProfileSource* Create(int32_t fd) {
361 DCHECK_GT(fd, -1);
362 return new ProfileSource(fd, MemMap::Invalid());
363 }
364
365 /**
366 * Create a profile source backed by a memory map. The map can be null in
367 * which case it will the treated as an empty source.
368 */
Create(MemMap && mem_map)369 static ProfileSource* Create(MemMap&& mem_map) {
370 return new ProfileSource(/*fd*/ -1, std::move(mem_map));
371 }
372
373 // Seek to the given offset in the source.
374 bool Seek(off_t offset);
375
376 /**
377 * Read bytes from this source.
378 * Reading will advance the current source position so subsequent
379 * invocations will read from the las position.
380 */
381 ProfileLoadStatus Read(void* buffer,
382 size_t byte_count,
383 const std::string& debug_stage,
384 std::string* error);
385
386 /** Return true if the source has 0 data. */
387 bool HasEmptyContent() const;
388
389 private:
ProfileSource(int32_t fd,MemMap && mem_map)390 ProfileSource(int32_t fd, MemMap&& mem_map)
391 : fd_(fd), mem_map_(std::move(mem_map)), mem_map_cur_(0) {}
392
IsMemMap() const393 bool IsMemMap() const {
394 return fd_ == -1;
395 }
396
397 int32_t fd_; // The fd is not owned by this class.
398 MemMap mem_map_;
399 size_t mem_map_cur_; // Current position in the map to read from.
400 };
401
402 // A helper structure to make sure we don't read past our buffers in the loops.
403 // Also used for writing but the buffer should be pre-sized correctly for that, so we
404 // DCHECK() we do not write beyond the end, rather than returning `false` on failure.
405 class ProfileCompilationInfo::SafeBuffer {
406 public:
SafeBuffer()407 SafeBuffer()
408 : storage_(nullptr),
409 ptr_current_(nullptr),
410 ptr_end_(nullptr) {}
411
SafeBuffer(size_t size)412 explicit SafeBuffer(size_t size)
413 : storage_(new uint8_t[size]),
414 ptr_current_(storage_.get()),
415 ptr_end_(ptr_current_ + size) {}
416
417 // Reads an uint value and advances the current pointer.
418 template <typename T>
ReadUintAndAdvance(T * value)419 bool ReadUintAndAdvance(/*out*/ T* value) {
420 static_assert(std::is_unsigned<T>::value, "Type is not unsigned");
421 if (sizeof(T) > GetAvailableBytes()) {
422 return false;
423 }
424 *value = 0;
425 for (size_t i = 0; i < sizeof(T); i++) {
426 *value += ptr_current_[i] << (i * kBitsPerByte);
427 }
428 ptr_current_ += sizeof(T);
429 return true;
430 }
431
432 // Reads a length-prefixed string as `std::string_view` and advances the current pointer.
433 // The length is `uint16_t`.
ReadStringAndAdvance(std::string_view * value)434 bool ReadStringAndAdvance(/*out*/ std::string_view* value) {
435 uint16_t length;
436 if (!ReadUintAndAdvance(&length)) {
437 return false;
438 }
439 if (length > GetAvailableBytes()) {
440 return false;
441 }
442 const void* null_char = memchr(GetCurrentPtr(), 0, length);
443 if (null_char != nullptr) {
444 // Embedded nulls are invalid.
445 return false;
446 }
447 *value = std::string_view(reinterpret_cast<const char*>(GetCurrentPtr()), length);
448 Advance(length);
449 return true;
450 }
451
452 // Compares the given data with the content at the current pointer.
453 // If the contents are equal it advances the current pointer by data_size.
CompareAndAdvance(const uint8_t * data,size_t data_size)454 bool CompareAndAdvance(const uint8_t* data, size_t data_size) {
455 if (data_size > GetAvailableBytes()) {
456 return false;
457 }
458 if (memcmp(ptr_current_, data, data_size) == 0) {
459 ptr_current_ += data_size;
460 return true;
461 }
462 return false;
463 }
464
WriteAndAdvance(const void * data,size_t data_size)465 void WriteAndAdvance(const void* data, size_t data_size) {
466 DCHECK_LE(data_size, GetAvailableBytes());
467 memcpy(ptr_current_, data, data_size);
468 ptr_current_ += data_size;
469 }
470
471 template <typename T>
WriteUintAndAdvance(T value)472 void WriteUintAndAdvance(T value) {
473 static_assert(std::is_integral_v<T>);
474 WriteAndAdvance(&value, sizeof(value));
475 }
476
477 // Deflate a filled buffer. Replaces the internal buffer with a new one, also filled.
Deflate()478 bool Deflate() {
479 DCHECK_EQ(GetAvailableBytes(), 0u);
480 DCHECK_NE(Size(), 0u);
481 ArrayRef<const uint8_t> in_buffer(Get(), Size());
482 uint32_t output_size = 0;
483 std::unique_ptr<uint8_t[]> compressed_buffer = DeflateBuffer(in_buffer, &output_size);
484 if (compressed_buffer == nullptr) {
485 return false;
486 }
487 storage_ = std::move(compressed_buffer);
488 ptr_current_ = storage_.get() + output_size;
489 ptr_end_ = ptr_current_;
490 return true;
491 }
492
493 // Inflate an unread buffer. Replaces the internal buffer with a new one, also unread.
Inflate(size_t uncompressed_data_size)494 bool Inflate(size_t uncompressed_data_size) {
495 DCHECK(ptr_current_ == storage_.get());
496 DCHECK_NE(Size(), 0u);
497 ArrayRef<const uint8_t> in_buffer(Get(), Size());
498 SafeBuffer uncompressed_buffer(uncompressed_data_size);
499 ArrayRef<uint8_t> out_buffer(uncompressed_buffer.Get(), uncompressed_data_size);
500 int ret = InflateBuffer(in_buffer, out_buffer);
501 if (ret != Z_STREAM_END) {
502 return false;
503 }
504 Swap(uncompressed_buffer);
505 DCHECK(ptr_current_ == storage_.get());
506 return true;
507 }
508
509 // Advances current pointer by data_size.
Advance(size_t data_size)510 void Advance(size_t data_size) {
511 DCHECK_LE(data_size, GetAvailableBytes());
512 ptr_current_ += data_size;
513 }
514
515 // Returns the count of unread bytes.
GetAvailableBytes() const516 size_t GetAvailableBytes() const {
517 DCHECK_LE(static_cast<void*>(ptr_current_), static_cast<void*>(ptr_end_));
518 return (ptr_end_ - ptr_current_) * sizeof(*ptr_current_);
519 }
520
521 // Returns the current pointer.
GetCurrentPtr()522 uint8_t* GetCurrentPtr() {
523 return ptr_current_;
524 }
525
526 // Get the underlying raw buffer.
Get()527 uint8_t* Get() {
528 return storage_.get();
529 }
530
531 // Get the size of the raw buffer.
Size() const532 size_t Size() const {
533 return ptr_end_ - storage_.get();
534 }
535
Swap(SafeBuffer & other)536 void Swap(SafeBuffer& other) {
537 std::swap(storage_, other.storage_);
538 std::swap(ptr_current_, other.ptr_current_);
539 std::swap(ptr_end_, other.ptr_end_);
540 }
541
542 private:
543 std::unique_ptr<uint8_t[]> storage_;
544 uint8_t* ptr_current_;
545 uint8_t* ptr_end_;
546 };
547
ProfileCompilationInfo(ArenaPool * custom_arena_pool,bool for_boot_image)548 ProfileCompilationInfo::ProfileCompilationInfo(ArenaPool* custom_arena_pool, bool for_boot_image)
549 : default_arena_pool_(),
550 allocator_(custom_arena_pool),
551 info_(allocator_.Adapter(kArenaAllocProfile)),
552 profile_key_map_(std::less<const std::string_view>(), allocator_.Adapter(kArenaAllocProfile)),
553 extra_descriptors_(),
554 extra_descriptors_indexes_(ExtraDescriptorHash(&extra_descriptors_),
555 ExtraDescriptorEquals(&extra_descriptors_)) {
556 memcpy(version_,
557 for_boot_image ? kProfileVersionForBootImage : kProfileVersion,
558 kProfileVersionSize);
559 }
560
ProfileCompilationInfo(ArenaPool * custom_arena_pool)561 ProfileCompilationInfo::ProfileCompilationInfo(ArenaPool* custom_arena_pool)
562 : ProfileCompilationInfo(custom_arena_pool, /*for_boot_image=*/ false) { }
563
ProfileCompilationInfo()564 ProfileCompilationInfo::ProfileCompilationInfo()
565 : ProfileCompilationInfo(/*for_boot_image=*/ false) { }
566
ProfileCompilationInfo(bool for_boot_image)567 ProfileCompilationInfo::ProfileCompilationInfo(bool for_boot_image)
568 : ProfileCompilationInfo(&default_arena_pool_, for_boot_image) { }
569
~ProfileCompilationInfo()570 ProfileCompilationInfo::~ProfileCompilationInfo() {
571 VLOG(profiler) << Dumpable<MemStats>(allocator_.GetMemStats());
572 }
573
AddClass(const dex::TypeIndex & type_idx)574 void ProfileCompilationInfo::DexPcData::AddClass(const dex::TypeIndex& type_idx) {
575 if (is_megamorphic || is_missing_types) {
576 return;
577 }
578
579 // Perform an explicit lookup for the type instead of directly emplacing the
580 // element. We do this because emplace() allocates the node before doing the
581 // lookup and if it then finds an identical element, it shall deallocate the
582 // node. For Arena allocations, that's essentially a leak.
583 auto lb = classes.lower_bound(type_idx);
584 if (lb != classes.end() && *lb == type_idx) {
585 // The type index exists.
586 return;
587 }
588
589 // Check if the adding the type will cause the cache to become megamorphic.
590 if (classes.size() + 1 >= ProfileCompilationInfo::kIndividualInlineCacheSize) {
591 is_megamorphic = true;
592 classes.clear();
593 return;
594 }
595
596 // The type does not exist and the inline cache will not be megamorphic.
597 classes.emplace_hint(lb, type_idx);
598 }
599
600 // Transform the actual dex location into a key used to index the dex file in the profile.
601 // See ProfileCompilationInfo#GetProfileDexFileBaseKey as well.
GetProfileDexFileAugmentedKey(const std::string & dex_location,const ProfileSampleAnnotation & annotation)602 std::string ProfileCompilationInfo::GetProfileDexFileAugmentedKey(
603 const std::string& dex_location,
604 const ProfileSampleAnnotation& annotation) {
605 std::string base_key = GetProfileDexFileBaseKey(dex_location);
606 return annotation == ProfileSampleAnnotation::kNone
607 ? base_key
608 : base_key + kSampleMetadataSeparator + annotation.GetOriginPackageName();;
609 }
610
611 // Transform the actual dex location into a base profile key (represented as relative paths).
612 // Note: this is OK because we don't store profiles of different apps into the same file.
613 // Apps with split apks don't cause trouble because each split has a different name and will not
614 // collide with other entries.
GetProfileDexFileBaseKeyView(std::string_view dex_location)615 std::string_view ProfileCompilationInfo::GetProfileDexFileBaseKeyView(
616 std::string_view dex_location) {
617 DCHECK(!dex_location.empty());
618 size_t last_sep_index = dex_location.find_last_of('/');
619 if (last_sep_index == std::string::npos) {
620 return dex_location;
621 } else {
622 DCHECK(last_sep_index < dex_location.size());
623 return dex_location.substr(last_sep_index + 1);
624 }
625 }
626
GetProfileDexFileBaseKey(const std::string & dex_location)627 std::string ProfileCompilationInfo::GetProfileDexFileBaseKey(const std::string& dex_location) {
628 // Note: Conversions between std::string and std::string_view.
629 return std::string(GetProfileDexFileBaseKeyView(dex_location));
630 }
631
GetBaseKeyViewFromAugmentedKey(std::string_view profile_key)632 std::string_view ProfileCompilationInfo::GetBaseKeyViewFromAugmentedKey(
633 std::string_view profile_key) {
634 size_t pos = profile_key.rfind(kSampleMetadataSeparator);
635 return (pos == std::string::npos) ? profile_key : profile_key.substr(0, pos);
636 }
637
GetBaseKeyFromAugmentedKey(const std::string & profile_key)638 std::string ProfileCompilationInfo::GetBaseKeyFromAugmentedKey(
639 const std::string& profile_key) {
640 // Note: Conversions between std::string and std::string_view.
641 return std::string(GetBaseKeyViewFromAugmentedKey(profile_key));
642 }
643
MigrateAnnotationInfo(const std::string & base_key,const std::string & augmented_key)644 std::string ProfileCompilationInfo::MigrateAnnotationInfo(
645 const std::string& base_key,
646 const std::string& augmented_key) {
647 size_t pos = augmented_key.rfind(kSampleMetadataSeparator);
648 return (pos == std::string::npos)
649 ? base_key
650 : base_key + augmented_key.substr(pos);
651 }
652
GetAnnotationFromKey(const std::string & augmented_key)653 ProfileCompilationInfo::ProfileSampleAnnotation ProfileCompilationInfo::GetAnnotationFromKey(
654 const std::string& augmented_key) {
655 size_t pos = augmented_key.rfind(kSampleMetadataSeparator);
656 return (pos == std::string::npos)
657 ? ProfileSampleAnnotation::kNone
658 : ProfileSampleAnnotation(augmented_key.substr(pos + 1));
659 }
660
AddMethods(const std::vector<ProfileMethodInfo> & methods,MethodHotness::Flag flags,const ProfileSampleAnnotation & annotation)661 bool ProfileCompilationInfo::AddMethods(const std::vector<ProfileMethodInfo>& methods,
662 MethodHotness::Flag flags,
663 const ProfileSampleAnnotation& annotation) {
664 for (const ProfileMethodInfo& method : methods) {
665 if (!AddMethod(method, flags, annotation)) {
666 return false;
667 }
668 }
669 return true;
670 }
671
FindOrCreateTypeIndex(const DexFile & dex_file,TypeReference class_ref)672 dex::TypeIndex ProfileCompilationInfo::FindOrCreateTypeIndex(const DexFile& dex_file,
673 TypeReference class_ref) {
674 DCHECK(class_ref.dex_file != nullptr);
675 DCHECK_LT(class_ref.TypeIndex().index_, class_ref.dex_file->NumTypeIds());
676 if (class_ref.dex_file == &dex_file) {
677 // We can use the type index from the `class_ref` as it's a valid index in the `dex_file`.
678 return class_ref.TypeIndex();
679 }
680 // Try to find a `TypeId` in the method's dex file.
681 const char* descriptor = class_ref.dex_file->StringByTypeIdx(class_ref.TypeIndex());
682 return FindOrCreateTypeIndex(dex_file, descriptor);
683 }
684
FindOrCreateTypeIndex(const DexFile & dex_file,const char * descriptor)685 dex::TypeIndex ProfileCompilationInfo::FindOrCreateTypeIndex(const DexFile& dex_file,
686 const char* descriptor) {
687 const dex::TypeId* type_id = dex_file.FindTypeId(descriptor);
688 if (type_id != nullptr) {
689 return dex_file.GetIndexForTypeId(*type_id);
690 }
691 // Try to find an existing extra descriptor.
692 uint32_t num_type_ids = dex_file.NumTypeIds();
693 uint32_t max_artificial_ids = DexFile::kDexNoIndex16 - num_type_ids;
694 std::string_view descriptor_view(descriptor);
695 // Check descriptor length for "extra descriptor". We are using `uint16_t` as prefix.
696 if (UNLIKELY(descriptor_view.size() > kMaxExtraDescriptorLength)) {
697 return dex::TypeIndex(); // Invalid.
698 }
699 auto it = extra_descriptors_indexes_.find(descriptor_view);
700 if (it != extra_descriptors_indexes_.end()) {
701 return (*it < max_artificial_ids) ? dex::TypeIndex(num_type_ids + *it) : dex::TypeIndex();
702 }
703 // Check if inserting the extra descriptor yields a valid artificial type index.
704 if (UNLIKELY(extra_descriptors_.size() >= max_artificial_ids)) {
705 return dex::TypeIndex(); // Invalid.
706 }
707 // Add the descriptor to extra descriptors and return the artificial type index.
708 ExtraDescriptorIndex new_extra_descriptor_index = AddExtraDescriptor(descriptor_view);
709 DCHECK_LT(new_extra_descriptor_index, max_artificial_ids);
710 return dex::TypeIndex(num_type_ids + new_extra_descriptor_index);
711 }
712
AddClass(const DexFile & dex_file,const char * descriptor,const ProfileSampleAnnotation & annotation)713 bool ProfileCompilationInfo::AddClass(const DexFile& dex_file,
714 const char* descriptor,
715 const ProfileSampleAnnotation& annotation) {
716 DexFileData* const data = GetOrAddDexFileData(&dex_file, annotation);
717 if (data == nullptr) { // checksum mismatch
718 return false;
719 }
720 dex::TypeIndex type_index = FindOrCreateTypeIndex(dex_file, descriptor);
721 if (!type_index.IsValid()) {
722 return false;
723 }
724 data->class_set.insert(type_index);
725 return true;
726 }
727
MergeWith(const std::string & filename)728 bool ProfileCompilationInfo::MergeWith(const std::string& filename) {
729 std::string error;
730 #ifdef _WIN32
731 int flags = O_RDONLY;
732 #else
733 int flags = O_RDONLY | O_NOFOLLOW | O_CLOEXEC;
734 #endif
735 ScopedFlock profile_file =
736 LockedFile::Open(filename.c_str(), flags, /*block=*/false, &error);
737
738 if (profile_file.get() == nullptr) {
739 LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
740 return false;
741 }
742
743 int fd = profile_file->Fd();
744
745 ProfileLoadStatus status = LoadInternal(fd, &error);
746 if (status == ProfileLoadStatus::kSuccess) {
747 return true;
748 }
749
750 LOG(WARNING) << "Could not load profile data from file " << filename << ": " << error;
751 return false;
752 }
753
Load(const std::string & filename,bool clear_if_invalid)754 bool ProfileCompilationInfo::Load(const std::string& filename, bool clear_if_invalid) {
755 ScopedTrace trace(__PRETTY_FUNCTION__);
756 std::string error;
757
758 if (!IsEmpty()) {
759 return false;
760 }
761
762 #ifdef _WIN32
763 int flags = O_RDWR;
764 #else
765 int flags = O_RDWR | O_NOFOLLOW | O_CLOEXEC;
766 #endif
767 // There's no need to fsync profile data right away. We get many chances
768 // to write it again in case something goes wrong. We can rely on a simple
769 // close(), no sync, and let to the kernel decide when to write to disk.
770 ScopedFlock profile_file =
771 LockedFile::Open(filename.c_str(), flags, /*block=*/false, &error);
772
773 if (profile_file.get() == nullptr) {
774 LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
775 return false;
776 }
777
778 int fd = profile_file->Fd();
779
780 ProfileLoadStatus status = LoadInternal(fd, &error);
781 if (status == ProfileLoadStatus::kSuccess) {
782 return true;
783 }
784
785 if (clear_if_invalid &&
786 ((status == ProfileLoadStatus::kBadMagic) ||
787 (status == ProfileLoadStatus::kVersionMismatch) ||
788 (status == ProfileLoadStatus::kBadData))) {
789 LOG(WARNING) << "Clearing bad or obsolete profile data from file "
790 << filename << ": " << error;
791 if (profile_file->ClearContent()) {
792 return true;
793 } else {
794 PLOG(WARNING) << "Could not clear profile file: " << filename;
795 return false;
796 }
797 }
798
799 LOG(WARNING) << "Could not load profile data from file " << filename << ": " << error;
800 return false;
801 }
802
Save(const std::string & filename,uint64_t * bytes_written)803 bool ProfileCompilationInfo::Save(const std::string& filename, uint64_t* bytes_written) {
804 ScopedTrace trace(__PRETTY_FUNCTION__);
805 std::string error;
806 #ifdef _WIN32
807 int flags = O_WRONLY;
808 #else
809 int flags = O_WRONLY | O_NOFOLLOW | O_CLOEXEC;
810 #endif
811 // There's no need to fsync profile data right away. We get many chances
812 // to write it again in case something goes wrong. We can rely on a simple
813 // close(), no sync, and let to the kernel decide when to write to disk.
814 ScopedFlock profile_file =
815 LockedFile::Open(filename.c_str(), flags, /*block=*/false, &error);
816 if (profile_file.get() == nullptr) {
817 LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
818 return false;
819 }
820
821 int fd = profile_file->Fd();
822
823 // We need to clear the data because we don't support appending to the profiles yet.
824 if (!profile_file->ClearContent()) {
825 PLOG(WARNING) << "Could not clear profile file: " << filename;
826 return false;
827 }
828
829 // This doesn't need locking because we are trying to lock the file for exclusive
830 // access and fail immediately if we can't.
831 bool result = Save(fd);
832 if (result) {
833 int64_t size = OS::GetFileSizeBytes(filename.c_str());
834 if (size != -1) {
835 VLOG(profiler)
836 << "Successfully saved profile info to " << filename << " Size: "
837 << size;
838 if (bytes_written != nullptr) {
839 *bytes_written = static_cast<uint64_t>(size);
840 }
841 }
842 } else {
843 VLOG(profiler) << "Failed to save profile info to " << filename;
844 }
845 return result;
846 }
847
848 // Returns true if all the bytes were successfully written to the file descriptor.
WriteBuffer(int fd,const void * buffer,size_t byte_count)849 static bool WriteBuffer(int fd, const void* buffer, size_t byte_count) {
850 while (byte_count > 0) {
851 int bytes_written = TEMP_FAILURE_RETRY(write(fd, buffer, byte_count));
852 if (bytes_written == -1) {
853 return false;
854 }
855 byte_count -= bytes_written; // Reduce the number of remaining bytes.
856 reinterpret_cast<const uint8_t*&>(buffer) += bytes_written; // Move the buffer forward.
857 }
858 return true;
859 }
860
861 /**
862 * Serialization format:
863 *
864 * The file starts with a header and section information:
865 * FileHeader
866 * FileSectionInfo[]
867 * The first FileSectionInfo must be for the DexFiles section.
868 *
869 * The rest of the file is allowed to contain different sections in any order,
870 * at arbitrary offsets, with any gaps betweeen them and each section can be
871 * either plaintext or separately zipped. However, we're writing sections
872 * without any gaps with the following order and compression:
873 * DexFiles - mandatory, plaintext
874 * ExtraDescriptors - optional, zipped
875 * Classes - optional, zipped
876 * Methods - optional, zipped
877 *
878 * DexFiles:
879 * number_of_dex_files
880 * (checksum,num_type_ids,num_method_ids,profile_key)[number_of_dex_files]
881 * where `profile_key` is a length-prefixed string, the length is `uint16_t`.
882 *
883 * ExtraDescriptors:
884 * number_of_extra_descriptors
885 * (extra_descriptor)[number_of_extra_descriptors]
886 * where `extra_descriptor` is a length-prefixed string, the length is `uint16_t`.
887 *
888 * Classes contains records for any number of dex files, each consisting of:
889 * profile_index // Index of the dex file in DexFiles section.
890 * number_of_classes
891 * type_index_diff[number_of_classes]
892 * where instead of storing plain sorted type indexes, we store their differences
893 * as smaller numbers are likely to compress better.
894 *
895 * Methods contains records for any number of dex files, each consisting of:
896 * profile_index // Index of the dex file in DexFiles section.
897 * following_data_size // For easy skipping of remaining data when dex file is filtered out.
898 * method_flags
899 * bitmap_data
900 * method_encoding[] // Until the size indicated by `following_data_size`.
901 * where `method_flags` is a union of flags recorded for methods in the referenced dex file,
902 * `bitmap_data` contains `num_method_ids` bits for each bit set in `method_flags` other
903 * than "hot" (the size of `bitmap_data` is rounded up to whole bytes) and `method_encoding[]`
904 * contains data for hot methods. The `method_encoding` is:
905 * method_index_diff
906 * number_of_inline_caches
907 * inline_cache_encoding[number_of_inline_caches]
908 * where differences in method indexes are used for better compression,
909 * and the `inline_cache_encoding` is
910 * dex_pc
911 * (M|dex_map_size)
912 * type_index_diff[dex_map_size]
913 * where `M` stands for special encodings indicating missing types (kIsMissingTypesEncoding)
914 * or memamorphic call (kIsMegamorphicEncoding) which both imply `dex_map_size == 0`.
915 **/
Save(int fd)916 bool ProfileCompilationInfo::Save(int fd) {
917 uint64_t start = NanoTime();
918 ScopedTrace trace(__PRETTY_FUNCTION__);
919 DCHECK_GE(fd, 0);
920
921 // Collect uncompressed section sizes.
922 // Use `uint64_t` and assume this cannot overflow as we would have run out of memory.
923 uint64_t extra_descriptors_section_size = 0u;
924 if (!extra_descriptors_.empty()) {
925 extra_descriptors_section_size += sizeof(uint16_t); // Number of descriptors.
926 for (const std::string& descriptor : extra_descriptors_) {
927 // Length-prefixed string, the length is `uint16_t`.
928 extra_descriptors_section_size += sizeof(uint16_t) + descriptor.size();
929 }
930 }
931 uint64_t dex_files_section_size = sizeof(ProfileIndexType); // Number of dex files.
932 uint64_t classes_section_size = 0u;
933 uint64_t methods_section_size = 0u;
934 DCHECK_LE(info_.size(), MaxProfileIndex());
935 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
936 if (dex_data->profile_key.size() > kMaxDexFileKeyLength) {
937 LOG(WARNING) << "DexFileKey exceeds allocated limit";
938 return false;
939 }
940 dex_files_section_size +=
941 3 * sizeof(uint32_t) + // Checksum, num_type_ids, num_method_ids.
942 // Length-prefixed string, the length is `uint16_t`.
943 sizeof(uint16_t) + dex_data->profile_key.size();
944 classes_section_size += dex_data->ClassesDataSize();
945 methods_section_size += dex_data->MethodsDataSize();
946 }
947
948 const uint32_t file_section_count =
949 /* dex files */ 1u +
950 /* extra descriptors */ (extra_descriptors_section_size != 0u ? 1u : 0u) +
951 /* classes */ (classes_section_size != 0u ? 1u : 0u) +
952 /* methods */ (methods_section_size != 0u ? 1u : 0u);
953 uint64_t header_and_infos_size =
954 sizeof(FileHeader) + file_section_count * sizeof(FileSectionInfo);
955
956 // Check size limit. Allow large profiles for non target builds for the case
957 // where we are merging many profiles to generate a boot image profile.
958 uint64_t total_uncompressed_size =
959 header_and_infos_size +
960 dex_files_section_size +
961 extra_descriptors_section_size +
962 classes_section_size +
963 methods_section_size;
964 VLOG(profiler) << "Required capacity: " << total_uncompressed_size << " bytes.";
965 if (total_uncompressed_size > GetSizeErrorThresholdBytes()) {
966 LOG(ERROR) << "Profile data size exceeds "
967 << GetSizeErrorThresholdBytes()
968 << " bytes. Profile will not be written to disk."
969 << " It requires " << total_uncompressed_size << " bytes.";
970 return false;
971 }
972
973 // Start with an invalid file header and section infos.
974 DCHECK_EQ(lseek(fd, 0, SEEK_CUR), 0);
975 constexpr uint32_t kMaxNumberOfSections = enum_cast<uint32_t>(FileSectionType::kNumberOfSections);
976 constexpr uint64_t kMaxHeaderAndInfosSize =
977 sizeof(FileHeader) + kMaxNumberOfSections * sizeof(FileSectionInfo);
978 DCHECK_LE(header_and_infos_size, kMaxHeaderAndInfosSize);
979 std::array<uint8_t, kMaxHeaderAndInfosSize> placeholder;
980 memset(placeholder.data(), 0, header_and_infos_size);
981 if (!WriteBuffer(fd, placeholder.data(), header_and_infos_size)) {
982 return false;
983 }
984
985 std::array<FileSectionInfo, kMaxNumberOfSections> section_infos;
986 size_t section_index = 0u;
987 uint32_t file_offset = header_and_infos_size;
988 auto add_section_info = [&](FileSectionType type, uint32_t file_size, uint32_t inflated_size) {
989 DCHECK_LT(section_index, section_infos.size());
990 section_infos[section_index] = FileSectionInfo(type, file_offset, file_size, inflated_size);
991 file_offset += file_size;
992 section_index += 1u;
993 };
994
995 // Write the dex files section.
996 {
997 SafeBuffer buffer(dex_files_section_size);
998 buffer.WriteUintAndAdvance(dchecked_integral_cast<ProfileIndexType>(info_.size()));
999 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1000 buffer.WriteUintAndAdvance(dex_data->checksum);
1001 buffer.WriteUintAndAdvance(dex_data->num_type_ids);
1002 buffer.WriteUintAndAdvance(dex_data->num_method_ids);
1003 buffer.WriteUintAndAdvance(dchecked_integral_cast<uint16_t>(dex_data->profile_key.size()));
1004 buffer.WriteAndAdvance(dex_data->profile_key.c_str(), dex_data->profile_key.size());
1005 }
1006 DCHECK_EQ(buffer.GetAvailableBytes(), 0u);
1007 // Write the dex files section uncompressed.
1008 if (!WriteBuffer(fd, buffer.Get(), dex_files_section_size)) {
1009 return false;
1010 }
1011 add_section_info(FileSectionType::kDexFiles, dex_files_section_size, /*inflated_size=*/ 0u);
1012 }
1013
1014 // Write the extra descriptors section.
1015 if (extra_descriptors_section_size != 0u) {
1016 SafeBuffer buffer(extra_descriptors_section_size);
1017 buffer.WriteUintAndAdvance(dchecked_integral_cast<uint16_t>(extra_descriptors_.size()));
1018 for (const std::string& descriptor : extra_descriptors_) {
1019 buffer.WriteUintAndAdvance(dchecked_integral_cast<uint16_t>(descriptor.size()));
1020 buffer.WriteAndAdvance(descriptor.c_str(), descriptor.size());
1021 }
1022 if (!buffer.Deflate()) {
1023 return false;
1024 }
1025 if (!WriteBuffer(fd, buffer.Get(), buffer.Size())) {
1026 return false;
1027 }
1028 add_section_info(
1029 FileSectionType::kExtraDescriptors, buffer.Size(), extra_descriptors_section_size);
1030 }
1031
1032 // Write the classes section.
1033 if (classes_section_size != 0u) {
1034 SafeBuffer buffer(classes_section_size);
1035 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1036 dex_data->WriteClasses(buffer);
1037 }
1038 if (!buffer.Deflate()) {
1039 return false;
1040 }
1041 if (!WriteBuffer(fd, buffer.Get(), buffer.Size())) {
1042 return false;
1043 }
1044 add_section_info(FileSectionType::kClasses, buffer.Size(), classes_section_size);
1045 }
1046
1047 // Write the methods section.
1048 if (methods_section_size != 0u) {
1049 SafeBuffer buffer(methods_section_size);
1050 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1051 dex_data->WriteMethods(buffer);
1052 }
1053 if (!buffer.Deflate()) {
1054 return false;
1055 }
1056 if (!WriteBuffer(fd, buffer.Get(), buffer.Size())) {
1057 return false;
1058 }
1059 add_section_info(FileSectionType::kMethods, buffer.Size(), methods_section_size);
1060 }
1061
1062 if (file_offset > GetSizeWarningThresholdBytes()) {
1063 LOG(WARNING) << "Profile data size exceeds "
1064 << GetSizeWarningThresholdBytes()
1065 << " It has " << file_offset << " bytes";
1066 }
1067
1068 // Write section infos.
1069 if (lseek64(fd, sizeof(FileHeader), SEEK_SET) != sizeof(FileHeader)) {
1070 return false;
1071 }
1072 SafeBuffer section_infos_buffer(section_index * 4u * sizeof(uint32_t));
1073 for (size_t i = 0; i != section_index; ++i) {
1074 const FileSectionInfo& info = section_infos[i];
1075 section_infos_buffer.WriteUintAndAdvance(enum_cast<uint32_t>(info.GetType()));
1076 section_infos_buffer.WriteUintAndAdvance(info.GetFileOffset());
1077 section_infos_buffer.WriteUintAndAdvance(info.GetFileSize());
1078 section_infos_buffer.WriteUintAndAdvance(info.GetInflatedSize());
1079 }
1080 DCHECK_EQ(section_infos_buffer.GetAvailableBytes(), 0u);
1081 if (!WriteBuffer(fd, section_infos_buffer.Get(), section_infos_buffer.Size())) {
1082 return false;
1083 }
1084
1085 // Write header.
1086 FileHeader header(version_, section_index);
1087 if (lseek(fd, 0, SEEK_SET) != 0) {
1088 return false;
1089 }
1090 if (!WriteBuffer(fd, &header, sizeof(FileHeader))) {
1091 return false;
1092 }
1093
1094 uint64_t total_time = NanoTime() - start;
1095 VLOG(profiler) << "Compressed from "
1096 << std::to_string(total_uncompressed_size)
1097 << " to "
1098 << std::to_string(file_offset);
1099 VLOG(profiler) << "Time to save profile: " << std::to_string(total_time);
1100 return true;
1101 }
1102
GetOrAddDexFileData(const std::string & profile_key,uint32_t checksum,uint32_t num_type_ids,uint32_t num_method_ids)1103 ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::GetOrAddDexFileData(
1104 const std::string& profile_key,
1105 uint32_t checksum,
1106 uint32_t num_type_ids,
1107 uint32_t num_method_ids) {
1108 DCHECK_EQ(profile_key_map_.size(), info_.size());
1109 auto profile_index_it = profile_key_map_.lower_bound(profile_key);
1110 if (profile_index_it == profile_key_map_.end() || profile_index_it->first != profile_key) {
1111 // We did not find the key. Create a new DexFileData if we did not reach the limit.
1112 DCHECK_LE(profile_key_map_.size(), MaxProfileIndex());
1113 if (profile_key_map_.size() == MaxProfileIndex()) {
1114 // Allow only a limited number dex files to be profiled. This allows us to save bytes
1115 // when encoding. For regular profiles this 2^8, and for boot profiles is 2^16
1116 // (well above what we expect for normal applications).
1117 LOG(ERROR) << "Exceeded the maximum number of dex file. Something went wrong";
1118 return nullptr;
1119 }
1120 ProfileIndexType new_profile_index = dchecked_integral_cast<ProfileIndexType>(info_.size());
1121 std::unique_ptr<DexFileData> dex_file_data(new (&allocator_) DexFileData(
1122 &allocator_,
1123 profile_key,
1124 checksum,
1125 new_profile_index,
1126 num_type_ids,
1127 num_method_ids,
1128 IsForBootImage()));
1129 // Record the new data in `profile_key_map_` and `info_`.
1130 std::string_view new_key(dex_file_data->profile_key);
1131 profile_index_it = profile_key_map_.PutBefore(profile_index_it, new_key, new_profile_index);
1132 info_.push_back(std::move(dex_file_data));
1133 DCHECK_EQ(profile_key_map_.size(), info_.size());
1134 }
1135
1136 ProfileIndexType profile_index = profile_index_it->second;
1137 DexFileData* result = info_[profile_index].get();
1138
1139 // Check that the checksum matches.
1140 // This may different if for example the dex file was updated and we had a record of the old one.
1141 if (result->checksum != checksum) {
1142 LOG(WARNING) << "Checksum mismatch for dex " << profile_key;
1143 return nullptr;
1144 }
1145
1146 // DCHECK that profile info map key is consistent with the one stored in the dex file data.
1147 // This should always be the case since since the cache map is managed by ProfileCompilationInfo.
1148 DCHECK_EQ(profile_key, result->profile_key);
1149 DCHECK_EQ(profile_index, result->profile_index);
1150
1151 if (num_type_ids != result->num_type_ids || num_method_ids != result->num_method_ids) {
1152 // This should not happen... added to help investigating b/65812889.
1153 LOG(ERROR) << "num_type_ids or num_method_ids mismatch for dex " << profile_key
1154 << ", types: expected=" << num_type_ids << " v. actual=" << result->num_type_ids
1155 << ", methods: expected=" << num_method_ids << " actual=" << result->num_method_ids;
1156 return nullptr;
1157 }
1158
1159 return result;
1160 }
1161
FindDexData(const std::string & profile_key,uint32_t checksum,bool verify_checksum) const1162 const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexData(
1163 const std::string& profile_key,
1164 uint32_t checksum,
1165 bool verify_checksum) const {
1166 const auto profile_index_it = profile_key_map_.find(profile_key);
1167 if (profile_index_it == profile_key_map_.end()) {
1168 return nullptr;
1169 }
1170
1171 ProfileIndexType profile_index = profile_index_it->second;
1172 const DexFileData* result = info_[profile_index].get();
1173 if (verify_checksum && !ChecksumMatch(result->checksum, checksum)) {
1174 return nullptr;
1175 }
1176 DCHECK_EQ(profile_key, result->profile_key);
1177 DCHECK_EQ(profile_index, result->profile_index);
1178 return result;
1179 }
1180
FindDexDataUsingAnnotations(const DexFile * dex_file,const ProfileSampleAnnotation & annotation) const1181 const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexDataUsingAnnotations(
1182 const DexFile* dex_file,
1183 const ProfileSampleAnnotation& annotation) const {
1184 if (annotation == ProfileSampleAnnotation::kNone) {
1185 std::string_view profile_key = GetProfileDexFileBaseKeyView(dex_file->GetLocation());
1186 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1187 if (profile_key == GetBaseKeyViewFromAugmentedKey(dex_data->profile_key)) {
1188 if (!ChecksumMatch(dex_data->checksum, dex_file->GetLocationChecksum())) {
1189 return nullptr;
1190 }
1191 return dex_data.get();
1192 }
1193 }
1194 } else {
1195 std::string profile_key = GetProfileDexFileAugmentedKey(dex_file->GetLocation(), annotation);
1196 return FindDexData(profile_key, dex_file->GetLocationChecksum());
1197 }
1198
1199 return nullptr;
1200 }
1201
FindAllDexData(const DexFile * dex_file,std::vector<const ProfileCompilationInfo::DexFileData * > * result) const1202 void ProfileCompilationInfo::FindAllDexData(
1203 const DexFile* dex_file,
1204 /*out*/ std::vector<const ProfileCompilationInfo::DexFileData*>* result) const {
1205 std::string_view profile_key = GetProfileDexFileBaseKeyView(dex_file->GetLocation());
1206 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1207 if (profile_key == GetBaseKeyViewFromAugmentedKey(dex_data->profile_key)) {
1208 if (ChecksumMatch(dex_data->checksum, dex_file->GetLocationChecksum())) {
1209 result->push_back(dex_data.get());
1210 }
1211 }
1212 }
1213 }
1214
AddExtraDescriptor(std::string_view extra_descriptor)1215 ProfileCompilationInfo::ExtraDescriptorIndex ProfileCompilationInfo::AddExtraDescriptor(
1216 std::string_view extra_descriptor) {
1217 DCHECK_LE(extra_descriptor.size(), kMaxExtraDescriptorLength);
1218 DCHECK(extra_descriptors_indexes_.find(extra_descriptor) == extra_descriptors_indexes_.end());
1219 ExtraDescriptorIndex new_extra_descriptor_index = extra_descriptors_.size();
1220 DCHECK_LE(new_extra_descriptor_index, kMaxExtraDescriptors);
1221 if (UNLIKELY(new_extra_descriptor_index == kMaxExtraDescriptors)) {
1222 return kMaxExtraDescriptors; // Cannot add another extra descriptor.
1223 }
1224 // Add the extra descriptor and record the new index.
1225 extra_descriptors_.emplace_back(extra_descriptor);
1226 extra_descriptors_indexes_.insert(new_extra_descriptor_index);
1227 return new_extra_descriptor_index;
1228 }
1229
AddMethod(const ProfileMethodInfo & pmi,MethodHotness::Flag flags,const ProfileSampleAnnotation & annotation)1230 bool ProfileCompilationInfo::AddMethod(const ProfileMethodInfo& pmi,
1231 MethodHotness::Flag flags,
1232 const ProfileSampleAnnotation& annotation) {
1233 DexFileData* const data = GetOrAddDexFileData(pmi.ref.dex_file, annotation);
1234 if (data == nullptr) { // checksum mismatch
1235 return false;
1236 }
1237 if (!data->AddMethod(flags, pmi.ref.index)) {
1238 return false;
1239 }
1240 if ((flags & MethodHotness::kFlagHot) == 0) {
1241 // The method is not hot, do not add inline caches.
1242 return true;
1243 }
1244
1245 // Add inline caches.
1246 InlineCacheMap* inline_cache = data->FindOrAddHotMethod(pmi.ref.index);
1247 DCHECK(inline_cache != nullptr);
1248
1249 for (const ProfileMethodInfo::ProfileInlineCache& cache : pmi.inline_caches) {
1250 if (cache.is_missing_types) {
1251 FindOrAddDexPc(inline_cache, cache.dex_pc)->SetIsMissingTypes();
1252 continue;
1253 }
1254 if (cache.is_megamorphic) {
1255 FindOrAddDexPc(inline_cache, cache.dex_pc)->SetIsMegamorphic();
1256 continue;
1257 }
1258 for (const TypeReference& class_ref : cache.classes) {
1259 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, cache.dex_pc);
1260 if (dex_pc_data->is_missing_types || dex_pc_data->is_megamorphic) {
1261 // Don't bother adding classes if we are missing types or already megamorphic.
1262 break;
1263 }
1264 dex::TypeIndex type_index = FindOrCreateTypeIndex(*pmi.ref.dex_file, class_ref);
1265 if (type_index.IsValid()) {
1266 dex_pc_data->AddClass(type_index);
1267 } else {
1268 // Could not create artificial type index.
1269 dex_pc_data->SetIsMissingTypes();
1270 }
1271 }
1272 }
1273 return true;
1274 }
1275
1276 // TODO(calin): Fix this API. ProfileCompilationInfo::Load should be static and
1277 // return a unique pointer to a ProfileCompilationInfo upon success.
Load(int fd,bool merge_classes,const ProfileLoadFilterFn & filter_fn)1278 bool ProfileCompilationInfo::Load(
1279 int fd, bool merge_classes, const ProfileLoadFilterFn& filter_fn) {
1280 std::string error;
1281
1282 ProfileLoadStatus status = LoadInternal(fd, &error, merge_classes, filter_fn);
1283
1284 if (status == ProfileLoadStatus::kSuccess) {
1285 return true;
1286 } else {
1287 LOG(WARNING) << "Error when reading profile: " << error;
1288 return false;
1289 }
1290 }
1291
VerifyProfileData(const std::vector<const DexFile * > & dex_files)1292 bool ProfileCompilationInfo::VerifyProfileData(const std::vector<const DexFile*>& dex_files) {
1293 std::unordered_map<std::string_view, const DexFile*> key_to_dex_file;
1294 for (const DexFile* dex_file : dex_files) {
1295 key_to_dex_file.emplace(GetProfileDexFileBaseKeyView(dex_file->GetLocation()), dex_file);
1296 }
1297 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1298 // We need to remove any annotation from the key during verification.
1299 const auto it = key_to_dex_file.find(GetBaseKeyViewFromAugmentedKey(dex_data->profile_key));
1300 if (it == key_to_dex_file.end()) {
1301 // It is okay if profile contains data for additional dex files.
1302 continue;
1303 }
1304 const DexFile* dex_file = it->second;
1305 const std::string& dex_location = dex_file->GetLocation();
1306 if (!ChecksumMatch(dex_data->checksum, dex_file->GetLocationChecksum())) {
1307 LOG(ERROR) << "Dex checksum mismatch while verifying profile "
1308 << "dex location " << dex_location << " (checksum="
1309 << dex_file->GetLocationChecksum() << ", profile checksum="
1310 << dex_data->checksum;
1311 return false;
1312 }
1313
1314 if (dex_data->num_method_ids != dex_file->NumMethodIds() ||
1315 dex_data->num_type_ids != dex_file->NumTypeIds()) {
1316 LOG(ERROR) << "Number of type or method ids in dex file and profile don't match."
1317 << "dex location " << dex_location
1318 << " dex_file.NumTypeIds=" << dex_file->NumTypeIds()
1319 << " .v dex_data.num_type_ids=" << dex_data->num_type_ids
1320 << ", dex_file.NumMethodIds=" << dex_file->NumMethodIds()
1321 << " v. dex_data.num_method_ids=" << dex_data->num_method_ids;
1322 return false;
1323 }
1324
1325 // Class and method data should be valid. Verify only in debug builds.
1326 if (kIsDebugBuild) {
1327 // Verify method_encoding.
1328 for (const auto& method_it : dex_data->method_map) {
1329 CHECK_LT(method_it.first, dex_data->num_method_ids);
1330
1331 // Verify class indices of inline caches.
1332 const InlineCacheMap &inline_cache_map = method_it.second;
1333 for (const auto& inline_cache_it : inline_cache_map) {
1334 const DexPcData& dex_pc_data = inline_cache_it.second;
1335 if (dex_pc_data.is_missing_types || dex_pc_data.is_megamorphic) {
1336 // No class indices to verify.
1337 CHECK(dex_pc_data.classes.empty());
1338 continue;
1339 }
1340
1341 for (const dex::TypeIndex& type_index : dex_pc_data.classes) {
1342 if (type_index.index_ >= dex_data->num_type_ids) {
1343 CHECK_LT(type_index.index_ - dex_data->num_type_ids, extra_descriptors_.size());
1344 }
1345 }
1346 }
1347 }
1348 // Verify class_ids.
1349 for (const dex::TypeIndex& type_index : dex_data->class_set) {
1350 if (type_index.index_ >= dex_data->num_type_ids) {
1351 CHECK_LT(type_index.index_ - dex_data->num_type_ids, extra_descriptors_.size());
1352 }
1353 }
1354 }
1355 }
1356 return true;
1357 }
1358
OpenSource(int32_t fd,std::unique_ptr<ProfileSource> * source,std::string * error)1359 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::OpenSource(
1360 int32_t fd,
1361 /*out*/ std::unique_ptr<ProfileSource>* source,
1362 /*out*/ std::string* error) {
1363 if (IsProfileFile(fd)) {
1364 source->reset(ProfileSource::Create(fd));
1365 return ProfileLoadStatus::kSuccess;
1366 } else {
1367 std::unique_ptr<ZipArchive> zip_archive(
1368 ZipArchive::OpenFromFd(DupCloexec(fd), "profile", error));
1369 if (zip_archive.get() == nullptr) {
1370 *error = "Could not open the profile zip archive";
1371 return ProfileLoadStatus::kBadData;
1372 }
1373 std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(kDexMetadataProfileEntry, error));
1374 if (zip_entry == nullptr) {
1375 // Allow archives without the profile entry. In this case, create an empty profile.
1376 // This gives more flexible when ure-using archives that may miss the entry.
1377 // (e.g. dex metadata files)
1378 LOG(WARNING) << "Could not find entry " << kDexMetadataProfileEntry
1379 << " in the zip archive. Creating an empty profile.";
1380 source->reset(ProfileSource::Create(MemMap::Invalid()));
1381 return ProfileLoadStatus::kSuccess;
1382 }
1383 if (zip_entry->GetUncompressedLength() == 0) {
1384 *error = "Empty profile entry in the zip archive.";
1385 return ProfileLoadStatus::kBadData;
1386 }
1387
1388 // TODO(calin) pass along file names to assist with debugging.
1389 MemMap map = zip_entry->MapDirectlyOrExtract(
1390 kDexMetadataProfileEntry, "profile file", error, alignof(ProfileSource));
1391
1392 if (map.IsValid()) {
1393 source->reset(ProfileSource::Create(std::move(map)));
1394 return ProfileLoadStatus::kSuccess;
1395 } else {
1396 return ProfileLoadStatus::kBadData;
1397 }
1398 }
1399 }
1400
Seek(off_t offset)1401 bool ProfileCompilationInfo::ProfileSource::Seek(off_t offset) {
1402 DCHECK_GE(offset, 0);
1403 if (IsMemMap()) {
1404 if (offset > static_cast<int64_t>(mem_map_.Size())) {
1405 return false;
1406 }
1407 mem_map_cur_ = offset;
1408 return true;
1409 } else {
1410 if (lseek64(fd_, offset, SEEK_SET) != offset) {
1411 return false;
1412 }
1413 return true;
1414 }
1415 }
1416
Read(void * buffer,size_t byte_count,const std::string & debug_stage,std::string * error)1417 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ProfileSource::Read(
1418 void* buffer,
1419 size_t byte_count,
1420 const std::string& debug_stage,
1421 std::string* error) {
1422 if (IsMemMap()) {
1423 DCHECK_LE(mem_map_cur_, mem_map_.Size());
1424 if (byte_count > mem_map_.Size() - mem_map_cur_) {
1425 return ProfileLoadStatus::kBadData;
1426 }
1427 memcpy(buffer, mem_map_.Begin() + mem_map_cur_, byte_count);
1428 mem_map_cur_ += byte_count;
1429 } else {
1430 while (byte_count > 0) {
1431 int bytes_read = TEMP_FAILURE_RETRY(read(fd_, buffer, byte_count));;
1432 if (bytes_read == 0) {
1433 *error += "Profile EOF reached prematurely for " + debug_stage;
1434 return ProfileLoadStatus::kBadData;
1435 } else if (bytes_read < 0) {
1436 *error += "Profile IO error for " + debug_stage + strerror(errno);
1437 return ProfileLoadStatus::kIOError;
1438 }
1439 byte_count -= bytes_read;
1440 reinterpret_cast<uint8_t*&>(buffer) += bytes_read;
1441 }
1442 }
1443 return ProfileLoadStatus::kSuccess;
1444 }
1445
1446
HasEmptyContent() const1447 bool ProfileCompilationInfo::ProfileSource::HasEmptyContent() const {
1448 if (IsMemMap()) {
1449 return !mem_map_.IsValid() || mem_map_.Size() == 0;
1450 } else {
1451 struct stat stat_buffer;
1452 if (fstat(fd_, &stat_buffer) != 0) {
1453 return false;
1454 }
1455 return stat_buffer.st_size == 0;
1456 }
1457 }
1458
ReadSectionData(ProfileSource & source,const FileSectionInfo & section_info,SafeBuffer * buffer,std::string * error)1459 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadSectionData(
1460 ProfileSource& source,
1461 const FileSectionInfo& section_info,
1462 /*out*/ SafeBuffer* buffer,
1463 /*out*/ std::string* error) {
1464 DCHECK_EQ(buffer->Size(), 0u);
1465 if (!source.Seek(section_info.GetFileOffset())) {
1466 *error = "Failed to seek to section data.";
1467 return ProfileLoadStatus::kIOError;
1468 }
1469 SafeBuffer temp_buffer(section_info.GetFileSize());
1470 ProfileLoadStatus status = source.Read(
1471 temp_buffer.GetCurrentPtr(), temp_buffer.GetAvailableBytes(), "ReadSectionData", error);
1472 if (status != ProfileLoadStatus::kSuccess) {
1473 return status;
1474 }
1475 if (section_info.GetInflatedSize() != 0u &&
1476 !temp_buffer.Inflate(section_info.GetInflatedSize())) {
1477 *error += "Error uncompressing section data.";
1478 return ProfileLoadStatus::kBadData;
1479 }
1480 buffer->Swap(temp_buffer);
1481 return ProfileLoadStatus::kSuccess;
1482 }
1483
ReadDexFilesSection(ProfileSource & source,const FileSectionInfo & section_info,const ProfileLoadFilterFn & filter_fn,dchecked_vector<ProfileIndexType> * dex_profile_index_remap,std::string * error)1484 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadDexFilesSection(
1485 ProfileSource& source,
1486 const FileSectionInfo& section_info,
1487 const ProfileLoadFilterFn& filter_fn,
1488 /*out*/ dchecked_vector<ProfileIndexType>* dex_profile_index_remap,
1489 /*out*/ std::string* error) {
1490 DCHECK(section_info.GetType() == FileSectionType::kDexFiles);
1491 SafeBuffer buffer;
1492 ProfileLoadStatus status = ReadSectionData(source, section_info, &buffer, error);
1493 if (status != ProfileLoadStatus::kSuccess) {
1494 return status;
1495 }
1496
1497 ProfileIndexType num_dex_files;
1498 if (!buffer.ReadUintAndAdvance(&num_dex_files)) {
1499 *error = "Error reading number of dex files.";
1500 return ProfileLoadStatus::kBadData;
1501 }
1502 if (num_dex_files >= MaxProfileIndex()) {
1503 *error = "Too many dex files.";
1504 return ProfileLoadStatus::kBadData;
1505 }
1506
1507 DCHECK(dex_profile_index_remap->empty());
1508 for (ProfileIndexType i = 0u; i != num_dex_files; ++i) {
1509 uint32_t checksum, num_type_ids, num_method_ids;
1510 if (!buffer.ReadUintAndAdvance(&checksum) ||
1511 !buffer.ReadUintAndAdvance(&num_type_ids) ||
1512 !buffer.ReadUintAndAdvance(&num_method_ids)) {
1513 *error = "Error reading dex file data.";
1514 return ProfileLoadStatus::kBadData;
1515 }
1516 std::string_view profile_key_view;
1517 if (!buffer.ReadStringAndAdvance(&profile_key_view)) {
1518 *error += "Missing terminating null character for profile key.";
1519 return ProfileLoadStatus::kBadData;
1520 }
1521 if (profile_key_view.size() == 0u || profile_key_view.size() > kMaxDexFileKeyLength) {
1522 *error = "ProfileKey has an invalid size: " + std::to_string(profile_key_view.size());
1523 return ProfileLoadStatus::kBadData;
1524 }
1525 std::string profile_key(profile_key_view);
1526 if (!filter_fn(profile_key, checksum)) {
1527 // Do not load data for this key. Store invalid index to `dex_profile_index_remap`.
1528 VLOG(compiler) << "Profile: Filtered out " << profile_key << " 0x" << std::hex << checksum;
1529 dex_profile_index_remap->push_back(MaxProfileIndex());
1530 continue;
1531 }
1532 DexFileData* data = GetOrAddDexFileData(profile_key, checksum, num_type_ids, num_method_ids);
1533 if (data == nullptr) {
1534 if (UNLIKELY(profile_key_map_.size() == MaxProfileIndex()) &&
1535 profile_key_map_.find(profile_key) == profile_key_map_.end()) {
1536 *error = "Too many dex files.";
1537 } else {
1538 *error = "Checksum, NumTypeIds, or NumMethodIds mismatch for " + profile_key;
1539 }
1540 return ProfileLoadStatus::kBadData;
1541 }
1542 dex_profile_index_remap->push_back(data->profile_index);
1543 }
1544 if (buffer.GetAvailableBytes() != 0u) {
1545 *error = "Unexpected data at end of dex files section.";
1546 return ProfileLoadStatus::kBadData;
1547 }
1548 return ProfileLoadStatus::kSuccess;
1549 }
1550
ReadExtraDescriptorsSection(ProfileSource & source,const FileSectionInfo & section_info,dchecked_vector<ExtraDescriptorIndex> * extra_descriptors_remap,std::string * error)1551 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadExtraDescriptorsSection(
1552 ProfileSource& source,
1553 const FileSectionInfo& section_info,
1554 /*out*/ dchecked_vector<ExtraDescriptorIndex>* extra_descriptors_remap,
1555 /*out*/ std::string* error) {
1556 DCHECK(section_info.GetType() == FileSectionType::kExtraDescriptors);
1557 SafeBuffer buffer;
1558 ProfileLoadStatus status = ReadSectionData(source, section_info, &buffer, error);
1559 if (status != ProfileLoadStatus::kSuccess) {
1560 return status;
1561 }
1562
1563 uint16_t num_extra_descriptors;
1564 if (!buffer.ReadUintAndAdvance(&num_extra_descriptors)) {
1565 *error = "Error reading number of extra descriptors.";
1566 return ProfileLoadStatus::kBadData;
1567 }
1568
1569 // Note: We allow multiple extra descriptors sections in a single profile file
1570 // but that can lead to `kMergeError` if there are too many extra descriptors.
1571 // Other sections can reference only extra descriptors from preceding sections.
1572 extra_descriptors_remap->reserve(
1573 std::min<size_t>(extra_descriptors_remap->size() + num_extra_descriptors,
1574 std::numeric_limits<uint16_t>::max()));
1575 for (uint16_t i = 0; i != num_extra_descriptors; ++i) {
1576 std::string_view extra_descriptor;
1577 if (!buffer.ReadStringAndAdvance(&extra_descriptor)) {
1578 *error += "Missing terminating null character for extra descriptor.";
1579 return ProfileLoadStatus::kBadData;
1580 }
1581 if (!IsValidDescriptor(std::string(extra_descriptor).c_str())) {
1582 *error += "Invalid extra descriptor.";
1583 return ProfileLoadStatus::kBadData;
1584 }
1585 // Try to match an existing extra descriptor.
1586 auto it = extra_descriptors_indexes_.find(extra_descriptor);
1587 if (it != extra_descriptors_indexes_.end()) {
1588 extra_descriptors_remap->push_back(*it);
1589 continue;
1590 }
1591 // Try to insert a new extra descriptor.
1592 ExtraDescriptorIndex extra_descriptor_index = AddExtraDescriptor(extra_descriptor);
1593 if (extra_descriptor_index == kMaxExtraDescriptors) {
1594 *error = "Too many extra descriptors.";
1595 return ProfileLoadStatus::kMergeError;
1596 }
1597 extra_descriptors_remap->push_back(extra_descriptor_index);
1598 }
1599 return ProfileLoadStatus::kSuccess;
1600 }
1601
ReadClassesSection(ProfileSource & source,const FileSectionInfo & section_info,const dchecked_vector<ProfileIndexType> & dex_profile_index_remap,const dchecked_vector<ExtraDescriptorIndex> & extra_descriptors_remap,std::string * error)1602 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadClassesSection(
1603 ProfileSource& source,
1604 const FileSectionInfo& section_info,
1605 const dchecked_vector<ProfileIndexType>& dex_profile_index_remap,
1606 const dchecked_vector<ExtraDescriptorIndex>& extra_descriptors_remap,
1607 /*out*/ std::string* error) {
1608 DCHECK(section_info.GetType() == FileSectionType::kClasses);
1609 SafeBuffer buffer;
1610 ProfileLoadStatus status = ReadSectionData(source, section_info, &buffer, error);
1611 if (status != ProfileLoadStatus::kSuccess) {
1612 return status;
1613 }
1614
1615 while (buffer.GetAvailableBytes() != 0u) {
1616 ProfileIndexType profile_index;
1617 if (!buffer.ReadUintAndAdvance(&profile_index)) {
1618 *error = "Error profile index in classes section.";
1619 return ProfileLoadStatus::kBadData;
1620 }
1621 if (profile_index >= dex_profile_index_remap.size()) {
1622 *error = "Invalid profile index in classes section.";
1623 return ProfileLoadStatus::kBadData;
1624 }
1625 profile_index = dex_profile_index_remap[profile_index];
1626 if (profile_index == MaxProfileIndex()) {
1627 status = DexFileData::SkipClasses(buffer, error);
1628 } else {
1629 status = info_[profile_index]->ReadClasses(buffer, extra_descriptors_remap, error);
1630 }
1631 if (status != ProfileLoadStatus::kSuccess) {
1632 return status;
1633 }
1634 }
1635 return ProfileLoadStatus::kSuccess;
1636 }
1637
ReadMethodsSection(ProfileSource & source,const FileSectionInfo & section_info,const dchecked_vector<ProfileIndexType> & dex_profile_index_remap,const dchecked_vector<ExtraDescriptorIndex> & extra_descriptors_remap,std::string * error)1638 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadMethodsSection(
1639 ProfileSource& source,
1640 const FileSectionInfo& section_info,
1641 const dchecked_vector<ProfileIndexType>& dex_profile_index_remap,
1642 const dchecked_vector<ExtraDescriptorIndex>& extra_descriptors_remap,
1643 /*out*/ std::string* error) {
1644 DCHECK(section_info.GetType() == FileSectionType::kMethods);
1645 SafeBuffer buffer;
1646 ProfileLoadStatus status = ReadSectionData(source, section_info, &buffer, error);
1647 if (status != ProfileLoadStatus::kSuccess) {
1648 return status;
1649 }
1650
1651 while (buffer.GetAvailableBytes() != 0u) {
1652 ProfileIndexType profile_index;
1653 if (!buffer.ReadUintAndAdvance(&profile_index)) {
1654 *error = "Error profile index in methods section.";
1655 return ProfileLoadStatus::kBadData;
1656 }
1657 if (profile_index >= dex_profile_index_remap.size()) {
1658 *error = "Invalid profile index in methods section.";
1659 return ProfileLoadStatus::kBadData;
1660 }
1661 profile_index = dex_profile_index_remap[profile_index];
1662 if (profile_index == MaxProfileIndex()) {
1663 status = DexFileData::SkipMethods(buffer, error);
1664 } else {
1665 status = info_[profile_index]->ReadMethods(buffer, extra_descriptors_remap, error);
1666 }
1667 if (status != ProfileLoadStatus::kSuccess) {
1668 return status;
1669 }
1670 }
1671 return ProfileLoadStatus::kSuccess;
1672 }
1673
1674 // TODO(calin): fail fast if the dex checksums don't match.
LoadInternal(int32_t fd,std::string * error,bool merge_classes,const ProfileLoadFilterFn & filter_fn)1675 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::LoadInternal(
1676 int32_t fd,
1677 std::string* error,
1678 bool merge_classes,
1679 const ProfileLoadFilterFn& filter_fn) {
1680 ScopedTrace trace(__PRETTY_FUNCTION__);
1681 DCHECK_GE(fd, 0);
1682
1683 std::unique_ptr<ProfileSource> source;
1684 ProfileLoadStatus status = OpenSource(fd, &source, error);
1685 if (status != ProfileLoadStatus::kSuccess) {
1686 return status;
1687 }
1688
1689 // We allow empty profile files.
1690 // Profiles may be created by ActivityManager or installd before we manage to
1691 // process them in the runtime or profman.
1692 if (source->HasEmptyContent()) {
1693 return ProfileLoadStatus::kSuccess;
1694 }
1695
1696 // Read file header.
1697 FileHeader header;
1698 status = source->Read(&header, sizeof(FileHeader), "ReadProfileHeader", error);
1699 if (status != ProfileLoadStatus::kSuccess) {
1700 return status;
1701 }
1702 if (!header.IsValid()) {
1703 return header.InvalidHeaderMessage(error);
1704 }
1705 if (memcmp(header.GetVersion(), version_, kProfileVersionSize) != 0) {
1706 *error = IsForBootImage() ? "Expected boot profile, got app profile."
1707 : "Expected app profile, got boot profile.";
1708 return ProfileLoadStatus::kMergeError;
1709 }
1710
1711 // Check if there are too many section infos.
1712 uint32_t section_count = header.GetFileSectionCount();
1713 uint32_t uncompressed_data_size = sizeof(FileHeader) + section_count * sizeof(FileSectionInfo);
1714 if (uncompressed_data_size > GetSizeErrorThresholdBytes()) {
1715 LOG(ERROR) << "Profile data size exceeds " << GetSizeErrorThresholdBytes()
1716 << " bytes. It has " << uncompressed_data_size << " bytes.";
1717 return ProfileLoadStatus::kBadData;
1718 }
1719
1720 // Read section infos.
1721 dchecked_vector<FileSectionInfo> section_infos(section_count);
1722 status = source->Read(
1723 section_infos.data(), section_count * sizeof(FileSectionInfo), "ReadSectionInfos", error);
1724 if (status != ProfileLoadStatus::kSuccess) {
1725 return status;
1726 }
1727
1728 // Finish uncompressed data size calculation.
1729 for (const FileSectionInfo& section_info : section_infos) {
1730 uint32_t mem_size = section_info.GetMemSize();
1731 if (UNLIKELY(mem_size > std::numeric_limits<uint32_t>::max() - uncompressed_data_size)) {
1732 *error = "Total memory size overflow.";
1733 return ProfileLoadStatus::kBadData;
1734 }
1735 uncompressed_data_size += mem_size;
1736 }
1737
1738 // Allow large profiles for non target builds for the case where we are merging many profiles
1739 // to generate a boot image profile.
1740 if (uncompressed_data_size > GetSizeErrorThresholdBytes()) {
1741 LOG(ERROR) << "Profile data size exceeds "
1742 << GetSizeErrorThresholdBytes()
1743 << " bytes. It has " << uncompressed_data_size << " bytes.";
1744 return ProfileLoadStatus::kBadData;
1745 }
1746 if (uncompressed_data_size > GetSizeWarningThresholdBytes()) {
1747 LOG(WARNING) << "Profile data size exceeds "
1748 << GetSizeWarningThresholdBytes()
1749 << " bytes. It has " << uncompressed_data_size << " bytes.";
1750 }
1751
1752 // Process the mandatory dex files section.
1753 DCHECK_NE(section_count, 0u); // Checked by `header.IsValid()` above.
1754 const FileSectionInfo& dex_files_section_info = section_infos[0];
1755 if (dex_files_section_info.GetType() != FileSectionType::kDexFiles) {
1756 *error = "First section is not dex files section.";
1757 return ProfileLoadStatus::kBadData;
1758 }
1759 dchecked_vector<ProfileIndexType> dex_profile_index_remap;
1760 status = ReadDexFilesSection(
1761 *source, dex_files_section_info, filter_fn, &dex_profile_index_remap, error);
1762 if (status != ProfileLoadStatus::kSuccess) {
1763 DCHECK(!error->empty());
1764 return status;
1765 }
1766
1767 // Process all other sections.
1768 dchecked_vector<ExtraDescriptorIndex> extra_descriptors_remap;
1769 for (uint32_t i = 1u; i != section_count; ++i) {
1770 const FileSectionInfo& section_info = section_infos[i];
1771 DCHECK(status == ProfileLoadStatus::kSuccess);
1772 switch (section_info.GetType()) {
1773 case FileSectionType::kDexFiles:
1774 *error = "Unsupported additional dex files section.";
1775 status = ProfileLoadStatus::kBadData;
1776 break;
1777 case FileSectionType::kExtraDescriptors:
1778 status = ReadExtraDescriptorsSection(
1779 *source, section_info, &extra_descriptors_remap, error);
1780 break;
1781 case FileSectionType::kClasses:
1782 // Skip if all dex files were filtered out.
1783 if (!info_.empty() && merge_classes) {
1784 status = ReadClassesSection(
1785 *source, section_info, dex_profile_index_remap, extra_descriptors_remap, error);
1786 }
1787 break;
1788 case FileSectionType::kMethods:
1789 // Skip if all dex files were filtered out.
1790 if (!info_.empty()) {
1791 status = ReadMethodsSection(
1792 *source, section_info, dex_profile_index_remap, extra_descriptors_remap, error);
1793 }
1794 break;
1795 default:
1796 // Unknown section. Skip it. New versions of ART are allowed
1797 // to add sections that shall be ignored by old versions.
1798 break;
1799 }
1800 if (status != ProfileLoadStatus::kSuccess) {
1801 DCHECK(!error->empty());
1802 return status;
1803 }
1804 }
1805
1806 return ProfileLoadStatus::kSuccess;
1807 }
1808
MergeWith(const ProfileCompilationInfo & other,bool merge_classes)1809 bool ProfileCompilationInfo::MergeWith(const ProfileCompilationInfo& other,
1810 bool merge_classes) {
1811 if (!SameVersion(other)) {
1812 LOG(WARNING) << "Cannot merge different profile versions";
1813 return false;
1814 }
1815
1816 // First verify that all checksums match. This will avoid adding garbage to
1817 // the current profile info.
1818 // Note that the number of elements should be very small, so this should not
1819 // be a performance issue.
1820 for (const std::unique_ptr<DexFileData>& other_dex_data : other.info_) {
1821 // verify_checksum is false because we want to differentiate between a missing dex data and
1822 // a mismatched checksum.
1823 const DexFileData* dex_data = FindDexData(other_dex_data->profile_key,
1824 /* checksum= */ 0u,
1825 /* verify_checksum= */ false);
1826 if ((dex_data != nullptr) && (dex_data->checksum != other_dex_data->checksum)) {
1827 LOG(WARNING) << "Checksum mismatch for dex " << other_dex_data->profile_key;
1828 return false;
1829 }
1830 }
1831 // All checksums match. Import the data.
1832
1833 // The other profile might have a different indexing of dex files.
1834 // That is because each dex files gets a 'dex_profile_index' on a first come first served basis.
1835 // That means that the order in with the methods are added to the profile matters for the
1836 // actual indices.
1837 // The reason we cannot rely on the actual multidex index is that a single profile may store
1838 // data from multiple splits. This means that a profile may contain a classes2.dex from split-A
1839 // and one from split-B.
1840
1841 // First, build a mapping from other_dex_profile_index to this_dex_profile_index.
1842 dchecked_vector<ProfileIndexType> dex_profile_index_remap;
1843 dex_profile_index_remap.reserve(other.info_.size());
1844 for (const std::unique_ptr<DexFileData>& other_dex_data : other.info_) {
1845 const DexFileData* dex_data = GetOrAddDexFileData(other_dex_data->profile_key,
1846 other_dex_data->checksum,
1847 other_dex_data->num_type_ids,
1848 other_dex_data->num_method_ids);
1849 if (dex_data == nullptr) {
1850 // Could happen if we exceed the number of allowed dex files or there is
1851 // a mismatch in `num_type_ids` or `num_method_ids`.
1852 return false;
1853 }
1854 DCHECK_EQ(other_dex_data->profile_index, dex_profile_index_remap.size());
1855 dex_profile_index_remap.push_back(dex_data->profile_index);
1856 }
1857
1858 // Then merge extra descriptors.
1859 dchecked_vector<ExtraDescriptorIndex> extra_descriptors_remap;
1860 extra_descriptors_remap.reserve(other.extra_descriptors_.size());
1861 for (const std::string& other_extra_descriptor : other.extra_descriptors_) {
1862 auto it = extra_descriptors_indexes_.find(std::string_view(other_extra_descriptor));
1863 if (it != extra_descriptors_indexes_.end()) {
1864 extra_descriptors_remap.push_back(*it);
1865 } else {
1866 ExtraDescriptorIndex extra_descriptor_index = AddExtraDescriptor(other_extra_descriptor);
1867 if (extra_descriptor_index == kMaxExtraDescriptors) {
1868 // Too many extra descriptors.
1869 return false;
1870 }
1871 extra_descriptors_remap.push_back(extra_descriptor_index);
1872 }
1873 }
1874
1875 // Merge the actual profile data.
1876 for (const std::unique_ptr<DexFileData>& other_dex_data : other.info_) {
1877 DexFileData* dex_data = info_[dex_profile_index_remap[other_dex_data->profile_index]].get();
1878 DCHECK_EQ(dex_data, FindDexData(other_dex_data->profile_key, other_dex_data->checksum));
1879
1880 // Merge the classes.
1881 uint32_t num_type_ids = dex_data->num_type_ids;
1882 DCHECK_EQ(num_type_ids, other_dex_data->num_type_ids);
1883 if (merge_classes) {
1884 // Classes are ordered by the `TypeIndex`, so we have the classes with a `TypeId`
1885 // in the dex file first, followed by classes using extra descriptors.
1886 auto it = other_dex_data->class_set.lower_bound(dex::TypeIndex(num_type_ids));
1887 dex_data->class_set.insert(other_dex_data->class_set.begin(), it);
1888 for (auto end = other_dex_data->class_set.end(); it != end; ++it) {
1889 ExtraDescriptorIndex new_extra_descriptor_index =
1890 extra_descriptors_remap[it->index_ - num_type_ids];
1891 if (new_extra_descriptor_index >= DexFile::kDexNoIndex16 - num_type_ids) {
1892 // Cannot represent the type with new extra descriptor index.
1893 return false;
1894 }
1895 dex_data->class_set.insert(dex::TypeIndex(num_type_ids + new_extra_descriptor_index));
1896 }
1897 }
1898
1899 // Merge the methods and the inline caches.
1900 for (const auto& other_method_it : other_dex_data->method_map) {
1901 uint16_t other_method_index = other_method_it.first;
1902 InlineCacheMap* inline_cache = dex_data->FindOrAddHotMethod(other_method_index);
1903 if (inline_cache == nullptr) {
1904 return false;
1905 }
1906 const auto& other_inline_cache = other_method_it.second;
1907 for (const auto& other_ic_it : other_inline_cache) {
1908 uint16_t other_dex_pc = other_ic_it.first;
1909 const ArenaSet<dex::TypeIndex>& other_class_set = other_ic_it.second.classes;
1910 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, other_dex_pc);
1911 if (other_ic_it.second.is_missing_types) {
1912 dex_pc_data->SetIsMissingTypes();
1913 } else if (other_ic_it.second.is_megamorphic) {
1914 dex_pc_data->SetIsMegamorphic();
1915 } else {
1916 for (dex::TypeIndex type_index : other_class_set) {
1917 if (type_index.index_ >= num_type_ids) {
1918 ExtraDescriptorIndex new_extra_descriptor_index =
1919 extra_descriptors_remap[type_index.index_ - num_type_ids];
1920 if (new_extra_descriptor_index >= DexFile::kDexNoIndex16 - num_type_ids) {
1921 // Cannot represent the type with new extra descriptor index.
1922 return false;
1923 }
1924 type_index = dex::TypeIndex(num_type_ids + new_extra_descriptor_index);
1925 }
1926 dex_pc_data->AddClass(type_index);
1927 }
1928 }
1929 }
1930 }
1931
1932 // Merge the method bitmaps.
1933 dex_data->MergeBitmap(*other_dex_data);
1934 }
1935
1936 return true;
1937 }
1938
GetMethodHotness(const MethodReference & method_ref,const ProfileSampleAnnotation & annotation) const1939 ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::GetMethodHotness(
1940 const MethodReference& method_ref,
1941 const ProfileSampleAnnotation& annotation) const {
1942 const DexFileData* dex_data = FindDexDataUsingAnnotations(method_ref.dex_file, annotation);
1943 return dex_data != nullptr
1944 ? dex_data->GetHotnessInfo(method_ref.index)
1945 : MethodHotness();
1946 }
1947
ContainsClass(const DexFile & dex_file,dex::TypeIndex type_idx,const ProfileSampleAnnotation & annotation) const1948 bool ProfileCompilationInfo::ContainsClass(const DexFile& dex_file,
1949 dex::TypeIndex type_idx,
1950 const ProfileSampleAnnotation& annotation) const {
1951 const DexFileData* dex_data = FindDexDataUsingAnnotations(&dex_file, annotation);
1952 return (dex_data != nullptr) && dex_data->ContainsClass(type_idx);
1953 }
1954
GetNumberOfMethods() const1955 uint32_t ProfileCompilationInfo::GetNumberOfMethods() const {
1956 uint32_t total = 0;
1957 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1958 total += dex_data->method_map.size();
1959 }
1960 return total;
1961 }
1962
GetNumberOfResolvedClasses() const1963 uint32_t ProfileCompilationInfo::GetNumberOfResolvedClasses() const {
1964 uint32_t total = 0;
1965 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1966 total += dex_data->class_set.size();
1967 }
1968 return total;
1969 }
1970
DumpInfo(const std::vector<const DexFile * > & dex_files,bool print_full_dex_location) const1971 std::string ProfileCompilationInfo::DumpInfo(const std::vector<const DexFile*>& dex_files,
1972 bool print_full_dex_location) const {
1973 std::ostringstream os;
1974
1975 os << "ProfileInfo [";
1976
1977 for (size_t k = 0; k < kProfileVersionSize - 1; k++) {
1978 // Iterate to 'kProfileVersionSize - 1' because the version_ ends with '\0'
1979 // which we don't want to print.
1980 os << static_cast<char>(version_[k]);
1981 }
1982 os << "]\n";
1983
1984 if (info_.empty()) {
1985 os << "-empty-";
1986 return os.str();
1987 }
1988
1989 if (!extra_descriptors_.empty()) {
1990 os << "\nextra descriptors:";
1991 for (const std::string& str : extra_descriptors_) {
1992 os << "\n\t" << str;
1993 }
1994 os << "\n";
1995 }
1996
1997 const std::string kFirstDexFileKeySubstitute = "!classes.dex";
1998
1999 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
2000 os << "\n";
2001 if (print_full_dex_location) {
2002 os << dex_data->profile_key;
2003 } else {
2004 // Replace the (empty) multidex suffix of the first key with a substitute for easier reading.
2005 std::string multidex_suffix = DexFileLoader::GetMultiDexSuffix(
2006 GetBaseKeyFromAugmentedKey(dex_data->profile_key));
2007 os << (multidex_suffix.empty() ? kFirstDexFileKeySubstitute : multidex_suffix);
2008 }
2009 os << " [index=" << static_cast<uint32_t>(dex_data->profile_index) << "]";
2010 os << " [checksum=" << std::hex << dex_data->checksum << "]" << std::dec;
2011 os << " [num_type_ids=" << dex_data->num_type_ids << "]";
2012 os << " [num_method_ids=" << dex_data->num_method_ids << "]";
2013 const DexFile* dex_file = nullptr;
2014 for (const DexFile* current : dex_files) {
2015 if (GetBaseKeyViewFromAugmentedKey(dex_data->profile_key) == current->GetLocation() &&
2016 dex_data->checksum == current->GetLocationChecksum()) {
2017 dex_file = current;
2018 }
2019 }
2020 os << "\n\thot methods: ";
2021 for (const auto& method_it : dex_data->method_map) {
2022 if (dex_file != nullptr) {
2023 os << "\n\t\t" << dex_file->PrettyMethod(method_it.first, true);
2024 } else {
2025 os << method_it.first;
2026 }
2027
2028 os << "[";
2029 for (const auto& inline_cache_it : method_it.second) {
2030 os << "{" << std::hex << inline_cache_it.first << std::dec << ":";
2031 if (inline_cache_it.second.is_missing_types) {
2032 os << "MT";
2033 } else if (inline_cache_it.second.is_megamorphic) {
2034 os << "MM";
2035 } else {
2036 const char* separator = "";
2037 for (dex::TypeIndex type_index : inline_cache_it.second.classes) {
2038 os << separator << type_index.index_;
2039 separator = ",";
2040 }
2041 }
2042 os << "}";
2043 }
2044 os << "], ";
2045 }
2046 bool startup = true;
2047 while (true) {
2048 os << "\n\t" << (startup ? "startup methods: " : "post startup methods: ");
2049 for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
2050 MethodHotness hotness_info(dex_data->GetHotnessInfo(method_idx));
2051 if (startup ? hotness_info.IsStartup() : hotness_info.IsPostStartup()) {
2052 if (dex_file != nullptr) {
2053 os << "\n\t\t" << dex_file->PrettyMethod(method_idx, true);
2054 } else {
2055 os << method_idx << ", ";
2056 }
2057 }
2058 }
2059 if (startup == false) {
2060 break;
2061 }
2062 startup = false;
2063 }
2064 os << "\n\tclasses: ";
2065 for (dex::TypeIndex type_index : dex_data->class_set) {
2066 if (dex_file != nullptr) {
2067 os << "\n\t\t" << PrettyDescriptor(GetTypeDescriptor(dex_file, type_index));
2068 } else {
2069 os << type_index.index_ << ",";
2070 }
2071 }
2072 }
2073 return os.str();
2074 }
2075
GetClassesAndMethods(const DexFile & dex_file,std::set<dex::TypeIndex> * class_set,std::set<uint16_t> * hot_method_set,std::set<uint16_t> * startup_method_set,std::set<uint16_t> * post_startup_method_method_set,const ProfileSampleAnnotation & annotation) const2076 bool ProfileCompilationInfo::GetClassesAndMethods(
2077 const DexFile& dex_file,
2078 /*out*/std::set<dex::TypeIndex>* class_set,
2079 /*out*/std::set<uint16_t>* hot_method_set,
2080 /*out*/std::set<uint16_t>* startup_method_set,
2081 /*out*/std::set<uint16_t>* post_startup_method_method_set,
2082 const ProfileSampleAnnotation& annotation) const {
2083 std::set<std::string> ret;
2084 const DexFileData* dex_data = FindDexDataUsingAnnotations(&dex_file, annotation);
2085 if (dex_data == nullptr) {
2086 return false;
2087 }
2088 for (const auto& it : dex_data->method_map) {
2089 hot_method_set->insert(it.first);
2090 }
2091 for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
2092 MethodHotness hotness = dex_data->GetHotnessInfo(method_idx);
2093 if (hotness.IsStartup()) {
2094 startup_method_set->insert(method_idx);
2095 }
2096 if (hotness.IsPostStartup()) {
2097 post_startup_method_method_set->insert(method_idx);
2098 }
2099 }
2100 for (const dex::TypeIndex& type_index : dex_data->class_set) {
2101 class_set->insert(type_index);
2102 }
2103 return true;
2104 }
2105
SameVersion(const ProfileCompilationInfo & other) const2106 bool ProfileCompilationInfo::SameVersion(const ProfileCompilationInfo& other) const {
2107 return memcmp(version_, other.version_, kProfileVersionSize) == 0;
2108 }
2109
Equals(const ProfileCompilationInfo & other)2110 bool ProfileCompilationInfo::Equals(const ProfileCompilationInfo& other) {
2111 // No need to compare profile_key_map_. That's only a cache for fast search.
2112 // All the information is already in the info_ vector.
2113 if (!SameVersion(other)) {
2114 return false;
2115 }
2116 if (info_.size() != other.info_.size()) {
2117 return false;
2118 }
2119 for (size_t i = 0; i < info_.size(); i++) {
2120 const DexFileData& dex_data = *info_[i];
2121 const DexFileData& other_dex_data = *other.info_[i];
2122 if (!(dex_data == other_dex_data)) {
2123 return false;
2124 }
2125 }
2126
2127 return true;
2128 }
2129
2130 // Naive implementation to generate a random profile file suitable for testing.
GenerateTestProfile(int fd,uint16_t number_of_dex_files,uint16_t method_percentage,uint16_t class_percentage,uint32_t random_seed)2131 bool ProfileCompilationInfo::GenerateTestProfile(int fd,
2132 uint16_t number_of_dex_files,
2133 uint16_t method_percentage,
2134 uint16_t class_percentage,
2135 uint32_t random_seed) {
2136 const std::string base_dex_location = "base.apk";
2137 ProfileCompilationInfo info;
2138 // The limits are defined by the dex specification.
2139 const uint16_t max_methods = std::numeric_limits<uint16_t>::max();
2140 const uint16_t max_classes = std::numeric_limits<uint16_t>::max();
2141 uint16_t number_of_methods = max_methods * method_percentage / 100;
2142 uint16_t number_of_classes = max_classes * class_percentage / 100;
2143
2144 std::srand(random_seed);
2145
2146 // Make sure we generate more samples with a low index value.
2147 // This makes it more likely to hit valid method/class indices in small apps.
2148 const uint16_t kFavorFirstN = 10000;
2149 const uint16_t kFavorSplit = 2;
2150
2151 for (uint16_t i = 0; i < number_of_dex_files; i++) {
2152 std::string dex_location = DexFileLoader::GetMultiDexLocation(i, base_dex_location.c_str());
2153 std::string profile_key = info.GetProfileDexFileBaseKey(dex_location);
2154
2155 DexFileData* const data =
2156 info.GetOrAddDexFileData(profile_key, /*checksum=*/ 0, max_classes, max_methods);
2157 for (uint16_t m = 0; m < number_of_methods; m++) {
2158 uint16_t method_idx = rand() % max_methods;
2159 if (m < (number_of_methods / kFavorSplit)) {
2160 method_idx %= kFavorFirstN;
2161 }
2162 // Alternate between startup and post startup.
2163 uint32_t flags = MethodHotness::kFlagHot;
2164 flags |= ((m & 1) != 0) ? MethodHotness::kFlagPostStartup : MethodHotness::kFlagStartup;
2165 data->AddMethod(static_cast<MethodHotness::Flag>(flags), method_idx);
2166 }
2167
2168 for (uint16_t c = 0; c < number_of_classes; c++) {
2169 uint16_t type_idx = rand() % max_classes;
2170 if (c < (number_of_classes / kFavorSplit)) {
2171 type_idx %= kFavorFirstN;
2172 }
2173 data->class_set.insert(dex::TypeIndex(type_idx));
2174 }
2175 }
2176 return info.Save(fd);
2177 }
2178
2179 // Naive implementation to generate a random profile file suitable for testing.
2180 // Description of random selection:
2181 // * Select a random starting point S.
2182 // * For every index i, add (S+i) % (N - total number of methods/classes) to profile with the
2183 // probably of 1/(N - i - number of methods/classes needed to add in profile).
GenerateTestProfile(int fd,std::vector<std::unique_ptr<const DexFile>> & dex_files,uint16_t method_percentage,uint16_t class_percentage,uint32_t random_seed)2184 bool ProfileCompilationInfo::GenerateTestProfile(
2185 int fd,
2186 std::vector<std::unique_ptr<const DexFile>>& dex_files,
2187 uint16_t method_percentage,
2188 uint16_t class_percentage,
2189 uint32_t random_seed) {
2190 ProfileCompilationInfo info;
2191 std::default_random_engine rng(random_seed);
2192 auto create_shuffled_range = [&rng](uint32_t take, uint32_t out_of) {
2193 CHECK_LE(take, out_of);
2194 std::vector<uint32_t> vec(out_of);
2195 std::iota(vec.begin(), vec.end(), 0u);
2196 std::shuffle(vec.begin(), vec.end(), rng);
2197 vec.erase(vec.begin() + take, vec.end());
2198 std::sort(vec.begin(), vec.end());
2199 return vec;
2200 };
2201 for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
2202 const std::string& profile_key = dex_file->GetLocation();
2203 uint32_t checksum = dex_file->GetLocationChecksum();
2204
2205 uint32_t number_of_classes = dex_file->NumClassDefs();
2206 uint32_t classes_required_in_profile = (number_of_classes * class_percentage) / 100;
2207
2208 DexFileData* const data = info.GetOrAddDexFileData(
2209 profile_key, checksum, dex_file->NumTypeIds(), dex_file->NumMethodIds());
2210 for (uint32_t class_index : create_shuffled_range(classes_required_in_profile,
2211 number_of_classes)) {
2212 data->class_set.insert(dex_file->GetClassDef(class_index).class_idx_);
2213 }
2214
2215 uint32_t number_of_methods = dex_file->NumMethodIds();
2216 uint32_t methods_required_in_profile = (number_of_methods * method_percentage) / 100;
2217 for (uint32_t method_index : create_shuffled_range(methods_required_in_profile,
2218 number_of_methods)) {
2219 // Alternate between startup and post startup.
2220 uint32_t flags = MethodHotness::kFlagHot;
2221 flags |= ((method_index & 1) != 0)
2222 ? MethodHotness::kFlagPostStartup
2223 : MethodHotness::kFlagStartup;
2224 data->AddMethod(static_cast<MethodHotness::Flag>(flags), method_index);
2225 }
2226 }
2227 return info.Save(fd);
2228 }
2229
IsEmpty() const2230 bool ProfileCompilationInfo::IsEmpty() const {
2231 DCHECK_EQ(info_.size(), profile_key_map_.size());
2232 // Note that this doesn't look at the bitmap region, so we will return true
2233 // when the profile contains only non-hot methods. This is generally ok
2234 // as for speed-profile to be useful we do need hot methods and resolved classes.
2235 return GetNumberOfMethods() == 0 && GetNumberOfResolvedClasses() == 0;
2236 }
2237
2238 ProfileCompilationInfo::InlineCacheMap*
FindOrAddHotMethod(uint16_t method_index)2239 ProfileCompilationInfo::DexFileData::FindOrAddHotMethod(uint16_t method_index) {
2240 if (method_index >= num_method_ids) {
2241 LOG(ERROR) << "Invalid method index " << method_index << ". num_method_ids=" << num_method_ids;
2242 return nullptr;
2243 }
2244 return &(method_map.FindOrAdd(
2245 method_index,
2246 InlineCacheMap(std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)))->second);
2247 }
2248
2249 // Mark a method as executed at least once.
AddMethod(MethodHotness::Flag flags,size_t index)2250 bool ProfileCompilationInfo::DexFileData::AddMethod(MethodHotness::Flag flags, size_t index) {
2251 if (index >= num_method_ids || index > kMaxSupportedMethodIndex) {
2252 LOG(ERROR) << "Invalid method index " << index << ". num_method_ids=" << num_method_ids
2253 << ", max: " << kMaxSupportedMethodIndex;
2254 return false;
2255 }
2256
2257 SetMethodHotness(index, flags);
2258
2259 if ((flags & MethodHotness::kFlagHot) != 0) {
2260 ProfileCompilationInfo::InlineCacheMap* result = FindOrAddHotMethod(index);
2261 DCHECK(result != nullptr);
2262 }
2263 return true;
2264 }
2265
2266 template <typename Fn>
ForMethodBitmapHotnessFlags(Fn fn) const2267 ALWAYS_INLINE void ProfileCompilationInfo::DexFileData::ForMethodBitmapHotnessFlags(Fn fn) const {
2268 uint32_t lastFlag = is_for_boot_image
2269 ? MethodHotness::kFlagLastBoot
2270 : MethodHotness::kFlagLastRegular;
2271 for (uint32_t flag = MethodHotness::kFlagFirst; flag <= lastFlag; flag = flag << 1) {
2272 if (flag == MethodHotness::kFlagHot) {
2273 // There's no bit for hotness in the bitmap.
2274 // We store the hotness by recording the method in the method list.
2275 continue;
2276 }
2277 fn(enum_cast<MethodHotness::Flag>(flag));
2278 }
2279 }
2280
SetMethodHotness(size_t index,MethodHotness::Flag flags)2281 void ProfileCompilationInfo::DexFileData::SetMethodHotness(size_t index,
2282 MethodHotness::Flag flags) {
2283 DCHECK_LT(index, num_method_ids);
2284 ForMethodBitmapHotnessFlags([&](MethodHotness::Flag flag) {
2285 if ((flags & flag) != 0) {
2286 method_bitmap.StoreBit(MethodFlagBitmapIndex(
2287 static_cast<MethodHotness::Flag>(flag), index), /*value=*/ true);
2288 }
2289 });
2290 }
2291
GetHotnessInfo(uint32_t dex_method_index) const2292 ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::DexFileData::GetHotnessInfo(
2293 uint32_t dex_method_index) const {
2294 MethodHotness ret;
2295 ForMethodBitmapHotnessFlags([&](MethodHotness::Flag flag) {
2296 if (method_bitmap.LoadBit(MethodFlagBitmapIndex(
2297 static_cast<MethodHotness::Flag>(flag), dex_method_index))) {
2298 ret.AddFlag(static_cast<MethodHotness::Flag>(flag));
2299 }
2300 });
2301 auto it = method_map.find(dex_method_index);
2302 if (it != method_map.end()) {
2303 ret.SetInlineCacheMap(&it->second);
2304 ret.AddFlag(MethodHotness::kFlagHot);
2305 }
2306 return ret;
2307 }
2308
2309 // To simplify the implementation we use the MethodHotness flag values as indexes into the internal
2310 // bitmap representation. As such, they should never change unless the profile version is updated
2311 // and the implementation changed accordingly.
2312 static_assert(ProfileCompilationInfo::MethodHotness::kFlagFirst == 1 << 0);
2313 static_assert(ProfileCompilationInfo::MethodHotness::kFlagHot == 1 << 0);
2314 static_assert(ProfileCompilationInfo::MethodHotness::kFlagStartup == 1 << 1);
2315 static_assert(ProfileCompilationInfo::MethodHotness::kFlagPostStartup == 1 << 2);
2316 static_assert(ProfileCompilationInfo::MethodHotness::kFlagLastRegular == 1 << 2);
2317 static_assert(ProfileCompilationInfo::MethodHotness::kFlag32bit == 1 << 3);
2318 static_assert(ProfileCompilationInfo::MethodHotness::kFlag64bit == 1 << 4);
2319 static_assert(ProfileCompilationInfo::MethodHotness::kFlagSensitiveThread == 1 << 5);
2320 static_assert(ProfileCompilationInfo::MethodHotness::kFlagAmStartup == 1 << 6);
2321 static_assert(ProfileCompilationInfo::MethodHotness::kFlagAmPostStartup == 1 << 7);
2322 static_assert(ProfileCompilationInfo::MethodHotness::kFlagBoot == 1 << 8);
2323 static_assert(ProfileCompilationInfo::MethodHotness::kFlagPostBoot == 1 << 9);
2324 static_assert(ProfileCompilationInfo::MethodHotness::kFlagStartupBin == 1 << 10);
2325 static_assert(ProfileCompilationInfo::MethodHotness::kFlagStartupMaxBin == 1 << 15);
2326 static_assert(ProfileCompilationInfo::MethodHotness::kFlagLastBoot == 1 << 15);
2327
MethodFlagBitmapIndex(MethodHotness::Flag flag,size_t method_index) const2328 size_t ProfileCompilationInfo::DexFileData::MethodFlagBitmapIndex(
2329 MethodHotness::Flag flag, size_t method_index) const {
2330 DCHECK_LT(method_index, num_method_ids);
2331 // The format is [startup bitmap][post startup bitmap][AmStartup][...]
2332 // This compresses better than ([startup bit][post startup bit])*
2333 return method_index + FlagBitmapIndex(flag) * num_method_ids;
2334 }
2335
FlagBitmapIndex(MethodHotness::Flag flag)2336 size_t ProfileCompilationInfo::DexFileData::FlagBitmapIndex(MethodHotness::Flag flag) {
2337 DCHECK(flag != MethodHotness::kFlagHot);
2338 DCHECK(IsPowerOfTwo(static_cast<uint32_t>(flag)));
2339 // We arrange the method flags in order, starting with the startup flag.
2340 // The kFlagHot is not encoded in the bitmap and thus not expected as an
2341 // argument here. Since all the other flags start at 1 we have to subtract
2342 // one for the power of 2.
2343 return WhichPowerOf2(static_cast<uint32_t>(flag)) - 1;
2344 }
2345
GetUsedBitmapFlags() const2346 uint16_t ProfileCompilationInfo::DexFileData::GetUsedBitmapFlags() const {
2347 uint32_t used_flags = 0u;
2348 ForMethodBitmapHotnessFlags([&](MethodHotness::Flag flag) {
2349 size_t index = FlagBitmapIndex(static_cast<MethodHotness::Flag>(flag));
2350 if (method_bitmap.HasSomeBitSet(index * num_method_ids, num_method_ids)) {
2351 used_flags |= flag;
2352 }
2353 });
2354 return dchecked_integral_cast<uint16_t>(used_flags);
2355 }
2356
2357 ProfileCompilationInfo::DexPcData*
FindOrAddDexPc(InlineCacheMap * inline_cache,uint32_t dex_pc)2358 ProfileCompilationInfo::FindOrAddDexPc(InlineCacheMap* inline_cache, uint32_t dex_pc) {
2359 return &(inline_cache->FindOrAdd(dex_pc, DexPcData(inline_cache->get_allocator()))->second);
2360 }
2361
GetClassDescriptors(const std::vector<const DexFile * > & dex_files,const ProfileSampleAnnotation & annotation)2362 HashSet<std::string> ProfileCompilationInfo::GetClassDescriptors(
2363 const std::vector<const DexFile*>& dex_files,
2364 const ProfileSampleAnnotation& annotation) {
2365 HashSet<std::string> ret;
2366 for (const DexFile* dex_file : dex_files) {
2367 const DexFileData* data = FindDexDataUsingAnnotations(dex_file, annotation);
2368 if (data != nullptr) {
2369 for (dex::TypeIndex type_idx : data->class_set) {
2370 ret.insert(GetTypeDescriptor(dex_file, type_idx));
2371 }
2372 } else {
2373 VLOG(compiler) << "Failed to find profile data for " << dex_file->GetLocation();
2374 }
2375 }
2376 return ret;
2377 }
2378
IsProfileFile(int fd)2379 bool ProfileCompilationInfo::IsProfileFile(int fd) {
2380 // First check if it's an empty file as we allow empty profile files.
2381 // Profiles may be created by ActivityManager or installd before we manage to
2382 // process them in the runtime or profman.
2383 struct stat stat_buffer;
2384 if (fstat(fd, &stat_buffer) != 0) {
2385 return false;
2386 }
2387
2388 if (stat_buffer.st_size == 0) {
2389 return true;
2390 }
2391
2392 // The files is not empty. Check if it contains the profile magic.
2393 size_t byte_count = sizeof(kProfileMagic);
2394 uint8_t buffer[sizeof(kProfileMagic)];
2395 if (!android::base::ReadFullyAtOffset(fd, buffer, byte_count, /*offset=*/ 0)) {
2396 return false;
2397 }
2398
2399 // Reset the offset to prepare the file for reading.
2400 off_t rc = TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET));
2401 if (rc == static_cast<off_t>(-1)) {
2402 PLOG(ERROR) << "Failed to reset the offset";
2403 return false;
2404 }
2405
2406 return memcmp(buffer, kProfileMagic, byte_count) == 0;
2407 }
2408
UpdateProfileKeys(const std::vector<std::unique_ptr<const DexFile>> & dex_files)2409 bool ProfileCompilationInfo::UpdateProfileKeys(
2410 const std::vector<std::unique_ptr<const DexFile>>& dex_files) {
2411 for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
2412 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
2413 if (dex_data->checksum == dex_file->GetLocationChecksum() &&
2414 dex_data->num_type_ids == dex_file->NumTypeIds() &&
2415 dex_data->num_method_ids == dex_file->NumMethodIds()) {
2416 std::string new_profile_key = GetProfileDexFileBaseKey(dex_file->GetLocation());
2417 std::string dex_data_base_key = GetBaseKeyFromAugmentedKey(dex_data->profile_key);
2418 if (dex_data_base_key != new_profile_key) {
2419 if (profile_key_map_.find(new_profile_key) != profile_key_map_.end()) {
2420 // We can't update the key if the new key belongs to a different dex file.
2421 LOG(ERROR) << "Cannot update profile key to " << new_profile_key
2422 << " because the new key belongs to another dex file.";
2423 return false;
2424 }
2425 profile_key_map_.erase(dex_data->profile_key);
2426 // Retain the annotation (if any) during the renaming by re-attaching the info
2427 // form the old key.
2428 dex_data->profile_key = MigrateAnnotationInfo(new_profile_key, dex_data->profile_key);
2429 profile_key_map_.Put(dex_data->profile_key, dex_data->profile_index);
2430 }
2431 }
2432 }
2433 }
2434 return true;
2435 }
2436
ProfileFilterFnAcceptAll(const std::string & dex_location ATTRIBUTE_UNUSED,uint32_t checksum ATTRIBUTE_UNUSED)2437 bool ProfileCompilationInfo::ProfileFilterFnAcceptAll(
2438 const std::string& dex_location ATTRIBUTE_UNUSED,
2439 uint32_t checksum ATTRIBUTE_UNUSED) {
2440 return true;
2441 }
2442
ClearData()2443 void ProfileCompilationInfo::ClearData() {
2444 profile_key_map_.clear();
2445 info_.clear();
2446 extra_descriptors_indexes_.clear();
2447 extra_descriptors_.clear();
2448 }
2449
ClearDataAndAdjustVersion(bool for_boot_image)2450 void ProfileCompilationInfo::ClearDataAndAdjustVersion(bool for_boot_image) {
2451 ClearData();
2452 memcpy(version_,
2453 for_boot_image ? kProfileVersionForBootImage : kProfileVersion,
2454 kProfileVersionSize);
2455 }
2456
IsForBootImage() const2457 bool ProfileCompilationInfo::IsForBootImage() const {
2458 return memcmp(version_, kProfileVersionForBootImage, sizeof(kProfileVersionForBootImage)) == 0;
2459 }
2460
GetVersion() const2461 const uint8_t* ProfileCompilationInfo::GetVersion() const {
2462 return version_;
2463 }
2464
ContainsClass(dex::TypeIndex type_index) const2465 bool ProfileCompilationInfo::DexFileData::ContainsClass(dex::TypeIndex type_index) const {
2466 return class_set.find(type_index) != class_set.end();
2467 }
2468
ClassesDataSize() const2469 uint32_t ProfileCompilationInfo::DexFileData::ClassesDataSize() const {
2470 return class_set.empty()
2471 ? 0u
2472 : sizeof(ProfileIndexType) + // Which dex file.
2473 sizeof(uint16_t) + // Number of classes.
2474 sizeof(uint16_t) * class_set.size(); // Type index diffs.
2475 }
2476
WriteClasses(SafeBuffer & buffer) const2477 void ProfileCompilationInfo::DexFileData::WriteClasses(SafeBuffer& buffer) const {
2478 if (class_set.empty()) {
2479 return;
2480 }
2481 buffer.WriteUintAndAdvance(profile_index);
2482 buffer.WriteUintAndAdvance(dchecked_integral_cast<uint16_t>(class_set.size()));
2483 WriteClassSet(buffer, class_set);
2484 }
2485
ReadClasses(SafeBuffer & buffer,const dchecked_vector<ExtraDescriptorIndex> & extra_descriptors_remap,std::string * error)2486 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::DexFileData::ReadClasses(
2487 SafeBuffer& buffer,
2488 const dchecked_vector<ExtraDescriptorIndex>& extra_descriptors_remap,
2489 std::string* error) {
2490 uint16_t classes_size;
2491 if (!buffer.ReadUintAndAdvance(&classes_size)) {
2492 *error = "Error reading classes size.";
2493 return ProfileLoadStatus::kBadData;
2494 }
2495 uint16_t num_valid_type_indexes = dchecked_integral_cast<uint16_t>(
2496 std::min<size_t>(num_type_ids + extra_descriptors_remap.size(), DexFile::kDexNoIndex16));
2497 uint16_t type_index = 0u;
2498 for (size_t i = 0; i != classes_size; ++i) {
2499 uint16_t type_index_diff;
2500 if (!buffer.ReadUintAndAdvance(&type_index_diff)) {
2501 *error = "Error reading class type index diff.";
2502 return ProfileLoadStatus::kBadData;
2503 }
2504 if (type_index_diff == 0u && i != 0u) {
2505 *error = "Duplicate type index.";
2506 return ProfileLoadStatus::kBadData;
2507 }
2508 if (type_index_diff >= num_valid_type_indexes - type_index) {
2509 *error = "Invalid type index.";
2510 return ProfileLoadStatus::kBadData;
2511 }
2512 type_index += type_index_diff;
2513 if (type_index >= num_type_ids) {
2514 uint32_t new_extra_descriptor_index = extra_descriptors_remap[type_index - num_type_ids];
2515 if (new_extra_descriptor_index >= DexFile::kDexNoIndex16 - num_type_ids) {
2516 *error = "Remapped type index out of range.";
2517 return ProfileLoadStatus::kMergeError;
2518 }
2519 type_index = num_type_ids + new_extra_descriptor_index;
2520 }
2521 class_set.insert(dex::TypeIndex(type_index));
2522 }
2523 return ProfileLoadStatus::kSuccess;
2524 }
2525
SkipClasses(SafeBuffer & buffer,std::string * error)2526 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::DexFileData::SkipClasses(
2527 SafeBuffer& buffer,
2528 std::string* error) {
2529 uint16_t classes_size;
2530 if (!buffer.ReadUintAndAdvance(&classes_size)) {
2531 *error = "Error reading classes size to skip.";
2532 return ProfileLoadStatus::kBadData;
2533 }
2534 size_t following_data_size = static_cast<size_t>(classes_size) * sizeof(uint16_t);
2535 if (following_data_size > buffer.GetAvailableBytes()) {
2536 *error = "Classes data size to skip exceeds remaining data.";
2537 return ProfileLoadStatus::kBadData;
2538 }
2539 buffer.Advance(following_data_size);
2540 return ProfileLoadStatus::kSuccess;
2541 }
2542
MethodsDataSize(uint16_t * method_flags,size_t * saved_bitmap_bit_size) const2543 uint32_t ProfileCompilationInfo::DexFileData::MethodsDataSize(
2544 /*out*/ uint16_t* method_flags,
2545 /*out*/ size_t* saved_bitmap_bit_size) const {
2546 uint16_t local_method_flags = GetUsedBitmapFlags();
2547 size_t local_saved_bitmap_bit_size = POPCOUNT(local_method_flags) * num_method_ids;
2548 if (!method_map.empty()) {
2549 local_method_flags |= enum_cast<uint16_t>(MethodHotness::kFlagHot);
2550 }
2551 size_t size = 0u;
2552 if (local_method_flags != 0u) {
2553 size_t num_hot_methods = method_map.size();
2554 size_t num_dex_pc_entries = 0u;
2555 size_t num_class_entries = 0u;
2556 for (const auto& method_entry : method_map) {
2557 const InlineCacheMap& inline_cache_map = method_entry.second;
2558 num_dex_pc_entries += inline_cache_map.size();
2559 for (const auto& inline_cache_entry : inline_cache_map) {
2560 const DexPcData& dex_pc_data = inline_cache_entry.second;
2561 num_class_entries += dex_pc_data.classes.size();
2562 }
2563 }
2564
2565 constexpr size_t kPerHotMethodSize =
2566 sizeof(uint16_t) + // Method index diff.
2567 sizeof(uint16_t); // Inline cache size.
2568 constexpr size_t kPerDexPcEntrySize =
2569 sizeof(uint16_t) + // Dex PC.
2570 sizeof(uint8_t); // Number of inline cache classes.
2571 constexpr size_t kPerClassEntrySize =
2572 sizeof(uint16_t); // Type index diff.
2573
2574 size_t saved_bitmap_byte_size = BitsToBytesRoundUp(local_saved_bitmap_bit_size);
2575 size = sizeof(ProfileIndexType) + // Which dex file.
2576 sizeof(uint32_t) + // Total size of following data.
2577 sizeof(uint16_t) + // Method flags.
2578 saved_bitmap_byte_size + // Bitmap data.
2579 num_hot_methods * kPerHotMethodSize + // Data for hot methods.
2580 num_dex_pc_entries * kPerDexPcEntrySize + // Data for dex pc entries.
2581 num_class_entries * kPerClassEntrySize; // Data for inline cache class entries.
2582 }
2583 if (method_flags != nullptr) {
2584 *method_flags = local_method_flags;
2585 }
2586 if (saved_bitmap_bit_size != nullptr) {
2587 *saved_bitmap_bit_size = local_saved_bitmap_bit_size;
2588 }
2589 return size;
2590 }
2591
WriteMethods(SafeBuffer & buffer) const2592 void ProfileCompilationInfo::DexFileData::WriteMethods(SafeBuffer& buffer) const {
2593 uint16_t method_flags;
2594 size_t saved_bitmap_bit_size;
2595 uint32_t methods_data_size = MethodsDataSize(&method_flags, &saved_bitmap_bit_size);
2596 if (methods_data_size == 0u) {
2597 return; // No data to write.
2598 }
2599 DCHECK_GE(buffer.GetAvailableBytes(), methods_data_size);
2600 uint32_t expected_available_bytes_at_end = buffer.GetAvailableBytes() - methods_data_size;
2601
2602 // Write the profile index.
2603 buffer.WriteUintAndAdvance(profile_index);
2604 // Write the total size of the following methods data (without the profile index
2605 // and the total size itself) for easy skipping when the dex file is filtered out.
2606 uint32_t following_data_size = methods_data_size - sizeof(ProfileIndexType) - sizeof(uint32_t);
2607 buffer.WriteUintAndAdvance(following_data_size);
2608 // Write the used method flags.
2609 buffer.WriteUintAndAdvance(method_flags);
2610
2611 // Write the bitmap data.
2612 size_t saved_bitmap_byte_size = BitsToBytesRoundUp(saved_bitmap_bit_size);
2613 DCHECK_LE(saved_bitmap_byte_size, buffer.GetAvailableBytes());
2614 BitMemoryRegion saved_bitmap(buffer.GetCurrentPtr(), /*bit_start=*/ 0, saved_bitmap_bit_size);
2615 size_t saved_bitmap_index = 0u;
2616 ForMethodBitmapHotnessFlags([&](MethodHotness::Flag flag) {
2617 if ((method_flags & flag) != 0u) {
2618 size_t index = FlagBitmapIndex(static_cast<MethodHotness::Flag>(flag));
2619 BitMemoryRegion src = method_bitmap.Subregion(index * num_method_ids, num_method_ids);
2620 saved_bitmap.StoreBits(saved_bitmap_index * num_method_ids, src, num_method_ids);
2621 ++saved_bitmap_index;
2622 }
2623 });
2624 DCHECK_EQ(saved_bitmap_index * num_method_ids, saved_bitmap_bit_size);
2625 buffer.Advance(saved_bitmap_byte_size);
2626
2627 uint16_t last_method_index = 0;
2628 for (const auto& method_entry : method_map) {
2629 uint16_t method_index = method_entry.first;
2630 const InlineCacheMap& inline_cache_map = method_entry.second;
2631
2632 // Store the difference between the method indices for better compression.
2633 // The SafeMap is ordered by method_id, so the difference will always be non negative.
2634 DCHECK_GE(method_index, last_method_index);
2635 uint16_t diff_with_last_method_index = method_index - last_method_index;
2636 last_method_index = method_index;
2637 buffer.WriteUintAndAdvance(diff_with_last_method_index);
2638
2639 // Add inline cache map size.
2640 buffer.WriteUintAndAdvance(dchecked_integral_cast<uint16_t>(inline_cache_map.size()));
2641
2642 // Add inline cache entries.
2643 for (const auto& inline_cache_entry : inline_cache_map) {
2644 uint16_t dex_pc = inline_cache_entry.first;
2645 const DexPcData& dex_pc_data = inline_cache_entry.second;
2646 const ArenaSet<dex::TypeIndex>& classes = dex_pc_data.classes;
2647
2648 // Add the dex pc.
2649 buffer.WriteUintAndAdvance(dex_pc);
2650
2651 // Add the megamorphic/missing_types encoding if needed and continue.
2652 // In either cases we don't add any classes to the profiles and so there's
2653 // no point to continue.
2654 // TODO: in case we miss types there is still value to add the rest of the
2655 // classes. (This requires changing profile version or using a new section type.)
2656 if (dex_pc_data.is_missing_types) {
2657 // At this point the megamorphic flag should not be set.
2658 DCHECK(!dex_pc_data.is_megamorphic);
2659 DCHECK_EQ(classes.size(), 0u);
2660 buffer.WriteUintAndAdvance(kIsMissingTypesEncoding);
2661 continue;
2662 } else if (dex_pc_data.is_megamorphic) {
2663 DCHECK_EQ(classes.size(), 0u);
2664 buffer.WriteUintAndAdvance(kIsMegamorphicEncoding);
2665 continue;
2666 }
2667
2668 DCHECK_LT(classes.size(), ProfileCompilationInfo::kIndividualInlineCacheSize);
2669 DCHECK_NE(classes.size(), 0u) << "InlineCache contains a dex_pc with 0 classes";
2670
2671 // Add the number of classes for the dex PC.
2672 buffer.WriteUintAndAdvance(dchecked_integral_cast<uint8_t>(classes.size()));
2673 // Store the class set.
2674 WriteClassSet(buffer, classes);
2675 }
2676 }
2677
2678 // Check if we've written the right number of bytes.
2679 DCHECK_EQ(buffer.GetAvailableBytes(), expected_available_bytes_at_end);
2680 }
2681
ReadMethods(SafeBuffer & buffer,const dchecked_vector<ExtraDescriptorIndex> & extra_descriptors_remap,std::string * error)2682 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::DexFileData::ReadMethods(
2683 SafeBuffer& buffer,
2684 const dchecked_vector<ExtraDescriptorIndex>& extra_descriptors_remap,
2685 std::string* error) {
2686 uint32_t following_data_size;
2687 if (!buffer.ReadUintAndAdvance(&following_data_size)) {
2688 *error = "Error reading methods data size.";
2689 return ProfileLoadStatus::kBadData;
2690 }
2691 if (following_data_size > buffer.GetAvailableBytes()) {
2692 *error = "Methods data size exceeds available data size.";
2693 return ProfileLoadStatus::kBadData;
2694 }
2695 uint32_t expected_available_bytes_at_end = buffer.GetAvailableBytes() - following_data_size;
2696
2697 // Read method flags.
2698 uint16_t method_flags;
2699 if (!buffer.ReadUintAndAdvance(&method_flags)) {
2700 *error = "Error reading method flags.";
2701 return ProfileLoadStatus::kBadData;
2702 }
2703 if (!is_for_boot_image && method_flags >= (MethodHotness::kFlagLastRegular << 1)) {
2704 // The profile we're loading contains data for boot image.
2705 *error = "Method flags contain boot image profile flags for non-boot image profile.";
2706 return ProfileLoadStatus::kBadData;
2707 }
2708
2709 // Read method bitmap.
2710 size_t saved_bitmap_bit_size = POPCOUNT(method_flags & ~MethodHotness::kFlagHot) * num_method_ids;
2711 size_t saved_bitmap_byte_size = BitsToBytesRoundUp(saved_bitmap_bit_size);
2712 if (sizeof(uint16_t) + saved_bitmap_byte_size > following_data_size) {
2713 *error = "Insufficient available data for method bitmap.";
2714 return ProfileLoadStatus::kBadData;
2715 }
2716 BitMemoryRegion saved_bitmap(buffer.GetCurrentPtr(), /*bit_start=*/ 0, saved_bitmap_bit_size);
2717 size_t saved_bitmap_index = 0u;
2718 ForMethodBitmapHotnessFlags([&](MethodHotness::Flag flag) {
2719 if ((method_flags & flag) != 0u) {
2720 size_t index = FlagBitmapIndex(static_cast<MethodHotness::Flag>(flag));
2721 BitMemoryRegion src =
2722 saved_bitmap.Subregion(saved_bitmap_index * num_method_ids, num_method_ids);
2723 method_bitmap.OrBits(index * num_method_ids, src, num_method_ids);
2724 ++saved_bitmap_index;
2725 }
2726 });
2727 buffer.Advance(saved_bitmap_byte_size);
2728
2729 // Load hot methods.
2730 if ((method_flags & MethodHotness::kFlagHot) != 0u) {
2731 uint32_t num_valid_method_indexes =
2732 std::min<uint32_t>(kMaxSupportedMethodIndex + 1u, num_method_ids);
2733 uint16_t num_valid_type_indexes = dchecked_integral_cast<uint16_t>(
2734 std::min<size_t>(num_type_ids + extra_descriptors_remap.size(), DexFile::kDexNoIndex16));
2735 uint16_t method_index = 0;
2736 bool first_diff = true;
2737 while (buffer.GetAvailableBytes() > expected_available_bytes_at_end) {
2738 uint16_t diff_with_last_method_index;
2739 if (!buffer.ReadUintAndAdvance(&diff_with_last_method_index)) {
2740 *error = "Error reading method index diff.";
2741 return ProfileLoadStatus::kBadData;
2742 }
2743 if (diff_with_last_method_index == 0u && !first_diff) {
2744 *error = "Duplicate method index.";
2745 return ProfileLoadStatus::kBadData;
2746 }
2747 first_diff = false;
2748 if (diff_with_last_method_index >= num_valid_method_indexes - method_index) {
2749 *error = "Invalid method index.";
2750 return ProfileLoadStatus::kBadData;
2751 }
2752 method_index += diff_with_last_method_index;
2753 InlineCacheMap* inline_cache = FindOrAddHotMethod(method_index);
2754 DCHECK(inline_cache != nullptr);
2755
2756 // Load inline cache map size.
2757 uint16_t inline_cache_size;
2758 if (!buffer.ReadUintAndAdvance(&inline_cache_size)) {
2759 *error = "Error reading inline cache size.";
2760 return ProfileLoadStatus::kBadData;
2761 }
2762 for (uint16_t ic_index = 0; ic_index != inline_cache_size; ++ic_index) {
2763 // Load dex pc.
2764 uint16_t dex_pc;
2765 if (!buffer.ReadUintAndAdvance(&dex_pc)) {
2766 *error = "Error reading inline cache dex pc.";
2767 return ProfileLoadStatus::kBadData;
2768 }
2769 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, dex_pc);
2770 DCHECK(dex_pc_data != nullptr);
2771
2772 // Load inline cache classes.
2773 uint8_t inline_cache_classes_size;
2774 if (!buffer.ReadUintAndAdvance(&inline_cache_classes_size)) {
2775 *error = "Error reading inline cache classes size.";
2776 return ProfileLoadStatus::kBadData;
2777 }
2778 if (inline_cache_classes_size == kIsMissingTypesEncoding) {
2779 dex_pc_data->SetIsMissingTypes();
2780 } else if (inline_cache_classes_size == kIsMegamorphicEncoding) {
2781 dex_pc_data->SetIsMegamorphic();
2782 } else if (inline_cache_classes_size >= kIndividualInlineCacheSize) {
2783 *error = "Inline cache size too large.";
2784 return ProfileLoadStatus::kBadData;
2785 } else {
2786 uint16_t type_index = 0u;
2787 for (size_t i = 0; i != inline_cache_classes_size; ++i) {
2788 uint16_t type_index_diff;
2789 if (!buffer.ReadUintAndAdvance(&type_index_diff)) {
2790 *error = "Error reading inline cache type index diff.";
2791 return ProfileLoadStatus::kBadData;
2792 }
2793 if (type_index_diff == 0u && i != 0u) {
2794 *error = "Duplicate inline cache type index.";
2795 return ProfileLoadStatus::kBadData;
2796 }
2797 if (type_index_diff >= num_valid_type_indexes - type_index) {
2798 *error = "Invalid inline cache type index.";
2799 return ProfileLoadStatus::kBadData;
2800 }
2801 type_index += type_index_diff;
2802 if (type_index >= num_type_ids) {
2803 ExtraDescriptorIndex new_extra_descriptor_index =
2804 extra_descriptors_remap[type_index - num_type_ids];
2805 if (new_extra_descriptor_index >= DexFile::kDexNoIndex16 - num_type_ids) {
2806 *error = "Remapped inline cache type index out of range.";
2807 return ProfileLoadStatus::kMergeError;
2808 }
2809 type_index = num_type_ids + new_extra_descriptor_index;
2810 }
2811 dex_pc_data->AddClass(dex::TypeIndex(type_index));
2812 }
2813 }
2814 }
2815 }
2816 }
2817
2818 if (buffer.GetAvailableBytes() != expected_available_bytes_at_end) {
2819 *error = "Methods data did not end at expected position.";
2820 return ProfileLoadStatus::kBadData;
2821 }
2822
2823 return ProfileLoadStatus::kSuccess;
2824 }
2825
SkipMethods(SafeBuffer & buffer,std::string * error)2826 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::DexFileData::SkipMethods(
2827 SafeBuffer& buffer,
2828 std::string* error) {
2829 uint32_t following_data_size;
2830 if (!buffer.ReadUintAndAdvance(&following_data_size)) {
2831 *error = "Error reading methods data size to skip.";
2832 return ProfileLoadStatus::kBadData;
2833 }
2834 if (following_data_size > buffer.GetAvailableBytes()) {
2835 *error = "Methods data size to skip exceeds remaining data.";
2836 return ProfileLoadStatus::kBadData;
2837 }
2838 buffer.Advance(following_data_size);
2839 return ProfileLoadStatus::kSuccess;
2840 }
2841
WriteClassSet(SafeBuffer & buffer,const ArenaSet<dex::TypeIndex> & class_set)2842 void ProfileCompilationInfo::DexFileData::WriteClassSet(
2843 SafeBuffer& buffer,
2844 const ArenaSet<dex::TypeIndex>& class_set) {
2845 // Store the difference between the type indexes for better compression.
2846 uint16_t last_type_index = 0u;
2847 for (const dex::TypeIndex& type_index : class_set) {
2848 DCHECK_GE(type_index.index_, last_type_index);
2849 uint16_t diff_with_last_type_index = type_index.index_ - last_type_index;
2850 last_type_index = type_index.index_;
2851 buffer.WriteUintAndAdvance(diff_with_last_type_index);
2852 }
2853 }
2854
GetSizeWarningThresholdBytes() const2855 size_t ProfileCompilationInfo::GetSizeWarningThresholdBytes() const {
2856 return IsForBootImage() ? kSizeWarningThresholdBootBytes : kSizeWarningThresholdBytes;
2857 }
2858
GetSizeErrorThresholdBytes() const2859 size_t ProfileCompilationInfo::GetSizeErrorThresholdBytes() const {
2860 return IsForBootImage() ? kSizeErrorThresholdBootBytes : kSizeErrorThresholdBytes;
2861 }
2862
operator <<(std::ostream & stream,ProfileCompilationInfo::DexReferenceDumper dumper)2863 std::ostream& operator<<(std::ostream& stream,
2864 ProfileCompilationInfo::DexReferenceDumper dumper) {
2865 stream << "[profile_key=" << dumper.GetProfileKey()
2866 << ",dex_checksum=" << std::hex << dumper.GetDexChecksum() << std::dec
2867 << ",num_type_ids=" << dumper.GetNumTypeIds()
2868 << ",num_method_ids=" << dumper.GetNumMethodIds()
2869 << "]";
2870 return stream;
2871 }
2872
FlattenProfileData()2873 FlattenProfileData::FlattenProfileData() :
2874 max_aggregation_for_methods_(0),
2875 max_aggregation_for_classes_(0) {
2876 }
2877
ItemMetadata()2878 FlattenProfileData::ItemMetadata::ItemMetadata() :
2879 flags_(0) {
2880 }
2881
ItemMetadata(const ItemMetadata & other)2882 FlattenProfileData::ItemMetadata::ItemMetadata(const ItemMetadata& other) :
2883 flags_(other.flags_),
2884 annotations_(other.annotations_) {
2885 }
2886
ExtractProfileData(const std::vector<std::unique_ptr<const DexFile>> & dex_files) const2887 std::unique_ptr<FlattenProfileData> ProfileCompilationInfo::ExtractProfileData(
2888 const std::vector<std::unique_ptr<const DexFile>>& dex_files) const {
2889
2890 std::unique_ptr<FlattenProfileData> result(new FlattenProfileData());
2891
2892 auto create_metadata_fn = []() { return FlattenProfileData::ItemMetadata(); };
2893
2894 // Iterate through all the dex files, find the methods/classes associated with each of them,
2895 // and add them to the flatten result.
2896 for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
2897 // Find all the dex data for the given dex file.
2898 // We may have multiple dex data if the methods or classes were added using
2899 // different annotations.
2900 std::vector<const DexFileData*> all_dex_data;
2901 FindAllDexData(dex_file.get(), &all_dex_data);
2902 for (const DexFileData* dex_data : all_dex_data) {
2903 // Extract the annotation from the key as we want to store it in the flatten result.
2904 ProfileSampleAnnotation annotation = GetAnnotationFromKey(dex_data->profile_key);
2905
2906 // Check which methods from the current dex files are in the profile.
2907 for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
2908 MethodHotness hotness = dex_data->GetHotnessInfo(method_idx);
2909 if (!hotness.IsInProfile()) {
2910 // Not in the profile, continue.
2911 continue;
2912 }
2913 // The method is in the profile, create metadata item for it and added to the result.
2914 MethodReference ref(dex_file.get(), method_idx);
2915 FlattenProfileData::ItemMetadata& metadata =
2916 result->method_metadata_.GetOrCreate(ref, create_metadata_fn);
2917 metadata.flags_ |= hotness.flags_;
2918 metadata.annotations_.push_back(annotation);
2919 // Update the max aggregation counter for methods.
2920 // This is essentially a cache, to avoid traversing all the methods just to find out
2921 // this value.
2922 result->max_aggregation_for_methods_ = std::max(
2923 result->max_aggregation_for_methods_,
2924 static_cast<uint32_t>(metadata.annotations_.size()));
2925 }
2926
2927 // Check which classes from the current dex files are in the profile.
2928 for (const dex::TypeIndex& type_index : dex_data->class_set) {
2929 if (type_index.index_ >= dex_file->NumTypeIds()) {
2930 // Not a valid `dex::TypeIndex` for `TypeReference`.
2931 // TODO: Rewrite the API to use descriptors or the `ProfileCompilationInfo` directly
2932 // instead of the `FlattenProfileData` helper class.
2933 continue;
2934 }
2935 TypeReference ref(dex_file.get(), type_index);
2936 FlattenProfileData::ItemMetadata& metadata =
2937 result->class_metadata_.GetOrCreate(ref, create_metadata_fn);
2938 metadata.annotations_.push_back(annotation);
2939 // Update the max aggregation counter for classes.
2940 result->max_aggregation_for_classes_ = std::max(
2941 result->max_aggregation_for_classes_,
2942 static_cast<uint32_t>(metadata.annotations_.size()));
2943 }
2944 }
2945 }
2946
2947 return result;
2948 }
2949
MergeData(const FlattenProfileData & other)2950 void FlattenProfileData::MergeData(const FlattenProfileData& other) {
2951 auto create_metadata_fn = []() { return FlattenProfileData::ItemMetadata(); };
2952 for (const auto& it : other.method_metadata_) {
2953 const MethodReference& otherRef = it.first;
2954 const FlattenProfileData::ItemMetadata otherData = it.second;
2955 const std::list<ProfileCompilationInfo::ProfileSampleAnnotation>& other_annotations =
2956 otherData.GetAnnotations();
2957
2958 FlattenProfileData::ItemMetadata& metadata =
2959 method_metadata_.GetOrCreate(otherRef, create_metadata_fn);
2960 metadata.flags_ |= otherData.GetFlags();
2961 metadata.annotations_.insert(
2962 metadata.annotations_.end(), other_annotations.begin(), other_annotations.end());
2963
2964 max_aggregation_for_methods_ = std::max(
2965 max_aggregation_for_methods_,
2966 static_cast<uint32_t>(metadata.annotations_.size()));
2967 }
2968 for (const auto& it : other.class_metadata_) {
2969 const TypeReference& otherRef = it.first;
2970 const FlattenProfileData::ItemMetadata otherData = it.second;
2971 const std::list<ProfileCompilationInfo::ProfileSampleAnnotation>& other_annotations =
2972 otherData.GetAnnotations();
2973
2974 FlattenProfileData::ItemMetadata& metadata =
2975 class_metadata_.GetOrCreate(otherRef, create_metadata_fn);
2976 metadata.flags_ |= otherData.GetFlags();
2977 metadata.annotations_.insert(
2978 metadata.annotations_.end(), other_annotations.begin(), other_annotations.end());
2979
2980 max_aggregation_for_classes_ = std::max(
2981 max_aggregation_for_classes_,
2982 static_cast<uint32_t>(metadata.annotations_.size()));
2983 }
2984 }
2985
2986 } // namespace art
2987