blob: 37a560d203cd234e3240cba5642d9d6eb4387b4d [file] [log] [blame]
Calin Juravle2e2db782016-02-23 12:00:03 +00001/*
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
Calin Juravle876f3502016-03-24 16:16:34 +000017#include "errno.h"
Calin Juravle2e2db782016-02-23 12:00:03 +000018#include <stdio.h>
19#include <stdlib.h>
20#include <sys/file.h>
21#include <sys/stat.h>
22#include <unistd.h>
23
Calin Juravle876f3502016-03-24 16:16:34 +000024#include <iostream>
Calin Juravle2e2db782016-02-23 12:00:03 +000025#include <string>
26#include <vector>
27
28#include "base/dumpable.h"
29#include "base/scoped_flock.h"
30#include "base/stringpiece.h"
31#include "base/stringprintf.h"
32#include "base/time_utils.h"
33#include "base/unix_file/fd_file.h"
34#include "jit/offline_profiling_info.h"
35#include "utils.h"
36#include "profile_assistant.h"
37
38namespace art {
39
40static int original_argc;
41static char** original_argv;
42
43static std::string CommandLine() {
44 std::vector<std::string> command;
45 for (int i = 0; i < original_argc; ++i) {
46 command.push_back(original_argv[i]);
47 }
48 return Join(command, ' ');
49}
50
51static void UsageErrorV(const char* fmt, va_list ap) {
52 std::string error;
53 StringAppendV(&error, fmt, ap);
54 LOG(ERROR) << error;
55}
56
57static void UsageError(const char* fmt, ...) {
58 va_list ap;
59 va_start(ap, fmt);
60 UsageErrorV(fmt, ap);
61 va_end(ap);
62}
63
64NO_RETURN static void Usage(const char *fmt, ...) {
65 va_list ap;
66 va_start(ap, fmt);
67 UsageErrorV(fmt, ap);
68 va_end(ap);
69
70 UsageError("Command: %s", CommandLine().c_str());
71 UsageError("Usage: profman [options]...");
72 UsageError("");
Calin Juravle876f3502016-03-24 16:16:34 +000073 UsageError(" --dump-info-for=<filename>: dumps the content of the profile file");
74 UsageError(" to standard output in a human readable form.");
75 UsageError("");
Calin Juravle2e2db782016-02-23 12:00:03 +000076 UsageError(" --profile-file=<filename>: specify profiler output file to use for compilation.");
77 UsageError(" Can be specified multiple time, in which case the data from the different");
78 UsageError(" profiles will be aggregated.");
79 UsageError("");
80 UsageError(" --profile-file-fd=<number>: same as --profile-file but accepts a file descriptor.");
81 UsageError(" Cannot be used together with --profile-file.");
82 UsageError("");
83 UsageError(" --reference-profile-file=<filename>: specify a reference profile.");
84 UsageError(" The data in this file will be compared with the data obtained by merging");
85 UsageError(" all the files specified with --profile-file or --profile-file-fd.");
86 UsageError(" If the exit code is EXIT_COMPILE then all --profile-file will be merged into");
87 UsageError(" --reference-profile-file. ");
88 UsageError("");
89 UsageError(" --reference-profile-file-fd=<number>: same as --reference-profile-file but");
90 UsageError(" accepts a file descriptor. Cannot be used together with");
91 UsageError(" --reference-profile-file.");
92 UsageError("");
93
94 exit(EXIT_FAILURE);
95}
96
97class ProfMan FINAL {
98 public:
99 ProfMan() :
100 reference_profile_file_fd_(-1),
101 start_ns_(NanoTime()) {}
102
103 ~ProfMan() {
104 LogCompletionTime();
105 }
106
107 void ParseArgs(int argc, char **argv) {
108 original_argc = argc;
109 original_argv = argv;
110
111 InitLogging(argv);
112
113 // Skip over the command name.
114 argv++;
115 argc--;
116
117 if (argc == 0) {
118 Usage("No arguments specified");
119 }
120
121 for (int i = 0; i < argc; ++i) {
122 const StringPiece option(argv[i]);
123 const bool log_options = false;
124 if (log_options) {
Calin Juravle876f3502016-03-24 16:16:34 +0000125 LOG(INFO) << "profman: option[" << i << "]=" << argv[i];
Calin Juravle2e2db782016-02-23 12:00:03 +0000126 }
Calin Juravle876f3502016-03-24 16:16:34 +0000127 if (option.starts_with("--dump-info-for=")) {
128 dump_info_for_ = option.substr(strlen("--dump-info-for=")).ToString();
129 } else if (option.starts_with("--profile-file=")) {
Calin Juravle2e2db782016-02-23 12:00:03 +0000130 profile_files_.push_back(option.substr(strlen("--profile-file=")).ToString());
131 } else if (option.starts_with("--profile-file-fd=")) {
132 ParseFdForCollection(option, "--profile-file-fd", &profile_files_fd_);
133 } else if (option.starts_with("--reference-profile-file=")) {
134 reference_profile_file_ = option.substr(strlen("--reference-profile-file=")).ToString();
135 } else if (option.starts_with("--reference-profile-file-fd=")) {
136 ParseUintOption(option, "--reference-profile-file-fd", &reference_profile_file_fd_, Usage);
137 } else {
138 Usage("Unknown argument %s", option.data());
139 }
140 }
141
Calin Juravle876f3502016-03-24 16:16:34 +0000142 bool has_profiles = !profile_files_.empty() || !profile_files_fd_.empty();
143 bool has_reference_profile = !reference_profile_file_.empty() ||
144 (reference_profile_file_fd_ != -1);
145
146 if (!dump_info_for_.empty()) {
147 if (has_profiles || has_reference_profile) {
148 Usage("dump-info-for cannot be specified together with other options");
149 }
150 return;
151 }
152 if (!has_profiles) {
Calin Juravle2e2db782016-02-23 12:00:03 +0000153 Usage("No profile files specified.");
154 }
155 if (!profile_files_.empty() && !profile_files_fd_.empty()) {
156 Usage("Profile files should not be specified with both --profile-file-fd and --profile-file");
157 }
Calin Juravle876f3502016-03-24 16:16:34 +0000158 if (!has_reference_profile) {
Calin Juravle2e2db782016-02-23 12:00:03 +0000159 Usage("--reference-profile-file-fd should only be supplied with --profile-file-fd");
160 }
161 if (reference_profile_file_.empty() && (reference_profile_file_fd_ == -1)) {
162 Usage("Reference profile file not specified");
163 }
164 }
165
166 ProfileAssistant::ProcessingResult ProcessProfiles() {
167 ProfileAssistant::ProcessingResult result;
168 if (profile_files_.empty()) {
169 // The file doesn't need to be flushed here (ProcessProfiles will do it)
170 // so don't check the usage.
171 File file(reference_profile_file_fd_, false);
172 result = ProfileAssistant::ProcessProfiles(profile_files_fd_, reference_profile_file_fd_);
173 CloseAllFds(profile_files_fd_, "profile_files_fd_");
174 } else {
175 result = ProfileAssistant::ProcessProfiles(profile_files_, reference_profile_file_);
176 }
177 return result;
178 }
179
Calin Juravle876f3502016-03-24 16:16:34 +0000180 int DumpProfileInfo() {
181 int fd = open(dump_info_for_.c_str(), O_RDWR);
182 if (fd < 0) {
183 std::cerr << "Cannot open " << dump_info_for_ << strerror(errno);
184 return -1;
185 }
186 ProfileCompilationInfo info;
187 if (!info.Load(fd)) {
188 std::cerr << "Cannot load profile info from " << dump_info_for_;
189 return -1;
190 }
191 std::string dump = info.DumpInfo(/*dex_files*/ nullptr);
192 info.Save(fd);
193 std::cout << dump << "\n";
194 return 0;
195 }
196
197 bool ShouldOnlyDumpProfile() {
198 return !dump_info_for_.empty();
199 }
200
Calin Juravle2e2db782016-02-23 12:00:03 +0000201 private:
202 static void ParseFdForCollection(const StringPiece& option,
203 const char* arg_name,
204 std::vector<int>* fds) {
205 int fd;
206 ParseUintOption(option, arg_name, &fd, Usage);
207 fds->push_back(fd);
208 }
209
210 static void CloseAllFds(const std::vector<int>& fds, const char* descriptor) {
211 for (size_t i = 0; i < fds.size(); i++) {
212 if (close(fds[i]) < 0) {
213 PLOG(WARNING) << "Failed to close descriptor for " << descriptor << " at index " << i;
214 }
215 }
216 }
217
218 void LogCompletionTime() {
David Sehr52683cf2016-05-05 09:02:38 -0700219 static constexpr uint64_t kLogThresholdTime = MsToNs(100); // 100ms
220 uint64_t time_taken = NanoTime() - start_ns_;
David Sehred793012016-05-05 13:39:43 -0700221 if (time_taken > kLogThresholdTime) {
David Sehrd8557182016-05-06 12:29:35 -0700222 LOG(WARNING) << "profman took " << PrettyDuration(time_taken);
David Sehred793012016-05-05 13:39:43 -0700223 }
Calin Juravle2e2db782016-02-23 12:00:03 +0000224 }
225
226 std::vector<std::string> profile_files_;
227 std::vector<int> profile_files_fd_;
228 std::string reference_profile_file_;
229 int reference_profile_file_fd_;
230 uint64_t start_ns_;
Calin Juravle876f3502016-03-24 16:16:34 +0000231 std::string dump_info_for_;
Calin Juravle2e2db782016-02-23 12:00:03 +0000232};
233
234// See ProfileAssistant::ProcessingResult for return codes.
235static int profman(int argc, char** argv) {
236 ProfMan profman;
237
238 // Parse arguments. Argument mistakes will lead to exit(EXIT_FAILURE) in UsageError.
239 profman.ParseArgs(argc, argv);
240
Calin Juravle876f3502016-03-24 16:16:34 +0000241 if (profman.ShouldOnlyDumpProfile()) {
242 return profman.DumpProfileInfo();
243 }
Calin Juravle2e2db782016-02-23 12:00:03 +0000244 // Process profile information and assess if we need to do a profile guided compilation.
245 // This operation involves I/O.
246 return profman.ProcessProfiles();
247}
248
249} // namespace art
250
251int main(int argc, char **argv) {
252 return art::profman(argc, argv);
253}
254