summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compiler/dex/frontend.cc2
-rw-r--r--compiler/dex/mir_analysis.cc2
-rw-r--r--compiler/driver/compiler_driver.cc29
-rw-r--r--compiler/driver/compiler_driver.h4
-rw-r--r--compiler/driver/compiler_options.h20
-rw-r--r--dex2oat/dex2oat.cc38
-rw-r--r--runtime/native/dalvik_system_DexFile.cc6
-rw-r--r--runtime/native/dalvik_system_VMRuntime.cc12
-rw-r--r--runtime/parsed_options.cc33
-rw-r--r--runtime/parsed_options.h7
-rw-r--r--runtime/profiler.cc74
-rw-r--r--runtime/profiler.h62
-rw-r--r--runtime/profiler_options.h131
-rw-r--r--runtime/runtime.cc33
-rw-r--r--runtime/runtime.h17
-rw-r--r--runtime/utils.cc19
-rw-r--r--runtime/utils.h4
17 files changed, 300 insertions, 193 deletions
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 3d22774..7848b06 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -903,7 +903,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& driver,
cu.mir_graph->EnableOpcodeCounting();
}
- // Check early if we should skip this compilation if using the profiled filter.
+ // Check early if we should skip this compilation if the profiler is enabled.
if (cu.compiler_driver->ProfilePresent()) {
std::string methodname = PrettyMethod(method_idx, dex_file);
if (cu.mir_graph->SkipCompilation(methodname)) {
diff --git a/compiler/dex/mir_analysis.cc b/compiler/dex/mir_analysis.cc
index 7129f8a..2ec17de 100644
--- a/compiler/dex/mir_analysis.cc
+++ b/compiler/dex/mir_analysis.cc
@@ -1015,7 +1015,7 @@ bool MIRGraph::SkipCompilation() {
return true;
}
- if (!compiler_options.IsCompilationEnabled() || compiler_filter == CompilerOptions::kProfiled) {
+ if (!compiler_options.IsCompilationEnabled()) {
return true;
}
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 15a086b..1cfd194 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -55,7 +55,6 @@
#include "thread_pool.h"
#include "trampolines/trampoline_compiler.h"
#include "transaction.h"
-#include "utils.h"
#include "verifier/method_verifier.h"
#include "verifier/method_verifier-inl.h"
@@ -331,7 +330,7 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options,
bool image, DescriptorSet* image_classes, size_t thread_count,
bool dump_stats, bool dump_passes, CumulativeLogger* timer,
std::string profile_file)
- : profile_ok_(false), compiler_options_(compiler_options),
+ : profile_present_(false), compiler_options_(compiler_options),
verification_results_(verification_results),
method_inliner_map_(method_inliner_map),
compiler_(Compiler::Create(this, compiler_kind)),
@@ -365,11 +364,6 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options,
CHECK_PTHREAD_CALL(pthread_key_create, (&tls_key_, NULL), "compiler tls key");
- // Read the profile file if one is provided.
- if (profile_file != "") {
- profile_ok_ = profile_file_.LoadFile(profile_file);
- }
-
dex_to_dex_compiler_ = reinterpret_cast<DexToDexCompilerFn>(ArtCompileDEX);
compiler_->Init();
@@ -385,6 +379,16 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options,
if (compiler_options->GetGenerateGDBInformation()) {
cfi_info_.reset(compiler_->GetCallFrameInformationInitialization(*this));
}
+
+ // Read the profile file if one is provided.
+ if (!profile_file.empty()) {
+ profile_present_ = profile_file_.LoadFile(profile_file);
+ if (profile_present_) {
+ LOG(INFO) << "Using profile data form file " << profile_file;
+ } else {
+ LOG(INFO) << "Failed to load profile file " << profile_file;
+ }
+ }
}
std::vector<uint8_t>* CompilerDriver::DeduplicateCode(const std::vector<uint8_t>& code) {
@@ -2044,7 +2048,7 @@ void CompilerDriver::InstructionSetToLLVMTarget(InstructionSet instruction_set,
}
bool CompilerDriver::SkipCompilation(const std::string& method_name) {
- if (!profile_ok_) {
+ if (!profile_present_) {
return false;
}
// First find the method in the profile file.
@@ -2056,18 +2060,17 @@ bool CompilerDriver::SkipCompilation(const std::string& method_name) {
}
// Methods that comprise top_k_threshold % of the total samples will be compiled.
- double top_k_threshold = GetDoubleProperty("dalvik.vm.profiler.compile_thr", 10.0, 90.0, 90.0);
-
// Compare against the start of the topK percentage bucket just in case the threshold
// falls inside a bucket.
- bool compile = data.GetTopKUsedPercentage() - data.GetUsedPercent() <= top_k_threshold;
+ bool compile = data.GetTopKUsedPercentage() - data.GetUsedPercent()
+ <= compiler_options_->GetTopKProfileThreshold();
if (compile) {
LOG(INFO) << "compiling method " << method_name << " because its usage is part of top "
<< data.GetTopKUsedPercentage() << "% with a percent of " << data.GetUsedPercent() << "%"
- << " (topKThreshold=" << top_k_threshold << ")";
+ << " (topKThreshold=" << compiler_options_->GetTopKProfileThreshold() << ")";
} else {
VLOG(compiler) << "not compiling method " << method_name << " because it's not part of leading "
- << top_k_threshold << "% samples)";
+ << compiler_options_->GetTopKProfileThreshold() << "% samples)";
}
return !compile;
}
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index e952f63..fad6798 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -143,7 +143,7 @@ class CompilerDriver {
}
bool ProfilePresent() const {
- return profile_ok_;
+ return profile_present_;
}
// Are we compiling and creating an image file?
@@ -596,7 +596,7 @@ class CompilerDriver {
}
ProfileFile profile_file_;
- bool profile_ok_;
+ bool profile_present_;
// Should the compiler run on this method given profile information?
bool SkipCompilation(const std::string& method_name);
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 20c6bc8..05a9ac7 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -24,7 +24,6 @@ class CompilerOptions {
enum CompilerFilter {
kVerifyNone, // Skip verification and compile nothing except JNI stubs.
kInterpretOnly, // Compile nothing except JNI stubs.
- kProfiled, // Compile based on profile.
kSpace, // Maximize space savings.
kBalanced, // Try to get the best performance return on compilation investment.
kSpeed, // Maximize runtime performance.
@@ -33,7 +32,7 @@ class CompilerOptions {
// Guide heuristics to determine whether to compile method if profile data not available.
#if ART_SMALL_MODE
- static const CompilerFilter kDefaultCompilerFilter = kProfiled;
+ static const CompilerFilter kDefaultCompilerFilter = kInterpretOnly;
#else
static const CompilerFilter kDefaultCompilerFilter = kSpeed;
#endif
@@ -42,6 +41,7 @@ class CompilerOptions {
static const size_t kDefaultSmallMethodThreshold = 60;
static const size_t kDefaultTinyMethodThreshold = 20;
static const size_t kDefaultNumDexMethodsThreshold = 900;
+ static constexpr double kDefaultTopKProfileThreshold = 90.0;
CompilerOptions() :
compiler_filter_(kDefaultCompilerFilter),
@@ -50,7 +50,8 @@ class CompilerOptions {
small_method_threshold_(kDefaultSmallMethodThreshold),
tiny_method_threshold_(kDefaultTinyMethodThreshold),
num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold),
- generate_gdb_information_(false)
+ generate_gdb_information_(false),
+ top_k_profile_threshold_(kDefaultTopKProfileThreshold)
#ifdef ART_SEA_IR_MODE
, sea_ir_mode_(false)
#endif
@@ -62,7 +63,8 @@ class CompilerOptions {
size_t small_method_threshold,
size_t tiny_method_threshold,
size_t num_dex_methods_threshold,
- bool generate_gdb_information
+ bool generate_gdb_information,
+ double top_k_profile_threshold
#ifdef ART_SEA_IR_MODE
, bool sea_ir_mode
#endif
@@ -73,7 +75,8 @@ class CompilerOptions {
small_method_threshold_(small_method_threshold),
tiny_method_threshold_(tiny_method_threshold),
num_dex_methods_threshold_(num_dex_methods_threshold),
- generate_gdb_information_(generate_gdb_information)
+ generate_gdb_information_(generate_gdb_information),
+ top_k_profile_threshold_(top_k_profile_threshold)
#ifdef ART_SEA_IR_MODE
, sea_ir_mode_(sea_ir_mode)
#endif
@@ -132,6 +135,10 @@ class CompilerOptions {
return num_dex_methods_threshold_;
}
+ double GetTopKProfileThreshold() const {
+ return top_k_profile_threshold_;
+ }
+
#ifdef ART_SEA_IR_MODE
bool GetSeaIrMode();
#endif
@@ -148,7 +155,8 @@ class CompilerOptions {
size_t tiny_method_threshold_;
size_t num_dex_methods_threshold_;
bool generate_gdb_information_;
-
+ // When using a profile file only the top K% of the profiled samples will be compiled.
+ double top_k_profile_threshold_;
#ifdef ART_SEA_IR_MODE
bool sea_ir_mode_;
#endif
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index c6b1aa5..e75e6d2 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -703,6 +703,38 @@ static InstructionSetFeatures ParseFeatureList(std::string str) {
return result;
}
+void ParseStringAfterChar(const std::string& s, char c, std::string* parsed_value) {
+ std::string::size_type colon = s.find(c);
+ if (colon == std::string::npos) {
+ Usage("Missing char %c in option %s\n", c, s.c_str());
+ }
+ // Add one to remove the char we were trimming until.
+ *parsed_value = s.substr(colon + 1);
+}
+
+void ParseDouble(const std::string& option, char after_char,
+ double min, double max, double* parsed_value) {
+ std::string substring;
+ ParseStringAfterChar(option, after_char, &substring);
+ bool sane_val = true;
+ double value;
+ if (false) {
+ // TODO: this doesn't seem to work on the emulator. b/15114595
+ std::stringstream iss(substring);
+ iss >> value;
+ // Ensure that we have a value, there was no cruft after it and it satisfies a sensible range.
+ sane_val = iss.eof() && (value >= min) && (value <= max);
+ } else {
+ char* end = nullptr;
+ value = strtod(substring.c_str(), &end);
+ sane_val = *end == '\0' && value >= min && value <= max;
+ }
+ if (!sane_val) {
+ Usage("Invalid double value %s for option %s\n", substring.c_str(), option.c_str());
+ }
+ *parsed_value = value;
+}
+
static int dex2oat(int argc, char** argv) {
original_argc = argc;
original_argv = argv;
@@ -755,6 +787,7 @@ static int dex2oat(int argc, char** argv) {
// Profile file to use
std::string profile_file;
+ double top_k_profile_threshold = CompilerOptions::kDefaultTopKProfileThreshold;
bool is_host = false;
bool dump_stats = false;
@@ -918,6 +951,8 @@ static int dex2oat(int argc, char** argv) {
VLOG(compiler) << "dex2oat: profile file is " << profile_file;
} else if (option == "--no-profile-file") {
// No profile
+ } else if (option.starts_with("--top-k-profile-threshold=")) {
+ ParseDouble(option.data(), '=', 10.0, 90.0, &top_k_profile_threshold);
} else if (option == "--print-pass-names") {
PassDriverMEOpts::PrintPassNames();
} else if (option.starts_with("--disable-passes=")) {
@@ -1063,7 +1098,8 @@ static int dex2oat(int argc, char** argv) {
small_method_threshold,
tiny_method_threshold,
num_dex_methods_threshold,
- generate_gdb_information
+ generate_gdb_information,
+ top_k_profile_threshold
#ifdef ART_SEA_IR_MODE
, compiler_options.sea_ir_ = true;
#endif
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 585c88e..e3fbd5c 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -328,7 +328,7 @@ static jboolean IsDexOptNeededInternal(JNIEnv* env, const char* filename,
// If the 'defer' argument is true then this will be retried later. In this case we
// need to make sure that the profile file copy is not made so that we will get the
// same result second time.
- if (pkgname != nullptr) {
+ if (Runtime::Current()->GetProfilerOptions().IsEnabled() && (pkgname != nullptr)) {
const std::string profile_file = GetDalvikCacheOrDie("profiles", false /* create_if_absent */)
+ std::string("/") + pkgname;
const std::string profile_cache_dir = GetDalvikCacheOrDie("profile-cache",
@@ -357,8 +357,8 @@ static jboolean IsDexOptNeededInternal(JNIEnv* env, const char* filename,
// There is a previous profile file. Check if the profile has changed significantly.
// A change in profile is considered significant if X% (change_thr property) of the top K%
// (compile_thr property) samples has changed.
- double top_k_threshold = GetDoubleProperty("dalvik.vm.profiler.dex2oat.compile_thr", 10.0, 90.0, 90.0);
- double change_threshold = GetDoubleProperty("dalvik.vm.profiler.dex2oat.change_thr", 1.0, 90.0, 10.0);
+ double top_k_threshold = Runtime::Current()->GetProfilerOptions().GetTopKThreshold();
+ double change_threshold = Runtime::Current()->GetProfilerOptions().GetTopKChangeThreshold();
double change_percent = 0.0;
ProfileFile new_profile, old_profile;
bool new_ok = new_profile.LoadFile(profile_file);
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index e5cc671..63d7c77 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -510,15 +510,13 @@ static void VMRuntime_preloadDexCaches(JNIEnv* env, jobject) {
* process name. We use this information to start up the sampling profiler for
* for ART.
*/
-static void VMRuntime_registerAppInfo(JNIEnv* env, jclass, jstring pkgName, jstring appDir, jstring procName) {
+static void VMRuntime_registerAppInfo(JNIEnv* env, jclass, jstring pkgName,
+ jstring appDir, jstring procName) {
const char *pkgNameChars = env->GetStringUTFChars(pkgName, NULL);
- const char *appDirChars = env->GetStringUTFChars(appDir, NULL);
- const char *procNameChars = env->GetStringUTFChars(procName, NULL);
-
std::string profileFile = StringPrintf("/data/dalvik-cache/profiles/%s", pkgNameChars);
- Runtime::Current()->StartProfiler(profileFile.c_str(), procNameChars);
- env->ReleaseStringUTFChars(appDir, appDirChars);
- env->ReleaseStringUTFChars(procName, procNameChars);
+
+ Runtime::Current()->StartProfiler(profileFile.c_str());
+
env->ReleaseStringUTFChars(pkgName, pkgNameChars);
}
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index db2a61b..fac9965 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -248,12 +248,6 @@ bool ParsedOptions::Parse(const Runtime::Options& options, bool ignore_unrecogni
method_trace_file_ = "/data/method-trace-file.bin";
method_trace_file_size_ = 10 * MB;
- profile_ = false;
- profile_period_s_ = 10; // Seconds.
- profile_duration_s_ = 20; // Seconds.
- profile_interval_us_ = 500; // Microseconds.
- profile_backoff_coefficient_ = 2.0;
- profile_start_immediately_ = true;
profile_clock_source_ = kDefaultProfilerClockSource;
verify_ = true;
@@ -534,29 +528,38 @@ bool ParsedOptions::Parse(const Runtime::Options& options, bool ignore_unrecogni
Trace::SetDefaultClockSource(kProfilerClockSourceWall);
} else if (option == "-Xprofile:dualclock") {
Trace::SetDefaultClockSource(kProfilerClockSourceDual);
+ } else if (option == "-Xenable-profiler") {
+ profiler_options_.enabled_ = true;
} else if (StartsWith(option, "-Xprofile-filename:")) {
if (!ParseStringAfterChar(option, ':', &profile_output_filename_)) {
return false;
}
- profile_ = true;
} else if (StartsWith(option, "-Xprofile-period:")) {
- if (!ParseUnsignedInteger(option, ':', &profile_period_s_)) {
+ if (!ParseUnsignedInteger(option, ':', &profiler_options_.period_s_)) {
return false;
}
} else if (StartsWith(option, "-Xprofile-duration:")) {
- if (!ParseUnsignedInteger(option, ':', &profile_duration_s_)) {
+ if (!ParseUnsignedInteger(option, ':', &profiler_options_.duration_s_)) {
return false;
}
} else if (StartsWith(option, "-Xprofile-interval:")) {
- if (!ParseUnsignedInteger(option, ':', &profile_interval_us_)) {
+ if (!ParseUnsignedInteger(option, ':', &profiler_options_.interval_us_)) {
return false;
}
} else if (StartsWith(option, "-Xprofile-backoff:")) {
- if (!ParseDouble(option, ':', 1.0, 10.0, &profile_backoff_coefficient_)) {
+ if (!ParseDouble(option, ':', 1.0, 10.0, &profiler_options_.backoff_coefficient_)) {
+ return false;
+ }
+ } else if (option == "-Xprofile-start-immediately") {
+ profiler_options_.start_immediately_ = true;
+ } else if (StartsWith(option, "-Xprofile-top-k-threshold:")) {
+ if (!ParseDouble(option, ':', 10.0, 90.0, &profiler_options_.top_k_threshold_)) {
+ return false;
+ }
+ } else if (StartsWith(option, "-Xprofile-top-k-change-threshold:")) {
+ if (!ParseDouble(option, ':', 10.0, 90.0, &profiler_options_.top_k_change_threshold_)) {
return false;
}
- } else if (option == "-Xprofile-start-lazy") {
- profile_start_immediately_ = false;
} else if (StartsWith(option, "-implicit-checks:")) {
std::string checks;
if (!ParseStringAfterChar(option, ':', &checks)) {
@@ -791,11 +794,15 @@ void ParsedOptions::Usage(const char* fmt, ...) {
UsageMessage(stream, " -Xmethod-trace\n");
UsageMessage(stream, " -Xmethod-trace-file:filename");
UsageMessage(stream, " -Xmethod-trace-file-size:integervalue\n");
+ UsageMessage(stream, " -Xenable-profiler\n");
UsageMessage(stream, " -Xprofile-filename:filename\n");
UsageMessage(stream, " -Xprofile-period:integervalue\n");
UsageMessage(stream, " -Xprofile-duration:integervalue\n");
UsageMessage(stream, " -Xprofile-interval:integervalue\n");
UsageMessage(stream, " -Xprofile-backoff:doublevalue\n");
+ UsageMessage(stream, " -Xprofile-start-immediately\n");
+ UsageMessage(stream, " -Xprofile-top-k-threshold:doublevalue\n");
+ UsageMessage(stream, " -Xprofile-top-k-change-threshold:doublevalue\n");
UsageMessage(stream, " -Xcompiler:filename\n");
UsageMessage(stream, " -Xcompiler-option dex2oat-option\n");
UsageMessage(stream, " -Ximage-compiler-option dex2oat-option\n");
diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h
index 25fc12a..a27eec6 100644
--- a/runtime/parsed_options.h
+++ b/runtime/parsed_options.h
@@ -77,13 +77,8 @@ class ParsedOptions {
std::string compiler_executable_;
std::vector<std::string> compiler_options_;
std::vector<std::string> image_compiler_options_;
- bool profile_;
+ ProfilerOptions profiler_options_;
std::string profile_output_filename_;
- uint32_t profile_period_s_;
- uint32_t profile_duration_s_;
- uint32_t profile_interval_us_;
- double profile_backoff_coefficient_;
- bool profile_start_immediately_;
ProfilerClockSource profile_clock_source_;
bool verify_;
InstructionSet image_isa_;
diff --git a/runtime/profiler.cc b/runtime/profiler.cc
index 75db9da..80ce205 100644
--- a/runtime/profiler.cc
+++ b/runtime/profiler.cc
@@ -53,7 +53,6 @@ BackgroundMethodSamplingProfiler* BackgroundMethodSamplingProfiler::profiler_ =
pthread_t BackgroundMethodSamplingProfiler::profiler_pthread_ = 0U;
volatile bool BackgroundMethodSamplingProfiler::shutting_down_ = false;
-
// TODO: this profiler runs regardless of the state of the machine. Maybe we should use the
// wakelock or something to modify the run characteristics. This can be done when we
// have some performance data after it's been used for a while.
@@ -126,6 +125,7 @@ void* BackgroundMethodSamplingProfiler::RunProfilerThread(void* arg) {
Thread* self = Thread::Current();
+ double backoff = 1.0;
while (true) {
if (ShuttingDown(self)) {
break;
@@ -133,13 +133,13 @@ void* BackgroundMethodSamplingProfiler::RunProfilerThread(void* arg) {
{
// wait until we need to run another profile
- uint64_t delay_secs = profiler->period_s_ * profiler->backoff_factor_;
+ uint64_t delay_secs = profiler->options_.GetPeriodS() * backoff;
// Add a startup delay to prevent all the profiles running at once.
delay_secs += startup_delay;
// Immediate startup for benchmarking?
- if (profiler->start_immediately_ && startup_delay > 0) {
+ if (profiler->options_.GetStartImmediately() && startup_delay > 0) {
delay_secs = 0;
}
@@ -150,10 +150,7 @@ void* BackgroundMethodSamplingProfiler::RunProfilerThread(void* arg) {
profiler->period_condition_.TimedWait(self, delay_secs * 1000, 0);
// Expand the backoff by its coefficient, but don't go beyond the max.
- double new_backoff = profiler->backoff_factor_ * profiler->backoff_coefficient_;
- if (new_backoff < kMaxBackoffSecs) {
- profiler->backoff_factor_ = new_backoff;
- }
+ backoff = std::min(backoff * profiler->options_.GetBackoffCoefficient(), kMaxBackoffSecs);
}
if (ShuttingDown(self)) {
@@ -162,11 +159,11 @@ void* BackgroundMethodSamplingProfiler::RunProfilerThread(void* arg) {
uint64_t start_us = MicroTime();
- uint64_t end_us = start_us + profiler->duration_s_ * UINT64_C(1000000);
+ uint64_t end_us = start_us + profiler->options_.GetDurationS() * UINT64_C(1000000);
uint64_t now_us = start_us;
- VLOG(profiler) << "Starting profiling run now for " << PrettyDuration((end_us - start_us) * 1000);
-
+ VLOG(profiler) << "Starting profiling run now for "
+ << PrettyDuration((end_us - start_us) * 1000);
SampleCheckpoint check_point(profiler);
@@ -176,7 +173,7 @@ void* BackgroundMethodSamplingProfiler::RunProfilerThread(void* arg) {
break;
}
- usleep(profiler->interval_us_); // Non-interruptible sleep.
+ usleep(profiler->options_.GetIntervalUs()); // Non-interruptible sleep.
ThreadList* thread_list = runtime->GetThreadList();
@@ -228,7 +225,7 @@ void* BackgroundMethodSamplingProfiler::RunProfilerThread(void* arg) {
// Write out the profile file if we are generating a profile.
uint32_t BackgroundMethodSamplingProfiler::WriteProfile() {
- std::string full_name = profile_file_name_;
+ std::string full_name = output_filename_;
VLOG(profiler) << "Saving profile to " << full_name;
int fd = open(full_name.c_str(), O_RDWR);
@@ -283,45 +280,35 @@ uint32_t BackgroundMethodSamplingProfiler::WriteProfile() {
return num_methods;
}
-// Start a profile thread with the user-supplied arguments.
-void BackgroundMethodSamplingProfiler::Start(int period, int duration,
- const std::string& profile_file_name, const std::string& procName,
- int interval_us,
- double backoff_coefficient, bool startImmediately) {
+bool BackgroundMethodSamplingProfiler::Start(
+ const std::string& output_filename, const ProfilerOptions& options) {
+ if (!options.IsEnabled()) {
+ LOG(INFO) << "Profiler disabled. To enable setprop dalvik.vm.profiler 1.";
+ return false;
+ }
+
+ CHECK(!output_filename.empty());
+
Thread* self = Thread::Current();
{
MutexLock mu(self, *Locks::profiler_lock_);
// Don't start two profiler threads.
if (profiler_ != nullptr) {
- return;
+ return true;
}
}
- // Only on target...
-#ifdef HAVE_ANDROID_OS
- // Switch off profiler if the dalvik.vm.profiler property has value 0.
- char buf[PROP_VALUE_MAX];
- property_get("dalvik.vm.profiler", buf, "0");
- if (strcmp(buf, "0") == 0) {
- LOG(INFO) << "Profiler disabled. To enable setprop dalvik.vm.profiler 1";
- return;
- }
-#endif
-
- LOG(INFO) << "Starting profile with period " << period << "s, duration " << duration <<
- "s, interval " << interval_us << "us. Profile file " << profile_file_name;
-
+ LOG(INFO) << "Starting profiler using output file: " << output_filename
+ << " and options: " << options;
{
MutexLock mu(self, *Locks::profiler_lock_);
- profiler_ = new BackgroundMethodSamplingProfiler(period, duration, profile_file_name,
- procName,
- backoff_coefficient,
- interval_us, startImmediately);
+ profiler_ = new BackgroundMethodSamplingProfiler(output_filename, options);
CHECK_PTHREAD_CALL(pthread_create, (&profiler_pthread_, nullptr, &RunProfilerThread,
reinterpret_cast<void*>(profiler_)),
"Profiler thread");
}
+ return true;
}
@@ -357,14 +344,10 @@ void BackgroundMethodSamplingProfiler::Shutdown() {
Stop();
}
-BackgroundMethodSamplingProfiler::BackgroundMethodSamplingProfiler(int period, int duration,
- const std::string& profile_file_name,
- const std::string& process_name,
- double backoff_coefficient, int interval_us, bool startImmediately)
- : profile_file_name_(profile_file_name), process_name_(process_name),
- period_s_(period), start_immediately_(startImmediately),
- interval_us_(interval_us), backoff_factor_(1.0),
- backoff_coefficient_(backoff_coefficient), duration_s_(duration),
+BackgroundMethodSamplingProfiler::BackgroundMethodSamplingProfiler(
+ const std::string& output_filename, const ProfilerOptions& options)
+ : output_filename_(output_filename),
+ options_(options),
wait_lock_("Profile wait lock"),
period_condition_("Profile condition", wait_lock_),
profile_table_(wait_lock_),
@@ -466,7 +449,8 @@ uint32_t ProfileSampleResults::Write(std::ostream &os) {
num_null_methods_ += previous_num_null_methods_;
num_boot_methods_ += previous_num_boot_methods_;
- VLOG(profiler) << "Profile: " << num_samples_ << "/" << num_null_methods_ << "/" << num_boot_methods_;
+ VLOG(profiler) << "Profile: "
+ << num_samples_ << "/" << num_null_methods_ << "/" << num_boot_methods_;
os << num_samples_ << "/" << num_null_methods_ << "/" << num_boot_methods_ << "\n";
uint32_t num_methods = 0;
for (int i = 0 ; i < kHashSize; i++) {
diff --git a/runtime/profiler.h b/runtime/profiler.h
index 2502289..0b18dbb 100644
--- a/runtime/profiler.h
+++ b/runtime/profiler.h
@@ -28,6 +28,7 @@
#include "base/mutex.h"
#include "globals.h"
#include "instrumentation.h"
+#include "profiler_options.h"
#include "os.h"
#include "safe_map.h"
@@ -62,17 +63,18 @@ class ProfileSampleResults {
private:
uint32_t Hash(mirror::ArtMethod* method);
static constexpr int kHashSize = 17;
- Mutex& lock_; // Reference to the main profiler lock - we don't need two of them.
- uint32_t num_samples_; // Total number of samples taken.
- uint32_t num_null_methods_; // Number of samples where can don't know the method.
- uint32_t num_boot_methods_; // Number of samples in the boot path.
+ Mutex& lock_; // Reference to the main profiler lock - we don't need two of them.
+ uint32_t num_samples_; // Total number of samples taken.
+ uint32_t num_null_methods_; // Number of samples where can don't know the method.
+ uint32_t num_boot_methods_; // Number of samples in the boot path.
typedef std::map<mirror::ArtMethod*, uint32_t> Map; // Map of method vs its count.
Map *table[kHashSize];
struct PreviousValue {
PreviousValue() : count_(0), method_size_(0) {}
- PreviousValue(uint32_t count, uint32_t method_size) : count_(count), method_size_(method_size) {}
+ PreviousValue(uint32_t count, uint32_t method_size)
+ : count_(count), method_size_(method_size) {}
uint32_t count_;
uint32_t method_size_;
};
@@ -101,9 +103,9 @@ class ProfileSampleResults {
class BackgroundMethodSamplingProfiler {
public:
- static void Start(int period, int duration, const std::string& profile_filename,
- const std::string& procName, int interval_us,
- double backoff_coefficient, bool startImmediately)
+ // Start a profile thread with the user-supplied arguments.
+ // Returns true if the profile was started or if it was already running. Returns false otherwise.
+ static bool Start(const std::string& output_filename, const ProfilerOptions& options)
LOCKS_EXCLUDED(Locks::mutator_lock_,
Locks::thread_list_lock_,
Locks::thread_suspend_count_lock_,
@@ -119,10 +121,8 @@ class BackgroundMethodSamplingProfiler {
}
private:
- explicit BackgroundMethodSamplingProfiler(int period, int duration,
- const std::string& profile_filename,
- const std::string& process_name,
- double backoff_coefficient, int interval_us, bool startImmediately);
+ explicit BackgroundMethodSamplingProfiler(
+ const std::string& output_filename, const ProfilerOptions& options);
// The sampling interval in microseconds is passed as an argument.
static void* RunProfilerThread(void* arg) LOCKS_EXCLUDED(Locks::profiler_lock_);
@@ -141,35 +141,14 @@ class BackgroundMethodSamplingProfiler {
// Sampling thread, non-zero when sampling.
static pthread_t profiler_pthread_;
- // Some measure of the number of samples that are significant
+ // Some measure of the number of samples that are significant.
static constexpr uint32_t kSignificantSamples = 10;
- // File to write profile data out to. Cannot be empty if we are profiling.
- std::string profile_file_name_;
+ // The name of the file where profile data will be written.
+ std::string output_filename_;
+ // The options used to start the profiler.
+ const ProfilerOptions& options_;
- // Process name.
- std::string process_name_;
-
- // Number of seconds between profile runs.
- uint32_t period_s_;
-
- // Most of the time we want to delay the profiler startup to prevent everything
- // running at the same time (all processes). This is the default, but if we
- // want to override this, set the 'start_immediately_' to true. This is done
- // if the -Xprofile option is given on the command line.
- bool start_immediately_;
-
- uint32_t interval_us_;
-
- // A backoff coefficent to adjust the profile period based on time.
- double backoff_factor_;
-
- // How much to increase the backoff by on each profile iteration.
- double backoff_coefficient_;
-
- // Duration of each profile run. The profile file will be written at the end
- // of each run.
- uint32_t duration_s_;
// Profile condition support.
Mutex wait_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
@@ -188,6 +167,7 @@ class BackgroundMethodSamplingProfiler {
DISALLOW_COPY_AND_ASSIGN(BackgroundMethodSamplingProfiler);
};
+//
// Contains profile data generated from previous runs of the program and stored
// in a file. It is used to determine whether to compile a particular method or not.
class ProfileFile {
@@ -212,12 +192,12 @@ class ProfileFile {
uint32_t count_; // Number of times it has been called.
uint32_t method_size_; // Size of the method on dex instructions.
double used_percent_; // Percentage of how many times this method was called.
- double top_k_used_percentage_; // The percentage of the group that comprise K% of the total used
- // methods this methods belongs to.
+ double top_k_used_percentage_; // The percentage of the group that comprise K% of the total
+ // used methods this methods belongs to.
};
public:
- // Loads profile data from the given file. The data are merged with any existing data.
+ // Loads profile data from the given file. The new data are merged with any existing data.
// Returns true if the file was loaded successfully and false otherwise.
bool LoadFile(const std::string& filename);
diff --git a/runtime/profiler_options.h b/runtime/profiler_options.h
new file mode 100644
index 0000000..08e32cc
--- /dev/null
+++ b/runtime/profiler_options.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_PROFILER_OPTIONS_H_
+#define ART_RUNTIME_PROFILER_OPTIONS_H_
+
+#include <string>
+#include <ostream>
+
+namespace art {
+
+class ProfilerOptions {
+ public:
+ static constexpr bool kDefaultEnabled = false;
+ static constexpr uint32_t kDefaultPeriodS = 10;
+ static constexpr uint32_t kDefaultDurationS = 20;
+ static constexpr uint32_t kDefaultIntervalUs = 500;
+ static constexpr double kDefaultBackoffCoefficient = 2.0;
+ static constexpr bool kDefaultStartImmediately = false;
+ static constexpr double kDefaultTopKThreshold = 90.0;
+ static constexpr double kDefaultChangeInTopKThreshold = 10.0;
+
+ ProfilerOptions() :
+ enabled_(kDefaultEnabled),
+ period_s_(kDefaultPeriodS),
+ duration_s_(kDefaultDurationS),
+ interval_us_(kDefaultIntervalUs),
+ backoff_coefficient_(kDefaultBackoffCoefficient),
+ start_immediately_(kDefaultStartImmediately),
+ top_k_threshold_(kDefaultTopKThreshold),
+ top_k_change_threshold_(kDefaultChangeInTopKThreshold) {}
+
+ ProfilerOptions(bool enabled,
+ uint32_t period_s,
+ uint32_t duration_s,
+ uint32_t interval_us,
+ double backoff_coefficient,
+ bool start_immediately,
+ double top_k_threshold,
+ double top_k_change_threshold):
+ enabled_(enabled),
+ period_s_(period_s),
+ duration_s_(duration_s),
+ interval_us_(interval_us),
+ backoff_coefficient_(backoff_coefficient),
+ start_immediately_(start_immediately),
+ top_k_threshold_(top_k_threshold),
+ top_k_change_threshold_(top_k_change_threshold) {}
+
+ bool IsEnabled() const {
+ return enabled_;
+ }
+
+ uint32_t GetPeriodS() const {
+ return period_s_;
+ }
+
+ uint32_t GetDurationS() const {
+ return duration_s_;
+ }
+
+ uint32_t GetIntervalUs() const {
+ return interval_us_;
+ }
+
+ double GetBackoffCoefficient() const {
+ return backoff_coefficient_;
+ }
+
+ bool GetStartImmediately() const {
+ return start_immediately_;
+ }
+
+ double GetTopKThreshold() const {
+ return top_k_threshold_;
+ }
+
+ double GetTopKChangeThreshold() const {
+ return top_k_change_threshold_;
+ }
+
+ private:
+ friend std::ostream & operator<<(std::ostream &os, const ProfilerOptions& po) {
+ os << "enabled=" << po.enabled_
+ << ", period_s=" << po.period_s_
+ << ", duration_s=" << po.duration_s_
+ << ", interval_us=" << po.interval_us_
+ << ", backoff_coefficient=" << po.backoff_coefficient_
+ << ", start_immediately=" << po.start_immediately_
+ << ", top_k_threshold=" << po.top_k_threshold_
+ << ", top_k_change_threshold=" << po.top_k_change_threshold_;
+ return os;
+ }
+
+ friend class ParsedOptions;
+
+ // Whether or not the applications should be profiled.
+ bool enabled_;
+ // Generate profile every n seconds.
+ uint32_t period_s_;
+ // Run profile for n seconds.
+ uint32_t duration_s_;
+ // Microseconds between samples.
+ uint32_t interval_us_;
+ // Coefficient to exponential backoff.
+ double backoff_coefficient_;
+ // Whether the profile should start upon app startup or be delayed by some random offset.
+ bool start_immediately_;
+ // Top K% of samples that are considered relevant when deciding if the app should be recompiled.
+ double top_k_threshold_;
+ // How much the top K% samples needs to change in order for the app to be recompiled.
+ double top_k_change_threshold_;
+};
+
+} // namespace art
+
+
+#endif // ART_RUNTIME_PROFILER_OPTIONS_H_
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 361070c..526d8f7 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -123,12 +123,7 @@ Runtime::Runtime()
abort_(nullptr),
stats_enabled_(false),
running_on_valgrind_(RUNNING_ON_VALGRIND > 0),
- profile_(false),
- profile_period_s_(0),
- profile_duration_s_(0),
- profile_interval_us_(0),
- profile_backoff_coefficient_(0),
- profile_start_immediately_(true),
+ profiler_started_(false),
method_trace_(false),
method_trace_file_size_(0),
instrumentation_(),
@@ -165,7 +160,7 @@ Runtime::~Runtime() {
shutting_down_ = true;
}
// Shut down background profiler before the runtime exits.
- if (profile_) {
+ if (profiler_started_) {
BackgroundMethodSamplingProfiler::Shutdown();
}
@@ -415,17 +410,16 @@ bool Runtime::Start() {
}
VLOG(startup) << "Runtime::Start exiting";
-
finished_starting_ = true;
- if (profile_) {
- // User has asked for a profile using -Xprofile
+ if (profiler_options_.IsEnabled() && !profile_output_filename_.empty()) {
+ // User has asked for a profile using -Xenable-profiler.
// Create the profile file if it doesn't exist.
int fd = open(profile_output_filename_.c_str(), O_RDWR|O_CREAT|O_EXCL, 0660);
if (fd >= 0) {
close(fd);
}
- StartProfiler(profile_output_filename_.c_str(), "");
+ StartProfiler(profile_output_filename_.c_str());
}
return true;
@@ -663,15 +657,9 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) {
method_trace_file_ = options->method_trace_file_;
method_trace_file_size_ = options->method_trace_file_size_;
- // Extract the profile options.
- // TODO: move into a Trace options struct?
- profile_period_s_ = options->profile_period_s_;
- profile_duration_s_ = options->profile_duration_s_;
- profile_interval_us_ = options->profile_interval_us_;
- profile_backoff_coefficient_ = options->profile_backoff_coefficient_;
- profile_start_immediately_ = options->profile_start_immediately_;
- profile_ = options->profile_;
profile_output_filename_ = options->profile_output_filename_;
+ profiler_options_ = options->profiler_options_;
+
// TODO: move this to just be an Trace::Start argument
Trace::SetDefaultClockSource(options->profile_clock_source_);
@@ -1124,9 +1112,10 @@ void Runtime::RemoveMethodVerifier(verifier::MethodVerifier* verifier) {
method_verifiers_.erase(it);
}
-void Runtime::StartProfiler(const char* appDir, const char* procName) {
- BackgroundMethodSamplingProfiler::Start(profile_period_s_, profile_duration_s_, appDir,
- procName, profile_interval_us_, profile_backoff_coefficient_, profile_start_immediately_);
+void Runtime::StartProfiler(const char* profile_output_filename) {
+ profile_output_filename_ = profile_output_filename;
+ profiler_started_ =
+ BackgroundMethodSamplingProfiler::Start(profile_output_filename_, profiler_options_);
}
// Transaction support.
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 261429e..be07828 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -34,6 +34,7 @@
#include "instrumentation.h"
#include "jobject_comparator.h"
#include "object_callbacks.h"
+#include "profiler_options.h"
#include "quick/quick_method_frame_info.h"
#include "runtime_stats.h"
#include "safe_map.h"
@@ -114,6 +115,10 @@ class Runtime {
return image_compiler_options_;
}
+ const ProfilerOptions& GetProfilerOptions() const {
+ return profiler_options_;
+ }
+
// Starts a runtime, which may cause threads to be started and code to run.
bool Start() UNLOCK_FUNCTION(Locks::mutator_lock_);
@@ -386,7 +391,7 @@ class Runtime {
const std::vector<const DexFile*>& GetCompileTimeClassPath(jobject class_loader);
void SetCompileTimeClassPath(jobject class_loader, std::vector<const DexFile*>& class_path);
- void StartProfiler(const char* appDir, const char* procName);
+ void StartProfiler(const char* profile_output_filename);
void UpdateProfilerState(int state);
// Transaction support.
@@ -551,15 +556,9 @@ class Runtime {
const bool running_on_valgrind_;
- // Runtime profile support.
- bool profile_;
std::string profile_output_filename_;
- uint32_t profile_period_s_; // Generate profile every n seconds.
- uint32_t profile_duration_s_; // Run profile for n seconds.
- uint32_t profile_interval_us_; // Microseconds between samples.
- double profile_backoff_coefficient_; // Coefficient to exponential backoff.
- bool profile_start_immediately_; // Whether the profile should start upon app
- // startup or be delayed by some random offset.
+ ProfilerOptions profiler_options_;
+ bool profiler_started_;
bool method_trace_;
std::string method_trace_file_;
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 05ff5ff..f562252 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1302,23 +1302,4 @@ bool Exec(std::vector<std::string>& arg_vector, std::string* error_msg) {
return true;
}
-double GetDoubleProperty(const char* property, double min_value, double max_value, double default_value) {
-#ifndef HAVE_ANDROID_OS
- return default_value;
-#else
- char buf[PROP_VALUE_MAX];
- char* endptr;
-
- property_get(property, buf, "");
- double value = strtod(buf, &endptr);
-
- // Return the defalt value if the string is invalid or the value is outside the given range
- if ((value == 0 && endptr == buf) // Invalid string
- || (value < min_value) || (value > max_value)) { // Out of range value
- return default_value;
- }
- return value;
-#endif
-}
-
} // namespace art
diff --git a/runtime/utils.h b/runtime/utils.h
index 0f9b22b..7be5d44 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -443,10 +443,6 @@ class VoidFunctor {
}
};
-// Returns the given property as a double or its default_value if the property string is not valid
-// or the parsed value is outside the interval [min_value, max_value].
-double GetDoubleProperty(const char* property, double min_value, double max_value, double default_value);
-
} // namespace art
#endif // ART_RUNTIME_UTILS_H_