From ed73a1d57de9a443ede4b82b3d9163578362c267 Mon Sep 17 00:00:00 2001 From: Matthew Cary Date: Fri, 23 Feb 2018 12:41:59 +0000 Subject: [PATCH] cygprofile: Orderfile-based madvise() and prefetch. Add support for madvising and prefetching different parts of the native library according to the orderfile. The orderfile will support organising the library text section into three parts: code that is used in startup only, commonly used code that is ordered, and all other code that is not ordered. This change adds another dummy_function_* to achieve that. The currently-experimental MadviseRandomText() function is replace with MadviseForOrderfile which performs more precise madvising of unordered code only as RANDOM. When madvising for the orderfile is done, library prefetching is disabled. This will be changed in the future to prefetch only startup or only ordered code depending on what is more effective in experiments. Bug: 758566 Change-Id: I85af8e33a79d9091e282f2640c47d6c83aca7fc2 Reviewed-on: https://chromium-review.googlesource.com/923965 Commit-Queue: Matthew Cary Reviewed-by: Camille Lamy Reviewed-by: Gabriel Charette Reviewed-by: agrieve Reviewed-by: Benoit L Cr-Commit-Position: refs/heads/master@{#538766} --- .../library_loader/library_loader_hooks.cc | 28 ++++++++----- .../library_loader/library_prefetcher.cc | 39 +++++++++++++++---- .../library_loader/library_prefetcher.h | 5 ++- base/base_switches.cc | 7 ++-- base/base_switches.h | 2 +- content/browser/gpu/gpu_process_host.cc | 2 +- .../renderer_host/render_process_host_impl.cc | 2 +- content/browser/utility_process_host_impl.cc | 2 +- 8 files changed, 60 insertions(+), 27 deletions(-) diff --git a/base/android/library_loader/library_loader_hooks.cc b/base/android/library_loader/library_loader_hooks.cc index e88c90d13d9ab2..75e0225fc9dfce 100644 --- a/base/android/library_loader/library_loader_hooks.cc +++ b/base/android/library_loader/library_loader_hooks.cc @@ -86,6 +86,13 @@ void RecordLibraryPreloaderRendereHistogram() { } } +#if BUILDFLAG(SUPPORTS_CODE_ORDERING) +bool ShouldDoOrderfileMemoryOptimization() { + return CommandLine::ForCurrentProcess()->HasSwitch( + switches::kOrderfileMemoryOptimization); +} +#endif + } // namespace static void JNI_LibraryLoader_RegisterChromiumAndroidLinkerRendererHistogram( @@ -168,15 +175,11 @@ void SetLibraryLoadedHook(LibraryLoadedHook* func) { static jboolean JNI_LibraryLoader_LibraryLoaded( JNIEnv* env, const JavaParamRef& jcaller) { - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kMadviseRandomExecutableCode)) { #if BUILDFLAG(SUPPORTS_CODE_ORDERING) - NativeLibraryPrefetcher::MadviseRandomText(); -#else - LOG(WARNING) << switches::kMadviseRandomExecutableCode - << " is not supported on this architecture."; -#endif + if (ShouldDoOrderfileMemoryOptimization()) { + NativeLibraryPrefetcher::MadviseForOrderfile(); } +#endif if (g_native_initialization_hook && !g_native_initialization_hook()) return false; @@ -196,10 +199,15 @@ static jboolean JNI_LibraryLoader_ForkAndPrefetchNativeLibrary( JNIEnv* env, const JavaParamRef& clazz) { #if BUILDFLAG(SUPPORTS_CODE_ORDERING) - return NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary(); -#else - return false; + // Calling madvise(MADV_RANDOM) and prefetching the same region have the + // opposite effects. + // TODO(crbug.com/758566): add library prefetching that only prefetches + // regions not madvise(MADV_RANDOM)'d. + if (!ShouldDoOrderfileMemoryOptimization()) { + return NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary(); + } #endif + return false; } static jint JNI_LibraryLoader_PercentageOfResidentNativeLibraryCode( diff --git a/base/android/library_loader/library_prefetcher.cc b/base/android/library_loader/library_prefetcher.cc index ac34c9c48e82dd..dda25778a1d3a8 100644 --- a/base/android/library_loader/library_prefetcher.cc +++ b/base/android/library_loader/library_prefetcher.cc @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -81,7 +82,7 @@ bool Mincore(size_t start, size_t end, std::vector* residency) { // Returns the start and end of .text, aligned to the lower and upper page // boundaries, respectively. std::pair GetTextRange() { - // |kStartOftext| may not be at the beginning of a page, since .plt can be + // |kStartOfText| may not be at the beginning of a page, since .plt can be // before it, yet in the same mapping for instance. size_t start_page = kStartOfText - kStartOfText % kPageSize; // Set the end to the page on which the beginning of the last symbol is. The @@ -91,6 +92,29 @@ std::pair GetTextRange() { return {start_page, end_page}; } +// Returns the start and end pages of the unordered section of .text, aligned to +// lower and upper page boundaries, respectively. +std::pair GetOrderedTextRange() { + size_t start_page = kStartOfOrderedText - kStartOfOrderedText % kPageSize; + // kEndOfUnorderedText is not considered ordered, but the byte immediately + // before is considered ordered and so can not be contained in the start page. + size_t end_page = base::bits::Align(kEndOfOrderedText, kPageSize); + return {start_page, end_page}; +} + +// Calls madvise(advice) on the specified range. Does nothing if the range is +// empty. +void MadviseOnRange(const std::pair& range, int advice) { + if (range.first >= range.second) { + return; + } + size_t size = range.second - range.first; + int err = madvise(reinterpret_cast(range.first), size, advice); + if (err) { + PLOG(ERROR) << "madvise() failed"; + } +} + // Timestamp in ns since Unix Epoch, and residency, as returned by mincore(). struct TimestampAndResidency { uint64_t timestamp_nanos; @@ -241,14 +265,13 @@ void NativeLibraryPrefetcher::PeriodicallyCollectResidency() { } // static -void NativeLibraryPrefetcher::MadviseRandomText() { +void NativeLibraryPrefetcher::MadviseForOrderfile() { CHECK(IsOrderingSane()); - const auto& range = GetTextRange(); - size_t size = range.second - range.first; - int err = madvise(reinterpret_cast(range.first), size, MADV_RANDOM); - if (err) { - PLOG(ERROR) << "madvise() failed"; - } + LOG(WARNING) << "Performing experimental madvise from orderfile information"; + // First MADV_RANDOM on all of text, then turn the ordered text range back to + // normal. The ordered range may be placed anywhere within .text. + MadviseOnRange(GetTextRange(), MADV_RANDOM); + MadviseOnRange(GetOrderedTextRange(), MADV_NORMAL); } } // namespace android diff --git a/base/android/library_loader/library_prefetcher.h b/base/android/library_loader/library_prefetcher.h index d6ed7f11cb2f42..e18dec2c2ff982 100644 --- a/base/android/library_loader/library_prefetcher.h +++ b/base/android/library_loader/library_prefetcher.h @@ -42,8 +42,9 @@ class BASE_EXPORT NativeLibraryPrefetcher { // dumps it to disk. static void PeriodicallyCollectResidency(); - // Calls madvise(MADV_RANDOM) on the native library executable code range. - static void MadviseRandomText(); + // Calls madvise() on the native library executable, using orderfile + // information to decide how to advise each part of the library. + static void MadviseForOrderfile(); private: // Returns the percentage of [start, end] currently resident in diff --git a/base/base_switches.cc b/base/base_switches.cc index 870d55c606f273..ab74d6aaf27375 100644 --- a/base/base_switches.cc +++ b/base/base_switches.cc @@ -128,9 +128,10 @@ const char kEnableCrashReporterForTesting[] = #endif #if defined(OS_ANDROID) -// Calls madvise(MADV_RANDOM) on executable code right after the library is -// loaded, from all processes. -const char kMadviseRandomExecutableCode[] = "madvise-random-executable-code"; +// Optimizes memory layout of the native library using the orderfile symbols +// given in base/android/library_loader/anchor_functions.h, via madvise and +// changing the library prefetch behavior. +const char kOrderfileMemoryOptimization[] = "orderfile-memory-optimization"; #endif } // namespace switches diff --git a/base/base_switches.h b/base/base_switches.h index 55c8ed23b85da5..566ecbbcc6b18f 100644 --- a/base/base_switches.h +++ b/base/base_switches.h @@ -46,7 +46,7 @@ extern const char kEnableCrashReporterForTesting[]; #endif #if defined(OS_ANDROID) -extern const char kMadviseRandomExecutableCode[]; +extern const char kOrderfileMemoryOptimization[]; #endif } // namespace switches diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index 3050b35d0c147e..7c71fb819a18e0 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc @@ -171,7 +171,7 @@ static const char* const kSwitchNames[] = { switches::kUseCmdDecoder, switches::kForceVideoOverlays, #if defined(OS_ANDROID) - switches::kMadviseRandomExecutableCode, + switches::kOrderfileMemoryOptimization, #endif }; diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index e33650ac216f51..4532ae1fd13f1c 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -2665,7 +2665,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer( switches::kDisallowNonExactResourceReuse, #if defined(OS_ANDROID) switches::kDisableMediaSessionAPI, - switches::kMadviseRandomExecutableCode, + switches::kOrderfileMemoryOptimization, switches::kRendererWaitForJavaDebugger, #endif #if defined(OS_MACOSX) diff --git a/content/browser/utility_process_host_impl.cc b/content/browser/utility_process_host_impl.cc index cc96884dca634a..51f997c262b5d3 100644 --- a/content/browser/utility_process_host_impl.cc +++ b/content/browser/utility_process_host_impl.cc @@ -314,7 +314,7 @@ bool UtilityProcessHostImpl::StartProcess() { switches::kUtilityStartupDialog, switches::kUseGL, #if defined(OS_ANDROID) - switches::kMadviseRandomExecutableCode, + switches::kOrderfileMemoryOptimization, #endif }; cmd_line->CopySwitchesFrom(browser_command_line, kSwitchNames,