Skip to content

Commit

Permalink
dex2oat: add --cpu-set command-line option
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
ohodson committed Mar 4, 2020
1 parent 87a7213 commit bd53ee4
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 2 deletions.
18 changes: 17 additions & 1 deletion cmdline/cmdline_parser_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

#include "gtest/gtest.h"

#include "base/mutex.h"
#include "base/utils.h"
#include "jdwp_provider.h"
#include "experimental_flags.h"
Expand Down Expand Up @@ -578,4 +577,21 @@ TEST_F(CmdlineParserTest, MultipleArguments) {
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
33 changes: 33 additions & 0 deletions cmdline/cmdline_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,39 @@ struct CmdlineType<ParseStringList<Separator>> : CmdlineTypeParser<ParseStringLi
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;
Expand Down
46 changes: 45 additions & 1 deletion dex2oat/dex2oat.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -222,6 +226,10 @@ NO_RETURN static void Usage(const char* fmt, ...) {
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("");
Expand Down Expand Up @@ -500,6 +508,36 @@ NO_RETURN static void Usage(const char* fmt, ...) {
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.
Expand Down Expand Up @@ -929,6 +967,10 @@ class Dex2Oat final {
}
}

if (!cpu_set_.empty()) {
SetCpuAffinity(cpu_set_);
}

if (compiler_options_->inline_max_code_units_ == CompilerOptions::kUnsetInlineMaxCodeUnits) {
compiler_options_->inline_max_code_units_ = CompilerOptions::kDefaultInlineMaxCodeUnits;
}
Expand Down Expand Up @@ -1136,6 +1178,7 @@ class Dex2Oat final {
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_);
Expand Down Expand Up @@ -2743,6 +2786,7 @@ class Dex2Oat final {
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_;
Expand Down
3 changes: 3 additions & 0 deletions dex2oat/dex2oat_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ static Parser CreateArgumentParser() {
.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)
Expand Down
1 change: 1 addition & 0 deletions dex2oat/dex2oat_options.def
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ DEX2OAT_OPTIONS_KEY (std::string, OatLocation)
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)
Expand Down

0 comments on commit bd53ee4

Please sign in to comment.