OSDN Git Service

Pass down to the runtime the application code paths.
authorCalin Juravle <calin@google.com>
Tue, 8 Dec 2015 15:09:10 +0000 (15:09 +0000)
committerCalin Juravle <calin@google.com>
Thu, 17 Dec 2015 10:38:27 +0000 (12:38 +0200)
When registering the app with the runtime the framework needs to pass
down the list of application code paths. This will be used by JIT to
know what profile info to persist.

This fixes the reliance on OatFileManager::GetPrimaryOatFile which may
produce inconsistent results based on external factors (i.e. class path
order or failing to compile the first dex file from the class path)

Bug: 26080105
Change-Id: Iadcebd2684fcd48569e8f76ef21bd4d117fedc05

runtime/jit/jit.cc
runtime/jit/jit.h
runtime/jit/jit_code_cache.cc
runtime/jit/jit_code_cache.h
runtime/jit/offline_profiling_info.cc
runtime/jit/offline_profiling_info.h
runtime/native/dalvik_system_VMRuntime.cc
runtime/runtime.cc
runtime/runtime.h

index a653440..4ee1446 100644 (file)
@@ -177,22 +177,13 @@ void Jit::SaveProfilingInfo(const std::string& filename) {
   if (offline_profile_info_ == nullptr) {
     return;
   }
-  // Note that we can't check the PrimaryOatFile when constructing the offline_profilie_info_
-  // because it becomes known to the Runtime after we create and initialize the JIT.
-  const OatFile* primary_oat_file = Runtime::Current()->GetOatFileManager().GetPrimaryOatFile();
-  if (primary_oat_file == nullptr) {
-    LOG(WARNING) << "Couldn't find a primary oat file when trying to save profile info to "
-                 << filename;
-    return;
-  }
-
   uint64_t last_update_ns = code_cache_->GetLastUpdateTimeNs();
   if (offline_profile_info_->NeedsSaving(last_update_ns)) {
     VLOG(profiler) << "Initiate save profiling information to: " << filename;
     std::set<ArtMethod*> methods;
     {
       ScopedObjectAccess soa(Thread::Current());
-      code_cache_->GetCompiledArtMethods(primary_oat_file, methods);
+      code_cache_->GetCompiledArtMethods(offline_profile_info_->GetTrackedDexLocations(), methods);
     }
     offline_profile_info_->SaveProfilingInfo(filename, last_update_ns, methods);
   } else {
@@ -219,5 +210,12 @@ void Jit::CreateInstrumentationCache(size_t compile_threshold, size_t warmup_thr
       new jit::JitInstrumentationCache(compile_threshold, warmup_threshold));
 }
 
+void Jit::SetDexLocationsForProfiling(const std::vector<std::string>& dex_base_locations) {
+  if (offline_profile_info_ == nullptr) {
+    return;
+  }
+  offline_profile_info_->SetTrackedDexLocations(dex_base_locations);
+}
+
 }  // namespace jit
 }  // namespace art
index 630eba3..8a0778c 100644 (file)
@@ -72,6 +72,7 @@ class Jit {
     return instrumentation_cache_.get();
   }
 
+  void SetDexLocationsForProfiling(const std::vector<std::string>& dex_locations);
   void SaveProfilingInfo(const std::string& filename);
 
  private:
index 3342e92..033a8f0 100644 (file)
@@ -19,6 +19,7 @@
 #include <sstream>
 
 #include "art_method-inl.h"
+#include "base/stl_util.h"
 #include "base/time_utils.h"
 #include "entrypoints/runtime_asm_entrypoints.h"
 #include "gc/accounting/bitmap-inl.h"
@@ -687,11 +688,11 @@ void* JitCodeCache::MoreCore(const void* mspace, intptr_t increment) NO_THREAD_S
   }
 }
 
-void JitCodeCache::GetCompiledArtMethods(const OatFile* oat_file,
+void JitCodeCache::GetCompiledArtMethods(const std::set<const std::string>& dex_base_locations,
                                          std::set<ArtMethod*>& methods) {
   MutexLock mu(Thread::Current(), lock_);
   for (auto it : method_code_map_) {
-    if (it.second->GetDexFile()->GetOatDexFile()->GetOatFile() == oat_file) {
+    if (ContainsElement(dex_base_locations, it.second->GetDexFile()->GetBaseLocation())) {
       methods.insert(it.second);
     }
   }
index 4e82916..fa43766 100644 (file)
@@ -146,8 +146,9 @@ class JitCodeCache {
 
   void* MoreCore(const void* mspace, intptr_t increment);
 
-  // Adds to `methods` all the compiled ArtMethods which are part of the given `oat_file`.
-  void GetCompiledArtMethods(const OatFile* oat_file, std::set<ArtMethod*>& methods)
+  // Adds to `methods` all the compiled ArtMethods which are part of any of the given dex locations.
+  void GetCompiledArtMethods(const std::set<const std::string>& dex_base_locations,
+                             std::set<ArtMethod*>& methods)
       REQUIRES(!lock_)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
index 7615870..511b53d 100644 (file)
@@ -24,9 +24,9 @@
 
 #include "art_method-inl.h"
 #include "base/mutex.h"
+#include "base/stl_util.h"
 #include "jit/profiling_info.h"
 #include "safe_map.h"
-#include "utils.h"
 
 namespace art {
 
@@ -34,8 +34,20 @@ namespace art {
 static constexpr const uint64_t kMilisecondsToNano = 1000000;
 static constexpr const uint64_t kMinimumTimeBetweenSavesNs = 500 * kMilisecondsToNano;
 
+void OfflineProfilingInfo::SetTrackedDexLocations(
+      const std::vector<std::string>& dex_base_locations) {
+  tracked_dex_base_locations_.clear();
+  tracked_dex_base_locations_.insert(dex_base_locations.begin(), dex_base_locations.end());
+  VLOG(profiler) << "Tracking dex locations: " << Join(dex_base_locations, ':');
+}
+
+const std::set<const std::string>& OfflineProfilingInfo::GetTrackedDexLocations() const {
+  return tracked_dex_base_locations_;
+}
+
 bool OfflineProfilingInfo::NeedsSaving(uint64_t last_update_time_ns) const {
-  return last_update_time_ns - last_update_time_ns_.LoadRelaxed() > kMinimumTimeBetweenSavesNs;
+  return !tracked_dex_base_locations_.empty() &&
+      (last_update_time_ns - last_update_time_ns_.LoadRelaxed() > kMinimumTimeBetweenSavesNs);
 }
 
 void OfflineProfilingInfo::SaveProfilingInfo(const std::string& filename,
@@ -55,6 +67,7 @@ void OfflineProfilingInfo::SaveProfilingInfo(const std::string& filename,
   {
     ScopedObjectAccess soa(Thread::Current());
     for (auto it = methods.begin(); it != methods.end(); it++) {
+      DCHECK(ContainsElement(tracked_dex_base_locations_, (*it)->GetDexFile()->GetBaseLocation()));
       AddMethodInfo(*it, &info);
     }
   }
@@ -146,11 +159,11 @@ static constexpr const char kLineSeparator = '\n';
 
 /**
  * Serialization format:
- *    multidex_suffix1,dex_location_checksum1,method_id11,method_id12...
- *    multidex_suffix2,dex_location_checksum2,method_id21,method_id22...
+ *    dex_location1,dex_location_checksum1,method_id11,method_id12...
+ *    dex_location2,dex_location_checksum2,method_id21,method_id22...
  * e.g.
- *    ,131232145,11,23,454,54               -> this is the first dex file, it has no multidex suffix
- *    :classes5.dex,218490184,39,13,49,1    -> this is the fifth dex file.
+ *    /system/priv-app/app/app.apk,131232145,11,23,454,54
+ *    /system/priv-app/app/app.apk:classes5.dex,218490184,39,13,49,1
  **/
 bool OfflineProfilingInfo::Serialize(const std::string& filename,
                                      const DexFileToMethodsMap& info) const {
@@ -167,7 +180,7 @@ bool OfflineProfilingInfo::Serialize(const std::string& filename,
     const DexFile* dex_file = it.first;
     const std::set<uint32_t>& method_dex_ids = it.second;
 
-    os << DexFile::GetMultiDexSuffix(dex_file->GetLocation())
+    os << dex_file->GetLocation()
         << kFieldSeparator
         << dex_file->GetLocationChecksum();
     for (auto method_it : method_dex_ids) {
@@ -214,7 +227,7 @@ bool ProfileCompilationInfo::ProcessLine(const std::string& line,
     return false;
   }
 
-  const std::string& multidex_suffix = parts[0];
+  const std::string& dex_location = parts[0];
   uint32_t checksum;
   if (!ParseInt(parts[1].c_str(), &checksum)) {
     return false;
@@ -222,7 +235,7 @@ bool ProfileCompilationInfo::ProcessLine(const std::string& line,
 
   const DexFile* current_dex_file = nullptr;
   for (auto dex_file : dex_files) {
-    if (DexFile::GetMultiDexSuffix(dex_file->GetLocation()) == multidex_suffix) {
+    if (dex_file->GetLocation() == dex_location) {
       if (checksum != dex_file->GetLocationChecksum()) {
         LOG(WARNING) << "Checksum mismatch for "
             << dex_file->GetLocation() << " when parsing " << filename_;
@@ -284,15 +297,15 @@ bool ProfileCompilationInfo::Load(const std::vector<const DexFile*>& dex_files)
     return true;
   }
   if (kIsDebugBuild) {
-    // In debug builds verify that the multidex suffixes are unique.
-    std::set<std::string> suffixes;
+    // In debug builds verify that the locations are unique.
+    std::set<std::string> locations;
     for (auto dex_file : dex_files) {
-      std::string multidex_suffix = DexFile::GetMultiDexSuffix(dex_file->GetLocation());
-      DCHECK(suffixes.find(multidex_suffix) == suffixes.end())
+      const std::string& location = dex_file->GetLocation();
+      DCHECK(locations.find(location) == locations.end())
           << "DexFiles appear to belong to different apks."
-          << " There are multiple dex files with the same multidex suffix: "
-          << multidex_suffix;
-      suffixes.insert(multidex_suffix);
+          << " There are multiple dex files with the same location: "
+          << location;
+      locations.insert(location);
     }
   }
   info_.clear();
index 90bda60..8c5ffbe 100644 (file)
@@ -40,6 +40,8 @@ class OfflineProfilingInfo {
   void SaveProfilingInfo(const std::string& filename,
                          uint64_t last_update_time_ns,
                          const std::set<ArtMethod*>& methods);
+  void SetTrackedDexLocations(const std::vector<std::string>& dex_locations);
+  const std::set<const std::string>& GetTrackedDexLocations() const;
 
  private:
   // Map identifying the location of the profiled methods.
@@ -53,6 +55,8 @@ class OfflineProfilingInfo {
   // TODO(calin): Verify if Atomic is really needed (are we sure to be called from a
   // single thread?)
   Atomic<uint64_t> last_update_time_ns_;
+
+  std::set<const std::string> tracked_dex_base_locations_;
 };
 
 /**
index b49d68f..424cc11 100644 (file)
@@ -566,17 +566,25 @@ static void VMRuntime_preloadDexCaches(JNIEnv* env, jobject) {
  */
 static void VMRuntime_registerAppInfo(JNIEnv* env,
                                       jclass clazz ATTRIBUTE_UNUSED,
-                                      jstring pkgName,
-                                      jstring appDir,
-                                      jstring procName ATTRIBUTE_UNUSED) {
-  const char* appDirChars = env->GetStringUTFChars(appDir, nullptr);
-  const char* pkgNameChars = env->GetStringUTFChars(pkgName, nullptr);
-  std::string profileFile = StringPrintf("%s/code_cache/%s.prof", appDirChars, pkgNameChars);
+                                      jstring pkg_name,
+                                      jstring app_dir,
+                                      jobjectArray code_paths) {
+  std::vector<std::string> code_paths_vec;
+  int code_paths_length = env->GetArrayLength(code_paths);
+  for (int i = 0; i < code_paths_length; i++) {
+    jstring code_path = reinterpret_cast<jstring>(env->GetObjectArrayElement(code_paths, i));
+    const char* raw_code_path = env->GetStringUTFChars(code_path, nullptr);
+    code_paths_vec.push_back(raw_code_path);
+    env->ReleaseStringUTFChars(code_path, raw_code_path);
+  }
 
-  Runtime::Current()->SetJitProfilingFilename(profileFile.c_str());
+  const char* raw_app_dir = env->GetStringUTFChars(app_dir, nullptr);
+  const char* raw_pkg_name = env->GetStringUTFChars(pkg_name, nullptr);
+  std::string profile_file = StringPrintf("%s/code_cache/%s.prof", raw_app_dir, raw_pkg_name);
+  env->ReleaseStringUTFChars(pkg_name, raw_pkg_name);
+  env->ReleaseStringUTFChars(app_dir, raw_app_dir);
 
-  env->ReleaseStringUTFChars(appDir, appDirChars);
-  env->ReleaseStringUTFChars(pkgName, pkgNameChars);
+  Runtime::Current()->RegisterAppInfo(code_paths_vec, profile_file);
 }
 
 static jboolean VMRuntime_isBootClassPathOnDisk(JNIEnv* env, jclass, jstring java_instruction_set) {
@@ -633,7 +641,7 @@ static JNINativeMethod gMethods[] = {
   NATIVE_METHOD(VMRuntime, isCheckJniEnabled, "!()Z"),
   NATIVE_METHOD(VMRuntime, preloadDexCaches, "()V"),
   NATIVE_METHOD(VMRuntime, registerAppInfo,
-                "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"),
+                "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V"),
   NATIVE_METHOD(VMRuntime, isBootClassPathOnDisk, "(Ljava/lang/String;)Z"),
   NATIVE_METHOD(VMRuntime, getCurrentInstructionSet, "()Ljava/lang/String;"),
 };
index 93ca347..32e8388 100644 (file)
@@ -1633,7 +1633,12 @@ void Runtime::SetCalleeSaveMethod(ArtMethod* method, CalleeSaveType type) {
   callee_save_methods_[type] = reinterpret_cast<uintptr_t>(method);
 }
 
-void Runtime::SetJitProfilingFilename(const char* profile_output_filename) {
+void Runtime::RegisterAppInfo(const std::vector<std::string>& code_paths,
+                              const std::string& profile_output_filename) {
+  DCHECK(!profile_output_filename.empty());
+  if (jit_.get() != nullptr) {
+    jit_->SetDexLocationsForProfiling(code_paths);
+  }
   profile_output_filename_ = profile_output_filename;
 }
 
index 93d8fcf..b45408e 100644 (file)
@@ -467,7 +467,8 @@ class Runtime {
     return &instrumentation_;
   }
 
-  void SetJitProfilingFilename(const char* profile_output_filename);
+  void RegisterAppInfo(const std::vector<std::string>& code_paths,
+                       const std::string& profile_output_filename);
   void UpdateProfilerState(int state);
 
   // Transaction support.