blob: 853afcd433c6122ed388f50586da4e4ead943034 [file] [log] [blame]
Yan Wangcdb97fa2019-10-18 18:18:48 -07001// Copyright (C) 2019 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "compiler/compiler.h"
16#include "maintenance/controller.h"
17
Yan Wang23d4cc32019-11-13 18:16:59 -080018#include "common/cmd_utils.h"
Yan Wangcdb97fa2019-10-18 18:18:48 -070019#include "common/debug.h"
20#include "common/expected.h"
21
22#include "db/models.h"
Yan Wangcdb97fa2019-10-18 18:18:48 -070023#include "inode2filename/inode.h"
24#include "inode2filename/search_directories.h"
25
26#include <android-base/file.h>
27
28#include <iostream>
29#include <filesystem>
30#include <fstream>
31#include <limits>
32#include <optional>
33#include <vector>
34#include <string>
Yan Wang9608f272020-02-21 19:16:28 -080035#include <sys/wait.h>
Yan Wangcdb97fa2019-10-18 18:18:48 -070036
37namespace iorap::maintenance {
38
Yan Wang23d4cc32019-11-13 18:16:59 -080039// Gets the path of output compiled trace.
40db::CompiledTraceFileModel CalculateNewestFilePath(
41 const std::string& package_name,
42 const std::string& activity_name,
Yan Wang16b8fce2020-02-20 18:08:33 +000043 int version) {
Yan Wang23d4cc32019-11-13 18:16:59 -080044 db::VersionedComponentName versioned_component_name{
45 package_name, activity_name, version};
46
47 db::CompiledTraceFileModel output_file =
48 db::CompiledTraceFileModel::CalculateNewestFilePath(versioned_component_name);
49
50 return output_file;
51}
52
Yan Wang65e905d2019-11-16 14:49:56 -080053using ArgString = const char*;
54
Yan Wang23d4cc32019-11-13 18:16:59 -080055static constexpr const char kCommandFileName[] = "/system/bin/iorap.cmd.compiler";
56
Yan Wang65e905d2019-11-16 14:49:56 -080057int Exec::Execve(const std::string& pathname,
58 std::vector<std::string>& argv_vec,
59 char *const envp[]) {
60 std::unique_ptr<ArgString[]> argv_ptr =
61 common::VecToArgv(kCommandFileName, argv_vec);
62
63 return execve(pathname.c_str(), (char**)argv_ptr.get(), envp);
64}
65
66pid_t Exec::Fork() {
67 return fork();
68}
69
Yan Wang23d4cc32019-11-13 18:16:59 -080070// Represents the parameters used when fork+exec compiler.
71struct CompilerForkParameters {
72 std::vector<std::string> input_pbs;
73 std::vector<uint64_t> timestamp_limit_ns;
74 std::string output_proto;
75 ControllerParameters controller_params;
76
77 CompilerForkParameters(const std::vector<compiler::CompilationInput>& perfetto_traces,
78 const std::string& output_proto,
79 ControllerParameters controller_params) :
80 output_proto(output_proto), controller_params(controller_params) {
81 for (compiler::CompilationInput perfetto_trace : perfetto_traces) {
82 input_pbs.push_back(perfetto_trace.filename);
83 timestamp_limit_ns.push_back(perfetto_trace.timestamp_limit_ns);
84 }
85 }
86};
87
Yan Wang23d4cc32019-11-13 18:16:59 -080088std::vector<std::string> MakeCompilerParams(const CompilerForkParameters& params) {
89 std::vector<std::string> argv;
90 ControllerParameters controller_params = params.controller_params;
91
92 common::AppendArgsRepeatedly(argv, params.input_pbs);
93 common::AppendArgsRepeatedly(argv, "--timestamp_limit_ns", params.timestamp_limit_ns);
94
95 if (controller_params.output_text) {
96 argv.push_back("--output-text");
97 }
98
99 common::AppendArgs(argv, "--output-proto", params.output_proto);
100
101 if (controller_params.inode_textcache) {
102 common::AppendArgs(argv, "--inode-textcache", *controller_params.inode_textcache);
103 }
104
105 if (controller_params.verbose) {
106 argv.push_back("--verbose");
107 }
108
109 return argv;
110}
111
112bool StartViaFork(const CompilerForkParameters& params) {
Yan Wang65e905d2019-11-16 14:49:56 -0800113 const ControllerParameters& controller_params = params.controller_params;
114 pid_t child = controller_params.exec->Fork();
Yan Wang23d4cc32019-11-13 18:16:59 -0800115
116 if (child == -1) {
117 LOG(FATAL) << "Failed to fork a process for compilation";
118 } else if (child > 0) { // we are the caller of this function
119 LOG(DEBUG) << "forked into a process for compilation , pid = " << child;
Yan Wang9608f272020-02-21 19:16:28 -0800120
121 int wstatus;
122 waitpid(child, /*out*/&wstatus, /*options*/0);
123 if (!WIFEXITED(wstatus)) {
124 LOG(ERROR) << "Child terminated abnormally, status: " << WEXITSTATUS(wstatus);
125 return false;
126 }
127 LOG(DEBUG) << "Child terminated, status: " << WEXITSTATUS(wstatus);
128
Yan Wang23d4cc32019-11-13 18:16:59 -0800129 return true;
130 } else {
131 // we are the child that was forked.
132 std::vector<std::string> argv_vec = MakeCompilerParams(params);
133 std::unique_ptr<ArgString[]> argv_ptr =
134 common::VecToArgv(kCommandFileName, argv_vec);
135
136 std::stringstream argv; // for debugging.
137 for (std::string arg : argv_vec) {
138 argv << arg << ' ';
139 }
140 LOG(DEBUG) << "fork+exec: " << kCommandFileName << " " << argv.str();
141
Yan Wang65e905d2019-11-16 14:49:56 -0800142 controller_params.exec->Execve(kCommandFileName,
143 argv_vec,
144 /*envp*/nullptr);
Yan Wang23d4cc32019-11-13 18:16:59 -0800145 // This should never return.
Yan Wang23d4cc32019-11-13 18:16:59 -0800146 }
Yan Wang23d4cc32019-11-13 18:16:59 -0800147 return false;
148}
149
Yan Wangcdb97fa2019-10-18 18:18:48 -0700150// Gets the perfetto trace infos in the histories.
151std::vector<compiler::CompilationInput> GetPerfettoTraceInfo(
152 const db::DbHandle& db,
153 const std::vector<db::AppLaunchHistoryModel>& histories) {
154 std::vector<compiler::CompilationInput> perfetto_traces;
155
156 for(db::AppLaunchHistoryModel history : histories) {
157 // Get perfetto trace.
158 std::optional<db::RawTraceModel> raw_trace =
159 db::RawTraceModel::SelectByHistoryId(db, history.id);
160 if (!raw_trace) {
161 LOG(ERROR) << "Cannot find raw trace for history_id: "
162 << history.id;
163 continue;
164 }
165
166 uint64_t timestamp_limit = std::numeric_limits<uint64_t>::max();
167 // Get corresponding timestamp limit.
168 if (history.report_fully_drawn_ns) {
169 timestamp_limit = *history.report_fully_drawn_ns;
170 } else if (history.total_time_ns) {
171 timestamp_limit = *history.total_time_ns;
172 } else {
173 LOG(ERROR) << " No timestamp exists. Using the max value.";
174 }
175 perfetto_traces.push_back({raw_trace->file_path, timestamp_limit});
176 }
177 return perfetto_traces;
178}
179
Yan Wangcdb97fa2019-10-18 18:18:48 -0700180// Helper struct for printing vector.
181template <class T>
182struct VectorPrinter {
183 std::vector<T>& values;
184};
185
186std::ostream& operator<<(std::ostream& os,
187 const struct compiler::CompilationInput& perfetto_trace) {
188 os << "file_path: " << perfetto_trace.filename << " "
189 << "timestamp_limit: " << perfetto_trace.timestamp_limit_ns;
190 return os;
191}
192
193template <class T>
194std::ostream& operator<<(std::ostream& os, const struct VectorPrinter<T>& printer) {
195 os << "[\n";
196 for (T i : printer.values) {
197 os << i << ",\n";
198 }
199 os << "]\n";
200 return os;
201}
202
203// Compiled the perfetto traces for an activity.
204bool CompileActivity(const db::DbHandle& db,
205 int package_id,
206 const std::string& package_name,
207 const std::string& activity_name,
Yan Wang16b8fce2020-02-20 18:08:33 +0000208 int version,
Yan Wang23d4cc32019-11-13 18:16:59 -0800209 const ControllerParameters& params) {
Yan Wang65e905d2019-11-16 14:49:56 -0800210 db::CompiledTraceFileModel output_file =
Yan Wang16b8fce2020-02-20 18:08:33 +0000211 CalculateNewestFilePath(package_name, activity_name, version);
Yan Wang23d4cc32019-11-13 18:16:59 -0800212
Yan Wangcdb97fa2019-10-18 18:18:48 -0700213 std::string file_path = output_file.FilePath();
214
Yan Wang23d4cc32019-11-13 18:16:59 -0800215 if (!params.recompile && std::filesystem::exists(file_path)) {
Yan Wangcdb97fa2019-10-18 18:18:48 -0700216 LOG(DEBUG) << "compiled trace exists in " << file_path;
217 return true;
218 }
219
Yan Wangcdb97fa2019-10-18 18:18:48 -0700220 std::optional<db::ActivityModel> activity =
221 db::ActivityModel::SelectByNameAndPackageId(db, activity_name.c_str(), package_id);
222 if (!activity) {
223 LOG(ERROR) << "Cannot find activity for package_id: " << package_id
224 <<" activity_name: " <<activity_name;
225 return false;
226 }
227
228 int activity_id = activity->id;
229
230 std::vector<db::AppLaunchHistoryModel> histories =
231 db::AppLaunchHistoryModel::SelectActivityHistoryForCompile(db, activity_id);
232
233 {
234 std::vector<compiler::CompilationInput> perfetto_traces =
235 GetPerfettoTraceInfo(db, histories);
236
Yan Wangb5a4b032019-11-14 12:10:04 -0800237 if (perfetto_traces.size() < params.min_traces) {
238 LOG(DEBUG) << "The number of perfetto traces is " << perfetto_traces.size()
239 <<", which is less than " << params.min_traces;
240 return false;
241 }
242
Yan Wangcdb97fa2019-10-18 18:18:48 -0700243 // Show the compilation config.
244 LOG(DEBUG) << "Try to compiled package_id: " << package_id
245 << " package_name: " << package_name
246 << " activity_name: " << activity_name
Yan Wang16b8fce2020-02-20 18:08:33 +0000247 << " version: " << version
Yan Wangcdb97fa2019-10-18 18:18:48 -0700248 << " file_path: " << file_path
Yan Wang23d4cc32019-11-13 18:16:59 -0800249 << " verbose: " << params.verbose
Yan Wangcdb97fa2019-10-18 18:18:48 -0700250 << " perfetto_traces: "
251 << VectorPrinter<compiler::CompilationInput>{perfetto_traces};
Yan Wang23d4cc32019-11-13 18:16:59 -0800252 if (params.inode_textcache) {
253 LOG(DEBUG) << "inode_textcache: " << *params.inode_textcache;
254 }
Yan Wangcdb97fa2019-10-18 18:18:48 -0700255
Yan Wang23d4cc32019-11-13 18:16:59 -0800256 CompilerForkParameters compiler_params{perfetto_traces, file_path, params};
257
Yan Wang65e905d2019-11-16 14:49:56 -0800258 if (!output_file.MkdirWithParents()) {
259 LOG(ERROR) << "Compile activity failed. Failed to mkdirs " << file_path;
260 return false;
261 }
262
Yan Wang23d4cc32019-11-13 18:16:59 -0800263 if (!StartViaFork(compiler_params)) {
Yan Wangcdb97fa2019-10-18 18:18:48 -0700264 LOG(ERROR) << "Compilation failed for package_id:" << package_id
265 <<" activity_name: " <<activity_name;
266 return false;
267 }
Yan Wang9608f272020-02-21 19:16:28 -0800268
Yan Wangcdb97fa2019-10-18 18:18:48 -0700269 }
270
271 std::optional<db::PrefetchFileModel> compiled_trace =
272 db::PrefetchFileModel::Insert(db, activity_id, file_path);
273 if (!compiled_trace) {
274 LOG(ERROR) << "Cannot insert compiled trace activity_id: " << activity_id
275 << " file_path: " << file_path;
276 return false;
277 }
278 return true;
279}
280
281// Compiled the perfetto traces for activities in an package.
282bool CompilePackage(const db::DbHandle& db,
283 const std::string& package_name,
Yan Wang16b8fce2020-02-20 18:08:33 +0000284 int version,
Yan Wang23d4cc32019-11-13 18:16:59 -0800285 const ControllerParameters& params) {
Yan Wangcdb97fa2019-10-18 18:18:48 -0700286 std::optional<db::PackageModel> package =
Yan Wang16b8fce2020-02-20 18:08:33 +0000287 db::PackageModel::SelectByNameAndVersion(db, package_name.c_str(), version);
Yan Wangcdb97fa2019-10-18 18:18:48 -0700288
289 if (!package) {
Yan Wang16b8fce2020-02-20 18:08:33 +0000290 LOG(ERROR) << "Cannot find package for package_name: "
291 << package_name
292 << " and version "
293 << version;
Yan Wangcdb97fa2019-10-18 18:18:48 -0700294 return false;
295 }
296
297 std::vector<db::ActivityModel> activities =
298 db::ActivityModel::SelectByPackageId(db, package->id);
299
300 bool ret = true;
301 for (db::ActivityModel activity : activities) {
Yan Wang16b8fce2020-02-20 18:08:33 +0000302 if (!CompileActivity(db, package->id, package->name, activity.name, version, params)) {
Yan Wangcdb97fa2019-10-18 18:18:48 -0700303 ret = false;
304 }
305 }
306 return ret;
307}
308
309// Compiled the perfetto traces for packages in a device.
Yan Wang23d4cc32019-11-13 18:16:59 -0800310bool CompileAppsOnDevice(const db::DbHandle& db, const ControllerParameters& params) {
Yan Wangcdb97fa2019-10-18 18:18:48 -0700311 std::vector<db::PackageModel> packages = db::PackageModel::SelectAll(db);
312 bool ret = true;
313 for (db::PackageModel package : packages) {
Yan Wang16b8fce2020-02-20 18:08:33 +0000314 if (!CompilePackage(db, package.name, package.version, params)) {
Yan Wangcdb97fa2019-10-18 18:18:48 -0700315 ret = false;
316 }
317 }
318
319 return ret;
320}
321
Yan Wang23d4cc32019-11-13 18:16:59 -0800322bool Compile(const std::string& db_path, const ControllerParameters& params) {
Yan Wangcdb97fa2019-10-18 18:18:48 -0700323 iorap::db::SchemaModel db_schema = db::SchemaModel::GetOrCreate(db_path);
324 db::DbHandle db{db_schema.db()};
Yan Wang23d4cc32019-11-13 18:16:59 -0800325 return CompileAppsOnDevice(db, params);
Yan Wangcdb97fa2019-10-18 18:18:48 -0700326}
327
328bool Compile(const std::string& db_path,
329 const std::string& package_name,
Yan Wang16b8fce2020-02-20 18:08:33 +0000330 int version,
Yan Wang23d4cc32019-11-13 18:16:59 -0800331 const ControllerParameters& params) {
Yan Wangcdb97fa2019-10-18 18:18:48 -0700332 iorap::db::SchemaModel db_schema = db::SchemaModel::GetOrCreate(db_path);
333 db::DbHandle db{db_schema.db()};
Yan Wang16b8fce2020-02-20 18:08:33 +0000334 return CompilePackage(db, package_name, version, params);
Yan Wangcdb97fa2019-10-18 18:18:48 -0700335}
336
337bool Compile(const std::string& db_path,
338 const std::string& package_name,
339 const std::string& activity_name,
Yan Wang16b8fce2020-02-20 18:08:33 +0000340 int version,
Yan Wang23d4cc32019-11-13 18:16:59 -0800341 const ControllerParameters& params) {
Yan Wangcdb97fa2019-10-18 18:18:48 -0700342 iorap::db::SchemaModel db_schema = db::SchemaModel::GetOrCreate(db_path);
343 db::DbHandle db{db_schema.db()};
344
345 std::optional<db::PackageModel> package =
Yan Wang16b8fce2020-02-20 18:08:33 +0000346 db::PackageModel::SelectByNameAndVersion(db, package_name.c_str(), version);
347
Yan Wangcdb97fa2019-10-18 18:18:48 -0700348 if (!package) {
Yan Wang16b8fce2020-02-20 18:08:33 +0000349 LOG(ERROR) << "Cannot find package with name "
350 << package_name
351 << " and version "
352 << version;
Yan Wangcdb97fa2019-10-18 18:18:48 -0700353 return false;
354 }
Yan Wang16b8fce2020-02-20 18:08:33 +0000355 return CompileActivity(db, package->id, package_name, activity_name, version, params);
Yan Wangcdb97fa2019-10-18 18:18:48 -0700356}
357
358} // namespace iorap::maintenance