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