1 /* 2 * Copyright (C) 2016 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 <errno.h> 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <sys/file.h> 21 #include <sys/param.h> 22 #include <sys/stat.h> 23 #include <unistd.h> 24 25 #include <fstream> 26 #include <iostream> 27 #include <set> 28 #include <string> 29 #include <unordered_set> 30 #include <vector> 31 32 #include "android-base/stringprintf.h" 33 #include "android-base/strings.h" 34 35 #include "base/dumpable.h" 36 #include "base/logging.h" // For InitLogging. 37 #include "base/mutex.h" 38 #include "base/scoped_flock.h" 39 #include "base/stringpiece.h" 40 #include "base/time_utils.h" 41 #include "base/unix_file/fd_file.h" 42 #include "base/utils.h" 43 #include "boot_image_profile.h" 44 #include "dex/art_dex_file_loader.h" 45 #include "dex/bytecode_utils.h" 46 #include "dex/code_item_accessors-inl.h" 47 #include "dex/dex_file.h" 48 #include "dex/dex_file_loader.h" 49 #include "dex/dex_file_types.h" 50 #include "dex/type_reference.h" 51 #include "jit/profile_compilation_info.h" 52 #include "profile_assistant.h" 53 #include "runtime.h" 54 #include "zip_archive.h" 55 56 namespace art { 57 58 static int original_argc; 59 static char** original_argv; 60 61 static std::string CommandLine() { 62 std::vector<std::string> command; 63 for (int i = 0; i < original_argc; ++i) { 64 command.push_back(original_argv[i]); 65 } 66 return android::base::Join(command, ' '); 67 } 68 69 static constexpr int kInvalidFd = -1; 70 71 static bool FdIsValid(int fd) { 72 return fd != kInvalidFd; 73 } 74 75 static void UsageErrorV(const char* fmt, va_list ap) { 76 std::string error; 77 android::base::StringAppendV(&error, fmt, ap); 78 LOG(ERROR) << error; 79 } 80 81 static void UsageError(const char* fmt, ...) { 82 va_list ap; 83 va_start(ap, fmt); 84 UsageErrorV(fmt, ap); 85 va_end(ap); 86 } 87 88 NO_RETURN static void Usage(const char *fmt, ...) { 89 va_list ap; 90 va_start(ap, fmt); 91 UsageErrorV(fmt, ap); 92 va_end(ap); 93 94 UsageError("Command: %s", CommandLine().c_str()); 95 UsageError("Usage: profman [options]..."); 96 UsageError(""); 97 UsageError(" --dump-only: dumps the content of the specified profile files"); 98 UsageError(" to standard output (default) in a human readable form."); 99 UsageError(""); 100 UsageError(" --dump-output-to-fd=<number>: redirects --dump-only output to a file descriptor."); 101 UsageError(""); 102 UsageError(" --dump-classes-and-methods: dumps a sorted list of classes and methods that are"); 103 UsageError(" in the specified profile file to standard output (default) in a human"); 104 UsageError(" readable form. The output is valid input for --create-profile-from"); 105 UsageError(""); 106 UsageError(" --profile-file=<filename>: specify profiler output file to use for compilation."); 107 UsageError(" Can be specified multiple time, in which case the data from the different"); 108 UsageError(" profiles will be aggregated."); 109 UsageError(""); 110 UsageError(" --profile-file-fd=<number>: same as --profile-file but accepts a file descriptor."); 111 UsageError(" Cannot be used together with --profile-file."); 112 UsageError(""); 113 UsageError(" --reference-profile-file=<filename>: specify a reference profile."); 114 UsageError(" The data in this file will be compared with the data obtained by merging"); 115 UsageError(" all the files specified with --profile-file or --profile-file-fd."); 116 UsageError(" If the exit code is EXIT_COMPILE then all --profile-file will be merged into"); 117 UsageError(" --reference-profile-file. "); 118 UsageError(""); 119 UsageError(" --reference-profile-file-fd=<number>: same as --reference-profile-file but"); 120 UsageError(" accepts a file descriptor. Cannot be used together with"); 121 UsageError(" --reference-profile-file."); 122 UsageError(""); 123 UsageError(" --generate-test-profile=<filename>: generates a random profile file for testing."); 124 UsageError(" --generate-test-profile-num-dex=<number>: number of dex files that should be"); 125 UsageError(" included in the generated profile. Defaults to 20."); 126 UsageError(" --generate-test-profile-method-percentage=<number>: the percentage from the maximum"); 127 UsageError(" number of methods that should be generated. Defaults to 5."); 128 UsageError(" --generate-test-profile-class-percentage=<number>: the percentage from the maximum"); 129 UsageError(" number of classes that should be generated. Defaults to 5."); 130 UsageError(" --generate-test-profile-seed=<number>: seed for random number generator used when"); 131 UsageError(" generating random test profiles. Defaults to using NanoTime."); 132 UsageError(""); 133 UsageError(" --create-profile-from=<filename>: creates a profile from a list of classes and"); 134 UsageError(" methods."); 135 UsageError(""); 136 UsageError(" --dex-location=<string>: location string to use with corresponding"); 137 UsageError(" apk-fd to find dex files"); 138 UsageError(""); 139 UsageError(" --apk-fd=<number>: file descriptor containing an open APK to"); 140 UsageError(" search for dex files"); 141 UsageError(" --apk-=<filename>: an APK to search for dex files"); 142 UsageError(" --skip-apk-verification: do not attempt to verify APKs"); 143 UsageError(""); 144 UsageError(" --generate-boot-image-profile: Generate a boot image profile based on input"); 145 UsageError(" profiles. Requires passing in dex files to inspect properties of classes."); 146 UsageError(" --boot-image-class-threshold=<value>: specify minimum number of class occurrences"); 147 UsageError(" to include a class in the boot image profile. Default is 10."); 148 UsageError(" --boot-image-clean-class-threshold=<value>: specify minimum number of clean class"); 149 UsageError(" occurrences to include a class in the boot image profile. A clean class is a"); 150 UsageError(" class that doesn't have any static fields or native methods and is likely to"); 151 UsageError(" remain clean in the image. Default is 3."); 152 UsageError(" --boot-image-sampled-method-threshold=<value>: minimum number of profiles a"); 153 UsageError(" non-hot method needs to be in order to be hot in the output profile. The"); 154 UsageError(" default is max int."); 155 UsageError(" --copy-and-update-profile-key: if present, profman will copy the profile from"); 156 UsageError(" the file passed with --profile-fd(file) to the profile passed with"); 157 UsageError(" --reference-profile-fd(file) and update at the same time the profile-key"); 158 UsageError(" of entries corresponding to the apks passed with --apk(-fd)."); 159 UsageError(""); 160 161 exit(EXIT_FAILURE); 162 } 163 164 // Note: make sure you update the Usage if you change these values. 165 static constexpr uint16_t kDefaultTestProfileNumDex = 20; 166 static constexpr uint16_t kDefaultTestProfileMethodPercentage = 5; 167 static constexpr uint16_t kDefaultTestProfileClassPercentage = 5; 168 169 // Separators used when parsing human friendly representation of profiles. 170 static const std::string kMethodSep = "->"; // NOLINT [runtime/string] [4] 171 static const std::string kMissingTypesMarker = "missing_types"; // NOLINT [runtime/string] [4] 172 static const std::string kInvalidClassDescriptor = "invalid_class"; // NOLINT [runtime/string] [4] 173 static const std::string kInvalidMethod = "invalid_method"; // NOLINT [runtime/string] [4] 174 static const std::string kClassAllMethods = "*"; // NOLINT [runtime/string] [4] 175 static constexpr char kProfileParsingInlineChacheSep = '+'; 176 static constexpr char kProfileParsingTypeSep = ','; 177 static constexpr char kProfileParsingFirstCharInSignature = '('; 178 static constexpr char kMethodFlagStringHot = 'H'; 179 static constexpr char kMethodFlagStringStartup = 'S'; 180 static constexpr char kMethodFlagStringPostStartup = 'P'; 181 182 // TODO(calin): This class has grown too much from its initial design. Split the functionality 183 // into smaller, more contained pieces. 184 class ProfMan FINAL { 185 public: 186 ProfMan() : 187 reference_profile_file_fd_(kInvalidFd), 188 dump_only_(false), 189 dump_classes_and_methods_(false), 190 generate_boot_image_profile_(false), 191 dump_output_to_fd_(kInvalidFd), 192 test_profile_num_dex_(kDefaultTestProfileNumDex), 193 test_profile_method_percerntage_(kDefaultTestProfileMethodPercentage), 194 test_profile_class_percentage_(kDefaultTestProfileClassPercentage), 195 test_profile_seed_(NanoTime()), 196 start_ns_(NanoTime()), 197 copy_and_update_profile_key_(false) {} 198 199 ~ProfMan() { 200 LogCompletionTime(); 201 } 202 203 void ParseArgs(int argc, char **argv) { 204 original_argc = argc; 205 original_argv = argv; 206 207 Locks::Init(); 208 InitLogging(argv, Runtime::Abort); 209 210 // Skip over the command name. 211 argv++; 212 argc--; 213 214 if (argc == 0) { 215 Usage("No arguments specified"); 216 } 217 218 for (int i = 0; i < argc; ++i) { 219 const StringPiece option(argv[i]); 220 const bool log_options = false; 221 if (log_options) { 222 LOG(INFO) << "profman: option[" << i << "]=" << argv[i]; 223 } 224 if (option == "--dump-only") { 225 dump_only_ = true; 226 } else if (option == "--dump-classes-and-methods") { 227 dump_classes_and_methods_ = true; 228 } else if (option.starts_with("--create-profile-from=")) { 229 create_profile_from_file_ = option.substr(strlen("--create-profile-from=")).ToString(); 230 } else if (option.starts_with("--dump-output-to-fd=")) { 231 ParseUintOption(option, "--dump-output-to-fd", &dump_output_to_fd_, Usage); 232 } else if (option == "--generate-boot-image-profile") { 233 generate_boot_image_profile_ = true; 234 } else if (option.starts_with("--boot-image-class-threshold=")) { 235 ParseUintOption(option, 236 "--boot-image-class-threshold", 237 &boot_image_options_.image_class_theshold, 238 Usage); 239 } else if (option.starts_with("--boot-image-clean-class-threshold=")) { 240 ParseUintOption(option, 241 "--boot-image-clean-class-threshold", 242 &boot_image_options_.image_class_clean_theshold, 243 Usage); 244 } else if (option.starts_with("--boot-image-sampled-method-threshold=")) { 245 ParseUintOption(option, 246 "--boot-image-sampled-method-threshold", 247 &boot_image_options_.compiled_method_threshold, 248 Usage); 249 } else if (option.starts_with("--profile-file=")) { 250 profile_files_.push_back(option.substr(strlen("--profile-file=")).ToString()); 251 } else if (option.starts_with("--profile-file-fd=")) { 252 ParseFdForCollection(option, "--profile-file-fd", &profile_files_fd_); 253 } else if (option.starts_with("--reference-profile-file=")) { 254 reference_profile_file_ = option.substr(strlen("--reference-profile-file=")).ToString(); 255 } else if (option.starts_with("--reference-profile-file-fd=")) { 256 ParseUintOption(option, "--reference-profile-file-fd", &reference_profile_file_fd_, Usage); 257 } else if (option.starts_with("--dex-location=")) { 258 dex_locations_.push_back(option.substr(strlen("--dex-location=")).ToString()); 259 } else if (option.starts_with("--apk-fd=")) { 260 ParseFdForCollection(option, "--apk-fd", &apks_fd_); 261 } else if (option.starts_with("--apk=")) { 262 apk_files_.push_back(option.substr(strlen("--apk=")).ToString()); 263 } else if (option.starts_with("--generate-test-profile=")) { 264 test_profile_ = option.substr(strlen("--generate-test-profile=")).ToString(); 265 } else if (option.starts_with("--generate-test-profile-num-dex=")) { 266 ParseUintOption(option, 267 "--generate-test-profile-num-dex", 268 &test_profile_num_dex_, 269 Usage); 270 } else if (option.starts_with("--generate-test-profile-method-percentage")) { 271 ParseUintOption(option, 272 "--generate-test-profile-method-percentage", 273 &test_profile_method_percerntage_, 274 Usage); 275 } else if (option.starts_with("--generate-test-profile-class-percentage")) { 276 ParseUintOption(option, 277 "--generate-test-profile-class-percentage", 278 &test_profile_class_percentage_, 279 Usage); 280 } else if (option.starts_with("--generate-test-profile-seed=")) { 281 ParseUintOption(option, "--generate-test-profile-seed", &test_profile_seed_, Usage); 282 } else if (option.starts_with("--copy-and-update-profile-key")) { 283 copy_and_update_profile_key_ = true; 284 } else { 285 Usage("Unknown argument '%s'", option.data()); 286 } 287 } 288 289 // Validate global consistency between file/fd options. 290 if (!profile_files_.empty() && !profile_files_fd_.empty()) { 291 Usage("Profile files should not be specified with both --profile-file-fd and --profile-file"); 292 } 293 if (!reference_profile_file_.empty() && FdIsValid(reference_profile_file_fd_)) { 294 Usage("Reference profile should not be specified with both " 295 "--reference-profile-file-fd and --reference-profile-file"); 296 } 297 if (!apk_files_.empty() && !apks_fd_.empty()) { 298 Usage("APK files should not be specified with both --apk-fd and --apk"); 299 } 300 } 301 302 struct ProfileFilterKey { 303 ProfileFilterKey(const std::string& dex_location, uint32_t checksum) 304 : dex_location_(dex_location), checksum_(checksum) {} 305 const std::string dex_location_; 306 uint32_t checksum_; 307 308 bool operator==(const ProfileFilterKey& other) const { 309 return checksum_ == other.checksum_ && dex_location_ == other.dex_location_; 310 } 311 bool operator<(const ProfileFilterKey& other) const { 312 return checksum_ == other.checksum_ 313 ? dex_location_ < other.dex_location_ 314 : checksum_ < other.checksum_; 315 } 316 }; 317 318 ProfileAssistant::ProcessingResult ProcessProfiles() { 319 // Validate that at least one profile file was passed, as well as a reference profile. 320 if (profile_files_.empty() && profile_files_fd_.empty()) { 321 Usage("No profile files specified."); 322 } 323 if (reference_profile_file_.empty() && !FdIsValid(reference_profile_file_fd_)) { 324 Usage("No reference profile file specified."); 325 } 326 if ((!profile_files_.empty() && FdIsValid(reference_profile_file_fd_)) || 327 (!profile_files_fd_.empty() && !FdIsValid(reference_profile_file_fd_))) { 328 Usage("Options --profile-file-fd and --reference-profile-file-fd " 329 "should only be used together"); 330 } 331 332 // Check if we have any apks which we should use to filter the profile data. 333 std::set<ProfileFilterKey> profile_filter_keys; 334 if (!GetProfileFilterKeyFromApks(&profile_filter_keys)) { 335 return ProfileAssistant::kErrorIO; 336 } 337 338 // Build the profile filter function. If the set of keys is empty it means we 339 // don't have any apks; as such we do not filter anything. 340 const ProfileCompilationInfo::ProfileLoadFilterFn& filter_fn = 341 [profile_filter_keys](const std::string& dex_location, uint32_t checksum) { 342 if (profile_filter_keys.empty()) { 343 // No --apk was specified. Accept all dex files. 344 return true; 345 } else { 346 bool res = profile_filter_keys.find( 347 ProfileFilterKey(dex_location, checksum)) != profile_filter_keys.end(); 348 return res; 349 } 350 }; 351 352 ProfileAssistant::ProcessingResult result; 353 354 if (profile_files_.empty()) { 355 // The file doesn't need to be flushed here (ProcessProfiles will do it) 356 // so don't check the usage. 357 File file(reference_profile_file_fd_, false); 358 result = ProfileAssistant::ProcessProfiles(profile_files_fd_, 359 reference_profile_file_fd_, 360 filter_fn); 361 CloseAllFds(profile_files_fd_, "profile_files_fd_"); 362 } else { 363 result = ProfileAssistant::ProcessProfiles(profile_files_, 364 reference_profile_file_, 365 filter_fn); 366 } 367 return result; 368 } 369 370 bool GetProfileFilterKeyFromApks(std::set<ProfileFilterKey>* profile_filter_keys) { 371 auto process_fn = [profile_filter_keys](std::unique_ptr<const DexFile>&& dex_file) { 372 // Store the profile key of the location instead of the location itself. 373 // This will make the matching in the profile filter method much easier. 374 profile_filter_keys->emplace(ProfileCompilationInfo::GetProfileDexFileKey( 375 dex_file->GetLocation()), dex_file->GetLocationChecksum()); 376 }; 377 return OpenApkFilesFromLocations(process_fn); 378 } 379 380 bool OpenApkFilesFromLocations(std::vector<std::unique_ptr<const DexFile>>* dex_files) { 381 auto process_fn = [dex_files](std::unique_ptr<const DexFile>&& dex_file) { 382 dex_files->emplace_back(std::move(dex_file)); 383 }; 384 return OpenApkFilesFromLocations(process_fn); 385 } 386 387 bool OpenApkFilesFromLocations( 388 std::function<void(std::unique_ptr<const DexFile>&&)> process_fn) { 389 bool use_apk_fd_list = !apks_fd_.empty(); 390 if (use_apk_fd_list) { 391 // Get the APKs from the collection of FDs. 392 if (dex_locations_.empty()) { 393 // Try to compute the dex locations from the file paths of the descriptions. 394 // This will make it easier to invoke profman with --apk-fd and without 395 // being force to pass --dex-location when the location would be the apk path. 396 if (!ComputeDexLocationsFromApkFds()) { 397 return false; 398 } 399 } else { 400 if (dex_locations_.size() != apks_fd_.size()) { 401 Usage("The number of apk-fds must match the number of dex-locations."); 402 } 403 } 404 } else if (!apk_files_.empty()) { 405 if (dex_locations_.empty()) { 406 // If no dex locations are specified use the apk names as locations. 407 dex_locations_ = apk_files_; 408 } else if (dex_locations_.size() != apk_files_.size()) { 409 Usage("The number of apk-fds must match the number of dex-locations."); 410 } 411 } else { 412 // No APKs were specified. 413 CHECK(dex_locations_.empty()); 414 return true; 415 } 416 static constexpr bool kVerifyChecksum = true; 417 for (size_t i = 0; i < dex_locations_.size(); ++i) { 418 std::string error_msg; 419 const ArtDexFileLoader dex_file_loader; 420 std::vector<std::unique_ptr<const DexFile>> dex_files_for_location; 421 // We do not need to verify the apk for processing profiles. 422 if (use_apk_fd_list) { 423 if (dex_file_loader.OpenZip(apks_fd_[i], 424 dex_locations_[i], 425 /* verify */ false, 426 kVerifyChecksum, 427 &error_msg, 428 &dex_files_for_location)) { 429 } else { 430 LOG(ERROR) << "OpenZip failed for '" << dex_locations_[i] << "' " << error_msg; 431 return false; 432 } 433 } else { 434 if (dex_file_loader.Open(apk_files_[i].c_str(), 435 dex_locations_[i], 436 /* verify */ false, 437 kVerifyChecksum, 438 &error_msg, 439 &dex_files_for_location)) { 440 } else { 441 LOG(ERROR) << "Open failed for '" << dex_locations_[i] << "' " << error_msg; 442 return false; 443 } 444 } 445 for (std::unique_ptr<const DexFile>& dex_file : dex_files_for_location) { 446 process_fn(std::move(dex_file)); 447 } 448 } 449 return true; 450 } 451 452 // Get the dex locations from the apk fds. 453 // The methods reads the links from /proc/self/fd/ to find the original apk paths 454 // and puts them in the dex_locations_ vector. 455 bool ComputeDexLocationsFromApkFds() { 456 // We can't use a char array of PATH_MAX size without exceeding the frame size. 457 // So we use a vector as the buffer for the path. 458 std::vector<char> buffer(PATH_MAX, 0); 459 for (size_t i = 0; i < apks_fd_.size(); ++i) { 460 std::string fd_path = "/proc/self/fd/" + std::to_string(apks_fd_[i]); 461 ssize_t len = readlink(fd_path.c_str(), buffer.data(), buffer.size() - 1); 462 if (len == -1) { 463 PLOG(ERROR) << "Could not open path from fd"; 464 return false; 465 } 466 467 buffer[len] = '\0'; 468 dex_locations_.push_back(buffer.data()); 469 } 470 return true; 471 } 472 473 std::unique_ptr<const ProfileCompilationInfo> LoadProfile(const std::string& filename, int fd) { 474 if (!filename.empty()) { 475 fd = open(filename.c_str(), O_RDWR); 476 if (fd < 0) { 477 LOG(ERROR) << "Cannot open " << filename << strerror(errno); 478 return nullptr; 479 } 480 } 481 std::unique_ptr<ProfileCompilationInfo> info(new ProfileCompilationInfo); 482 if (!info->Load(fd)) { 483 LOG(ERROR) << "Cannot load profile info from fd=" << fd << "\n"; 484 return nullptr; 485 } 486 return info; 487 } 488 489 int DumpOneProfile(const std::string& banner, 490 const std::string& filename, 491 int fd, 492 const std::vector<std::unique_ptr<const DexFile>>* dex_files, 493 std::string* dump) { 494 std::unique_ptr<const ProfileCompilationInfo> info(LoadProfile(filename, fd)); 495 if (info == nullptr) { 496 LOG(ERROR) << "Cannot load profile info from filename=" << filename << " fd=" << fd; 497 return -1; 498 } 499 *dump += banner + "\n" + info->DumpInfo(dex_files) + "\n"; 500 return 0; 501 } 502 503 int DumpProfileInfo() { 504 // Validate that at least one profile file or reference was specified. 505 if (profile_files_.empty() && profile_files_fd_.empty() && 506 reference_profile_file_.empty() && !FdIsValid(reference_profile_file_fd_)) { 507 Usage("No profile files or reference profile specified."); 508 } 509 static const char* kEmptyString = ""; 510 static const char* kOrdinaryProfile = "=== profile ==="; 511 static const char* kReferenceProfile = "=== reference profile ==="; 512 513 std::vector<std::unique_ptr<const DexFile>> dex_files; 514 OpenApkFilesFromLocations(&dex_files); 515 std::string dump; 516 // Dump individual profile files. 517 if (!profile_files_fd_.empty()) { 518 for (int profile_file_fd : profile_files_fd_) { 519 int ret = DumpOneProfile(kOrdinaryProfile, 520 kEmptyString, 521 profile_file_fd, 522 &dex_files, 523 &dump); 524 if (ret != 0) { 525 return ret; 526 } 527 } 528 } 529 if (!profile_files_.empty()) { 530 for (const std::string& profile_file : profile_files_) { 531 int ret = DumpOneProfile(kOrdinaryProfile, profile_file, kInvalidFd, &dex_files, &dump); 532 if (ret != 0) { 533 return ret; 534 } 535 } 536 } 537 // Dump reference profile file. 538 if (FdIsValid(reference_profile_file_fd_)) { 539 int ret = DumpOneProfile(kReferenceProfile, 540 kEmptyString, 541 reference_profile_file_fd_, 542 &dex_files, 543 &dump); 544 if (ret != 0) { 545 return ret; 546 } 547 } 548 if (!reference_profile_file_.empty()) { 549 int ret = DumpOneProfile(kReferenceProfile, 550 reference_profile_file_, 551 kInvalidFd, 552 &dex_files, 553 &dump); 554 if (ret != 0) { 555 return ret; 556 } 557 } 558 if (!FdIsValid(dump_output_to_fd_)) { 559 std::cout << dump; 560 } else { 561 unix_file::FdFile out_fd(dump_output_to_fd_, false /*check_usage*/); 562 if (!out_fd.WriteFully(dump.c_str(), dump.length())) { 563 return -1; 564 } 565 } 566 return 0; 567 } 568 569 bool ShouldOnlyDumpProfile() { 570 return dump_only_; 571 } 572 573 bool GetClassNamesAndMethods(int fd, 574 std::vector<std::unique_ptr<const DexFile>>* dex_files, 575 std::set<std::string>* out_lines) { 576 ProfileCompilationInfo profile_info; 577 if (!profile_info.Load(fd)) { 578 LOG(ERROR) << "Cannot load profile info"; 579 return false; 580 } 581 for (const std::unique_ptr<const DexFile>& dex_file : *dex_files) { 582 std::set<dex::TypeIndex> class_types; 583 std::set<uint16_t> hot_methods; 584 std::set<uint16_t> startup_methods; 585 std::set<uint16_t> post_startup_methods; 586 std::set<uint16_t> combined_methods; 587 if (profile_info.GetClassesAndMethods(*dex_file.get(), 588 &class_types, 589 &hot_methods, 590 &startup_methods, 591 &post_startup_methods)) { 592 for (const dex::TypeIndex& type_index : class_types) { 593 const DexFile::TypeId& type_id = dex_file->GetTypeId(type_index); 594 out_lines->insert(std::string(dex_file->GetTypeDescriptor(type_id))); 595 } 596 combined_methods = hot_methods; 597 combined_methods.insert(startup_methods.begin(), startup_methods.end()); 598 combined_methods.insert(post_startup_methods.begin(), post_startup_methods.end()); 599 for (uint16_t dex_method_idx : combined_methods) { 600 const DexFile::MethodId& id = dex_file->GetMethodId(dex_method_idx); 601 std::string signature_string(dex_file->GetMethodSignature(id).ToString()); 602 std::string type_string(dex_file->GetTypeDescriptor(dex_file->GetTypeId(id.class_idx_))); 603 std::string method_name(dex_file->GetMethodName(id)); 604 std::string flags_string; 605 if (hot_methods.find(dex_method_idx) != hot_methods.end()) { 606 flags_string += kMethodFlagStringHot; 607 } 608 if (startup_methods.find(dex_method_idx) != startup_methods.end()) { 609 flags_string += kMethodFlagStringStartup; 610 } 611 if (post_startup_methods.find(dex_method_idx) != post_startup_methods.end()) { 612 flags_string += kMethodFlagStringPostStartup; 613 } 614 out_lines->insert(flags_string + 615 type_string + 616 kMethodSep + 617 method_name + 618 signature_string); 619 } 620 } 621 } 622 return true; 623 } 624 625 bool GetClassNamesAndMethods(const std::string& profile_file, 626 std::vector<std::unique_ptr<const DexFile>>* dex_files, 627 std::set<std::string>* out_lines) { 628 int fd = open(profile_file.c_str(), O_RDONLY); 629 if (!FdIsValid(fd)) { 630 LOG(ERROR) << "Cannot open " << profile_file << strerror(errno); 631 return false; 632 } 633 if (!GetClassNamesAndMethods(fd, dex_files, out_lines)) { 634 return false; 635 } 636 if (close(fd) < 0) { 637 PLOG(WARNING) << "Failed to close descriptor"; 638 } 639 return true; 640 } 641 642 int DumpClassesAndMethods() { 643 // Validate that at least one profile file or reference was specified. 644 if (profile_files_.empty() && profile_files_fd_.empty() && 645 reference_profile_file_.empty() && !FdIsValid(reference_profile_file_fd_)) { 646 Usage("No profile files or reference profile specified."); 647 } 648 649 // Open the dex files to get the names for classes. 650 std::vector<std::unique_ptr<const DexFile>> dex_files; 651 OpenApkFilesFromLocations(&dex_files); 652 // Build a vector of class names from individual profile files. 653 std::set<std::string> class_names; 654 if (!profile_files_fd_.empty()) { 655 for (int profile_file_fd : profile_files_fd_) { 656 if (!GetClassNamesAndMethods(profile_file_fd, &dex_files, &class_names)) { 657 return -1; 658 } 659 } 660 } 661 if (!profile_files_.empty()) { 662 for (const std::string& profile_file : profile_files_) { 663 if (!GetClassNamesAndMethods(profile_file, &dex_files, &class_names)) { 664 return -1; 665 } 666 } 667 } 668 // Concatenate class names from reference profile file. 669 if (FdIsValid(reference_profile_file_fd_)) { 670 if (!GetClassNamesAndMethods(reference_profile_file_fd_, &dex_files, &class_names)) { 671 return -1; 672 } 673 } 674 if (!reference_profile_file_.empty()) { 675 if (!GetClassNamesAndMethods(reference_profile_file_, &dex_files, &class_names)) { 676 return -1; 677 } 678 } 679 // Dump the class names. 680 std::string dump; 681 for (const std::string& class_name : class_names) { 682 dump += class_name + std::string("\n"); 683 } 684 if (!FdIsValid(dump_output_to_fd_)) { 685 std::cout << dump; 686 } else { 687 unix_file::FdFile out_fd(dump_output_to_fd_, false /*check_usage*/); 688 if (!out_fd.WriteFully(dump.c_str(), dump.length())) { 689 return -1; 690 } 691 } 692 return 0; 693 } 694 695 bool ShouldOnlyDumpClassesAndMethods() { 696 return dump_classes_and_methods_; 697 } 698 699 // Read lines from the given file, dropping comments and empty lines. Post-process each line with 700 // the given function. 701 template <typename T> 702 static T* ReadCommentedInputFromFile( 703 const char* input_filename, std::function<std::string(const char*)>* process) { 704 std::unique_ptr<std::ifstream> input_file(new std::ifstream(input_filename, std::ifstream::in)); 705 if (input_file.get() == nullptr) { 706 LOG(ERROR) << "Failed to open input file " << input_filename; 707 return nullptr; 708 } 709 std::unique_ptr<T> result( 710 ReadCommentedInputStream<T>(*input_file, process)); 711 input_file->close(); 712 return result.release(); 713 } 714 715 // Read lines from the given stream, dropping comments and empty lines. Post-process each line 716 // with the given function. 717 template <typename T> 718 static T* ReadCommentedInputStream( 719 std::istream& in_stream, 720 std::function<std::string(const char*)>* process) { 721 std::unique_ptr<T> output(new T()); 722 while (in_stream.good()) { 723 std::string dot; 724 std::getline(in_stream, dot); 725 if (android::base::StartsWith(dot, "#") || dot.empty()) { 726 continue; 727 } 728 if (process != nullptr) { 729 std::string descriptor((*process)(dot.c_str())); 730 output->insert(output->end(), descriptor); 731 } else { 732 output->insert(output->end(), dot); 733 } 734 } 735 return output.release(); 736 } 737 738 // Find class klass_descriptor in the given dex_files and store its reference 739 // in the out parameter class_ref. 740 // Return true if the definition of the class was found in any of the dex_files. 741 bool FindClass(const std::vector<std::unique_ptr<const DexFile>>& dex_files, 742 const std::string& klass_descriptor, 743 /*out*/TypeReference* class_ref) { 744 constexpr uint16_t kInvalidTypeIndex = std::numeric_limits<uint16_t>::max() - 1; 745 for (const std::unique_ptr<const DexFile>& dex_file_ptr : dex_files) { 746 const DexFile* dex_file = dex_file_ptr.get(); 747 if (klass_descriptor == kInvalidClassDescriptor) { 748 if (kInvalidTypeIndex >= dex_file->NumTypeIds()) { 749 // The dex file does not contain all possible type ids which leaves us room 750 // to add an "invalid" type id. 751 *class_ref = TypeReference(dex_file, dex::TypeIndex(kInvalidTypeIndex)); 752 return true; 753 } else { 754 // The dex file contains all possible type ids. We don't have any free type id 755 // that we can use as invalid. 756 continue; 757 } 758 } 759 760 const DexFile::TypeId* type_id = dex_file->FindTypeId(klass_descriptor.c_str()); 761 if (type_id == nullptr) { 762 continue; 763 } 764 dex::TypeIndex type_index = dex_file->GetIndexForTypeId(*type_id); 765 if (dex_file->FindClassDef(type_index) == nullptr) { 766 // Class is only referenced in the current dex file but not defined in it. 767 continue; 768 } 769 *class_ref = TypeReference(dex_file, type_index); 770 return true; 771 } 772 return false; 773 } 774 775 // Find the method specified by method_spec in the class class_ref. 776 uint32_t FindMethodIndex(const TypeReference& class_ref, 777 const std::string& method_spec) { 778 const DexFile* dex_file = class_ref.dex_file; 779 if (method_spec == kInvalidMethod) { 780 constexpr uint16_t kInvalidMethodIndex = std::numeric_limits<uint16_t>::max() - 1; 781 return kInvalidMethodIndex >= dex_file->NumMethodIds() 782 ? kInvalidMethodIndex 783 : dex::kDexNoIndex; 784 } 785 786 std::vector<std::string> name_and_signature; 787 Split(method_spec, kProfileParsingFirstCharInSignature, &name_and_signature); 788 if (name_and_signature.size() != 2) { 789 LOG(ERROR) << "Invalid method name and signature " << method_spec; 790 return dex::kDexNoIndex; 791 } 792 793 const std::string& name = name_and_signature[0]; 794 const std::string& signature = kProfileParsingFirstCharInSignature + name_and_signature[1]; 795 796 const DexFile::StringId* name_id = dex_file->FindStringId(name.c_str()); 797 if (name_id == nullptr) { 798 LOG(WARNING) << "Could not find name: " << name; 799 return dex::kDexNoIndex; 800 } 801 dex::TypeIndex return_type_idx; 802 std::vector<dex::TypeIndex> param_type_idxs; 803 if (!dex_file->CreateTypeList(signature, &return_type_idx, ¶m_type_idxs)) { 804 LOG(WARNING) << "Could not create type list" << signature; 805 return dex::kDexNoIndex; 806 } 807 const DexFile::ProtoId* proto_id = dex_file->FindProtoId(return_type_idx, param_type_idxs); 808 if (proto_id == nullptr) { 809 LOG(WARNING) << "Could not find proto_id: " << name; 810 return dex::kDexNoIndex; 811 } 812 const DexFile::MethodId* method_id = dex_file->FindMethodId( 813 dex_file->GetTypeId(class_ref.TypeIndex()), *name_id, *proto_id); 814 if (method_id == nullptr) { 815 LOG(WARNING) << "Could not find method_id: " << name; 816 return dex::kDexNoIndex; 817 } 818 819 return dex_file->GetIndexForMethodId(*method_id); 820 } 821 822 // Given a method, return true if the method has a single INVOKE_VIRTUAL in its byte code. 823 // Upon success it returns true and stores the method index and the invoke dex pc 824 // in the output parameters. 825 // The format of the method spec is "inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;". 826 // 827 // TODO(calin): support INVOKE_INTERFACE and the range variants. 828 bool HasSingleInvoke(const TypeReference& class_ref, 829 uint16_t method_index, 830 /*out*/uint32_t* dex_pc) { 831 const DexFile* dex_file = class_ref.dex_file; 832 uint32_t offset = dex_file->FindCodeItemOffset( 833 *dex_file->FindClassDef(class_ref.TypeIndex()), 834 method_index); 835 const DexFile::CodeItem* code_item = dex_file->GetCodeItem(offset); 836 837 bool found_invoke = false; 838 for (const DexInstructionPcPair& inst : CodeItemInstructionAccessor(*dex_file, code_item)) { 839 if (inst->Opcode() == Instruction::INVOKE_VIRTUAL) { 840 if (found_invoke) { 841 LOG(ERROR) << "Multiple invoke INVOKE_VIRTUAL found: " 842 << dex_file->PrettyMethod(method_index); 843 return false; 844 } 845 found_invoke = true; 846 *dex_pc = inst.DexPc(); 847 } 848 } 849 if (!found_invoke) { 850 LOG(ERROR) << "Could not find any INVOKE_VIRTUAL: " << dex_file->PrettyMethod(method_index); 851 } 852 return found_invoke; 853 } 854 855 // Process a line defining a class or a method and its inline caches. 856 // Upon success return true and add the class or the method info to profile. 857 // The possible line formats are: 858 // "LJustTheCass;". 859 // "LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;". 860 // "LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,invalid_class". 861 // "LTestInline;->inlineMissingTypes(LSuper;)I+missing_types". 862 // "LTestInline;->inlineNoInlineCaches(LSuper;)I". 863 // "LTestInline;->*". 864 // "invalid_class". 865 // "LTestInline;->invalid_method". 866 // The method and classes are searched only in the given dex files. 867 bool ProcessLine(const std::vector<std::unique_ptr<const DexFile>>& dex_files, 868 const std::string& line, 869 /*out*/ProfileCompilationInfo* profile) { 870 std::string klass; 871 std::string method_str; 872 bool is_hot = false; 873 bool is_startup = false; 874 bool is_post_startup = false; 875 const size_t method_sep_index = line.find(kMethodSep, 0); 876 if (method_sep_index == std::string::npos) { 877 klass = line.substr(0); 878 } else { 879 // The method prefix flags are only valid for method strings. 880 size_t start_index = 0; 881 while (start_index < line.size() && line[start_index] != 'L') { 882 const char c = line[start_index]; 883 if (c == kMethodFlagStringHot) { 884 is_hot = true; 885 } else if (c == kMethodFlagStringStartup) { 886 is_startup = true; 887 } else if (c == kMethodFlagStringPostStartup) { 888 is_post_startup = true; 889 } else { 890 LOG(WARNING) << "Invalid flag " << c; 891 return false; 892 } 893 ++start_index; 894 } 895 klass = line.substr(start_index, method_sep_index - start_index); 896 method_str = line.substr(method_sep_index + kMethodSep.size()); 897 } 898 899 uint32_t flags = 0; 900 if (is_hot) { 901 flags |= ProfileCompilationInfo::MethodHotness::kFlagHot; 902 } 903 if (is_startup) { 904 flags |= ProfileCompilationInfo::MethodHotness::kFlagStartup; 905 } 906 if (is_post_startup) { 907 flags |= ProfileCompilationInfo::MethodHotness::kFlagPostStartup; 908 } 909 910 TypeReference class_ref(/* dex_file */ nullptr, dex::TypeIndex()); 911 if (!FindClass(dex_files, klass, &class_ref)) { 912 LOG(WARNING) << "Could not find class: " << klass; 913 return false; 914 } 915 916 if (method_str.empty() || method_str == kClassAllMethods) { 917 // Start by adding the class. 918 std::set<DexCacheResolvedClasses> resolved_class_set; 919 const DexFile* dex_file = class_ref.dex_file; 920 const auto& dex_resolved_classes = resolved_class_set.emplace( 921 dex_file->GetLocation(), 922 DexFileLoader::GetBaseLocation(dex_file->GetLocation()), 923 dex_file->GetLocationChecksum(), 924 dex_file->NumMethodIds()); 925 dex_resolved_classes.first->AddClass(class_ref.TypeIndex()); 926 std::vector<ProfileMethodInfo> methods; 927 if (method_str == kClassAllMethods) { 928 // Add all of the methods. 929 const DexFile::ClassDef* class_def = dex_file->FindClassDef(class_ref.TypeIndex()); 930 const uint8_t* class_data = dex_file->GetClassData(*class_def); 931 if (class_data != nullptr) { 932 ClassDataItemIterator it(*dex_file, class_data); 933 it.SkipAllFields(); 934 while (it.HasNextMethod()) { 935 if (it.GetMethodCodeItemOffset() != 0) { 936 // Add all of the methods that have code to the profile. 937 const uint32_t method_idx = it.GetMemberIndex(); 938 methods.push_back(ProfileMethodInfo(MethodReference(dex_file, method_idx))); 939 } 940 it.Next(); 941 } 942 } 943 } 944 // TODO: Check return values? 945 profile->AddMethods(methods, static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags)); 946 profile->AddClasses(resolved_class_set); 947 return true; 948 } 949 950 // Process the method. 951 std::string method_spec; 952 std::vector<std::string> inline_cache_elems; 953 954 // If none of the flags are set, default to hot. 955 is_hot = is_hot || (!is_hot && !is_startup && !is_post_startup); 956 957 std::vector<std::string> method_elems; 958 bool is_missing_types = false; 959 Split(method_str, kProfileParsingInlineChacheSep, &method_elems); 960 if (method_elems.size() == 2) { 961 method_spec = method_elems[0]; 962 is_missing_types = method_elems[1] == kMissingTypesMarker; 963 if (!is_missing_types) { 964 Split(method_elems[1], kProfileParsingTypeSep, &inline_cache_elems); 965 } 966 } else if (method_elems.size() == 1) { 967 method_spec = method_elems[0]; 968 } else { 969 LOG(ERROR) << "Invalid method line: " << line; 970 return false; 971 } 972 973 const uint32_t method_index = FindMethodIndex(class_ref, method_spec); 974 if (method_index == dex::kDexNoIndex) { 975 return false; 976 } 977 978 std::vector<ProfileMethodInfo::ProfileInlineCache> inline_caches; 979 if (is_missing_types || !inline_cache_elems.empty()) { 980 uint32_t dex_pc; 981 if (!HasSingleInvoke(class_ref, method_index, &dex_pc)) { 982 return false; 983 } 984 std::vector<TypeReference> classes(inline_cache_elems.size(), 985 TypeReference(/* dex_file */ nullptr, dex::TypeIndex())); 986 size_t class_it = 0; 987 for (const std::string& ic_class : inline_cache_elems) { 988 if (!FindClass(dex_files, ic_class, &(classes[class_it++]))) { 989 LOG(ERROR) << "Could not find class: " << ic_class; 990 return false; 991 } 992 } 993 inline_caches.emplace_back(dex_pc, is_missing_types, classes); 994 } 995 MethodReference ref(class_ref.dex_file, method_index); 996 if (is_hot) { 997 profile->AddMethod(ProfileMethodInfo(ref, inline_caches), 998 static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags)); 999 } 1000 if (flags != 0) { 1001 if (!profile->AddMethodIndex( 1002 static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags), ref)) { 1003 return false; 1004 } 1005 DCHECK(profile->GetMethodHotness(ref).IsInProfile()); 1006 } 1007 return true; 1008 } 1009 1010 int OpenReferenceProfile() const { 1011 int fd = reference_profile_file_fd_; 1012 if (!FdIsValid(fd)) { 1013 CHECK(!reference_profile_file_.empty()); 1014 fd = open(reference_profile_file_.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0644); 1015 if (fd < 0) { 1016 LOG(ERROR) << "Cannot open " << reference_profile_file_ << strerror(errno); 1017 return kInvalidFd; 1018 } 1019 } 1020 return fd; 1021 } 1022 1023 // Creates a profile from a human friendly textual representation. 1024 // The expected input format is: 1025 // # Classes 1026 // Ljava/lang/Comparable; 1027 // Ljava/lang/Math; 1028 // # Methods with inline caches 1029 // LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC; 1030 // LTestInline;->noInlineCache(LSuper;)I 1031 int CreateProfile() { 1032 // Validate parameters for this command. 1033 if (apk_files_.empty() && apks_fd_.empty()) { 1034 Usage("APK files must be specified"); 1035 } 1036 if (dex_locations_.empty()) { 1037 Usage("DEX locations must be specified"); 1038 } 1039 if (reference_profile_file_.empty() && !FdIsValid(reference_profile_file_fd_)) { 1040 Usage("Reference profile must be specified with --reference-profile-file or " 1041 "--reference-profile-file-fd"); 1042 } 1043 if (!profile_files_.empty() || !profile_files_fd_.empty()) { 1044 Usage("Profile must be specified with --reference-profile-file or " 1045 "--reference-profile-file-fd"); 1046 } 1047 // Open the profile output file if needed. 1048 int fd = OpenReferenceProfile(); 1049 if (!FdIsValid(fd)) { 1050 return -1; 1051 } 1052 // Read the user-specified list of classes and methods. 1053 std::unique_ptr<std::unordered_set<std::string>> 1054 user_lines(ReadCommentedInputFromFile<std::unordered_set<std::string>>( 1055 create_profile_from_file_.c_str(), nullptr)); // No post-processing. 1056 1057 // Open the dex files to look up classes and methods. 1058 std::vector<std::unique_ptr<const DexFile>> dex_files; 1059 OpenApkFilesFromLocations(&dex_files); 1060 1061 // Process the lines one by one and add the successful ones to the profile. 1062 ProfileCompilationInfo info; 1063 1064 for (const auto& line : *user_lines) { 1065 ProcessLine(dex_files, line, &info); 1066 } 1067 1068 // Write the profile file. 1069 CHECK(info.Save(fd)); 1070 if (close(fd) < 0) { 1071 PLOG(WARNING) << "Failed to close descriptor"; 1072 } 1073 return 0; 1074 } 1075 1076 bool ShouldCreateBootProfile() const { 1077 return generate_boot_image_profile_; 1078 } 1079 1080 int CreateBootProfile() { 1081 // Open the profile output file. 1082 const int reference_fd = OpenReferenceProfile(); 1083 if (!FdIsValid(reference_fd)) { 1084 PLOG(ERROR) << "Error opening reference profile"; 1085 return -1; 1086 } 1087 // Open the dex files. 1088 std::vector<std::unique_ptr<const DexFile>> dex_files; 1089 OpenApkFilesFromLocations(&dex_files); 1090 if (dex_files.empty()) { 1091 PLOG(ERROR) << "Expected dex files for creating boot profile"; 1092 return -2; 1093 } 1094 // Open the input profiles. 1095 std::vector<std::unique_ptr<const ProfileCompilationInfo>> profiles; 1096 if (!profile_files_fd_.empty()) { 1097 for (int profile_file_fd : profile_files_fd_) { 1098 std::unique_ptr<const ProfileCompilationInfo> profile(LoadProfile("", profile_file_fd)); 1099 if (profile == nullptr) { 1100 return -3; 1101 } 1102 profiles.emplace_back(std::move(profile)); 1103 } 1104 } 1105 if (!profile_files_.empty()) { 1106 for (const std::string& profile_file : profile_files_) { 1107 std::unique_ptr<const ProfileCompilationInfo> profile(LoadProfile(profile_file, kInvalidFd)); 1108 if (profile == nullptr) { 1109 return -4; 1110 } 1111 profiles.emplace_back(std::move(profile)); 1112 } 1113 } 1114 ProfileCompilationInfo out_profile; 1115 GenerateBootImageProfile(dex_files, 1116 profiles, 1117 boot_image_options_, 1118 VLOG_IS_ON(profiler), 1119 &out_profile); 1120 out_profile.Save(reference_fd); 1121 close(reference_fd); 1122 return 0; 1123 } 1124 1125 bool ShouldCreateProfile() { 1126 return !create_profile_from_file_.empty(); 1127 } 1128 1129 int GenerateTestProfile() { 1130 // Validate parameters for this command. 1131 if (test_profile_method_percerntage_ > 100) { 1132 Usage("Invalid percentage for --generate-test-profile-method-percentage"); 1133 } 1134 if (test_profile_class_percentage_ > 100) { 1135 Usage("Invalid percentage for --generate-test-profile-class-percentage"); 1136 } 1137 // If given APK files or DEX locations, check that they're ok. 1138 if (!apk_files_.empty() || !apks_fd_.empty() || !dex_locations_.empty()) { 1139 if (apk_files_.empty() && apks_fd_.empty()) { 1140 Usage("APK files must be specified when passing DEX locations to --generate-test-profile"); 1141 } 1142 if (dex_locations_.empty()) { 1143 Usage("DEX locations must be specified when passing APK files to --generate-test-profile"); 1144 } 1145 } 1146 // ShouldGenerateTestProfile confirms !test_profile_.empty(). 1147 int profile_test_fd = open(test_profile_.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0644); 1148 if (profile_test_fd < 0) { 1149 LOG(ERROR) << "Cannot open " << test_profile_ << strerror(errno); 1150 return -1; 1151 } 1152 bool result; 1153 if (apk_files_.empty() && apks_fd_.empty() && dex_locations_.empty()) { 1154 result = ProfileCompilationInfo::GenerateTestProfile(profile_test_fd, 1155 test_profile_num_dex_, 1156 test_profile_method_percerntage_, 1157 test_profile_class_percentage_, 1158 test_profile_seed_); 1159 } else { 1160 // Open the dex files to look up classes and methods. 1161 std::vector<std::unique_ptr<const DexFile>> dex_files; 1162 OpenApkFilesFromLocations(&dex_files); 1163 // Create a random profile file based on the set of dex files. 1164 result = ProfileCompilationInfo::GenerateTestProfile(profile_test_fd, 1165 dex_files, 1166 test_profile_method_percerntage_, 1167 test_profile_class_percentage_, 1168 test_profile_seed_); 1169 } 1170 close(profile_test_fd); // ignore close result. 1171 return result ? 0 : -1; 1172 } 1173 1174 bool ShouldGenerateTestProfile() { 1175 return !test_profile_.empty(); 1176 } 1177 1178 bool ShouldCopyAndUpdateProfileKey() const { 1179 return copy_and_update_profile_key_; 1180 } 1181 1182 int32_t CopyAndUpdateProfileKey() { 1183 // Validate that at least one profile file was passed, as well as a reference profile. 1184 if (!(profile_files_.size() == 1 ^ profile_files_fd_.size() == 1)) { 1185 Usage("Only one profile file should be specified."); 1186 } 1187 if (reference_profile_file_.empty() && !FdIsValid(reference_profile_file_fd_)) { 1188 Usage("No reference profile file specified."); 1189 } 1190 1191 if (apk_files_.empty() && apks_fd_.empty()) { 1192 Usage("No apk files specified"); 1193 } 1194 1195 static constexpr int32_t kErrorFailedToUpdateProfile = -1; 1196 static constexpr int32_t kErrorFailedToSaveProfile = -2; 1197 static constexpr int32_t kErrorFailedToLoadProfile = -3; 1198 1199 bool use_fds = profile_files_fd_.size() == 1; 1200 1201 ProfileCompilationInfo profile; 1202 // Do not clear if invalid. The input might be an archive. 1203 bool load_ok = use_fds 1204 ? profile.Load(profile_files_fd_[0]) 1205 : profile.Load(profile_files_[0], /*clear_if_invalid*/ false); 1206 if (load_ok) { 1207 // Open the dex files to look up classes and methods. 1208 std::vector<std::unique_ptr<const DexFile>> dex_files; 1209 OpenApkFilesFromLocations(&dex_files); 1210 if (!profile.UpdateProfileKeys(dex_files)) { 1211 return kErrorFailedToUpdateProfile; 1212 } 1213 bool result = use_fds 1214 ? profile.Save(reference_profile_file_fd_) 1215 : profile.Save(reference_profile_file_, /*bytes_written*/ nullptr); 1216 return result ? 0 : kErrorFailedToSaveProfile; 1217 } else { 1218 return kErrorFailedToLoadProfile; 1219 } 1220 } 1221 1222 private: 1223 static void ParseFdForCollection(const StringPiece& option, 1224 const char* arg_name, 1225 std::vector<int>* fds) { 1226 int fd; 1227 ParseUintOption(option, arg_name, &fd, Usage); 1228 fds->push_back(fd); 1229 } 1230 1231 static void CloseAllFds(const std::vector<int>& fds, const char* descriptor) { 1232 for (size_t i = 0; i < fds.size(); i++) { 1233 if (close(fds[i]) < 0) { 1234 PLOG(WARNING) << "Failed to close descriptor for " 1235 << descriptor << " at index " << i << ": " << fds[i]; 1236 } 1237 } 1238 } 1239 1240 void LogCompletionTime() { 1241 static constexpr uint64_t kLogThresholdTime = MsToNs(100); // 100ms 1242 uint64_t time_taken = NanoTime() - start_ns_; 1243 if (time_taken > kLogThresholdTime) { 1244 LOG(WARNING) << "profman took " << PrettyDuration(time_taken); 1245 } 1246 } 1247 1248 std::vector<std::string> profile_files_; 1249 std::vector<int> profile_files_fd_; 1250 std::vector<std::string> dex_locations_; 1251 std::vector<std::string> apk_files_; 1252 std::vector<int> apks_fd_; 1253 std::string reference_profile_file_; 1254 int reference_profile_file_fd_; 1255 bool dump_only_; 1256 bool dump_classes_and_methods_; 1257 bool generate_boot_image_profile_; 1258 int dump_output_to_fd_; 1259 BootImageOptions boot_image_options_; 1260 std::string test_profile_; 1261 std::string create_profile_from_file_; 1262 uint16_t test_profile_num_dex_; 1263 uint16_t test_profile_method_percerntage_; 1264 uint16_t test_profile_class_percentage_; 1265 uint32_t test_profile_seed_; 1266 uint64_t start_ns_; 1267 bool copy_and_update_profile_key_; 1268 }; 1269 1270 // See ProfileAssistant::ProcessingResult for return codes. 1271 static int profman(int argc, char** argv) { 1272 ProfMan profman; 1273 1274 // Parse arguments. Argument mistakes will lead to exit(EXIT_FAILURE) in UsageError. 1275 profman.ParseArgs(argc, argv); 1276 1277 // Initialize MemMap for ZipArchive::OpenFromFd. 1278 MemMap::Init(); 1279 1280 if (profman.ShouldGenerateTestProfile()) { 1281 return profman.GenerateTestProfile(); 1282 } 1283 if (profman.ShouldOnlyDumpProfile()) { 1284 return profman.DumpProfileInfo(); 1285 } 1286 if (profman.ShouldOnlyDumpClassesAndMethods()) { 1287 return profman.DumpClassesAndMethods(); 1288 } 1289 if (profman.ShouldCreateProfile()) { 1290 return profman.CreateProfile(); 1291 } 1292 1293 if (profman.ShouldCreateBootProfile()) { 1294 return profman.CreateBootProfile(); 1295 } 1296 1297 if (profman.ShouldCopyAndUpdateProfileKey()) { 1298 return profman.CopyAndUpdateProfileKey(); 1299 } 1300 1301 // Process profile information and assess if we need to do a profile guided compilation. 1302 // This operation involves I/O. 1303 return profman.ProcessProfiles(); 1304 } 1305 1306 } // namespace art 1307 1308 int main(int argc, char **argv) { 1309 return art::profman(argc, argv); 1310 } 1311 1312