Commit c187f890 authored by Benoît Lizé's avatar Benoît Lizé Committed by Commit Bot

base/android: Log the ordered code range during startup.

This is required to pin ordered code in memory on platforms that support it.

This forwards the file and locations within it of the ordered code to Java, from
native, as this is not discoverable purely from Java. This is controlled by a
feature which is disabled by default, and the logging code will be replaced by
the actual pinning one on supported platforms.

Bug: 929926
Change-Id: I8c79c0609dd2709e3e4eefc5d8c971d84df6f4dc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1631659
Commit-Queue: Benoit L <lizeb@chromium.org>
Reviewed-by: default avatarYaron Friedman <yfriedman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#663774}
parent dcb95dec
...@@ -8,6 +8,7 @@ import org.chromium.base.CommandLine; ...@@ -8,6 +8,7 @@ import org.chromium.base.CommandLine;
import org.chromium.base.ContextUtils; import org.chromium.base.ContextUtils;
import org.chromium.base.SysUtils; import org.chromium.base.SysUtils;
import org.chromium.base.TraceEvent; import org.chromium.base.TraceEvent;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.MainDex; import org.chromium.base.annotations.MainDex;
import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordHistogram;
...@@ -25,6 +26,28 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -25,6 +26,28 @@ import java.util.concurrent.atomic.AtomicBoolean;
@MainDex @MainDex
@JNINamespace("base::android") @JNINamespace("base::android")
public class LibraryPrefetcher { public class LibraryPrefetcher {
/**
* Used to pass ordered code info back from native.
*/
private final static class OrderedCodeInfo {
public final String filename;
public final long startOffset;
public final long length;
@CalledByNative("OrderedCodeInfo")
public OrderedCodeInfo(String filename, long startOffset, long length) {
this.filename = filename;
this.startOffset = startOffset;
this.length = length;
}
@Override
public String toString() {
return "filename = " + filename + " startOffset = " + startOffset
+ " length = " + length;
}
}
// One-way switch that becomes true once // One-way switch that becomes true once
// {@link asyncPrefetchLibrariesToMemory} has been called. // {@link asyncPrefetchLibrariesToMemory} has been called.
private final static AtomicBoolean sPrefetchLibraryHasBeenCalled = new AtomicBoolean(); private final static AtomicBoolean sPrefetchLibraryHasBeenCalled = new AtomicBoolean();
...@@ -70,9 +93,18 @@ public class LibraryPrefetcher { ...@@ -70,9 +93,18 @@ public class LibraryPrefetcher {
} }
// Removes a dead flag, don't remove the removal code before M77 at least. // Removes a dead flag, don't remove the removal code before M77 at least.
ContextUtils.getAppSharedPreferences().edit().remove("dont_prefetch_libraries").apply(); ContextUtils.getAppSharedPreferences().edit().remove("dont_prefetch_libraries").apply();
pinOrderedCodeInMemory();
}); });
} }
public static void pinOrderedCodeInMemory() {
try (TraceEvent e = TraceEvent.scoped("LibraryPrefetcher::pinOrderedCodeInMemory")) {
OrderedCodeInfo info = nativeGetOrderedCodeInfo();
if (info != null) TraceEvent.instant("pinOrderedCodeInMemory", info.toString());
}
}
// Finds the ranges corresponding to the native library pages, forks a new // Finds the ranges corresponding to the native library pages, forks a new
// process to prefetch these pages and waits for it. The new process then // process to prefetch these pages and waits for it. The new process then
// terminates. This is blocking. // terminates. This is blocking.
...@@ -84,4 +116,8 @@ public class LibraryPrefetcher { ...@@ -84,4 +116,8 @@ public class LibraryPrefetcher {
// Periodically logs native library residency from this thread. // Periodically logs native library residency from this thread.
private static native void nativePeriodicallyCollectResidency(); private static native void nativePeriodicallyCollectResidency();
// Returns the range within a file of the ordered code section, or null if this is not
// available.
private static native OrderedCodeInfo nativeGetOrderedCodeInfo();
} }
...@@ -19,12 +19,14 @@ ...@@ -19,12 +19,14 @@
#include "base/android/library_loader/anchor_functions.h" #include "base/android/library_loader/anchor_functions.h"
#include "base/android/orderfile/orderfile_buildflags.h" #include "base/android/orderfile/orderfile_buildflags.h"
#include "base/bits.h" #include "base/bits.h"
#include "base/debug/proc_maps_linux.h"
#include "base/files/file.h" #include "base/files/file.h"
#include "base/format_macros.h" #include "base/format_macros.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/posix/eintr_wrapper.h" #include "base/posix/eintr_wrapper.h"
#include "base/process/process_metrics.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "build/build_config.h" #include "build/build_config.h"
...@@ -344,6 +346,54 @@ void NativeLibraryPrefetcher::MadviseForResidencyCollection() { ...@@ -344,6 +346,54 @@ void NativeLibraryPrefetcher::MadviseForResidencyCollection() {
MadviseOnRange(GetTextRange(), MADV_RANDOM); MadviseOnRange(GetTextRange(), MADV_RANDOM);
} }
// static
bool NativeLibraryPrefetcher::GetOrderedCodeInfo(std::string* filename,
size_t* start_offset,
size_t* size) {
// Need all the anchors to identify the range.
if (!IsOrderingSane()) {
LOG(WARNING) << "Incorrect code ordering";
return false;
}
std::vector<base::debug::MappedMemoryRegion> regions;
{
std::string proc_maps;
bool ok = base::debug::ReadProcMaps(&proc_maps);
if (!ok)
return false;
ok = base::debug::ParseProcMaps(proc_maps, &regions);
if (!ok)
return false;
}
for (const auto& region : regions) {
if (region.start <= kStartOfOrderedText &&
region.end >= kEndOfOrderedText) {
size_t page_size = GetPageSize();
size_t page_mask = ~(page_size - 1);
DCHECK_EQ(0u, region.start % page_size);
DCHECK_EQ(0u, region.offset % page_size); // mmap() enforces this.
size_t start_offset_in_range =
(kStartOfOrderedText & page_mask) - region.start;
DCHECK_EQ(0u, start_offset_in_range % page_size);
size_t start_offset_in_file = start_offset_in_range + region.offset;
DCHECK_EQ(0u, start_offset_in_file % page_size);
*filename = region.path;
*start_offset = start_offset_in_file;
*size =
base::bits::Align(kEndOfOrderedText - kStartOfOrderedText, page_size);
return true;
}
}
LOG(WARNING) << "Didn't find the ordered code, yet code is ordered.";
return false;
}
} // namespace android } // namespace android
} // namespace base } // namespace base
#endif // BUILDFLAG(SUPPORTS_CODE_ORDERING) #endif // BUILDFLAG(SUPPORTS_CODE_ORDERING)
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <jni.h> #include <jni.h>
#include <stdint.h> #include <stdint.h>
#include <string>
#include "base/android/library_loader/anchor_functions_buildflags.h" #include "base/android/library_loader/anchor_functions_buildflags.h"
#include "base/base_export.h" #include "base/base_export.h"
...@@ -51,6 +52,11 @@ class BASE_EXPORT NativeLibraryPrefetcher { ...@@ -51,6 +52,11 @@ class BASE_EXPORT NativeLibraryPrefetcher {
// collection is accurate. // collection is accurate.
static void MadviseForResidencyCollection(); static void MadviseForResidencyCollection();
// Returns true for success.
static bool GetOrderedCodeInfo(std::string* filename,
size_t* start_offset,
size_t* size);
private: private:
// Returns the percentage of [start, end] currently resident in // Returns the percentage of [start, end] currently resident in
// memory, or -1 in case of error. // memory, or -1 in case of error.
......
...@@ -2,15 +2,30 @@ ...@@ -2,15 +2,30 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include <string>
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/android/library_loader/anchor_functions_buildflags.h" #include "base/android/library_loader/anchor_functions_buildflags.h"
#include "base/android/library_loader/library_loader_hooks.h" #include "base/android/library_loader/library_loader_hooks.h"
#include "base/android/library_loader/library_prefetcher.h" #include "base/android/library_loader/library_prefetcher.h"
#include "base/android/scoped_java_ref.h"
#include "base/feature_list.h"
#include "base/logging.h" #include "base/logging.h"
#include "jni/LibraryPrefetcher_jni.h" #include "jni/LibraryPrefetcher_jni.h"
namespace base { namespace base {
namespace android { namespace android {
namespace {
// Whether to pin code in memory. Pinning happens in Java, but is controlled
// from here, to obtain the range.
const Feature kPinOrderedCodeInMemory{"PinOrderedCodeInMemory",
FEATURE_DISABLED_BY_DEFAULT};
} // namespace
static void JNI_LibraryPrefetcher_ForkAndPrefetchNativeLibrary(JNIEnv* env) { static void JNI_LibraryPrefetcher_ForkAndPrefetchNativeLibrary(JNIEnv* env) {
#if BUILDFLAG(SUPPORTS_CODE_ORDERING) #if BUILDFLAG(SUPPORTS_CODE_ORDERING)
return NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary( return NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary(
...@@ -35,5 +50,27 @@ static void JNI_LibraryPrefetcher_PeriodicallyCollectResidency(JNIEnv* env) { ...@@ -35,5 +50,27 @@ static void JNI_LibraryPrefetcher_PeriodicallyCollectResidency(JNIEnv* env) {
#endif #endif
} }
static ScopedJavaLocalRef<jobject> JNI_LibraryPrefetcher_GetOrderedCodeInfo(
JNIEnv* env) {
#if BUILDFLAG(SUPPORTS_CODE_ORDERING)
if (!FeatureList::IsEnabled(kPinOrderedCodeInMemory))
return {};
std::string filename;
size_t start_offset, size;
bool ok = NativeLibraryPrefetcher::GetOrderedCodeInfo(&filename,
&start_offset, &size);
if (!ok)
return {};
auto java_filename = ConvertUTF8ToJavaString(env, filename);
return Java_OrderedCodeInfo_Constructor(env, java_filename,
static_cast<jlong>(start_offset),
static_cast<jlong>(size));
#else
return {};
#endif // BUILDFLAG(SUPPORTS_CODE_ORDERING)
}
} // namespace android } // namespace android
} // namespace base } // namespace base
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment