diff options
author | 2022-09-13 14:14:16 +0100 | |
---|---|---|
committer | 2022-09-16 20:14:46 +0000 | |
commit | 1a8cc460546a3bf5f55acf46efb5073d5ed412d3 (patch) | |
tree | 24c2ffff1efae12e9f6f10c5a8df74b8ff7a2e0e /runtime/exec_utils.cc | |
parent | 4c9498e8f1c8ef8c54cfd7462e24a505690cdc10 (diff) |
odrefresh: Report dex2oat result for each stage.
This is the first step to improve odrefresh metrics collection. More CLs
will follow.
After the change, the metrics should tell:
- whether dex2oat is invoked or not
- whether dex2oat crashed or exited with a code
Partially cherry-picked from
commit fa152ba922a6301a10671d4684b75fe8cb2a2330
Bug: 246534524
Test: m test-art-host-gtest-art_runtime_tests
Test: atest ArtGtestsTargetChroot:OdRefreshTest
Merged-In: Id962a6e6a765371d290a836c51059d725c9250f3
Change-Id: I69ddf64552d4f2e51e111a40871890d41c88721d
Diffstat (limited to 'runtime/exec_utils.cc')
-rw-r--r-- | runtime/exec_utils.cc | 99 |
1 files changed, 45 insertions, 54 deletions
diff --git a/runtime/exec_utils.cc b/runtime/exec_utils.cc index 929f09f784..dd389f8c97 100644 --- a/runtime/exec_utils.cc +++ b/runtime/exec_utils.cc @@ -102,10 +102,10 @@ pid_t ExecWithoutWait(const std::vector<std::string>& arg_vector, std::string* e } } -int WaitChild(pid_t pid, - const std::vector<std::string>& arg_vector, - bool no_wait, - std::string* error_msg) { +ExecResult WaitChild(pid_t pid, + const std::vector<std::string>& arg_vector, + bool no_wait, + std::string* error_msg) { siginfo_t info; // WNOWAIT leaves the child in a waitable state. The call is still blocking. int options = WEXITED | (no_wait ? WNOWAIT : 0); @@ -114,7 +114,7 @@ int WaitChild(pid_t pid, ToCommandLine(arg_vector).c_str(), pid, strerror(errno)); - return -1; + return {.status = ExecResult::kUnknown}; } if (info.si_pid != pid) { *error_msg = StringPrintf("waitid failed for (%s): wanted pid %d, got %d: %s", @@ -122,38 +122,38 @@ int WaitChild(pid_t pid, pid, info.si_pid, strerror(errno)); - return -1; + return {.status = ExecResult::kUnknown}; } if (info.si_code != CLD_EXITED) { *error_msg = StringPrintf("Failed to execute (%s) because the child process is terminated by signal %d", ToCommandLine(arg_vector).c_str(), info.si_status); - return -1; + return {.status = ExecResult::kSignaled, .signal = info.si_status}; } - return info.si_status; + return {.status = ExecResult::kExited, .exit_code = info.si_status}; } // A fallback implementation of `WaitChildWithTimeout` that creates a thread to wait instead of // relying on `pidfd_open`. -int WaitChildWithTimeoutFallback(pid_t pid, - const std::vector<std::string>& arg_vector, - int timeout_ms, - bool* timed_out, - std::string* error_msg) { +ExecResult WaitChildWithTimeoutFallback(pid_t pid, + const std::vector<std::string>& arg_vector, + int timeout_ms, + std::string* error_msg) { bool child_exited = false; + bool timed_out = false; std::condition_variable cv; std::mutex m; std::thread wait_thread([&]() { std::unique_lock<std::mutex> lock(m); if (!cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), [&] { return child_exited; })) { - *timed_out = true; + timed_out = true; kill(pid, SIGKILL); } }); - int status = WaitChild(pid, arg_vector, /*no_wait=*/true, error_msg); + ExecResult result = WaitChild(pid, arg_vector, /*no_wait=*/true, error_msg); { std::unique_lock<std::mutex> lock(m); @@ -163,24 +163,23 @@ int WaitChildWithTimeoutFallback(pid_t pid, wait_thread.join(); // The timeout error should have a higher priority than any other error. - if (*timed_out) { + if (timed_out) { *error_msg = StringPrintf("Failed to execute (%s) because the child process timed out after %dms", ToCommandLine(arg_vector).c_str(), timeout_ms); - return -1; + return ExecResult{.status = ExecResult::kTimedOut}; } - return status; + return result; } // Waits for the child process to finish and leaves the child in a waitable state. -int WaitChildWithTimeout(pid_t pid, - unique_fd pidfd, - const std::vector<std::string>& arg_vector, - int timeout_ms, - bool* timed_out, - std::string* error_msg) { +ExecResult WaitChildWithTimeout(pid_t pid, + unique_fd pidfd, + const std::vector<std::string>& arg_vector, + int timeout_ms, + std::string* error_msg) { auto cleanup = android::base::make_scope_guard([&]() { kill(pid, SIGKILL); std::string ignored_error_msg; @@ -196,15 +195,14 @@ int WaitChildWithTimeout(pid_t pid, if (poll_ret < 0) { *error_msg = StringPrintf("poll failed for pid %d: %s", pid, strerror(errno)); - return -1; + return {.status = ExecResult::kUnknown}; } if (poll_ret == 0) { - *timed_out = true; *error_msg = StringPrintf("Failed to execute (%s) because the child process timed out after %dms", ToCommandLine(arg_vector).c_str(), timeout_ms); - return -1; + return {.status = ExecResult::kTimedOut}; } cleanup.Disable(); @@ -242,54 +240,47 @@ bool ParseProcStat(const std::string& stat_content, int ExecUtils::ExecAndReturnCode(const std::vector<std::string>& arg_vector, std::string* error_msg) const { - bool ignored_timed_out; - return ExecAndReturnCode(arg_vector, /*timeout_sec=*/-1, &ignored_timed_out, error_msg); + return ExecAndReturnResult(arg_vector, /*timeout_sec=*/-1, error_msg).exit_code; } -int ExecUtils::ExecAndReturnCode(const std::vector<std::string>& arg_vector, - int timeout_sec, - bool* timed_out, - std::string* error_msg) const { - return ExecAndReturnCode( - arg_vector, timeout_sec, ExecCallbacks(), timed_out, /*stat=*/nullptr, error_msg); +ExecResult ExecUtils::ExecAndReturnResult(const std::vector<std::string>& arg_vector, + int timeout_sec, + std::string* error_msg) const { + return ExecAndReturnResult(arg_vector, timeout_sec, ExecCallbacks(), /*stat=*/nullptr, error_msg); } -int ExecUtils::ExecAndReturnCode(const std::vector<std::string>& arg_vector, - int timeout_sec, - const ExecCallbacks& callbacks, - /*out*/ bool* timed_out, - /*out*/ ProcessStat* stat, - /*out*/ std::string* error_msg) const { - *timed_out = false; - +ExecResult ExecUtils::ExecAndReturnResult(const std::vector<std::string>& arg_vector, + int timeout_sec, + const ExecCallbacks& callbacks, + /*out*/ ProcessStat* stat, + /*out*/ std::string* error_msg) const { if (timeout_sec > INT_MAX / 1000) { *error_msg = "Timeout too large"; - return -1; + return {.status = ExecResult::kStartFailed}; } // Start subprocess. pid_t pid = ExecWithoutWait(arg_vector, error_msg); if (pid == -1) { - return -1; + return {.status = ExecResult::kStartFailed}; } callbacks.on_start(pid); // Wait for subprocess to finish. - int status; + ExecResult result; if (timeout_sec >= 0) { unique_fd pidfd = PidfdOpen(pid); if (pidfd.get() >= 0) { - status = WaitChildWithTimeout( - pid, std::move(pidfd), arg_vector, timeout_sec * 1000, timed_out, error_msg); + result = + WaitChildWithTimeout(pid, std::move(pidfd), arg_vector, timeout_sec * 1000, error_msg); } else { LOG(DEBUG) << StringPrintf( "pidfd_open failed for pid %d: %s, falling back", pid, strerror(errno)); - status = - WaitChildWithTimeoutFallback(pid, arg_vector, timeout_sec * 1000, timed_out, error_msg); + result = WaitChildWithTimeoutFallback(pid, arg_vector, timeout_sec * 1000, error_msg); } } else { - status = WaitChild(pid, arg_vector, /*no_wait=*/true, error_msg); + result = WaitChild(pid, arg_vector, /*no_wait=*/true, error_msg); } if (stat != nullptr) { @@ -303,12 +294,12 @@ int ExecUtils::ExecAndReturnCode(const std::vector<std::string>& arg_vector, std::string local_error_msg; // TODO(jiakaiz): Use better logic to detect waitid failure. - if (WaitChild(pid, arg_vector, /*no_wait=*/false, &local_error_msg) < 0 && - local_error_msg.find("waitid failed") == 0) { + if (WaitChild(pid, arg_vector, /*no_wait=*/false, &local_error_msg).status == + ExecResult::kUnknown) { LOG(ERROR) << "Failed to clean up child process '" << arg_vector[0] << "': " << local_error_msg; } - return status; + return result; } bool ExecUtils::Exec(const std::vector<std::string>& arg_vector, std::string* error_msg) const { |