Add and use loaded class profiling
Class profiling is a way to keep track of which classes are resolved.
From here the compiler can use this information to generate a smaller
app image.
TODO: Add tests for profile stuff.
Bug: 22858531
(cherry picked from commit 8913fc1a27df8cf3b37fd99e94d87f290591328e)
Change-Id: Ifcd09230cbdc266305bc1247e0d31e7920eb353e
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index b1a5a4b..ab26f6f 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -32,6 +32,7 @@
static constexpr const uint64_t kRandomDelayMaxMs = 20 * 1000; // 20 seconds
static constexpr const uint64_t kMaxBackoffMs = 5 * 60 * 1000; // 5 minutes
static constexpr const uint64_t kSavePeriodMs = 10 * 1000; // 10 seconds
+static constexpr const uint64_t kInitialDelayMs = 2 * 1000; // 2 seconds
static constexpr const double kBackoffCoef = 1.5;
static constexpr const uint32_t kMinimumNrOrMethodsToSave = 10;
@@ -45,6 +46,7 @@
: jit_code_cache_(jit_code_cache),
code_cache_last_update_time_ns_(0),
shutting_down_(false),
+ first_profile_(true),
wait_lock_("ProfileSaver wait lock"),
period_condition_("ProfileSaver period condition", wait_lock_) {
AddTrackedLocations(output_filename, code_paths);
@@ -56,13 +58,18 @@
uint64_t save_period_ms = kSavePeriodMs;
VLOG(profiler) << "Save profiling information every " << save_period_ms << " ms";
- while (true) {
- if (ShuttingDown(self)) {
- break;
- }
- uint64_t random_sleep_delay_ms = rand() % kRandomDelayMaxMs;
- uint64_t sleep_time_ms = save_period_ms + random_sleep_delay_ms;
+ bool first_iteration = true;
+ while (!ShuttingDown(self)) {
+ uint64_t sleep_time_ms;
+ if (first_iteration) {
+ // Sleep less long for the first iteration since we want to record loaded classes shortly
+ // after app launch.
+ sleep_time_ms = kInitialDelayMs;
+ } else {
+ const uint64_t random_sleep_delay_ms = rand() % kRandomDelayMaxMs;
+ sleep_time_ms = save_period_ms + random_sleep_delay_ms;
+ }
{
MutexLock mu(self, wait_lock_);
period_condition_.TimedWait(self, sleep_time_ms, 0);
@@ -81,13 +88,14 @@
// Reset the period to the initial value as it's highly likely to JIT again.
save_period_ms = kSavePeriodMs;
}
+ first_iteration = false;
}
}
bool ProfileSaver::ProcessProfilingInfo() {
uint64_t last_update_time_ns = jit_code_cache_->GetLastUpdateTimeNs();
- if (last_update_time_ns - code_cache_last_update_time_ns_
- < kMinimumTimeBetweenCodeCacheUpdatesNs) {
+ if (!first_profile_ && last_update_time_ns - code_cache_last_update_time_ns_
+ < kMinimumTimeBetweenCodeCacheUpdatesNs) {
VLOG(profiler) << "Not enough time has passed since the last code cache update."
<< "Last update: " << last_update_time_ns
<< " Last save: " << code_cache_last_update_time_ns_;
@@ -113,19 +121,27 @@
ScopedObjectAccess soa(Thread::Current());
jit_code_cache_->GetCompiledArtMethods(locations, methods);
}
- if (methods.size() < kMinimumNrOrMethodsToSave) {
+ // Always save for the first one for loaded classes profile.
+ if (methods.size() < kMinimumNrOrMethodsToSave && !first_profile_) {
VLOG(profiler) << "Not enough information to save to: " << filename
<<" Nr of methods: " << methods.size();
return false;
}
- if (!ProfileCompilationInfo::SaveProfilingInfo(filename, methods)) {
+ std::set<DexCacheResolvedClasses> resolved_classes;
+ if (first_profile_) {
+ ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
+ resolved_classes = class_linker->GetResolvedClasses(/*ignore boot classes*/true);
+ }
+
+ if (!ProfileCompilationInfo::SaveProfilingInfo(filename, methods, resolved_classes)) {
LOG(WARNING) << "Could not save profiling info to " << filename;
return false;
}
VLOG(profiler) << "Profile process time: " << PrettyDuration(NanoTime() - start);
}
+ first_profile_ = false;
return true;
}