summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-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
11 files changed, 229 insertions, 169 deletions
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 6085722..2c24e33 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 a369365..f1a987f 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -509,15 +509,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 72a868e..29868e3 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 68b10cc..f16eddf 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_(),
@@ -166,7 +161,7 @@ Runtime::~Runtime() {
shutting_down_ = true;
}
// Shut down background profiler before the runtime exits.
- if (profile_) {
+ if (profiler_started_) {
BackgroundMethodSamplingProfiler::Shutdown();
}
@@ -416,17 +411,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;
@@ -664,15 +658,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_);
@@ -1125,9 +1113,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 afb5aa7..808d706 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.
@@ -559,15 +564,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_