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