Skip to content

Commit

Permalink
android: Don't parse /proc/self/maps to prefetch the library.
Browse files Browse the repository at this point in the history
This commit changes the behavior of the native library prefetcher to
rely on sentinel symbols rather than parsing /proc/self/maps.

Behavior changes:
1. This will make the code no longer prefetch .data (because we don't
   look for it in the mappings), neither the sections that are part of
   the same mapping as .text (for instance, .rodata when using
   ld.gold). This is intended.
2. As a consequence, the UMA metric
   LibraryLoader.PercentageOfResidentCodeBeforePrefetch will move, as
   both sides of the ratio will change, and the population will change
   slightly as well (since code is currently not correctly ordered on
   ARM64 and x86_64)

- Removes the reliance on a somewhat brittle parsing of a file
- Parsing /proc/self/maps costs ~50ms of CPU on a Nexus 5X (on a little
  core, as this is triggered from an AsyncTask)
- Allows to only fetch part of the native library (in a forthcoming CL)

Rationale: 
Change-Id: I0bb7b28af3c3bd4af5745e2ebcc1fbf283bcc0c1
Reviewed-on: https://chromium-review.googlesource.com/874470
Commit-Queue: Benoit L <lizeb@chromium.org>
Reviewed-by: Egor Pasko <pasko@chromium.org>
Reviewed-by: agrieve <agrieve@chromium.org>
Reviewed-by: Matthew Cary <mattcary@chromium.org>
Cr-Commit-Position: refs/heads/master@{#531515}
  • Loading branch information
Benoit Lize authored and Commit Bot committed Jan 24, 2018
1 parent 102db4c commit ef6f0fb
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 318 deletions.
6 changes: 5 additions & 1 deletion base/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -1787,10 +1787,14 @@ buildflag_header("synchronization_flags") {
buildflag_header("anchor_functions_flags") {
header = "anchor_functions_flags.h"
header_dir = "base/android/library_loader"
_supports_code_ordering = current_cpu == "arm"

# buildflag entries added to this header must also must be manually added to
# tools/gn/bootstrap/bootstrap.py
flags = [ "USE_LLD=$use_lld" ]
flags = [
"USE_LLD=$use_lld",
"SUPPORTS_CODE_ORDERING=$_supports_code_ordering",
]
}

# This is the subset of files from base that should not be used with a dynamic
Expand Down
22 changes: 9 additions & 13 deletions base/android/library_loader/anchor_functions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@

#include "base/android/library_loader/anchor_functions.h"

#include "base/android/library_loader/anchor_functions_flags.h"
#include "base/logging.h"
#include "build/build_config.h"

// asm() macros below don't compile on x86, and haven't been validated outside
// ARM.
#if defined(ARCH_CPU_ARMEL)
#if BUILDFLAG(SUPPORTS_CODE_ORDERING)

// These functions are here to, respectively:
// 1. Check that functions are ordered
// 2. Delimit the start of .text
Expand Down Expand Up @@ -68,20 +66,18 @@ const size_t kStartOfText =
const size_t kEndOfText =
reinterpret_cast<size_t>(dummy_function_at_the_end_of_text);

void CheckOrderingSanity() {
bool IsOrderingSane() {
size_t dummy = reinterpret_cast<size_t>(&dummy_function_to_check_ordering);
size_t here = reinterpret_cast<size_t>(&IsOrderingSane);
// The linker usually keeps the input file ordering for symbols.
// dummy_function_to_anchor_text() should then be after
// dummy_function_to_check_ordering() without ordering.
// This check is thus intended to catch the lack of ordering.
CHECK_LT(kStartOfText,
reinterpret_cast<size_t>(&dummy_function_to_check_ordering));
CHECK_LT(kStartOfText, kEndOfText);
CHECK_LT(kStartOfText,
reinterpret_cast<size_t>(&dummy_function_to_check_ordering));
CHECK_LT(kStartOfText, reinterpret_cast<size_t>(&CheckOrderingSanity));
CHECK_GT(kEndOfText, reinterpret_cast<size_t>(&CheckOrderingSanity));
return kStartOfText < dummy && dummy < kEndOfText && kStartOfText < here &&
here < kEndOfText;
}

} // namespace android
} // namespace base
#endif // defined(ARCH_CPU_ARMEL)

#endif // BUILDFLAG(SUPPORTS_CODE_ORDERING)
11 changes: 6 additions & 5 deletions base/android/library_loader/anchor_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,24 @@
#define BASE_ANDROID_LIBRARY_LOADER_ANCHOR_FUNCTIONS_H_

#include <cstdint>
#include "base/android/library_loader/anchor_functions_flags.h"

#include "base/base_export.h"
#include "build/build_config.h"

#if defined(ARCH_CPU_ARMEL)
#if BUILDFLAG(SUPPORTS_CODE_ORDERING)

namespace base {
namespace android {

// Start and end of .text, respectively.
BASE_EXPORT extern const size_t kStartOfText;
BASE_EXPORT extern const size_t kEndOfText;

// Basic CHECK()s ensuring that the symbols above are correctly set.
BASE_EXPORT void CheckOrderingSanity();
// Returns true if the ordering looks sane.
BASE_EXPORT bool IsOrderingSane();

} // namespace android
} // namespace base
#endif // defined(ARCH_CPU_ARMEL)
#endif // BUILDFLAG(SUPPORTS_CODE_ORDERING)

#endif // BASE_ANDROID_LIBRARY_LOADER_ANCHOR_FUNCTIONS_H_
20 changes: 19 additions & 1 deletion base/android/library_loader/library_loader_hooks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "base/android/library_loader/library_loader_hooks.h"

#include "base/android/jni_string.h"
#include "base/android/library_loader/anchor_functions_flags.h"
#include "base/android/library_loader/library_load_from_apk_status_codes.h"
#include "base/android/library_loader/library_prefetcher.h"
#include "base/at_exit.h"
Expand Down Expand Up @@ -169,7 +170,12 @@ static jboolean JNI_LibraryLoader_LibraryLoaded(
const JavaParamRef<jobject>& 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 (g_native_initialization_hook && !g_native_initialization_hook())
Expand All @@ -189,19 +195,31 @@ void LibraryLoaderExitHook() {
static jboolean JNI_LibraryLoader_ForkAndPrefetchNativeLibrary(
JNIEnv* env,
const JavaParamRef<jclass>& clazz) {
#if BUILDFLAG(SUPPORTS_CODE_ORDERING)
return NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary();
#else
return false;
#endif
}

static jint JNI_LibraryLoader_PercentageOfResidentNativeLibraryCode(
JNIEnv* env,
const JavaParamRef<jclass>& clazz) {
#if BUILDFLAG(SUPPORTS_CODE_ORDERING)
return NativeLibraryPrefetcher::PercentageOfResidentNativeLibraryCode();
#else
return -1;
#endif
}

static void JNI_LibraryLoader_PeriodicallyCollectResidency(
JNIEnv* env,
const JavaParamRef<jclass>& clazz) {
return NativeLibraryPrefetcher::PeriodicallyCollectResidency();
#if BUILDFLAG(SUPPORTS_CODE_ORDERING)
NativeLibraryPrefetcher::PercentageOfResidentNativeLibraryCode();
#else
LOG(WARNING) << "Collecting residency is not supported.";
#endif
}

void SetVersionNumber(const char* version_number) {
Expand Down
Loading

0 comments on commit ef6f0fb

Please sign in to comment.