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 <sys/uio.h> 23 #include <unistd.h> 24 #include <zlib.h> 25 26 #include <cerrno> 27 #include <climits> 28 #include <cstdlib> 29 #include <string> 30 #include <vector> 31 #include <iostream> 32 33 #include "android-base/file.h" 34 35 #include "base/arena_allocator.h" 36 #include "base/dumpable.h" 37 #include "base/file_utils.h" 38 #include "base/logging.h" // For VLOG. 39 #include "base/mutex.h" 40 #include "base/os.h" 41 #include "base/safe_map.h" 42 #include "base/scoped_flock.h" 43 #include "base/stl_util.h" 44 #include "base/systrace.h" 45 #include "base/time_utils.h" 46 #include "base/unix_file/fd_file.h" 47 #include "base/utils.h" 48 #include "dex/dex_file_loader.h" 49 #include "jit/profiling_info.h" 50 #include "zip_archive.h" 51 52 namespace art { 53 54 const uint8_t ProfileCompilationInfo::kProfileMagic[] = { 'p', 'r', 'o', '\0' }; 55 // Last profile version: merge profiles directly from the file without creating 56 // profile_compilation_info object. All the profile line headers are now placed together 57 // before corresponding method_encodings and class_ids. 58 const uint8_t ProfileCompilationInfo::kProfileVersion[] = { '0', '1', '0', '\0' }; 59 60 // The name of the profile entry in the dex metadata file. 61 // DO NOT CHANGE THIS! (it's similar to classes.dex in the apk files). 62 const char* ProfileCompilationInfo::kDexMetadataProfileEntry = "primary.prof"; 63 64 static constexpr uint16_t kMaxDexFileKeyLength = PATH_MAX; 65 66 // Debug flag to ignore checksums when testing if a method or a class is present in the profile. 67 // Used to facilitate testing profile guided compilation across a large number of apps 68 // using the same test profile. 69 static constexpr bool kDebugIgnoreChecksum = false; 70 71 static constexpr uint8_t kIsMissingTypesEncoding = 6; 72 static constexpr uint8_t kIsMegamorphicEncoding = 7; 73 74 static_assert(sizeof(InlineCache::kIndividualCacheSize) == sizeof(uint8_t), 75 "InlineCache::kIndividualCacheSize does not have the expect type size"); 76 static_assert(InlineCache::kIndividualCacheSize < kIsMegamorphicEncoding, 77 "InlineCache::kIndividualCacheSize is larger than expected"); 78 static_assert(InlineCache::kIndividualCacheSize < kIsMissingTypesEncoding, 79 "InlineCache::kIndividualCacheSize is larger than expected"); 80 81 static bool ChecksumMatch(uint32_t dex_file_checksum, uint32_t checksum) { 82 return kDebugIgnoreChecksum || dex_file_checksum == checksum; 83 } 84 85 ProfileCompilationInfo::ProfileCompilationInfo(ArenaPool* custom_arena_pool) 86 : default_arena_pool_(), 87 allocator_(custom_arena_pool), 88 info_(allocator_.Adapter(kArenaAllocProfile)), 89 profile_key_map_(std::less<const std::string>(), allocator_.Adapter(kArenaAllocProfile)) { 90 } 91 92 ProfileCompilationInfo::ProfileCompilationInfo() 93 : default_arena_pool_(/*use_malloc*/true, /*low_4gb*/false, "ProfileCompilationInfo"), 94 allocator_(&default_arena_pool_), 95 info_(allocator_.Adapter(kArenaAllocProfile)), 96 profile_key_map_(std::less<const std::string>(), allocator_.Adapter(kArenaAllocProfile)) { 97 } 98 99 ProfileCompilationInfo::~ProfileCompilationInfo() { 100 VLOG(profiler) << Dumpable<MemStats>(allocator_.GetMemStats()); 101 ClearData(); 102 } 103 104 void ProfileCompilationInfo::DexPcData::AddClass(uint16_t dex_profile_idx, 105 const dex::TypeIndex& type_idx) { 106 if (is_megamorphic || is_missing_types) { 107 return; 108 } 109 110 // Perform an explicit lookup for the type instead of directly emplacing the 111 // element. We do this because emplace() allocates the node before doing the 112 // lookup and if it then finds an identical element, it shall deallocate the 113 // node. For Arena allocations, that's essentially a leak. 114 ClassReference ref(dex_profile_idx, type_idx); 115 auto it = classes.find(ref); 116 if (it != classes.end()) { 117 // The type index exists. 118 return; 119 } 120 121 // Check if the adding the type will cause the cache to become megamorphic. 122 if (classes.size() + 1 >= InlineCache::kIndividualCacheSize) { 123 is_megamorphic = true; 124 classes.clear(); 125 return; 126 } 127 128 // The type does not exist and the inline cache will not be megamorphic. 129 classes.insert(ref); 130 } 131 132 // Transform the actual dex location into relative paths. 133 // Note: this is OK because we don't store profiles of different apps into the same file. 134 // Apps with split apks don't cause trouble because each split has a different name and will not 135 // collide with other entries. 136 std::string ProfileCompilationInfo::GetProfileDexFileKey(const std::string& dex_location) { 137 DCHECK(!dex_location.empty()); 138 size_t last_sep_index = dex_location.find_last_of('/'); 139 if (last_sep_index == std::string::npos) { 140 return dex_location; 141 } else { 142 DCHECK(last_sep_index < dex_location.size()); 143 return dex_location.substr(last_sep_index + 1); 144 } 145 } 146 147 bool ProfileCompilationInfo::AddMethodIndex(MethodHotness::Flag flags, const MethodReference& ref) { 148 DexFileData* data = GetOrAddDexFileData(ref.dex_file); 149 if (data == nullptr) { 150 return false; 151 } 152 return data->AddMethod(flags, ref.index); 153 } 154 155 bool ProfileCompilationInfo::AddMethodIndex(MethodHotness::Flag flags, 156 const std::string& dex_location, 157 uint32_t checksum, 158 uint16_t method_idx, 159 uint32_t num_method_ids) { 160 DexFileData* data = GetOrAddDexFileData(GetProfileDexFileKey(dex_location), 161 checksum, 162 num_method_ids); 163 if (data == nullptr) { 164 return false; 165 } 166 return data->AddMethod(flags, method_idx); 167 } 168 169 bool ProfileCompilationInfo::AddMethods(const std::vector<ProfileMethodInfo>& methods, 170 MethodHotness::Flag flags) { 171 for (const ProfileMethodInfo& method : methods) { 172 if (!AddMethod(method, flags)) { 173 return false; 174 } 175 } 176 return true; 177 } 178 179 bool ProfileCompilationInfo::AddClasses(const std::set<DexCacheResolvedClasses>& resolved_classes) { 180 for (const DexCacheResolvedClasses& dex_cache : resolved_classes) { 181 if (!AddResolvedClasses(dex_cache)) { 182 return false; 183 } 184 } 185 return true; 186 } 187 188 bool ProfileCompilationInfo::MergeWith(const std::string& filename) { 189 std::string error; 190 int flags = O_RDONLY | O_NOFOLLOW | O_CLOEXEC; 191 ScopedFlock profile_file = LockedFile::Open(filename.c_str(), flags, 192 /*block*/false, &error); 193 194 if (profile_file.get() == nullptr) { 195 LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error; 196 return false; 197 } 198 199 int fd = profile_file->Fd(); 200 201 ProfileLoadStatus status = LoadInternal(fd, &error); 202 if (status == kProfileLoadSuccess) { 203 return true; 204 } 205 206 LOG(WARNING) << "Could not load profile data from file " << filename << ": " << error; 207 return false; 208 } 209 210 bool ProfileCompilationInfo::Load(const std::string& filename, bool clear_if_invalid) { 211 ScopedTrace trace(__PRETTY_FUNCTION__); 212 std::string error; 213 214 if (!IsEmpty()) { 215 return kProfileLoadWouldOverwiteData; 216 } 217 218 int flags = O_RDWR | O_NOFOLLOW | O_CLOEXEC; 219 // There's no need to fsync profile data right away. We get many chances 220 // to write it again in case something goes wrong. We can rely on a simple 221 // close(), no sync, and let to the kernel decide when to write to disk. 222 ScopedFlock profile_file = LockedFile::Open(filename.c_str(), flags, 223 /*block*/false, &error); 224 225 if (profile_file.get() == nullptr) { 226 LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error; 227 return false; 228 } 229 230 int fd = profile_file->Fd(); 231 232 ProfileLoadStatus status = LoadInternal(fd, &error); 233 if (status == kProfileLoadSuccess) { 234 return true; 235 } 236 237 if (clear_if_invalid && 238 ((status == kProfileLoadVersionMismatch) || (status == kProfileLoadBadData))) { 239 LOG(WARNING) << "Clearing bad or obsolete profile data from file " 240 << filename << ": " << error; 241 if (profile_file->ClearContent()) { 242 return true; 243 } else { 244 PLOG(WARNING) << "Could not clear profile file: " << filename; 245 return false; 246 } 247 } 248 249 LOG(WARNING) << "Could not load profile data from file " << filename << ": " << error; 250 return false; 251 } 252 253 bool ProfileCompilationInfo::Save(const std::string& filename, uint64_t* bytes_written) { 254 ScopedTrace trace(__PRETTY_FUNCTION__); 255 std::string error; 256 int flags = O_WRONLY | O_NOFOLLOW | O_CLOEXEC; 257 // There's no need to fsync profile data right away. We get many chances 258 // to write it again in case something goes wrong. We can rely on a simple 259 // close(), no sync, and let to the kernel decide when to write to disk. 260 ScopedFlock profile_file = LockedFile::Open(filename.c_str(), flags, 261 /*block*/false, &error); 262 if (profile_file.get() == nullptr) { 263 LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error; 264 return false; 265 } 266 267 int fd = profile_file->Fd(); 268 269 // We need to clear the data because we don't support appending to the profiles yet. 270 if (!profile_file->ClearContent()) { 271 PLOG(WARNING) << "Could not clear profile file: " << filename; 272 return false; 273 } 274 275 // This doesn't need locking because we are trying to lock the file for exclusive 276 // access and fail immediately if we can't. 277 bool result = Save(fd); 278 if (result) { 279 int64_t size = OS::GetFileSizeBytes(filename.c_str()); 280 if (size != -1) { 281 VLOG(profiler) 282 << "Successfully saved profile info to " << filename << " Size: " 283 << size; 284 if (bytes_written != nullptr) { 285 *bytes_written = static_cast<uint64_t>(size); 286 } 287 } 288 } else { 289 VLOG(profiler) << "Failed to save profile info to " << filename; 290 } 291 return result; 292 } 293 294 // Returns true if all the bytes were successfully written to the file descriptor. 295 static bool WriteBuffer(int fd, const uint8_t* buffer, size_t byte_count) { 296 while (byte_count > 0) { 297 int bytes_written = TEMP_FAILURE_RETRY(write(fd, buffer, byte_count)); 298 if (bytes_written == -1) { 299 return false; 300 } 301 byte_count -= bytes_written; // Reduce the number of remaining bytes. 302 buffer += bytes_written; // Move the buffer forward. 303 } 304 return true; 305 } 306 307 // Add the string bytes to the buffer. 308 static void AddStringToBuffer(std::vector<uint8_t>* buffer, const std::string& value) { 309 buffer->insert(buffer->end(), value.begin(), value.end()); 310 } 311 312 // Insert each byte, from low to high into the buffer. 313 template <typename T> 314 static void AddUintToBuffer(std::vector<uint8_t>* buffer, T value) { 315 for (size_t i = 0; i < sizeof(T); i++) { 316 buffer->push_back((value >> (i * kBitsPerByte)) & 0xff); 317 } 318 } 319 320 static constexpr size_t kLineHeaderSize = 321 2 * sizeof(uint16_t) + // class_set.size + dex_location.size 322 3 * sizeof(uint32_t); // method_map.size + checksum + num_method_ids 323 324 /** 325 * Serialization format: 326 * [profile_header, zipped[[profile_line_header1, profile_line_header2...],[profile_line_data1, 327 * profile_line_data2...]]] 328 * profile_header: 329 * magic,version,number_of_dex_files,uncompressed_size_of_zipped_data,compressed_data_size 330 * profile_line_header: 331 * dex_location,number_of_classes,methods_region_size,dex_location_checksum,num_method_ids 332 * profile_line_data: 333 * method_encoding_1,method_encoding_2...,class_id1,class_id2...,startup/post startup bitmap 334 * The method_encoding is: 335 * method_id,number_of_inline_caches,inline_cache1,inline_cache2... 336 * The inline_cache is: 337 * dex_pc,[M|dex_map_size], dex_profile_index,class_id1,class_id2...,dex_profile_index2,... 338 * dex_map_size is the number of dex_indeces that follows. 339 * Classes are grouped per their dex files and the line 340 * `dex_profile_index,class_id1,class_id2...,dex_profile_index2,...` encodes the 341 * mapping from `dex_profile_index` to the set of classes `class_id1,class_id2...` 342 * M stands for megamorphic or missing types and it's encoded as either 343 * the byte kIsMegamorphicEncoding or kIsMissingTypesEncoding. 344 * When present, there will be no class ids following. 345 **/ 346 bool ProfileCompilationInfo::Save(int fd) { 347 uint64_t start = NanoTime(); 348 ScopedTrace trace(__PRETTY_FUNCTION__); 349 DCHECK_GE(fd, 0); 350 351 // Use a vector wrapper to avoid keeping track of offsets when we add elements. 352 std::vector<uint8_t> buffer; 353 if (!WriteBuffer(fd, kProfileMagic, sizeof(kProfileMagic))) { 354 return false; 355 } 356 if (!WriteBuffer(fd, kProfileVersion, sizeof(kProfileVersion))) { 357 return false; 358 } 359 DCHECK_LE(info_.size(), std::numeric_limits<uint8_t>::max()); 360 AddUintToBuffer(&buffer, static_cast<uint8_t>(info_.size())); 361 362 uint32_t required_capacity = 0; 363 for (const DexFileData* dex_data_ptr : info_) { 364 const DexFileData& dex_data = *dex_data_ptr; 365 uint32_t methods_region_size = GetMethodsRegionSize(dex_data); 366 required_capacity += kLineHeaderSize + 367 dex_data.profile_key.size() + 368 sizeof(uint16_t) * dex_data.class_set.size() + 369 methods_region_size + 370 dex_data.bitmap_storage.size(); 371 } 372 // Allow large profiles for non target builds for the case where we are merging many profiles 373 // to generate a boot image profile. 374 if (kIsTargetBuild && required_capacity > kProfileSizeErrorThresholdInBytes) { 375 LOG(ERROR) << "Profile data size exceeds " 376 << std::to_string(kProfileSizeErrorThresholdInBytes) 377 << " bytes. Profile will not be written to disk."; 378 return false; 379 } 380 AddUintToBuffer(&buffer, required_capacity); 381 if (!WriteBuffer(fd, buffer.data(), buffer.size())) { 382 return false; 383 } 384 // Make sure that the buffer has enough capacity to avoid repeated resizings 385 // while we add data. 386 buffer.reserve(required_capacity); 387 buffer.clear(); 388 389 // Dex files must be written in the order of their profile index. This 390 // avoids writing the index in the output file and simplifies the parsing logic. 391 // Write profile line headers. 392 for (const DexFileData* dex_data_ptr : info_) { 393 const DexFileData& dex_data = *dex_data_ptr; 394 395 if (dex_data.profile_key.size() >= kMaxDexFileKeyLength) { 396 LOG(WARNING) << "DexFileKey exceeds allocated limit"; 397 return false; 398 } 399 400 uint32_t methods_region_size = GetMethodsRegionSize(dex_data); 401 402 DCHECK_LE(dex_data.profile_key.size(), std::numeric_limits<uint16_t>::max()); 403 DCHECK_LE(dex_data.class_set.size(), std::numeric_limits<uint16_t>::max()); 404 // Write profile line header. 405 AddUintToBuffer(&buffer, static_cast<uint16_t>(dex_data.profile_key.size())); 406 AddUintToBuffer(&buffer, static_cast<uint16_t>(dex_data.class_set.size())); 407 AddUintToBuffer(&buffer, methods_region_size); // uint32_t 408 AddUintToBuffer(&buffer, dex_data.checksum); // uint32_t 409 AddUintToBuffer(&buffer, dex_data.num_method_ids); // uint32_t 410 411 AddStringToBuffer(&buffer, dex_data.profile_key); 412 } 413 414 for (const DexFileData* dex_data_ptr : info_) { 415 const DexFileData& dex_data = *dex_data_ptr; 416 417 // Note that we allow dex files without any methods or classes, so that 418 // inline caches can refer valid dex files. 419 420 uint16_t last_method_index = 0; 421 for (const auto& method_it : dex_data.method_map) { 422 // Store the difference between the method indices. The SafeMap is ordered by 423 // method_id, so the difference will always be non negative. 424 DCHECK_GE(method_it.first, last_method_index); 425 uint16_t diff_with_last_method_index = method_it.first - last_method_index; 426 last_method_index = method_it.first; 427 AddUintToBuffer(&buffer, diff_with_last_method_index); 428 AddInlineCacheToBuffer(&buffer, method_it.second); 429 } 430 431 uint16_t last_class_index = 0; 432 for (const auto& class_id : dex_data.class_set) { 433 // Store the difference between the class indices. The set is ordered by 434 // class_id, so the difference will always be non negative. 435 DCHECK_GE(class_id.index_, last_class_index); 436 uint16_t diff_with_last_class_index = class_id.index_ - last_class_index; 437 last_class_index = class_id.index_; 438 AddUintToBuffer(&buffer, diff_with_last_class_index); 439 } 440 441 buffer.insert(buffer.end(), 442 dex_data.bitmap_storage.begin(), 443 dex_data.bitmap_storage.end()); 444 } 445 446 uint32_t output_size = 0; 447 std::unique_ptr<uint8_t[]> compressed_buffer = DeflateBuffer(buffer.data(), 448 required_capacity, 449 &output_size); 450 451 if (output_size > kProfileSizeWarningThresholdInBytes) { 452 LOG(WARNING) << "Profile data size exceeds " 453 << std::to_string(kProfileSizeWarningThresholdInBytes); 454 } 455 456 buffer.clear(); 457 AddUintToBuffer(&buffer, output_size); 458 459 if (!WriteBuffer(fd, buffer.data(), buffer.size())) { 460 return false; 461 } 462 if (!WriteBuffer(fd, compressed_buffer.get(), output_size)) { 463 return false; 464 } 465 uint64_t total_time = NanoTime() - start; 466 VLOG(profiler) << "Compressed from " 467 << std::to_string(required_capacity) 468 << " to " 469 << std::to_string(output_size); 470 VLOG(profiler) << "Time to save profile: " << std::to_string(total_time); 471 return true; 472 } 473 474 void ProfileCompilationInfo::AddInlineCacheToBuffer(std::vector<uint8_t>* buffer, 475 const InlineCacheMap& inline_cache_map) { 476 // Add inline cache map size. 477 AddUintToBuffer(buffer, static_cast<uint16_t>(inline_cache_map.size())); 478 if (inline_cache_map.size() == 0) { 479 return; 480 } 481 for (const auto& inline_cache_it : inline_cache_map) { 482 uint16_t dex_pc = inline_cache_it.first; 483 const DexPcData dex_pc_data = inline_cache_it.second; 484 const ClassSet& classes = dex_pc_data.classes; 485 486 // Add the dex pc. 487 AddUintToBuffer(buffer, dex_pc); 488 489 // Add the megamorphic/missing_types encoding if needed and continue. 490 // In either cases we don't add any classes to the profiles and so there's 491 // no point to continue. 492 // TODO(calin): in case we miss types there is still value to add the 493 // rest of the classes. They can be added without bumping the profile version. 494 if (dex_pc_data.is_missing_types) { 495 DCHECK(!dex_pc_data.is_megamorphic); // at this point the megamorphic flag should not be set. 496 DCHECK_EQ(classes.size(), 0u); 497 AddUintToBuffer(buffer, kIsMissingTypesEncoding); 498 continue; 499 } else if (dex_pc_data.is_megamorphic) { 500 DCHECK_EQ(classes.size(), 0u); 501 AddUintToBuffer(buffer, kIsMegamorphicEncoding); 502 continue; 503 } 504 505 DCHECK_LT(classes.size(), InlineCache::kIndividualCacheSize); 506 DCHECK_NE(classes.size(), 0u) << "InlineCache contains a dex_pc with 0 classes"; 507 508 SafeMap<uint8_t, std::vector<dex::TypeIndex>> dex_to_classes_map; 509 // Group the classes by dex. We expect that most of the classes will come from 510 // the same dex, so this will be more efficient than encoding the dex index 511 // for each class reference. 512 GroupClassesByDex(classes, &dex_to_classes_map); 513 // Add the dex map size. 514 AddUintToBuffer(buffer, static_cast<uint8_t>(dex_to_classes_map.size())); 515 for (const auto& dex_it : dex_to_classes_map) { 516 uint8_t dex_profile_index = dex_it.first; 517 const std::vector<dex::TypeIndex>& dex_classes = dex_it.second; 518 // Add the dex profile index. 519 AddUintToBuffer(buffer, dex_profile_index); 520 // Add the the number of classes for each dex profile index. 521 AddUintToBuffer(buffer, static_cast<uint8_t>(dex_classes.size())); 522 for (size_t i = 0; i < dex_classes.size(); i++) { 523 // Add the type index of the classes. 524 AddUintToBuffer(buffer, dex_classes[i].index_); 525 } 526 } 527 } 528 } 529 530 uint32_t ProfileCompilationInfo::GetMethodsRegionSize(const DexFileData& dex_data) { 531 // ((uint16_t)method index + (uint16_t)inline cache size) * number of methods 532 uint32_t size = 2 * sizeof(uint16_t) * dex_data.method_map.size(); 533 for (const auto& method_it : dex_data.method_map) { 534 const InlineCacheMap& inline_cache = method_it.second; 535 size += sizeof(uint16_t) * inline_cache.size(); // dex_pc 536 for (const auto& inline_cache_it : inline_cache) { 537 const ClassSet& classes = inline_cache_it.second.classes; 538 SafeMap<uint8_t, std::vector<dex::TypeIndex>> dex_to_classes_map; 539 GroupClassesByDex(classes, &dex_to_classes_map); 540 size += sizeof(uint8_t); // dex_to_classes_map size 541 for (const auto& dex_it : dex_to_classes_map) { 542 size += sizeof(uint8_t); // dex profile index 543 size += sizeof(uint8_t); // number of classes 544 const std::vector<dex::TypeIndex>& dex_classes = dex_it.second; 545 size += sizeof(uint16_t) * dex_classes.size(); // the actual classes 546 } 547 } 548 } 549 return size; 550 } 551 552 void ProfileCompilationInfo::GroupClassesByDex( 553 const ClassSet& classes, 554 /*out*/SafeMap<uint8_t, std::vector<dex::TypeIndex>>* dex_to_classes_map) { 555 for (const auto& classes_it : classes) { 556 auto dex_it = dex_to_classes_map->FindOrAdd(classes_it.dex_profile_index); 557 dex_it->second.push_back(classes_it.type_index); 558 } 559 } 560 561 ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::GetOrAddDexFileData( 562 const std::string& profile_key, 563 uint32_t checksum, 564 uint32_t num_method_ids) { 565 const auto profile_index_it = profile_key_map_.FindOrAdd(profile_key, profile_key_map_.size()); 566 if (profile_key_map_.size() > std::numeric_limits<uint8_t>::max()) { 567 // Allow only 255 dex files to be profiled. This allows us to save bytes 568 // when encoding. The number is well above what we expect for normal applications. 569 if (kIsDebugBuild) { 570 LOG(ERROR) << "Exceeded the maximum number of dex files (255). Something went wrong"; 571 } 572 profile_key_map_.erase(profile_key); 573 return nullptr; 574 } 575 576 uint8_t profile_index = profile_index_it->second; 577 if (info_.size() <= profile_index) { 578 // This is a new addition. Add it to the info_ array. 579 DexFileData* dex_file_data = new (&allocator_) DexFileData( 580 &allocator_, 581 profile_key, 582 checksum, 583 profile_index, 584 num_method_ids); 585 info_.push_back(dex_file_data); 586 } 587 DexFileData* result = info_[profile_index]; 588 589 // Check that the checksum matches. 590 // This may different if for example the dex file was updated and we had a record of the old one. 591 if (result->checksum != checksum) { 592 LOG(WARNING) << "Checksum mismatch for dex " << profile_key; 593 return nullptr; 594 } 595 596 // DCHECK that profile info map key is consistent with the one stored in the dex file data. 597 // This should always be the case since since the cache map is managed by ProfileCompilationInfo. 598 DCHECK_EQ(profile_key, result->profile_key); 599 DCHECK_EQ(profile_index, result->profile_index); 600 601 if (num_method_ids != result->num_method_ids) { 602 // This should not happen... added to help investigating b/65812889. 603 LOG(ERROR) << "num_method_ids mismatch for dex " << profile_key 604 << ", expected=" << num_method_ids 605 << ", actual=" << result->num_method_ids; 606 return nullptr; 607 } 608 609 return result; 610 } 611 612 const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexData( 613 const std::string& profile_key, 614 uint32_t checksum, 615 bool verify_checksum) const { 616 const auto profile_index_it = profile_key_map_.find(profile_key); 617 if (profile_index_it == profile_key_map_.end()) { 618 return nullptr; 619 } 620 621 uint8_t profile_index = profile_index_it->second; 622 const DexFileData* result = info_[profile_index]; 623 if (verify_checksum && !ChecksumMatch(result->checksum, checksum)) { 624 return nullptr; 625 } 626 DCHECK_EQ(profile_key, result->profile_key); 627 DCHECK_EQ(profile_index, result->profile_index); 628 return result; 629 } 630 631 bool ProfileCompilationInfo::AddResolvedClasses(const DexCacheResolvedClasses& classes) { 632 const std::string dex_location = GetProfileDexFileKey(classes.GetDexLocation()); 633 const uint32_t checksum = classes.GetLocationChecksum(); 634 DexFileData* const data = GetOrAddDexFileData(dex_location, checksum, classes.NumMethodIds()); 635 if (data == nullptr) { 636 return false; 637 } 638 data->class_set.insert(classes.GetClasses().begin(), classes.GetClasses().end()); 639 return true; 640 } 641 642 bool ProfileCompilationInfo::AddMethod(const std::string& dex_location, 643 uint32_t dex_checksum, 644 uint16_t method_index, 645 uint32_t num_method_ids, 646 const OfflineProfileMethodInfo& pmi, 647 MethodHotness::Flag flags) { 648 DexFileData* const data = GetOrAddDexFileData(GetProfileDexFileKey(dex_location), 649 dex_checksum, 650 num_method_ids); 651 if (data == nullptr) { 652 // The data is null if there is a mismatch in the checksum or number of method ids. 653 return false; 654 } 655 656 // Add the method. 657 InlineCacheMap* inline_cache = data->FindOrAddMethod(method_index); 658 if (inline_cache == nullptr) { 659 // Happens if the method index is outside the range (i.e. is greater then the number 660 // of methods in the dex file). This should not happen during normal execution, 661 // But tools (e.g. boot image aggregation tools) and tests stress this behaviour. 662 return false; 663 } 664 665 data->SetMethodHotness(method_index, flags); 666 667 if (pmi.inline_caches == nullptr) { 668 // If we don't have inline caches return success right away. 669 return true; 670 } 671 for (const auto& pmi_inline_cache_it : *pmi.inline_caches) { 672 uint16_t pmi_ic_dex_pc = pmi_inline_cache_it.first; 673 const DexPcData& pmi_ic_dex_pc_data = pmi_inline_cache_it.second; 674 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, pmi_ic_dex_pc); 675 if (dex_pc_data->is_missing_types || dex_pc_data->is_megamorphic) { 676 // We are already megamorphic or we are missing types; no point in going forward. 677 continue; 678 } 679 680 if (pmi_ic_dex_pc_data.is_missing_types) { 681 dex_pc_data->SetIsMissingTypes(); 682 continue; 683 } 684 if (pmi_ic_dex_pc_data.is_megamorphic) { 685 dex_pc_data->SetIsMegamorphic(); 686 continue; 687 } 688 689 for (const ClassReference& class_ref : pmi_ic_dex_pc_data.classes) { 690 const DexReference& dex_ref = pmi.dex_references[class_ref.dex_profile_index]; 691 DexFileData* class_dex_data = GetOrAddDexFileData( 692 GetProfileDexFileKey(dex_ref.dex_location), 693 dex_ref.dex_checksum, 694 dex_ref.num_method_ids); 695 if (class_dex_data == nullptr) { // checksum mismatch 696 return false; 697 } 698 dex_pc_data->AddClass(class_dex_data->profile_index, class_ref.type_index); 699 } 700 } 701 return true; 702 } 703 704 bool ProfileCompilationInfo::AddMethod(const ProfileMethodInfo& pmi, MethodHotness::Flag flags) { 705 DexFileData* const data = GetOrAddDexFileData(pmi.ref.dex_file); 706 if (data == nullptr) { // checksum mismatch 707 return false; 708 } 709 InlineCacheMap* inline_cache = data->FindOrAddMethod(pmi.ref.index); 710 if (inline_cache == nullptr) { 711 return false; 712 } 713 data->SetMethodHotness(pmi.ref.index, flags); 714 715 for (const ProfileMethodInfo::ProfileInlineCache& cache : pmi.inline_caches) { 716 if (cache.is_missing_types) { 717 FindOrAddDexPc(inline_cache, cache.dex_pc)->SetIsMissingTypes(); 718 continue; 719 } 720 for (const TypeReference& class_ref : cache.classes) { 721 DexFileData* class_dex_data = GetOrAddDexFileData(class_ref.dex_file); 722 if (class_dex_data == nullptr) { // checksum mismatch 723 return false; 724 } 725 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, cache.dex_pc); 726 if (dex_pc_data->is_missing_types) { 727 // Don't bother adding classes if we are missing types. 728 break; 729 } 730 dex_pc_data->AddClass(class_dex_data->profile_index, class_ref.TypeIndex()); 731 } 732 } 733 return true; 734 } 735 736 bool ProfileCompilationInfo::AddClassIndex(const std::string& dex_location, 737 uint32_t checksum, 738 dex::TypeIndex type_idx, 739 uint32_t num_method_ids) { 740 DexFileData* const data = GetOrAddDexFileData(dex_location, checksum, num_method_ids); 741 if (data == nullptr) { 742 return false; 743 } 744 data->class_set.insert(type_idx); 745 return true; 746 } 747 748 #define READ_UINT(type, buffer, dest, error) \ 749 do { \ 750 if (!(buffer).ReadUintAndAdvance<type>(&(dest))) { \ 751 *(error) = "Could not read "#dest; \ 752 return false; \ 753 } \ 754 } \ 755 while (false) 756 757 bool ProfileCompilationInfo::ReadInlineCache( 758 SafeBuffer& buffer, 759 uint8_t number_of_dex_files, 760 const SafeMap<uint8_t, uint8_t>& dex_profile_index_remap, 761 /*out*/ InlineCacheMap* inline_cache, 762 /*out*/ std::string* error) { 763 uint16_t inline_cache_size; 764 READ_UINT(uint16_t, buffer, inline_cache_size, error); 765 for (; inline_cache_size > 0; inline_cache_size--) { 766 uint16_t dex_pc; 767 uint8_t dex_to_classes_map_size; 768 READ_UINT(uint16_t, buffer, dex_pc, error); 769 READ_UINT(uint8_t, buffer, dex_to_classes_map_size, error); 770 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, dex_pc); 771 if (dex_to_classes_map_size == kIsMissingTypesEncoding) { 772 dex_pc_data->SetIsMissingTypes(); 773 continue; 774 } 775 if (dex_to_classes_map_size == kIsMegamorphicEncoding) { 776 dex_pc_data->SetIsMegamorphic(); 777 continue; 778 } 779 for (; dex_to_classes_map_size > 0; dex_to_classes_map_size--) { 780 uint8_t dex_profile_index; 781 uint8_t dex_classes_size; 782 READ_UINT(uint8_t, buffer, dex_profile_index, error); 783 READ_UINT(uint8_t, buffer, dex_classes_size, error); 784 if (dex_profile_index >= number_of_dex_files) { 785 *error = "dex_profile_index out of bounds "; 786 *error += std::to_string(dex_profile_index) + " " + std::to_string(number_of_dex_files); 787 return false; 788 } 789 for (; dex_classes_size > 0; dex_classes_size--) { 790 uint16_t type_index; 791 READ_UINT(uint16_t, buffer, type_index, error); 792 auto it = dex_profile_index_remap.find(dex_profile_index); 793 if (it == dex_profile_index_remap.end()) { 794 // If we don't have an index that's because the dex file was filtered out when loading. 795 // Set missing types on the dex pc data. 796 dex_pc_data->SetIsMissingTypes(); 797 } else { 798 dex_pc_data->AddClass(it->second, dex::TypeIndex(type_index)); 799 } 800 } 801 } 802 } 803 return true; 804 } 805 806 bool ProfileCompilationInfo::ReadMethods(SafeBuffer& buffer, 807 uint8_t number_of_dex_files, 808 const ProfileLineHeader& line_header, 809 const SafeMap<uint8_t, uint8_t>& dex_profile_index_remap, 810 /*out*/std::string* error) { 811 uint32_t unread_bytes_before_operation = buffer.CountUnreadBytes(); 812 if (unread_bytes_before_operation < line_header.method_region_size_bytes) { 813 *error += "Profile EOF reached prematurely for ReadMethod"; 814 return kProfileLoadBadData; 815 } 816 size_t expected_unread_bytes_after_operation = buffer.CountUnreadBytes() 817 - line_header.method_region_size_bytes; 818 uint16_t last_method_index = 0; 819 while (buffer.CountUnreadBytes() > expected_unread_bytes_after_operation) { 820 DexFileData* const data = GetOrAddDexFileData(line_header.dex_location, 821 line_header.checksum, 822 line_header.num_method_ids); 823 uint16_t diff_with_last_method_index; 824 READ_UINT(uint16_t, buffer, diff_with_last_method_index, error); 825 uint16_t method_index = last_method_index + diff_with_last_method_index; 826 last_method_index = method_index; 827 InlineCacheMap* inline_cache = data->FindOrAddMethod(method_index); 828 if (inline_cache == nullptr) { 829 return false; 830 } 831 if (!ReadInlineCache(buffer, 832 number_of_dex_files, 833 dex_profile_index_remap, 834 inline_cache, 835 error)) { 836 return false; 837 } 838 } 839 uint32_t total_bytes_read = unread_bytes_before_operation - buffer.CountUnreadBytes(); 840 if (total_bytes_read != line_header.method_region_size_bytes) { 841 *error += "Profile data inconsistent for ReadMethods"; 842 return false; 843 } 844 return true; 845 } 846 847 bool ProfileCompilationInfo::ReadClasses(SafeBuffer& buffer, 848 const ProfileLineHeader& line_header, 849 /*out*/std::string* error) { 850 size_t unread_bytes_before_op = buffer.CountUnreadBytes(); 851 if (unread_bytes_before_op < line_header.class_set_size) { 852 *error += "Profile EOF reached prematurely for ReadClasses"; 853 return kProfileLoadBadData; 854 } 855 856 uint16_t last_class_index = 0; 857 for (uint16_t i = 0; i < line_header.class_set_size; i++) { 858 uint16_t diff_with_last_class_index; 859 READ_UINT(uint16_t, buffer, diff_with_last_class_index, error); 860 uint16_t type_index = last_class_index + diff_with_last_class_index; 861 last_class_index = type_index; 862 if (!AddClassIndex(line_header.dex_location, 863 line_header.checksum, 864 dex::TypeIndex(type_index), 865 line_header.num_method_ids)) { 866 return false; 867 } 868 } 869 size_t total_bytes_read = unread_bytes_before_op - buffer.CountUnreadBytes(); 870 uint32_t expected_bytes_read = line_header.class_set_size * sizeof(uint16_t); 871 if (total_bytes_read != expected_bytes_read) { 872 *error += "Profile data inconsistent for ReadClasses"; 873 return false; 874 } 875 return true; 876 } 877 878 // Tests for EOF by trying to read 1 byte from the descriptor. 879 // Returns: 880 // 0 if the descriptor is at the EOF, 881 // -1 if there was an IO error 882 // 1 if the descriptor has more content to read 883 static int testEOF(int fd) { 884 uint8_t buffer[1]; 885 return TEMP_FAILURE_RETRY(read(fd, buffer, 1)); 886 } 887 888 // Reads an uint value previously written with AddUintToBuffer. 889 template <typename T> 890 bool ProfileCompilationInfo::SafeBuffer::ReadUintAndAdvance(/*out*/T* value) { 891 static_assert(std::is_unsigned<T>::value, "Type is not unsigned"); 892 if (ptr_current_ + sizeof(T) > ptr_end_) { 893 return false; 894 } 895 *value = 0; 896 for (size_t i = 0; i < sizeof(T); i++) { 897 *value += ptr_current_[i] << (i * kBitsPerByte); 898 } 899 ptr_current_ += sizeof(T); 900 return true; 901 } 902 903 bool ProfileCompilationInfo::SafeBuffer::CompareAndAdvance(const uint8_t* data, size_t data_size) { 904 if (ptr_current_ + data_size > ptr_end_) { 905 return false; 906 } 907 if (memcmp(ptr_current_, data, data_size) == 0) { 908 ptr_current_ += data_size; 909 return true; 910 } 911 return false; 912 } 913 914 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::SafeBuffer::Fill( 915 ProfileSource& source, 916 const std::string& debug_stage, 917 /*out*/ std::string* error) { 918 size_t byte_count = (ptr_end_ - ptr_current_) * sizeof(*ptr_current_); 919 uint8_t* buffer = ptr_current_; 920 return source.Read(buffer, byte_count, debug_stage, error); 921 } 922 923 size_t ProfileCompilationInfo::SafeBuffer::CountUnreadBytes() { 924 return (ptr_end_ - ptr_current_) * sizeof(*ptr_current_); 925 } 926 927 const uint8_t* ProfileCompilationInfo::SafeBuffer::GetCurrentPtr() { 928 return ptr_current_; 929 } 930 931 void ProfileCompilationInfo::SafeBuffer::Advance(size_t data_size) { 932 ptr_current_ += data_size; 933 } 934 935 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadProfileHeader( 936 ProfileSource& source, 937 /*out*/uint8_t* number_of_dex_files, 938 /*out*/uint32_t* uncompressed_data_size, 939 /*out*/uint32_t* compressed_data_size, 940 /*out*/std::string* error) { 941 // Read magic and version 942 const size_t kMagicVersionSize = 943 sizeof(kProfileMagic) + 944 sizeof(kProfileVersion) + 945 sizeof(uint8_t) + // number of dex files 946 sizeof(uint32_t) + // size of uncompressed profile data 947 sizeof(uint32_t); // size of compressed profile data 948 949 SafeBuffer safe_buffer(kMagicVersionSize); 950 951 ProfileLoadStatus status = safe_buffer.Fill(source, "ReadProfileHeader", error); 952 if (status != kProfileLoadSuccess) { 953 return status; 954 } 955 956 if (!safe_buffer.CompareAndAdvance(kProfileMagic, sizeof(kProfileMagic))) { 957 *error = "Profile missing magic"; 958 return kProfileLoadVersionMismatch; 959 } 960 if (!safe_buffer.CompareAndAdvance(kProfileVersion, sizeof(kProfileVersion))) { 961 *error = "Profile version mismatch"; 962 return kProfileLoadVersionMismatch; 963 } 964 if (!safe_buffer.ReadUintAndAdvance<uint8_t>(number_of_dex_files)) { 965 *error = "Cannot read the number of dex files"; 966 return kProfileLoadBadData; 967 } 968 if (!safe_buffer.ReadUintAndAdvance<uint32_t>(uncompressed_data_size)) { 969 *error = "Cannot read the size of uncompressed data"; 970 return kProfileLoadBadData; 971 } 972 if (!safe_buffer.ReadUintAndAdvance<uint32_t>(compressed_data_size)) { 973 *error = "Cannot read the size of compressed data"; 974 return kProfileLoadBadData; 975 } 976 return kProfileLoadSuccess; 977 } 978 979 bool ProfileCompilationInfo::ReadProfileLineHeaderElements(SafeBuffer& buffer, 980 /*out*/uint16_t* dex_location_size, 981 /*out*/ProfileLineHeader* line_header, 982 /*out*/std::string* error) { 983 READ_UINT(uint16_t, buffer, *dex_location_size, error); 984 READ_UINT(uint16_t, buffer, line_header->class_set_size, error); 985 READ_UINT(uint32_t, buffer, line_header->method_region_size_bytes, error); 986 READ_UINT(uint32_t, buffer, line_header->checksum, error); 987 READ_UINT(uint32_t, buffer, line_header->num_method_ids, error); 988 return true; 989 } 990 991 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadProfileLineHeader( 992 SafeBuffer& buffer, 993 /*out*/ProfileLineHeader* line_header, 994 /*out*/std::string* error) { 995 if (buffer.CountUnreadBytes() < kLineHeaderSize) { 996 *error += "Profile EOF reached prematurely for ReadProfileLineHeader"; 997 return kProfileLoadBadData; 998 } 999 1000 uint16_t dex_location_size; 1001 if (!ReadProfileLineHeaderElements(buffer, &dex_location_size, line_header, error)) { 1002 return kProfileLoadBadData; 1003 } 1004 1005 if (dex_location_size == 0 || dex_location_size > kMaxDexFileKeyLength) { 1006 *error = "DexFileKey has an invalid size: " + 1007 std::to_string(static_cast<uint32_t>(dex_location_size)); 1008 return kProfileLoadBadData; 1009 } 1010 1011 if (buffer.CountUnreadBytes() < dex_location_size) { 1012 *error += "Profile EOF reached prematurely for ReadProfileHeaderDexLocation"; 1013 return kProfileLoadBadData; 1014 } 1015 const uint8_t* base_ptr = buffer.GetCurrentPtr(); 1016 line_header->dex_location.assign( 1017 reinterpret_cast<const char*>(base_ptr), dex_location_size); 1018 buffer.Advance(dex_location_size); 1019 return kProfileLoadSuccess; 1020 } 1021 1022 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadProfileLine( 1023 SafeBuffer& buffer, 1024 uint8_t number_of_dex_files, 1025 const ProfileLineHeader& line_header, 1026 const SafeMap<uint8_t, uint8_t>& dex_profile_index_remap, 1027 bool merge_classes, 1028 /*out*/std::string* error) { 1029 DexFileData* data = GetOrAddDexFileData(line_header.dex_location, 1030 line_header.checksum, 1031 line_header.num_method_ids); 1032 if (data == nullptr) { 1033 *error = "Error when reading profile file line header: checksum mismatch for " 1034 + line_header.dex_location; 1035 return kProfileLoadBadData; 1036 } 1037 1038 if (!ReadMethods(buffer, number_of_dex_files, line_header, dex_profile_index_remap, error)) { 1039 return kProfileLoadBadData; 1040 } 1041 1042 if (merge_classes) { 1043 if (!ReadClasses(buffer, line_header, error)) { 1044 return kProfileLoadBadData; 1045 } 1046 } 1047 1048 const size_t bytes = data->bitmap_storage.size(); 1049 if (buffer.CountUnreadBytes() < bytes) { 1050 *error += "Profile EOF reached prematurely for ReadProfileHeaderDexLocation"; 1051 return kProfileLoadBadData; 1052 } 1053 const uint8_t* base_ptr = buffer.GetCurrentPtr(); 1054 std::copy_n(base_ptr, bytes, data->bitmap_storage.data()); 1055 buffer.Advance(bytes); 1056 // Read method bitmap. 1057 return kProfileLoadSuccess; 1058 } 1059 1060 // TODO(calin): Fix this API. ProfileCompilationInfo::Load should be static and 1061 // return a unique pointer to a ProfileCompilationInfo upon success. 1062 bool ProfileCompilationInfo::Load( 1063 int fd, bool merge_classes, const ProfileLoadFilterFn& filter_fn) { 1064 std::string error; 1065 1066 ProfileLoadStatus status = LoadInternal(fd, &error, merge_classes, filter_fn); 1067 1068 if (status == kProfileLoadSuccess) { 1069 return true; 1070 } else { 1071 LOG(WARNING) << "Error when reading profile: " << error; 1072 return false; 1073 } 1074 } 1075 1076 bool ProfileCompilationInfo::VerifyProfileData(const std::vector<const DexFile*>& dex_files) { 1077 std::unordered_map<std::string, const DexFile*> key_to_dex_file; 1078 for (const DexFile* dex_file : dex_files) { 1079 key_to_dex_file.emplace(GetProfileDexFileKey(dex_file->GetLocation()), dex_file); 1080 } 1081 for (const DexFileData* dex_data : info_) { 1082 const auto it = key_to_dex_file.find(dex_data->profile_key); 1083 if (it == key_to_dex_file.end()) { 1084 // It is okay if profile contains data for additional dex files. 1085 continue; 1086 } 1087 const DexFile* dex_file = it->second; 1088 const std::string& dex_location = dex_file->GetLocation(); 1089 if (!ChecksumMatch(dex_data->checksum, dex_file->GetLocationChecksum())) { 1090 LOG(ERROR) << "Dex checksum mismatch while verifying profile " 1091 << "dex location " << dex_location << " (checksum=" 1092 << dex_file->GetLocationChecksum() << ", profile checksum=" 1093 << dex_data->checksum; 1094 return false; 1095 } 1096 1097 if (dex_data->num_method_ids != dex_file->NumMethodIds()) { 1098 LOG(ERROR) << "Number of method ids in dex file and profile don't match." 1099 << "dex location " << dex_location << " NumMethodId in DexFile" 1100 << dex_file->NumMethodIds() << ", NumMethodId in profile" 1101 << dex_data->num_method_ids; 1102 return false; 1103 } 1104 1105 // Verify method_encoding. 1106 for (const auto& method_it : dex_data->method_map) { 1107 size_t method_id = (size_t)(method_it.first); 1108 if (method_id >= dex_file->NumMethodIds()) { 1109 LOG(ERROR) << "Invalid method id in profile file. dex location=" 1110 << dex_location << " method_id=" << method_id << " NumMethodIds=" 1111 << dex_file->NumMethodIds(); 1112 return false; 1113 } 1114 1115 // Verify class indices of inline caches. 1116 const InlineCacheMap &inline_cache_map = method_it.second; 1117 for (const auto& inline_cache_it : inline_cache_map) { 1118 const DexPcData dex_pc_data = inline_cache_it.second; 1119 if (dex_pc_data.is_missing_types || dex_pc_data.is_megamorphic) { 1120 // No class indices to verify. 1121 continue; 1122 } 1123 1124 const ClassSet &classes = dex_pc_data.classes; 1125 SafeMap<uint8_t, std::vector<dex::TypeIndex>> dex_to_classes_map; 1126 // Group the classes by dex. We expect that most of the classes will come from 1127 // the same dex, so this will be more efficient than encoding the dex index 1128 // for each class reference. 1129 GroupClassesByDex(classes, &dex_to_classes_map); 1130 for (const auto &dex_it : dex_to_classes_map) { 1131 uint8_t dex_profile_index = dex_it.first; 1132 const auto dex_file_inline_cache_it = key_to_dex_file.find( 1133 info_[dex_profile_index]->profile_key); 1134 if (dex_file_inline_cache_it == key_to_dex_file.end()) { 1135 // It is okay if profile contains data for additional dex files. 1136 continue; 1137 } 1138 const DexFile *dex_file_for_inline_cache_check = dex_file_inline_cache_it->second; 1139 const std::vector<dex::TypeIndex> &dex_classes = dex_it.second; 1140 for (size_t i = 0; i < dex_classes.size(); i++) { 1141 if (dex_classes[i].index_ >= dex_file_for_inline_cache_check->NumTypeIds()) { 1142 LOG(ERROR) << "Invalid inline cache in profile file. dex location=" 1143 << dex_location << " method_id=" << method_id 1144 << " dex_profile_index=" 1145 << static_cast<uint16_t >(dex_profile_index) << " type_index=" 1146 << dex_classes[i].index_ 1147 << " NumTypeIds=" 1148 << dex_file_for_inline_cache_check->NumTypeIds(); 1149 return false; 1150 } 1151 } 1152 } 1153 } 1154 } 1155 // Verify class_ids. 1156 for (const auto& class_id : dex_data->class_set) { 1157 if (class_id.index_ >= dex_file->NumTypeIds()) { 1158 LOG(ERROR) << "Invalid class id in profile file. dex_file location " 1159 << dex_location << " class_id=" << class_id.index_ << " NumClassIds=" 1160 << dex_file->NumClassDefs(); 1161 return false; 1162 } 1163 } 1164 } 1165 return true; 1166 } 1167 1168 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::OpenSource( 1169 int32_t fd, 1170 /*out*/ std::unique_ptr<ProfileSource>* source, 1171 /*out*/ std::string* error) { 1172 if (IsProfileFile(fd)) { 1173 source->reset(ProfileSource::Create(fd)); 1174 return kProfileLoadSuccess; 1175 } else { 1176 std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, "profile", error)); 1177 if (zip_archive.get() == nullptr) { 1178 *error = "Could not open the profile zip archive"; 1179 return kProfileLoadBadData; 1180 } 1181 std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(kDexMetadataProfileEntry, error)); 1182 if (zip_entry == nullptr) { 1183 // Allow archives without the profile entry. In this case, create an empty profile. 1184 // This gives more flexible when ure-using archives that may miss the entry. 1185 // (e.g. dex metadata files) 1186 LOG(WARNING) << std::string("Could not find entry ") + kDexMetadataProfileEntry + 1187 " in the zip archive. Creating an empty profile."; 1188 source->reset(ProfileSource::Create(nullptr)); 1189 return kProfileLoadSuccess; 1190 } 1191 if (zip_entry->GetUncompressedLength() == 0) { 1192 *error = "Empty profile entry in the zip archive."; 1193 return kProfileLoadBadData; 1194 } 1195 1196 // TODO(calin) pass along file names to assist with debugging. 1197 std::unique_ptr<MemMap> map(zip_entry->MapDirectlyOrExtract(kDexMetadataProfileEntry, 1198 "profile file", 1199 error)); 1200 1201 if (map != nullptr) { 1202 source->reset(ProfileSource::Create(std::move(map))); 1203 return kProfileLoadSuccess; 1204 } else { 1205 return kProfileLoadBadData; 1206 } 1207 } 1208 } 1209 1210 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ProfileSource::Read( 1211 uint8_t* buffer, 1212 size_t byte_count, 1213 const std::string& debug_stage, 1214 std::string* error) { 1215 if (IsMemMap()) { 1216 if (mem_map_cur_ + byte_count > mem_map_->Size()) { 1217 return kProfileLoadBadData; 1218 } 1219 for (size_t i = 0; i < byte_count; i++) { 1220 buffer[i] = *(mem_map_->Begin() + mem_map_cur_); 1221 mem_map_cur_++; 1222 } 1223 } else { 1224 while (byte_count > 0) { 1225 int bytes_read = TEMP_FAILURE_RETRY(read(fd_, buffer, byte_count));; 1226 if (bytes_read == 0) { 1227 *error += "Profile EOF reached prematurely for " + debug_stage; 1228 return kProfileLoadBadData; 1229 } else if (bytes_read < 0) { 1230 *error += "Profile IO error for " + debug_stage + strerror(errno); 1231 return kProfileLoadIOError; 1232 } 1233 byte_count -= bytes_read; 1234 buffer += bytes_read; 1235 } 1236 } 1237 return kProfileLoadSuccess; 1238 } 1239 1240 bool ProfileCompilationInfo::ProfileSource::HasConsumedAllData() const { 1241 return IsMemMap() 1242 ? (mem_map_ == nullptr || mem_map_cur_ == mem_map_->Size()) 1243 : (testEOF(fd_) == 0); 1244 } 1245 1246 bool ProfileCompilationInfo::ProfileSource::HasEmptyContent() const { 1247 if (IsMemMap()) { 1248 return mem_map_ == nullptr || mem_map_->Size() == 0; 1249 } else { 1250 struct stat stat_buffer; 1251 if (fstat(fd_, &stat_buffer) != 0) { 1252 return false; 1253 } 1254 return stat_buffer.st_size == 0; 1255 } 1256 } 1257 1258 // TODO(calin): fail fast if the dex checksums don't match. 1259 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::LoadInternal( 1260 int32_t fd, 1261 std::string* error, 1262 bool merge_classes, 1263 const ProfileLoadFilterFn& filter_fn) { 1264 ScopedTrace trace(__PRETTY_FUNCTION__); 1265 DCHECK_GE(fd, 0); 1266 1267 std::unique_ptr<ProfileSource> source; 1268 ProfileLoadStatus status = OpenSource(fd, &source, error); 1269 if (status != kProfileLoadSuccess) { 1270 return status; 1271 } 1272 1273 // We allow empty profile files. 1274 // Profiles may be created by ActivityManager or installd before we manage to 1275 // process them in the runtime or profman. 1276 if (source->HasEmptyContent()) { 1277 return kProfileLoadSuccess; 1278 } 1279 1280 // Read profile header: magic + version + number_of_dex_files. 1281 uint8_t number_of_dex_files; 1282 uint32_t uncompressed_data_size; 1283 uint32_t compressed_data_size; 1284 status = ReadProfileHeader(*source, 1285 &number_of_dex_files, 1286 &uncompressed_data_size, 1287 &compressed_data_size, 1288 error); 1289 1290 if (status != kProfileLoadSuccess) { 1291 return status; 1292 } 1293 // Allow large profiles for non target builds for the case where we are merging many profiles 1294 // to generate a boot image profile. 1295 if (kIsTargetBuild && uncompressed_data_size > kProfileSizeErrorThresholdInBytes) { 1296 LOG(ERROR) << "Profile data size exceeds " 1297 << std::to_string(kProfileSizeErrorThresholdInBytes) 1298 << " bytes"; 1299 return kProfileLoadBadData; 1300 } 1301 if (uncompressed_data_size > kProfileSizeWarningThresholdInBytes) { 1302 LOG(WARNING) << "Profile data size exceeds " 1303 << std::to_string(kProfileSizeWarningThresholdInBytes) 1304 << " bytes"; 1305 } 1306 1307 std::unique_ptr<uint8_t[]> compressed_data(new uint8_t[compressed_data_size]); 1308 status = source->Read(compressed_data.get(), compressed_data_size, "ReadContent", error); 1309 if (status != kProfileLoadSuccess) { 1310 *error += "Unable to read compressed profile data"; 1311 return status; 1312 } 1313 1314 if (!source->HasConsumedAllData()) { 1315 *error += "Unexpected data in the profile file."; 1316 return kProfileLoadBadData; 1317 } 1318 1319 SafeBuffer uncompressed_data(uncompressed_data_size); 1320 1321 int ret = InflateBuffer(compressed_data.get(), 1322 compressed_data_size, 1323 uncompressed_data_size, 1324 uncompressed_data.Get()); 1325 1326 if (ret != Z_STREAM_END) { 1327 *error += "Error reading uncompressed profile data"; 1328 return kProfileLoadBadData; 1329 } 1330 1331 std::vector<ProfileLineHeader> profile_line_headers; 1332 // Read profile line headers. 1333 for (uint8_t k = 0; k < number_of_dex_files; k++) { 1334 ProfileLineHeader line_header; 1335 1336 // First, read the line header to get the amount of data we need to read. 1337 status = ReadProfileLineHeader(uncompressed_data, &line_header, error); 1338 if (status != kProfileLoadSuccess) { 1339 return status; 1340 } 1341 profile_line_headers.push_back(line_header); 1342 } 1343 1344 SafeMap<uint8_t, uint8_t> dex_profile_index_remap; 1345 if (!RemapProfileIndex(profile_line_headers, filter_fn, &dex_profile_index_remap)) { 1346 return kProfileLoadBadData; 1347 } 1348 1349 for (uint8_t k = 0; k < number_of_dex_files; k++) { 1350 if (!filter_fn(profile_line_headers[k].dex_location, profile_line_headers[k].checksum)) { 1351 // We have to skip the line. Advanced the current pointer of the buffer. 1352 size_t profile_line_size = 1353 profile_line_headers[k].class_set_size * sizeof(uint16_t) + 1354 profile_line_headers[k].method_region_size_bytes + 1355 DexFileData::ComputeBitmapStorage(profile_line_headers[k].num_method_ids); 1356 uncompressed_data.Advance(profile_line_size); 1357 } else { 1358 // Now read the actual profile line. 1359 status = ReadProfileLine(uncompressed_data, 1360 number_of_dex_files, 1361 profile_line_headers[k], 1362 dex_profile_index_remap, 1363 merge_classes, 1364 error); 1365 if (status != kProfileLoadSuccess) { 1366 return status; 1367 } 1368 } 1369 } 1370 1371 // Check that we read everything and that profiles don't contain junk data. 1372 if (uncompressed_data.CountUnreadBytes() > 0) { 1373 *error = "Unexpected content in the profile file"; 1374 return kProfileLoadBadData; 1375 } else { 1376 return kProfileLoadSuccess; 1377 } 1378 } 1379 1380 bool ProfileCompilationInfo::RemapProfileIndex( 1381 const std::vector<ProfileLineHeader>& profile_line_headers, 1382 const ProfileLoadFilterFn& filter_fn, 1383 /*out*/SafeMap<uint8_t, uint8_t>* dex_profile_index_remap) { 1384 // First verify that all checksums match. This will avoid adding garbage to 1385 // the current profile info. 1386 // Note that the number of elements should be very small, so this should not 1387 // be a performance issue. 1388 for (const ProfileLineHeader other_profile_line_header : profile_line_headers) { 1389 if (!filter_fn(other_profile_line_header.dex_location, other_profile_line_header.checksum)) { 1390 continue; 1391 } 1392 // verify_checksum is false because we want to differentiate between a missing dex data and 1393 // a mismatched checksum. 1394 const DexFileData* dex_data = FindDexData(other_profile_line_header.dex_location, 1395 0u, 1396 false /* verify_checksum */); 1397 if ((dex_data != nullptr) && (dex_data->checksum != other_profile_line_header.checksum)) { 1398 LOG(WARNING) << "Checksum mismatch for dex " << other_profile_line_header.dex_location; 1399 return false; 1400 } 1401 } 1402 // All checksums match. Import the data. 1403 uint32_t num_dex_files = static_cast<uint32_t>(profile_line_headers.size()); 1404 for (uint32_t i = 0; i < num_dex_files; i++) { 1405 if (!filter_fn(profile_line_headers[i].dex_location, profile_line_headers[i].checksum)) { 1406 continue; 1407 } 1408 const DexFileData* dex_data = GetOrAddDexFileData(profile_line_headers[i].dex_location, 1409 profile_line_headers[i].checksum, 1410 profile_line_headers[i].num_method_ids); 1411 if (dex_data == nullptr) { 1412 return false; // Could happen if we exceed the number of allowed dex files. 1413 } 1414 dex_profile_index_remap->Put(i, dex_data->profile_index); 1415 } 1416 return true; 1417 } 1418 1419 std::unique_ptr<uint8_t[]> ProfileCompilationInfo::DeflateBuffer(const uint8_t* in_buffer, 1420 uint32_t in_size, 1421 uint32_t* compressed_data_size) { 1422 z_stream strm; 1423 strm.zalloc = Z_NULL; 1424 strm.zfree = Z_NULL; 1425 strm.opaque = Z_NULL; 1426 int ret = deflateInit(&strm, 1); 1427 if (ret != Z_OK) { 1428 return nullptr; 1429 } 1430 1431 uint32_t out_size = deflateBound(&strm, in_size); 1432 1433 std::unique_ptr<uint8_t[]> compressed_buffer(new uint8_t[out_size]); 1434 strm.avail_in = in_size; 1435 strm.next_in = const_cast<uint8_t*>(in_buffer); 1436 strm.avail_out = out_size; 1437 strm.next_out = &compressed_buffer[0]; 1438 ret = deflate(&strm, Z_FINISH); 1439 if (ret == Z_STREAM_ERROR) { 1440 return nullptr; 1441 } 1442 *compressed_data_size = out_size - strm.avail_out; 1443 deflateEnd(&strm); 1444 return compressed_buffer; 1445 } 1446 1447 int ProfileCompilationInfo::InflateBuffer(const uint8_t* in_buffer, 1448 uint32_t in_size, 1449 uint32_t expected_uncompressed_data_size, 1450 uint8_t* out_buffer) { 1451 z_stream strm; 1452 1453 /* allocate inflate state */ 1454 strm.zalloc = Z_NULL; 1455 strm.zfree = Z_NULL; 1456 strm.opaque = Z_NULL; 1457 strm.avail_in = in_size; 1458 strm.next_in = const_cast<uint8_t*>(in_buffer); 1459 strm.avail_out = expected_uncompressed_data_size; 1460 strm.next_out = out_buffer; 1461 1462 int ret; 1463 inflateInit(&strm); 1464 ret = inflate(&strm, Z_NO_FLUSH); 1465 1466 if (strm.avail_in != 0 || strm.avail_out != 0) { 1467 return Z_DATA_ERROR; 1468 } 1469 inflateEnd(&strm); 1470 return ret; 1471 } 1472 1473 bool ProfileCompilationInfo::MergeWith(const ProfileCompilationInfo& other, 1474 bool merge_classes) { 1475 // First verify that all checksums match. This will avoid adding garbage to 1476 // the current profile info. 1477 // Note that the number of elements should be very small, so this should not 1478 // be a performance issue. 1479 for (const DexFileData* other_dex_data : other.info_) { 1480 // verify_checksum is false because we want to differentiate between a missing dex data and 1481 // a mismatched checksum. 1482 const DexFileData* dex_data = FindDexData(other_dex_data->profile_key, 1483 0u, 1484 /* verify_checksum */ false); 1485 if ((dex_data != nullptr) && (dex_data->checksum != other_dex_data->checksum)) { 1486 LOG(WARNING) << "Checksum mismatch for dex " << other_dex_data->profile_key; 1487 return false; 1488 } 1489 } 1490 // All checksums match. Import the data. 1491 1492 // The other profile might have a different indexing of dex files. 1493 // That is because each dex files gets a 'dex_profile_index' on a first come first served basis. 1494 // That means that the order in with the methods are added to the profile matters for the 1495 // actual indices. 1496 // The reason we cannot rely on the actual multidex index is that a single profile may store 1497 // data from multiple splits. This means that a profile may contain a classes2.dex from split-A 1498 // and one from split-B. 1499 1500 // First, build a mapping from other_dex_profile_index to this_dex_profile_index. 1501 // This will make sure that the ClassReferences will point to the correct dex file. 1502 SafeMap<uint8_t, uint8_t> dex_profile_index_remap; 1503 for (const DexFileData* other_dex_data : other.info_) { 1504 const DexFileData* dex_data = GetOrAddDexFileData(other_dex_data->profile_key, 1505 other_dex_data->checksum, 1506 other_dex_data->num_method_ids); 1507 if (dex_data == nullptr) { 1508 return false; // Could happen if we exceed the number of allowed dex files. 1509 } 1510 dex_profile_index_remap.Put(other_dex_data->profile_index, dex_data->profile_index); 1511 } 1512 1513 // Merge the actual profile data. 1514 for (const DexFileData* other_dex_data : other.info_) { 1515 DexFileData* dex_data = const_cast<DexFileData*>(FindDexData(other_dex_data->profile_key, 1516 other_dex_data->checksum)); 1517 DCHECK(dex_data != nullptr); 1518 1519 // Merge the classes. 1520 if (merge_classes) { 1521 dex_data->class_set.insert(other_dex_data->class_set.begin(), 1522 other_dex_data->class_set.end()); 1523 } 1524 1525 // Merge the methods and the inline caches. 1526 for (const auto& other_method_it : other_dex_data->method_map) { 1527 uint16_t other_method_index = other_method_it.first; 1528 InlineCacheMap* inline_cache = dex_data->FindOrAddMethod(other_method_index); 1529 if (inline_cache == nullptr) { 1530 return false; 1531 } 1532 const auto& other_inline_cache = other_method_it.second; 1533 for (const auto& other_ic_it : other_inline_cache) { 1534 uint16_t other_dex_pc = other_ic_it.first; 1535 const ClassSet& other_class_set = other_ic_it.second.classes; 1536 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, other_dex_pc); 1537 if (other_ic_it.second.is_missing_types) { 1538 dex_pc_data->SetIsMissingTypes(); 1539 } else if (other_ic_it.second.is_megamorphic) { 1540 dex_pc_data->SetIsMegamorphic(); 1541 } else { 1542 for (const auto& class_it : other_class_set) { 1543 dex_pc_data->AddClass(dex_profile_index_remap.Get( 1544 class_it.dex_profile_index), class_it.type_index); 1545 } 1546 } 1547 } 1548 } 1549 1550 // Merge the method bitmaps. 1551 dex_data->MergeBitmap(*other_dex_data); 1552 } 1553 return true; 1554 } 1555 1556 const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexData( 1557 const DexFile* dex_file) const { 1558 return FindDexData(GetProfileDexFileKey(dex_file->GetLocation()), 1559 dex_file->GetLocationChecksum()); 1560 } 1561 1562 ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::GetMethodHotness( 1563 const MethodReference& method_ref) const { 1564 const DexFileData* dex_data = FindDexData(method_ref.dex_file); 1565 return dex_data != nullptr 1566 ? dex_data->GetHotnessInfo(method_ref.index) 1567 : MethodHotness(); 1568 } 1569 1570 bool ProfileCompilationInfo::AddMethodHotness(const MethodReference& method_ref, 1571 const MethodHotness& hotness) { 1572 DexFileData* dex_data = GetOrAddDexFileData(method_ref.dex_file); 1573 if (dex_data != nullptr) { 1574 // TODO: Add inline caches. 1575 return dex_data->AddMethod( 1576 static_cast<MethodHotness::Flag>(hotness.GetFlags()), method_ref.index); 1577 } 1578 return false; 1579 } 1580 1581 ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::GetMethodHotness( 1582 const std::string& dex_location, 1583 uint32_t dex_checksum, 1584 uint16_t dex_method_index) const { 1585 const DexFileData* dex_data = FindDexData(GetProfileDexFileKey(dex_location), dex_checksum); 1586 return dex_data != nullptr ? dex_data->GetHotnessInfo(dex_method_index) : MethodHotness(); 1587 } 1588 1589 1590 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> ProfileCompilationInfo::GetMethod( 1591 const std::string& dex_location, 1592 uint32_t dex_checksum, 1593 uint16_t dex_method_index) const { 1594 MethodHotness hotness(GetMethodHotness(dex_location, dex_checksum, dex_method_index)); 1595 if (!hotness.IsHot()) { 1596 return nullptr; 1597 } 1598 const InlineCacheMap* inline_caches = hotness.GetInlineCacheMap(); 1599 DCHECK(inline_caches != nullptr); 1600 std::unique_ptr<OfflineProfileMethodInfo> pmi(new OfflineProfileMethodInfo(inline_caches)); 1601 1602 pmi->dex_references.resize(info_.size()); 1603 for (const DexFileData* dex_data : info_) { 1604 pmi->dex_references[dex_data->profile_index].dex_location = dex_data->profile_key; 1605 pmi->dex_references[dex_data->profile_index].dex_checksum = dex_data->checksum; 1606 pmi->dex_references[dex_data->profile_index].num_method_ids = dex_data->num_method_ids; 1607 } 1608 1609 return pmi; 1610 } 1611 1612 1613 bool ProfileCompilationInfo::ContainsClass(const DexFile& dex_file, dex::TypeIndex type_idx) const { 1614 const DexFileData* dex_data = FindDexData(&dex_file); 1615 if (dex_data != nullptr) { 1616 const ArenaSet<dex::TypeIndex>& classes = dex_data->class_set; 1617 return classes.find(type_idx) != classes.end(); 1618 } 1619 return false; 1620 } 1621 1622 uint32_t ProfileCompilationInfo::GetNumberOfMethods() const { 1623 uint32_t total = 0; 1624 for (const DexFileData* dex_data : info_) { 1625 total += dex_data->method_map.size(); 1626 } 1627 return total; 1628 } 1629 1630 uint32_t ProfileCompilationInfo::GetNumberOfResolvedClasses() const { 1631 uint32_t total = 0; 1632 for (const DexFileData* dex_data : info_) { 1633 total += dex_data->class_set.size(); 1634 } 1635 return total; 1636 } 1637 1638 // Produce a non-owning vector from a vector. 1639 template<typename T> 1640 const std::vector<T*>* MakeNonOwningVector(const std::vector<std::unique_ptr<T>>* owning_vector) { 1641 auto non_owning_vector = new std::vector<T*>(); 1642 for (auto& element : *owning_vector) { 1643 non_owning_vector->push_back(element.get()); 1644 } 1645 return non_owning_vector; 1646 } 1647 1648 std::string ProfileCompilationInfo::DumpInfo( 1649 const std::vector<std::unique_ptr<const DexFile>>* dex_files, 1650 bool print_full_dex_location) const { 1651 std::unique_ptr<const std::vector<const DexFile*>> non_owning_dex_files( 1652 MakeNonOwningVector(dex_files)); 1653 return DumpInfo(non_owning_dex_files.get(), print_full_dex_location); 1654 } 1655 1656 std::string ProfileCompilationInfo::DumpInfo(const std::vector<const DexFile*>* dex_files, 1657 bool print_full_dex_location) const { 1658 std::ostringstream os; 1659 if (info_.empty()) { 1660 return "ProfileInfo: empty"; 1661 } 1662 1663 os << "ProfileInfo:"; 1664 1665 const std::string kFirstDexFileKeySubstitute = "!classes.dex"; 1666 1667 for (const DexFileData* dex_data : info_) { 1668 os << "\n"; 1669 if (print_full_dex_location) { 1670 os << dex_data->profile_key; 1671 } else { 1672 // Replace the (empty) multidex suffix of the first key with a substitute for easier reading. 1673 std::string multidex_suffix = DexFileLoader::GetMultiDexSuffix(dex_data->profile_key); 1674 os << (multidex_suffix.empty() ? kFirstDexFileKeySubstitute : multidex_suffix); 1675 } 1676 os << " [index=" << static_cast<uint32_t>(dex_data->profile_index) << "]"; 1677 const DexFile* dex_file = nullptr; 1678 if (dex_files != nullptr) { 1679 for (size_t i = 0; i < dex_files->size(); i++) { 1680 if (dex_data->profile_key == (*dex_files)[i]->GetLocation()) { 1681 dex_file = (*dex_files)[i]; 1682 } 1683 } 1684 } 1685 os << "\n\thot methods: "; 1686 for (const auto& method_it : dex_data->method_map) { 1687 if (dex_file != nullptr) { 1688 os << "\n\t\t" << dex_file->PrettyMethod(method_it.first, true); 1689 } else { 1690 os << method_it.first; 1691 } 1692 1693 os << "["; 1694 for (const auto& inline_cache_it : method_it.second) { 1695 os << "{" << std::hex << inline_cache_it.first << std::dec << ":"; 1696 if (inline_cache_it.second.is_missing_types) { 1697 os << "MT"; 1698 } else if (inline_cache_it.second.is_megamorphic) { 1699 os << "MM"; 1700 } else { 1701 for (const ClassReference& class_ref : inline_cache_it.second.classes) { 1702 os << "(" << static_cast<uint32_t>(class_ref.dex_profile_index) 1703 << "," << class_ref.type_index.index_ << ")"; 1704 } 1705 } 1706 os << "}"; 1707 } 1708 os << "], "; 1709 } 1710 bool startup = true; 1711 while (true) { 1712 os << "\n\t" << (startup ? "startup methods: " : "post startup methods: "); 1713 for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) { 1714 MethodHotness hotness_info(dex_data->GetHotnessInfo(method_idx)); 1715 if (startup ? hotness_info.IsStartup() : hotness_info.IsPostStartup()) { 1716 if (dex_file != nullptr) { 1717 os << "\n\t\t" << dex_file->PrettyMethod(method_idx, true); 1718 } else { 1719 os << method_idx << ", "; 1720 } 1721 } 1722 } 1723 if (startup == false) { 1724 break; 1725 } 1726 startup = false; 1727 } 1728 os << "\n\tclasses: "; 1729 for (const auto class_it : dex_data->class_set) { 1730 if (dex_file != nullptr) { 1731 os << "\n\t\t" << dex_file->PrettyType(class_it); 1732 } else { 1733 os << class_it.index_ << ","; 1734 } 1735 } 1736 } 1737 return os.str(); 1738 } 1739 1740 bool ProfileCompilationInfo::GetClassesAndMethods( 1741 const DexFile& dex_file, 1742 /*out*/std::set<dex::TypeIndex>* class_set, 1743 /*out*/std::set<uint16_t>* hot_method_set, 1744 /*out*/std::set<uint16_t>* startup_method_set, 1745 /*out*/std::set<uint16_t>* post_startup_method_method_set) const { 1746 std::set<std::string> ret; 1747 const DexFileData* dex_data = FindDexData(&dex_file); 1748 if (dex_data == nullptr) { 1749 return false; 1750 } 1751 for (const auto& it : dex_data->method_map) { 1752 hot_method_set->insert(it.first); 1753 } 1754 for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) { 1755 MethodHotness hotness = dex_data->GetHotnessInfo(method_idx); 1756 if (hotness.IsStartup()) { 1757 startup_method_set->insert(method_idx); 1758 } 1759 if (hotness.IsPostStartup()) { 1760 post_startup_method_method_set->insert(method_idx); 1761 } 1762 } 1763 for (const dex::TypeIndex& type_index : dex_data->class_set) { 1764 class_set->insert(type_index); 1765 } 1766 return true; 1767 } 1768 1769 bool ProfileCompilationInfo::Equals(const ProfileCompilationInfo& other) { 1770 // No need to compare profile_key_map_. That's only a cache for fast search. 1771 // All the information is already in the info_ vector. 1772 if (info_.size() != other.info_.size()) { 1773 return false; 1774 } 1775 for (size_t i = 0; i < info_.size(); i++) { 1776 const DexFileData& dex_data = *info_[i]; 1777 const DexFileData& other_dex_data = *other.info_[i]; 1778 if (!(dex_data == other_dex_data)) { 1779 return false; 1780 } 1781 } 1782 return true; 1783 } 1784 1785 std::set<DexCacheResolvedClasses> ProfileCompilationInfo::GetResolvedClasses( 1786 const std::vector<const DexFile*>& dex_files) const { 1787 std::unordered_map<std::string, const DexFile* > key_to_dex_file; 1788 for (const DexFile* dex_file : dex_files) { 1789 key_to_dex_file.emplace(GetProfileDexFileKey(dex_file->GetLocation()), dex_file); 1790 } 1791 std::set<DexCacheResolvedClasses> ret; 1792 for (const DexFileData* dex_data : info_) { 1793 const auto it = key_to_dex_file.find(dex_data->profile_key); 1794 if (it != key_to_dex_file.end()) { 1795 const DexFile* dex_file = it->second; 1796 const std::string& dex_location = dex_file->GetLocation(); 1797 if (dex_data->checksum != it->second->GetLocationChecksum()) { 1798 LOG(ERROR) << "Dex checksum mismatch when getting resolved classes from profile for " 1799 << "location " << dex_location << " (checksum=" << dex_file->GetLocationChecksum() 1800 << ", profile checksum=" << dex_data->checksum; 1801 return std::set<DexCacheResolvedClasses>(); 1802 } 1803 DexCacheResolvedClasses classes(dex_location, 1804 dex_location, 1805 dex_data->checksum, 1806 dex_data->num_method_ids); 1807 classes.AddClasses(dex_data->class_set.begin(), dex_data->class_set.end()); 1808 ret.insert(classes); 1809 } 1810 } 1811 return ret; 1812 } 1813 1814 // Naive implementation to generate a random profile file suitable for testing. 1815 bool ProfileCompilationInfo::GenerateTestProfile(int fd, 1816 uint16_t number_of_dex_files, 1817 uint16_t method_percentage, 1818 uint16_t class_percentage, 1819 uint32_t random_seed) { 1820 const std::string base_dex_location = "base.apk"; 1821 ProfileCompilationInfo info; 1822 // The limits are defined by the dex specification. 1823 const uint16_t max_method = std::numeric_limits<uint16_t>::max(); 1824 const uint16_t max_classes = std::numeric_limits<uint16_t>::max(); 1825 uint16_t number_of_methods = max_method * method_percentage / 100; 1826 uint16_t number_of_classes = max_classes * class_percentage / 100; 1827 1828 std::srand(random_seed); 1829 1830 // Make sure we generate more samples with a low index value. 1831 // This makes it more likely to hit valid method/class indices in small apps. 1832 const uint16_t kFavorFirstN = 10000; 1833 const uint16_t kFavorSplit = 2; 1834 1835 for (uint16_t i = 0; i < number_of_dex_files; i++) { 1836 std::string dex_location = DexFileLoader::GetMultiDexLocation(i, base_dex_location.c_str()); 1837 std::string profile_key = GetProfileDexFileKey(dex_location); 1838 1839 for (uint16_t m = 0; m < number_of_methods; m++) { 1840 uint16_t method_idx = rand() % max_method; 1841 if (m < (number_of_methods / kFavorSplit)) { 1842 method_idx %= kFavorFirstN; 1843 } 1844 // Alternate between startup and post startup. 1845 uint32_t flags = MethodHotness::kFlagHot; 1846 flags |= ((m & 1) != 0) ? MethodHotness::kFlagPostStartup : MethodHotness::kFlagStartup; 1847 info.AddMethodIndex(static_cast<MethodHotness::Flag>(flags), 1848 profile_key, 1849 /*method_idx*/ 0, 1850 method_idx, 1851 max_method); 1852 } 1853 1854 for (uint16_t c = 0; c < number_of_classes; c++) { 1855 uint16_t type_idx = rand() % max_classes; 1856 if (c < (number_of_classes / kFavorSplit)) { 1857 type_idx %= kFavorFirstN; 1858 } 1859 info.AddClassIndex(profile_key, 0, dex::TypeIndex(type_idx), max_method); 1860 } 1861 } 1862 return info.Save(fd); 1863 } 1864 1865 // Naive implementation to generate a random profile file suitable for testing. 1866 // Description of random selection: 1867 // * Select a random starting point S. 1868 // * For every index i, add (S+i) % (N - total number of methods/classes) to profile with the 1869 // probably of 1/(N - i - number of methods/classes needed to add in profile). 1870 bool ProfileCompilationInfo::GenerateTestProfile( 1871 int fd, 1872 std::vector<std::unique_ptr<const DexFile>>& dex_files, 1873 uint16_t method_percentage, 1874 uint16_t class_percentage, 1875 uint32_t random_seed) { 1876 std::srand(random_seed); 1877 ProfileCompilationInfo info; 1878 for (std::unique_ptr<const DexFile>& dex_file : dex_files) { 1879 const std::string& location = dex_file->GetLocation(); 1880 uint32_t checksum = dex_file->GetLocationChecksum(); 1881 1882 uint32_t number_of_classes = dex_file->NumClassDefs(); 1883 uint32_t classes_required_in_profile = (number_of_classes * class_percentage) / 100; 1884 uint32_t class_start_index = rand() % number_of_classes; 1885 for (uint32_t i = 0; i < number_of_classes && classes_required_in_profile; ++i) { 1886 if (number_of_classes - i == classes_required_in_profile || 1887 std::rand() % (number_of_classes - i - classes_required_in_profile) == 0) { 1888 uint32_t class_index = (i + class_start_index) % number_of_classes; 1889 info.AddClassIndex(location, 1890 checksum, 1891 dex_file->GetClassDef(class_index).class_idx_, 1892 dex_file->NumMethodIds()); 1893 classes_required_in_profile--; 1894 } 1895 } 1896 1897 uint32_t number_of_methods = dex_file->NumMethodIds(); 1898 uint32_t methods_required_in_profile = (number_of_methods * method_percentage) / 100; 1899 uint32_t method_start_index = rand() % number_of_methods; 1900 for (uint32_t i = 0; i < number_of_methods && methods_required_in_profile; ++i) { 1901 if (number_of_methods - i == methods_required_in_profile || 1902 std::rand() % (number_of_methods - i - methods_required_in_profile) == 0) { 1903 uint32_t method_index = (method_start_index + i) % number_of_methods; 1904 // Alternate between startup and post startup. 1905 uint32_t flags = MethodHotness::kFlagHot; 1906 flags |= ((method_index & 1) != 0) 1907 ? MethodHotness::kFlagPostStartup 1908 : MethodHotness::kFlagStartup; 1909 info.AddMethodIndex(static_cast<MethodHotness::Flag>(flags), 1910 MethodReference(dex_file.get(), method_index)); 1911 methods_required_in_profile--; 1912 } 1913 } 1914 } 1915 return info.Save(fd); 1916 } 1917 1918 bool ProfileCompilationInfo::OfflineProfileMethodInfo::operator==( 1919 const OfflineProfileMethodInfo& other) const { 1920 if (inline_caches->size() != other.inline_caches->size()) { 1921 return false; 1922 } 1923 1924 // We can't use a simple equality test because we need to match the dex files 1925 // of the inline caches which might have different profile indexes. 1926 for (const auto& inline_cache_it : *inline_caches) { 1927 uint16_t dex_pc = inline_cache_it.first; 1928 const DexPcData dex_pc_data = inline_cache_it.second; 1929 const auto& other_it = other.inline_caches->find(dex_pc); 1930 if (other_it == other.inline_caches->end()) { 1931 return false; 1932 } 1933 const DexPcData& other_dex_pc_data = other_it->second; 1934 if (dex_pc_data.is_megamorphic != other_dex_pc_data.is_megamorphic || 1935 dex_pc_data.is_missing_types != other_dex_pc_data.is_missing_types) { 1936 return false; 1937 } 1938 for (const ClassReference& class_ref : dex_pc_data.classes) { 1939 bool found = false; 1940 for (const ClassReference& other_class_ref : other_dex_pc_data.classes) { 1941 CHECK_LE(class_ref.dex_profile_index, dex_references.size()); 1942 CHECK_LE(other_class_ref.dex_profile_index, other.dex_references.size()); 1943 const DexReference& dex_ref = dex_references[class_ref.dex_profile_index]; 1944 const DexReference& other_dex_ref = other.dex_references[other_class_ref.dex_profile_index]; 1945 if (class_ref.type_index == other_class_ref.type_index && 1946 dex_ref == other_dex_ref) { 1947 found = true; 1948 break; 1949 } 1950 } 1951 if (!found) { 1952 return false; 1953 } 1954 } 1955 } 1956 return true; 1957 } 1958 1959 bool ProfileCompilationInfo::IsEmpty() const { 1960 DCHECK_EQ(info_.empty(), profile_key_map_.empty()); 1961 return info_.empty(); 1962 } 1963 1964 ProfileCompilationInfo::InlineCacheMap* 1965 ProfileCompilationInfo::DexFileData::FindOrAddMethod(uint16_t method_index) { 1966 if (method_index >= num_method_ids) { 1967 LOG(ERROR) << "Invalid method index " << method_index << ". num_method_ids=" << num_method_ids; 1968 return nullptr; 1969 } 1970 return &(method_map.FindOrAdd( 1971 method_index, 1972 InlineCacheMap(std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)))->second); 1973 } 1974 1975 // Mark a method as executed at least once. 1976 bool ProfileCompilationInfo::DexFileData::AddMethod(MethodHotness::Flag flags, size_t index) { 1977 if (index >= num_method_ids) { 1978 LOG(ERROR) << "Invalid method index " << index << ". num_method_ids=" << num_method_ids; 1979 return false; 1980 } 1981 1982 SetMethodHotness(index, flags); 1983 1984 if ((flags & MethodHotness::kFlagHot) != 0) { 1985 method_map.FindOrAdd( 1986 index, 1987 InlineCacheMap(std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile))); 1988 } 1989 return true; 1990 } 1991 1992 void ProfileCompilationInfo::DexFileData::SetMethodHotness(size_t index, 1993 MethodHotness::Flag flags) { 1994 DCHECK_LT(index, num_method_ids); 1995 if ((flags & MethodHotness::kFlagStartup) != 0) { 1996 method_bitmap.StoreBit(MethodBitIndex(/*startup*/ true, index), /*value*/ true); 1997 } 1998 if ((flags & MethodHotness::kFlagPostStartup) != 0) { 1999 method_bitmap.StoreBit(MethodBitIndex(/*startup*/ false, index), /*value*/ true); 2000 } 2001 } 2002 2003 ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::DexFileData::GetHotnessInfo( 2004 uint32_t dex_method_index) const { 2005 MethodHotness ret; 2006 if (method_bitmap.LoadBit(MethodBitIndex(/*startup*/ true, dex_method_index))) { 2007 ret.AddFlag(MethodHotness::kFlagStartup); 2008 } 2009 if (method_bitmap.LoadBit(MethodBitIndex(/*startup*/ false, dex_method_index))) { 2010 ret.AddFlag(MethodHotness::kFlagPostStartup); 2011 } 2012 auto it = method_map.find(dex_method_index); 2013 if (it != method_map.end()) { 2014 ret.SetInlineCacheMap(&it->second); 2015 ret.AddFlag(MethodHotness::kFlagHot); 2016 } 2017 return ret; 2018 } 2019 2020 ProfileCompilationInfo::DexPcData* 2021 ProfileCompilationInfo::FindOrAddDexPc(InlineCacheMap* inline_cache, uint32_t dex_pc) { 2022 return &(inline_cache->FindOrAdd(dex_pc, DexPcData(&allocator_))->second); 2023 } 2024 2025 std::unordered_set<std::string> ProfileCompilationInfo::GetClassDescriptors( 2026 const std::vector<const DexFile*>& dex_files) { 2027 std::unordered_set<std::string> ret; 2028 for (const DexFile* dex_file : dex_files) { 2029 const DexFileData* data = FindDexData(dex_file); 2030 if (data != nullptr) { 2031 for (dex::TypeIndex type_idx : data->class_set) { 2032 if (!dex_file->IsTypeIndexValid(type_idx)) { 2033 // Something went bad. The profile is probably corrupted. Abort and return an emtpy set. 2034 LOG(WARNING) << "Corrupted profile: invalid type index " 2035 << type_idx.index_ << " in dex " << dex_file->GetLocation(); 2036 return std::unordered_set<std::string>(); 2037 } 2038 const DexFile::TypeId& type_id = dex_file->GetTypeId(type_idx); 2039 ret.insert(dex_file->GetTypeDescriptor(type_id)); 2040 } 2041 } else { 2042 VLOG(compiler) << "Failed to find profile data for " << dex_file->GetLocation(); 2043 } 2044 } 2045 return ret; 2046 } 2047 2048 bool ProfileCompilationInfo::IsProfileFile(int fd) { 2049 // First check if it's an empty file as we allow empty profile files. 2050 // Profiles may be created by ActivityManager or installd before we manage to 2051 // process them in the runtime or profman. 2052 struct stat stat_buffer; 2053 if (fstat(fd, &stat_buffer) != 0) { 2054 return false; 2055 } 2056 2057 if (stat_buffer.st_size == 0) { 2058 return true; 2059 } 2060 2061 // The files is not empty. Check if it contains the profile magic. 2062 size_t byte_count = sizeof(kProfileMagic); 2063 uint8_t buffer[sizeof(kProfileMagic)]; 2064 if (!android::base::ReadFully(fd, buffer, byte_count)) { 2065 return false; 2066 } 2067 2068 // Reset the offset to prepare the file for reading. 2069 off_t rc = TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)); 2070 if (rc == static_cast<off_t>(-1)) { 2071 PLOG(ERROR) << "Failed to reset the offset"; 2072 return false; 2073 } 2074 2075 return memcmp(buffer, kProfileMagic, byte_count) == 0; 2076 } 2077 2078 bool ProfileCompilationInfo::UpdateProfileKeys( 2079 const std::vector<std::unique_ptr<const DexFile>>& dex_files) { 2080 for (const std::unique_ptr<const DexFile>& dex_file : dex_files) { 2081 for (DexFileData* dex_data : info_) { 2082 if (dex_data->checksum == dex_file->GetLocationChecksum() 2083 && dex_data->num_method_ids == dex_file->NumMethodIds()) { 2084 std::string new_profile_key = GetProfileDexFileKey(dex_file->GetLocation()); 2085 if (dex_data->profile_key != new_profile_key) { 2086 if (profile_key_map_.find(new_profile_key) != profile_key_map_.end()) { 2087 // We can't update the key if the new key belongs to a different dex file. 2088 LOG(ERROR) << "Cannot update profile key to " << new_profile_key 2089 << " because the new key belongs to another dex file."; 2090 return false; 2091 } 2092 profile_key_map_.erase(dex_data->profile_key); 2093 profile_key_map_.Put(new_profile_key, dex_data->profile_index); 2094 dex_data->profile_key = new_profile_key; 2095 } 2096 } 2097 } 2098 } 2099 return true; 2100 } 2101 2102 bool ProfileCompilationInfo::ProfileFilterFnAcceptAll( 2103 const std::string& dex_location ATTRIBUTE_UNUSED, 2104 uint32_t checksum ATTRIBUTE_UNUSED) { 2105 return true; 2106 } 2107 2108 void ProfileCompilationInfo::ClearData() { 2109 for (DexFileData* data : info_) { 2110 delete data; 2111 } 2112 info_.clear(); 2113 profile_key_map_.clear(); 2114 } 2115 2116 } // namespace art 2117