blob: 7c9e449ed5a46b610cc94131e11875a2d9d674d0 [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
17#include <stdio.h>
18#include <stdlib.h>
19#include <sys/file.h>
20#include <sys/stat.h>
21#include <unistd.h>
22
23#include <string>
24#include <vector>
25
26#include "base/dumpable.h"
27#include "base/scoped_flock.h"
28#include "base/stringpiece.h"
29#include "base/stringprintf.h"
30#include "base/time_utils.h"
31#include "base/unix_file/fd_file.h"
32#include "jit/offline_profiling_info.h"
33#include "utils.h"
34#include "profile_assistant.h"
35
36namespace art {
37
38static int original_argc;
39static char** original_argv;
40
41static std::string CommandLine() {
42 std::vector<std::string> command;
43 for (int i = 0; i < original_argc; ++i) {
44 command.push_back(original_argv[i]);
45 }
46 return Join(command, ' ');
47}
48
49static void UsageErrorV(const char* fmt, va_list ap) {
50 std::string error;
51 StringAppendV(&error, fmt, ap);
52 LOG(ERROR) << error;
53}
54
55static void UsageError(const char* fmt, ...) {
56 va_list ap;
57 va_start(ap, fmt);
58 UsageErrorV(fmt, ap);
59 va_end(ap);
60}
61
62NO_RETURN static void Usage(const char *fmt, ...) {
63 va_list ap;
64 va_start(ap, fmt);
65 UsageErrorV(fmt, ap);
66 va_end(ap);
67
68 UsageError("Command: %s", CommandLine().c_str());
69 UsageError("Usage: profman [options]...");
70 UsageError("");
71 UsageError(" --profile-file=<filename>: specify profiler output file to use for compilation.");
72 UsageError(" Can be specified multiple time, in which case the data from the different");
73 UsageError(" profiles will be aggregated.");
74 UsageError("");
75 UsageError(" --profile-file-fd=<number>: same as --profile-file but accepts a file descriptor.");
76 UsageError(" Cannot be used together with --profile-file.");
77 UsageError("");
78 UsageError(" --reference-profile-file=<filename>: specify a reference profile.");
79 UsageError(" The data in this file will be compared with the data obtained by merging");
80 UsageError(" all the files specified with --profile-file or --profile-file-fd.");
81 UsageError(" If the exit code is EXIT_COMPILE then all --profile-file will be merged into");
82 UsageError(" --reference-profile-file. ");
83 UsageError("");
84 UsageError(" --reference-profile-file-fd=<number>: same as --reference-profile-file but");
85 UsageError(" accepts a file descriptor. Cannot be used together with");
86 UsageError(" --reference-profile-file.");
87 UsageError("");
88
89 exit(EXIT_FAILURE);
90}
91
92class ProfMan FINAL {
93 public:
94 ProfMan() :
95 reference_profile_file_fd_(-1),
96 start_ns_(NanoTime()) {}
97
98 ~ProfMan() {
99 LogCompletionTime();
100 }
101
102 void ParseArgs(int argc, char **argv) {
103 original_argc = argc;
104 original_argv = argv;
105
106 InitLogging(argv);
107
108 // Skip over the command name.
109 argv++;
110 argc--;
111
112 if (argc == 0) {
113 Usage("No arguments specified");
114 }
115
116 for (int i = 0; i < argc; ++i) {
117 const StringPiece option(argv[i]);
118 const bool log_options = false;
119 if (log_options) {
120 LOG(INFO) << "patchoat: option[" << i << "]=" << argv[i];
121 }
122 if (option.starts_with("--profile-file=")) {
123 profile_files_.push_back(option.substr(strlen("--profile-file=")).ToString());
124 } else if (option.starts_with("--profile-file-fd=")) {
125 ParseFdForCollection(option, "--profile-file-fd", &profile_files_fd_);
126 } else if (option.starts_with("--reference-profile-file=")) {
127 reference_profile_file_ = option.substr(strlen("--reference-profile-file=")).ToString();
128 } else if (option.starts_with("--reference-profile-file-fd=")) {
129 ParseUintOption(option, "--reference-profile-file-fd", &reference_profile_file_fd_, Usage);
130 } else {
131 Usage("Unknown argument %s", option.data());
132 }
133 }
134
135 if (profile_files_.empty() && profile_files_fd_.empty()) {
136 Usage("No profile files specified.");
137 }
138 if (!profile_files_.empty() && !profile_files_fd_.empty()) {
139 Usage("Profile files should not be specified with both --profile-file-fd and --profile-file");
140 }
141 if (!reference_profile_file_.empty() && (reference_profile_file_fd_ != -1)) {
142 Usage("--reference-profile-file-fd should only be supplied with --profile-file-fd");
143 }
144 if (reference_profile_file_.empty() && (reference_profile_file_fd_ == -1)) {
145 Usage("Reference profile file not specified");
146 }
147 }
148
149 ProfileAssistant::ProcessingResult ProcessProfiles() {
150 ProfileAssistant::ProcessingResult result;
151 if (profile_files_.empty()) {
152 // The file doesn't need to be flushed here (ProcessProfiles will do it)
153 // so don't check the usage.
154 File file(reference_profile_file_fd_, false);
155 result = ProfileAssistant::ProcessProfiles(profile_files_fd_, reference_profile_file_fd_);
156 CloseAllFds(profile_files_fd_, "profile_files_fd_");
157 } else {
158 result = ProfileAssistant::ProcessProfiles(profile_files_, reference_profile_file_);
159 }
160 return result;
161 }
162
163 private:
164 static void ParseFdForCollection(const StringPiece& option,
165 const char* arg_name,
166 std::vector<int>* fds) {
167 int fd;
168 ParseUintOption(option, arg_name, &fd, Usage);
169 fds->push_back(fd);
170 }
171
172 static void CloseAllFds(const std::vector<int>& fds, const char* descriptor) {
173 for (size_t i = 0; i < fds.size(); i++) {
174 if (close(fds[i]) < 0) {
175 PLOG(WARNING) << "Failed to close descriptor for " << descriptor << " at index " << i;
176 }
177 }
178 }
179
180 void LogCompletionTime() {
181 LOG(INFO) << "profman took " << PrettyDuration(NanoTime() - start_ns_);
182 }
183
184 std::vector<std::string> profile_files_;
185 std::vector<int> profile_files_fd_;
186 std::string reference_profile_file_;
187 int reference_profile_file_fd_;
188 uint64_t start_ns_;
189};
190
191// See ProfileAssistant::ProcessingResult for return codes.
192static int profman(int argc, char** argv) {
193 ProfMan profman;
194
195 // Parse arguments. Argument mistakes will lead to exit(EXIT_FAILURE) in UsageError.
196 profman.ParseArgs(argc, argv);
197
198 // Process profile information and assess if we need to do a profile guided compilation.
199 // This operation involves I/O.
200 return profman.ProcessProfiles();
201}
202
203} // namespace art
204
205int main(int argc, char **argv) {
206 return art::profman(argc, argv);
207}
208