diff options
-rw-r--r-- | libartbase/base/unix_file/fd_file.h | 3 | ||||
-rw-r--r-- | libprofile/profile/profile_compilation_info.cc | 45 | ||||
-rw-r--r-- | libprofile/profile/profile_compilation_info.h | 6 | ||||
-rw-r--r-- | runtime/jit/profile_saver.cc | 2 |
4 files changed, 43 insertions, 13 deletions
diff --git a/libartbase/base/unix_file/fd_file.h b/libartbase/base/unix_file/fd_file.h index 58fc3ee525..a46ef81586 100644 --- a/libartbase/base/unix_file/fd_file.h +++ b/libartbase/base/unix_file/fd_file.h @@ -74,6 +74,7 @@ class FdFile : public RandomAccessFile { int64_t Write(const char* buf, int64_t byte_count, int64_t offset) override WARN_UNUSED; int Flush() override WARN_UNUSED { return Flush(/*flush_metadata=*/false); } + int Flush(bool flush_metadata) WARN_UNUSED; // Short for SetLength(0); Flush(); Close(); // If the file was opened with a path name and unlink = true, also calls Unlink() on the path. @@ -175,8 +176,6 @@ class FdFile : public RandomAccessFile { template <bool kUseOffset> bool WriteFullyGeneric(const void* buffer, size_t byte_count, size_t offset); - int Flush(bool flush_metadata) WARN_UNUSED; - // The file path we hold for the file descriptor may be invalid, or may not even exist (e.g. if // the FdFile wasn't initialised with a path). This helper function checks if calling open() on // the file path (if it is set) returns the expected up-to-date file descriptor. This is still diff --git a/libprofile/profile/profile_compilation_info.cc b/libprofile/profile/profile_compilation_info.cc index 799ad86919..160e27e15e 100644 --- a/libprofile/profile/profile_compilation_info.cc +++ b/libprofile/profile/profile_compilation_info.cc @@ -823,11 +823,13 @@ bool ProfileCompilationInfo::Load(const std::string& filename, bool clear_if_inv return false; } -bool ProfileCompilationInfo::Save(const std::string& filename, uint64_t* bytes_written) { +bool ProfileCompilationInfo::Save(const std::string& filename, + uint64_t* bytes_written, + bool flush) { ScopedTrace trace(__PRETTY_FUNCTION__); #ifndef ART_TARGET_ANDROID - return SaveFallback(filename, bytes_written); + return SaveFallback(filename, bytes_written, flush); #else // Prior to U, SELinux policy doesn't allow apps to create profile files. // Additionally, when installd is being used for dexopt, it acquires a flock when working on a @@ -836,7 +838,7 @@ bool ProfileCompilationInfo::Save(const std::string& filename, uint64_t* bytes_w // partners. Therefore, we fall back to using a flock as well just to be safe. if (!android::modules::sdklevel::IsAtLeastU() || !android::base::GetBoolProperty("dalvik.vm.useartservice", /*default_value=*/false)) { - return SaveFallback(filename, bytes_written); + return SaveFallback(filename, bytes_written, flush); } std::string tmp_filename = filename + ".XXXXXX.tmp"; @@ -855,7 +857,7 @@ bool ProfileCompilationInfo::Save(const std::string& filename, uint64_t* bytes_w } }); - bool result = Save(fd.get()); + bool result = Save(fd.get(), flush); if (!result) { VLOG(profiler) << "Failed to save profile info to temp profile file " << tmp_filename; return false; @@ -871,6 +873,14 @@ bool ProfileCompilationInfo::Save(const std::string& filename, uint64_t* bytes_w remove_tmp_file.Disable(); + if (flush) { + std::string dirname = android::base::Dirname(filename); + std::unique_ptr<File> dir(OS::OpenFileForReading(dirname.c_str())); + if (dir == nullptr || dir->Flush(/*flush_metadata=*/true) != 0) { + PLOG(WARNING) << "Failed to flush directory " << dirname; + } + } + int64_t size = OS::GetFileSizeBytes(filename.c_str()); if (size != -1) { VLOG(profiler) << "Successfully saved profile info to " << filename << " Size: " << size; @@ -886,7 +896,9 @@ bool ProfileCompilationInfo::Save(const std::string& filename, uint64_t* bytes_w #endif } -bool ProfileCompilationInfo::SaveFallback(const std::string& filename, uint64_t* bytes_written) { +bool ProfileCompilationInfo::SaveFallback(const std::string& filename, + uint64_t* bytes_written, + bool flush) { std::string error; #ifdef _WIN32 int flags = O_WRONLY | O_CREAT; @@ -913,7 +925,16 @@ bool ProfileCompilationInfo::SaveFallback(const std::string& filename, uint64_t* // This doesn't need locking because we are trying to lock the file for exclusive // access and fail immediately if we can't. - bool result = Save(fd); + bool result = Save(fd, flush); + + if (flush) { + std::string dirname = android::base::Dirname(filename); + std::unique_ptr<File> dir(OS::OpenFileForReading(dirname.c_str())); + if (dir == nullptr || dir->Flush(/*flush_metadata=*/true) != 0) { + PLOG(WARNING) << "Failed to flush directory " << dirname; + } + } + if (result) { int64_t size = OS::GetFileSizeBytes(filename.c_str()); if (size != -1) { @@ -1002,7 +1023,7 @@ static bool WriteBuffer(int fd, const void* buffer, size_t byte_count) { * where `M` stands for special encodings indicating missing types (kIsMissingTypesEncoding) * or memamorphic call (kIsMegamorphicEncoding) which both imply `dex_map_size == 0`. **/ -bool ProfileCompilationInfo::Save(int fd) { +bool ProfileCompilationInfo::Save(int fd, bool flush) { uint64_t start = NanoTime(); ScopedTrace trace(__PRETTY_FUNCTION__); DCHECK_GE(fd, 0); @@ -1180,6 +1201,16 @@ bool ProfileCompilationInfo::Save(int fd) { return false; } + if (flush) { + // We do not flush for non-Linux because `flush` is only used by the runtime and the runtime + // only supports Linux. +#ifdef __linux__ + if (fsync(fd) != 0) { + PLOG(WARNING) << "Failed to flush profile data"; + } +#endif + } + uint64_t total_time = NanoTime() - start; VLOG(profiler) << "Compressed from " << std::to_string(total_uncompressed_size) diff --git a/libprofile/profile/profile_compilation_info.h b/libprofile/profile/profile_compilation_info.h index c8c325939c..5df8c1b575 100644 --- a/libprofile/profile/profile_compilation_info.h +++ b/libprofile/profile/profile_compilation_info.h @@ -474,13 +474,13 @@ class ProfileCompilationInfo { bool MergeWith(const std::string& filename); // Save the profile data to the given file descriptor. - bool Save(int fd); + bool Save(int fd, bool flush = false); // Save the current profile into the given file. Overwrites any existing data. - bool Save(const std::string& filename, uint64_t* bytes_written); + bool Save(const std::string& filename, uint64_t* bytes_written, bool flush = false); // A fallback implementation of `Save` that uses a flock. - bool SaveFallback(const std::string& filename, uint64_t* bytes_written); + bool SaveFallback(const std::string& filename, uint64_t* bytes_written, bool flush = false); // Return the number of dex files referenced in the profile. size_t GetNumberOfDexFiles() const { diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc index d2aa0f4772..733ad47ef3 100644 --- a/runtime/jit/profile_saver.cc +++ b/runtime/jit/profile_saver.cc @@ -898,7 +898,7 @@ bool ProfileSaver::ProcessProfilingInfo(bool force_save, /*out*/uint16_t* number uint64_t bytes_written; // Force the save. In case the profile data is corrupted or the profile // has the wrong version this will "fix" the file to the correct format. - if (info.Save(filename, &bytes_written)) { + if (info.Save(filename, &bytes_written, force_save)) { // We managed to save the profile. Clear the cache stored during startup. if (profile_cache_it != profile_cache_.end()) { ProfileCompilationInfo *cached_info = profile_cache_it->second; |