ART: Make dex2oat watchdog configurable
Allow the watchdog timeout to be set on the command line. Add a
test.
Test: m
Test: m test-art-host
Change-Id: I04d0bd15fc7925d95fd2b6d87caf21fb85a797bd
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 192fc27..026a567 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -419,12 +419,9 @@
} while (false)
public:
- explicit WatchDog(bool is_watch_dog_enabled) {
- is_watch_dog_enabled_ = is_watch_dog_enabled;
- if (!is_watch_dog_enabled_) {
- return;
- }
- shutting_down_ = false;
+ explicit WatchDog(int64_t timeout_in_milliseconds)
+ : timeout_in_milliseconds_(timeout_in_milliseconds),
+ shutting_down_(false) {
const char* reason = "dex2oat watch dog thread startup";
CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_init, (&mutex_, nullptr), reason);
CHECK_WATCH_DOG_PTHREAD_CALL(pthread_cond_init, (&cond_, nullptr), reason);
@@ -433,9 +430,6 @@
CHECK_WATCH_DOG_PTHREAD_CALL(pthread_attr_destroy, (&attr_), reason);
}
~WatchDog() {
- if (!is_watch_dog_enabled_) {
- return;
- }
const char* reason = "dex2oat watch dog thread shutdown";
CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_lock, (&mutex_), reason);
shutting_down_ = true;
@@ -448,6 +442,23 @@
CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_destroy, (&mutex_), reason);
}
+ // TODO: tune the multiplier for GC verification, the following is just to make the timeout
+ // large.
+ static constexpr int64_t kWatchdogVerifyMultiplier =
+ kVerifyObjectSupport > kVerifyObjectModeFast ? 100 : 1;
+
+ // When setting timeouts, keep in mind that the build server may not be as fast as your
+ // desktop. Debug builds are slower so they have larger timeouts.
+ static constexpr int64_t kWatchdogSlowdownFactor = kIsDebugBuild ? 5U : 1U;
+
+ // 9.5 minutes scaled by kSlowdownFactor. This is slightly smaller than the Package Manager
+ // watchdog (PackageManagerService.WATCHDOG_TIMEOUT, 10 minutes), so that dex2oat will abort
+ // itself before that watchdog would take down the system server.
+ static constexpr int64_t kWatchDogTimeoutSeconds = kWatchdogSlowdownFactor * (9 * 60 + 30);
+
+ static constexpr int64_t kDefaultWatchdogTimeoutInMS =
+ kWatchdogVerifyMultiplier * kWatchDogTimeoutSeconds * 1000;
+
private:
static void* CallBack(void* arg) {
WatchDog* self = reinterpret_cast<WatchDog*>(arg);
@@ -470,18 +481,15 @@
}
void Wait() {
- // TODO: tune the multiplier for GC verification, the following is just to make the timeout
- // large.
- constexpr int64_t multiplier = kVerifyObjectSupport > kVerifyObjectModeFast ? 100 : 1;
timespec timeout_ts;
- InitTimeSpec(true, CLOCK_REALTIME, multiplier * kWatchDogTimeoutSeconds * 1000, 0, &timeout_ts);
+ InitTimeSpec(true, CLOCK_REALTIME, timeout_in_milliseconds_, 0, &timeout_ts);
const char* reason = "dex2oat watch dog thread waiting";
CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_lock, (&mutex_), reason);
while (!shutting_down_) {
int rc = TEMP_FAILURE_RETRY(pthread_cond_timedwait(&cond_, &mutex_, &timeout_ts));
if (rc == ETIMEDOUT) {
Fatal(StringPrintf("dex2oat did not finish after %" PRId64 " seconds",
- kWatchDogTimeoutSeconds));
+ timeout_in_milliseconds_/1000));
} else if (rc != 0) {
std::string message(StringPrintf("pthread_cond_timedwait failed: %s",
strerror(errno)));
@@ -491,16 +499,7 @@
CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_unlock, (&mutex_), reason);
}
- // When setting timeouts, keep in mind that the build server may not be as fast as your desktop.
- // Debug builds are slower so they have larger timeouts.
- static constexpr int64_t kSlowdownFactor = kIsDebugBuild ? 5U : 1U;
-
- // 9.5 minutes scaled by kSlowdownFactor. This is slightly smaller than the Package Manager
- // watchdog (PackageManagerService.WATCHDOG_TIMEOUT, 10 minutes), so that dex2oat will abort
- // itself before that watchdog would take down the system server.
- static constexpr int64_t kWatchDogTimeoutSeconds = kSlowdownFactor * (9 * 60 + 30);
-
- bool is_watch_dog_enabled_;
+ const int64_t timeout_in_milliseconds_;
bool shutting_down_;
// TODO: Switch to Mutex when we can guarantee it won't prevent shutdown in error cases.
pthread_mutex_t mutex_;
@@ -591,6 +590,7 @@
struct ParserOptions {
std::vector<const char*> oat_symbols;
std::string boot_image_filename;
+ int64_t watch_dog_timeout_in_ms = -1;
bool watch_dog_enabled = true;
bool requested_specific_compiler = false;
std::string error_msg;
@@ -919,7 +919,10 @@
// Done with usage checks, enable watchdog if requested
if (parser_options->watch_dog_enabled) {
- watchdog_.reset(new WatchDog(true));
+ int64_t timeout = parser_options->watch_dog_timeout_in_ms > 0
+ ? parser_options->watch_dog_timeout_in_ms
+ : WatchDog::kDefaultWatchdogTimeoutInMS;
+ watchdog_.reset(new WatchDog(timeout));
}
// Fill some values into the key-value store for the oat header.
@@ -1150,6 +1153,11 @@
parser_options->watch_dog_enabled = true;
} else if (option == "--no-watch-dog") {
parser_options->watch_dog_enabled = false;
+ } else if (option.starts_with("--watchdog-timeout=")) {
+ ParseIntOption(option,
+ "--watchdog-timeout",
+ &parser_options->watch_dog_timeout_in_ms,
+ Usage);
} else if (option.starts_with("-j")) {
ParseJ(option);
} else if (option.starts_with("--image=")) {
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index c2275ac..05cf0fc 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -66,7 +66,7 @@
bool success = Dex2Oat(args, &error_msg);
if (expect_success) {
- ASSERT_TRUE(success) << error_msg;
+ ASSERT_TRUE(success) << error_msg << std::endl << output_;
// Verify the odex file was generated as expected.
std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
@@ -658,4 +658,41 @@
RunTest();
}
+class Dex2oatWatchdogTest : public Dex2oatTest {
+ protected:
+ void RunTest(bool expect_success, const std::vector<std::string>& extra_args = {}) {
+ std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
+ std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
+
+ Copy(GetTestDexFileName(), dex_location);
+
+ std::vector<std::string> copy(extra_args);
+
+ std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
+ copy.push_back("--swap-file=" + swap_location);
+ GenerateOdexForTest(dex_location,
+ odex_location,
+ CompilerFilter::kSpeed,
+ copy,
+ expect_success);
+ }
+
+ std::string GetTestDexFileName() {
+ return GetDexSrc1();
+ }
+};
+
+TEST_F(Dex2oatWatchdogTest, TestWatchdogOK) {
+ // Check with default.
+ RunTest(true);
+
+ // Check with ten minutes.
+ RunTest(true, { "--watchdog-timeout=600000" });
+}
+
+TEST_F(Dex2oatWatchdogTest, TestWatchdogTrigger) {
+ // Check with ten milliseconds.
+ RunTest(false, { "--watchdog-timeout=10" });
+}
+
} // namespace art