dex2oat: add --cpu-set command-line option
Enables affinitizing dex2oat threads to a specific group of CPUs.
Bug: 141446571
Bug: 149395059
Test: art/test/run-test -Xcompiler-option --cpu-set=0,1 956
Test: art/test/run-test -Xcompiler-option --cpu-set=,0,1 956
Test: art/test/run-test -Xcompiler-option --cpu-set=,, 956
Test: art/test/run-test -Xcompiler-option --cpu-set=0,a 956
Test: cmdline_parser_test
Change-Id: I4bb1519beacd329da1a69af31982a6154d315865
Merged-In: I4bb1519beacd329da1a69af31982a6154d315865
(cherry picked from commit ffc791c748dd28cc6bc7fff825b3c1b7af96abb3)
diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc
index 101e5c4..a70b34d 100644
--- a/cmdline/cmdline_parser_test.cc
+++ b/cmdline/cmdline_parser_test.cc
@@ -20,7 +20,6 @@
#include "gtest/gtest.h"
-#include "base/mutex.h"
#include "base/utils.h"
#include "jdwp_provider.h"
#include "experimental_flags.h"
@@ -578,4 +577,21 @@
EXPECT_KEY_VALUE(map, M::MethodTrace, Unit{});
EXPECT_KEY_VALUE(map, M::LargeObjectSpace, gc::space::LargeObjectSpaceType::kMap);
} // TEST_F
+
+TEST_F(CmdlineParserTest, TypesNotInRuntime) {
+ CmdlineType<std::vector<int32_t>> ct;
+ auto success0 =
+ CmdlineParseResult<std::vector<int32_t>>::Success(std::vector<int32_t>({1, 2, 3, 4}));
+ EXPECT_EQ(success0, ct.Parse("1,2,3,4"));
+ auto success1 = CmdlineParseResult<std::vector<int32_t>>::Success(std::vector<int32_t>({0}));
+ EXPECT_EQ(success1, ct.Parse("1"));
+
+ EXPECT_FALSE(ct.Parse("").IsSuccess());
+ EXPECT_FALSE(ct.Parse(",").IsSuccess());
+ EXPECT_FALSE(ct.Parse("1,").IsSuccess());
+ EXPECT_FALSE(ct.Parse(",1").IsSuccess());
+ EXPECT_FALSE(ct.Parse("1a2").IsSuccess());
+ EXPECT_EQ(CmdlineResult::kOutOfRange, ct.Parse("1,10000000000000").GetStatus());
+ EXPECT_EQ(CmdlineResult::kOutOfRange, ct.Parse("-10000000000000,123").GetStatus());
+} // TEST_F
} // namespace art
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index dd9221d..6f784b3 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -405,6 +405,39 @@
static const char* Name() { return "ParseStringList<Separator>"; }
};
+template <>
+struct CmdlineType<std::vector<int32_t>> : CmdlineTypeParser<std::vector<int32_t>> {
+ using Result = CmdlineParseResult<std::vector<int32_t>>;
+
+ Result Parse(const std::string& args) {
+ std::vector<int32_t> list;
+ const char* pos = args.c_str();
+ errno = 0;
+
+ while (true) {
+ char* end = nullptr;
+ int64_t value = strtol(pos, &end, 10);
+ if (pos == end || errno == EINVAL) {
+ return Result::Failure("Failed to parse integer from " + args);
+ } else if ((errno == ERANGE) || // NOLINT [runtime/int] [4]
+ value < std::numeric_limits<int32_t>::min() ||
+ value > std::numeric_limits<int32_t>::max()) {
+ return Result::OutOfRange("Failed to parse integer from " + args + "; out of range");
+ }
+ list.push_back(static_cast<int32_t>(value));
+ if (*end == '\0') {
+ break;
+ } else if (*end != ',') {
+ return Result::Failure(std::string("Unexpected character: ") + *end);
+ }
+ pos = end + 1;
+ }
+ return Result::Success(std::move(list));
+ }
+
+ static const char* Name() { return "std::vector<int32_t>"; }
+};
+
static gc::CollectorType ParseCollectorType(const std::string& option) {
if (option == "MS" || option == "nonconcurrent") {
return gc::kCollectorTypeMS;
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 278523e..9961608 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -29,11 +29,15 @@
#include <type_traits>
#include <vector>
-#if defined(__linux__) && defined(__arm__)
+#if defined(__linux__)
+#include <sched.h>
+#if defined(__arm__)
#include <sys/personality.h>
#include <sys/utsname.h>
+#endif // __arm__
#endif
+#include "android-base/parseint.h"
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
@@ -222,6 +226,10 @@
UsageError(" host system.");
UsageError(" Example: -j12");
UsageError("");
+ UsageError(" --cpu-set=<set>: sets the cpu affinity to <set>. The <set> argument is a comma");
+ UsageError(" separated list of CPUs.");
+ UsageError(" Example: --cpu-set=0,1,2,3");
+ UsageError("");
UsageError(" --dex-file=<dex-file>: specifies a .dex, .jar, or .apk file to compile.");
UsageError(" Example: --dex-file=/system/framework/core.jar");
UsageError("");
@@ -500,6 +508,36 @@
exit(EXIT_FAILURE);
}
+
+// Set CPU affinity from a string containing a comma-separated list of numeric CPU identifiers.
+static void SetCpuAffinity(const std::vector<int32_t>& cpu_list) {
+#ifdef __linux__
+ int cpu_count = sysconf(_SC_NPROCESSORS_CONF);
+ cpu_set_t target_cpu_set;
+ CPU_ZERO(&target_cpu_set);
+
+ for (int32_t cpu : cpu_list) {
+ if (cpu >= 0 && cpu < cpu_count) {
+ CPU_SET(cpu, &target_cpu_set);
+ } else {
+ // Argument error is considered fatal, suggests misconfigured system properties.
+ Usage("Invalid cpu \"d\" specified in --cpu-set argument (nprocessors = %d)",
+ cpu, cpu_count);
+ }
+ }
+
+ if (sched_setaffinity(getpid(), sizeof(target_cpu_set), &target_cpu_set) == -1) {
+ // Failure to set affinity may be outside control of requestor, log warning rather than
+ // treating as fatal.
+ PLOG(WARNING) << "Failed to set CPU affinity.";
+ }
+#else
+ LOG(WARNING) << "--cpu-set not supported on this platform.";
+#endif // __linux__
+}
+
+
+
// The primary goal of the watchdog is to prevent stuck build servers
// during development when fatal aborts lead to a cascade of failures
// that result in a deadlock.
@@ -929,6 +967,10 @@
}
}
+ if (!cpu_set_.empty()) {
+ SetCpuAffinity(cpu_set_);
+ }
+
if (compiler_options_->inline_max_code_units_ == CompilerOptions::kUnsetInlineMaxCodeUnits) {
compiler_options_->inline_max_code_units_ = CompilerOptions::kDefaultInlineMaxCodeUnits;
}
@@ -1136,6 +1178,7 @@
AssignIfExists(args, M::Threads, &thread_count_);
AssignIfExists(args, M::ImageClasses, &image_classes_filename_);
AssignIfExists(args, M::ImageClassesZip, &image_classes_zip_filename_);
+ AssignIfExists(args, M::CpuSet, &cpu_set_);
AssignIfExists(args, M::Passes, &passes_to_run_filename_);
AssignIfExists(args, M::BootImage, &parser_options->boot_image_filename);
AssignIfExists(args, M::AndroidRoot, &android_root_);
@@ -2743,6 +2786,7 @@
std::unique_ptr<ClassLoaderContext> stored_class_loader_context_;
size_t thread_count_;
+ std::vector<int32_t> cpu_set_;
uint64_t start_ns_;
uint64_t start_cputime_ns_;
std::unique_ptr<WatchDog> watchdog_;
diff --git a/dex2oat/dex2oat_options.cc b/dex2oat/dex2oat_options.cc
index 4a19fb1..80c9a16 100644
--- a/dex2oat/dex2oat_options.cc
+++ b/dex2oat/dex2oat_options.cc
@@ -206,6 +206,9 @@
.Define("-j_")
.WithType<unsigned int>()
.IntoKey(M::Threads)
+ .Define("--cpu-set=_")
+ .WithType<std::vector<int32_t>>()
+ .IntoKey(M::CpuSet)
.Define("--android-root=_")
.WithType<std::string>()
.IntoKey(M::AndroidRoot)
diff --git a/dex2oat/dex2oat_options.def b/dex2oat/dex2oat_options.def
index 0717e1a..8201c3c 100644
--- a/dex2oat/dex2oat_options.def
+++ b/dex2oat/dex2oat_options.def
@@ -53,6 +53,7 @@
DEX2OAT_OPTIONS_KEY (bool, Watchdog)
DEX2OAT_OPTIONS_KEY (int, WatchdogTimeout)
DEX2OAT_OPTIONS_KEY (unsigned int, Threads)
+DEX2OAT_OPTIONS_KEY (std::vector<std::int32_t>, CpuSet)
DEX2OAT_OPTIONS_KEY (std::vector<std::string>, ImageFilenames)
DEX2OAT_OPTIONS_KEY (std::string, ImageClasses)
DEX2OAT_OPTIONS_KEY (std::string, ImageClassesZip)