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 {
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
return instrumentation_cache_.get();
}
+ void SetDexLocationsForProfiling(const std::vector<std::string>& dex_locations);
void SaveProfilingInfo(const std::string& filename);
private:
#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"
}
}
-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);
}
}
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_);
#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 {
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,
{
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);
}
}
/**
* 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 {
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) {
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;
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_;
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();
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.
// 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_;
};
/**
*/
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) {
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;"),
};
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;
}
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.