Commit 12cd16ac authored by ssid's avatar ssid Committed by Commit Bot

Add experiment param to configure reached code sampling interval

BUG=916263

Change-Id: I2bb13e274d18e1dac5d0a91ac86cbd0cdbf2cc18
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2263473
Commit-Queue: ssid <ssid@chromium.org>
Reviewed-by: default avatarBo <boliu@chromium.org>
Reviewed-by: default avatarkylechar <kylechar@chromium.org>
Reviewed-by: default avatarTommy Nyquist <nyquist@chromium.org>
Reviewed-by: default avatarEgor Pasko <pasko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#782760}
parent f5f8d99b
......@@ -30,6 +30,10 @@ public abstract class BaseSwitches {
// Enables the reached code profiler.
public static final String ENABLE_REACHED_CODE_PROFILER = "enable-reached-code-profiler";
// Specifies the profiling interval for reached code profiler in microseconds.
public static final String REACHED_CODE_SAMPLING_INTERVAL_US =
"reached-code-sampling-interval-us";
// Comma-separated list of feature names to enable.
public static final String ENABLE_FEATURES = "enable-features";
......
......@@ -6,6 +6,7 @@ package org.chromium.base.library_loader;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.os.Build;
import android.os.Build.VERSION_CODES;
......@@ -63,7 +64,13 @@ public class LibraryLoader {
private static final String LIBRARY_DIR = "native_libraries";
// Shared preferences key for the reached code profiler.
private static final String REACHED_CODE_PROFILER_ENABLED_KEY = "reached_code_profiler_enabled";
private static final String DEPRECATED_REACHED_CODE_PROFILER_KEY =
"reached_code_profiler_enabled";
private static final String REACHED_CODE_SAMPLING_INTERVAL_KEY =
"reached_code_sampling_interval";
// Default sampling interval for reached code profiler in microseconds.
private static final int DEFAULT_REACHED_CODE_SAMPLING_INTERVAL_US = 10000;
// The singleton instance of LibraryLoader. Never null (not final for tests).
private static LibraryLoader sInstance = new LibraryLoader();
......@@ -376,23 +383,35 @@ public class LibraryLoader {
* on ChromeFeatureList, and has to rely on external code pushing the value.
*
* @param enabled whether to enable the reached code profiler.
* @param samplingIntervalUs the sampling interval for reached code profiler.
*/
public static void setReachedCodeProfilerEnabledOnNextRuns(boolean enabled) {
ContextUtils.getAppSharedPreferences()
.edit()
.putBoolean(REACHED_CODE_PROFILER_ENABLED_KEY, enabled)
.apply();
public static void setReachedCodeProfilerEnabledOnNextRuns(
boolean enabled, int samplingIntervalUs) {
// Store 0 if the profiler is not enabled, otherwise store the sampling interval in
// microseconds.
if (enabled && samplingIntervalUs == 0) {
samplingIntervalUs = DEFAULT_REACHED_CODE_SAMPLING_INTERVAL_US;
} else if (!enabled) {
samplingIntervalUs = 0;
}
SharedPreferences.Editor editor = ContextUtils.getAppSharedPreferences().edit();
editor.remove(DEPRECATED_REACHED_CODE_PROFILER_KEY);
editor.putInt(REACHED_CODE_SAMPLING_INTERVAL_KEY, samplingIntervalUs).apply();
}
/**
* @return whether to enable reached code profiler (see
* @return sampling interval for reached code profiler, or 0 when the profiler is disabled. (see
* setReachedCodeProfilerEnabledOnNextRuns()).
*/
@VisibleForTesting
public static boolean isReachedCodeProfilerEnabled() {
public static int getReachedCodeSamplingIntervalUs() {
try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) {
return ContextUtils.getAppSharedPreferences().getBoolean(
REACHED_CODE_PROFILER_ENABLED_KEY, false);
if (ContextUtils.getAppSharedPreferences().getBoolean(
DEPRECATED_REACHED_CODE_PROFILER_KEY, false)) {
return DEFAULT_REACHED_CODE_SAMPLING_INTERVAL_US;
}
return ContextUtils.getAppSharedPreferences().getInt(
REACHED_CODE_SAMPLING_INTERVAL_KEY, 0);
}
}
......@@ -581,9 +600,14 @@ public class LibraryLoader {
// Add a switch for the reached code profiler as late as possible since it requires a read
// from the shared preferences. At this point the shared preferences are usually warmed up.
if (mLibraryProcessType == LibraryProcessType.PROCESS_BROWSER
&& isReachedCodeProfilerEnabled()) {
CommandLine.getInstance().appendSwitch(BaseSwitches.ENABLE_REACHED_CODE_PROFILER);
if (mLibraryProcessType == LibraryProcessType.PROCESS_BROWSER) {
int reachedCodeSamplingIntervalUs = getReachedCodeSamplingIntervalUs();
if (reachedCodeSamplingIntervalUs > 0) {
CommandLine.getInstance().appendSwitch(BaseSwitches.ENABLE_REACHED_CODE_PROFILER);
CommandLine.getInstance().appendSwitchWithValue(
BaseSwitches.REACHED_CODE_SAMPLING_INTERVAL_US,
Integer.toString(reachedCodeSamplingIntervalUs));
}
}
ensureCommandLineSwitchedAlreadyLocked();
......
......@@ -28,6 +28,7 @@
#include "base/path_service.h"
#include "base/scoped_generic.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
......@@ -117,7 +118,8 @@ class ReachedCodeProfiler {
}
// Starts to periodically send |kProfilerSignal| to all threads.
void Start(LibraryProcessType library_process_type) {
void Start(LibraryProcessType library_process_type,
base::TimeDelta sampling_interval) {
if (is_enabled_)
return;
......@@ -154,7 +156,7 @@ class ReachedCodeProfiler {
// Start the interval timer.
struct itimerspec its;
memset(&its, 0, sizeof(its));
its.it_interval.tv_nsec = kSamplingInterval.InNanoseconds();
its.it_interval.tv_nsec = sampling_interval.InNanoseconds();
its.it_value = its.it_interval;
ret = timer_settime(timerid, 0, &its, nullptr);
if (ret) {
......@@ -268,7 +270,17 @@ void InitReachedCodeProfilerAtStartup(LibraryProcessType library_process_type) {
if (!ShouldEnableReachedCodeProfiler())
return;
ReachedCodeProfiler::GetInstance()->Start(library_process_type);
int interval_us = 0;
base::TimeDelta sampling_interval = kSamplingInterval;
if (base::StringToInt(
base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(
switches::kReachedCodeSamplingIntervalUs),
&interval_us) &&
interval_us > 0) {
sampling_interval = base::TimeDelta::FromMicroseconds(interval_us);
}
ReachedCodeProfiler::GetInstance()->Start(library_process_type,
sampling_interval);
}
bool IsReachedCodeProfilerEnabled() {
......
......@@ -136,6 +136,10 @@ const char kEnableCrashReporterForTesting[] =
// Enables the reached code profiler that samples all threads in all processes
// to determine which functions are almost never executed.
const char kEnableReachedCodeProfiler[] = "enable-reached-code-profiler";
// Specifies the profiling interval in microseconds for reached code profiler.
const char kReachedCodeSamplingIntervalUs[] =
"reached-code-sampling-interval-us";
#endif
#if defined(OS_LINUX)
......
......@@ -48,6 +48,7 @@ extern const char kEnableCrashReporterForTesting[];
#if defined(OS_ANDROID)
extern const char kEnableReachedCodeProfiler[];
extern const char kReachedCodeSamplingIntervalUs[];
extern const char kOrderfileMemoryOptimization[];
#endif
......
......@@ -54,11 +54,17 @@ public final class ReachedCodeProfilerTest {
*/
@Test
@SmallTest
@EnableFeatures(ChromeFeatureList.REACHED_CODE_PROFILER)
public void testEnabledViaCachedSharedPreference() {
LibraryLoader.setReachedCodeProfilerEnabledOnNextRuns(true);
@CommandLineFlags.Add({"enable-features=" + ChromeFeatureList.REACHED_CODE_PROFILER + "<"
+ ChromeFeatureList.REACHED_CODE_PROFILER,
"force-fieldtrials=" + ChromeFeatureList.REACHED_CODE_PROFILER + "/" + FAKE_GROUP_NAME,
"force-fieldtrial-params=" + ChromeFeatureList.REACHED_CODE_PROFILER + "."
+ FAKE_GROUP_NAME + ":sampling_interval_us/42"})
public void
testEnabledViaCachedSharedPreference() {
LibraryLoader.setReachedCodeProfilerEnabledOnNextRuns(true, 42);
mActivityTestRule.startMainActivityFromLauncher();
assertReachedCodeProfilerIsEnabled();
Assert.assertEquals(42, LibraryLoader.getReachedCodeSamplingIntervalUs());
}
/**
......@@ -71,7 +77,7 @@ public final class ReachedCodeProfilerTest {
public void testSharedPreferenceIsCached_Enable() {
mActivityTestRule.startMainActivityFromLauncher();
Assert.assertTrue(LibraryLoader.isReachedCodeProfilerEnabled());
Assert.assertEquals(10000, LibraryLoader.getReachedCodeSamplingIntervalUs());
// Enabling takes effect only on the second startup.
Assert.assertFalse(ReachedCodeProfiler.isEnabled());
}
......@@ -85,10 +91,9 @@ public final class ReachedCodeProfilerTest {
@SmallTest
@DisableFeatures(ChromeFeatureList.REACHED_CODE_PROFILER)
public void testSharedPreferenceIsCached_Disable() {
LibraryLoader.setReachedCodeProfilerEnabledOnNextRuns(true);
LibraryLoader.setReachedCodeProfilerEnabledOnNextRuns(true, 0);
mActivityTestRule.startMainActivityFromLauncher();
Assert.assertFalse(LibraryLoader.isReachedCodeProfilerEnabled());
Assert.assertEquals(0, LibraryLoader.getReachedCodeSamplingIntervalUs());
// Disabling takes effect only on the second startup.
assertReachedCodeProfilerIsEnabled();
}
......
......@@ -248,7 +248,9 @@ public class CachedFeatureFlags {
// Propagate REACHED_CODE_PROFILER feature value to LibraryLoader. This can't be done in
// LibraryLoader itself because it lives in //base and can't depend on ChromeFeatureList.
LibraryLoader.setReachedCodeProfilerEnabledOnNextRuns(
ChromeFeatureList.isEnabled(ChromeFeatureList.REACHED_CODE_PROFILER));
ChromeFeatureList.isEnabled(ChromeFeatureList.REACHED_CODE_PROFILER),
ChromeFeatureList.getFieldTrialParamByFeatureAsInt(
ChromeFeatureList.REACHED_CODE_PROFILER, "sampling_interval_us", 0));
}
/**
......
......@@ -282,6 +282,7 @@ static const char* const kSwitchNames[] = {
switches::kForceVideoOverlays,
#if defined(OS_ANDROID)
switches::kEnableReachedCodeProfiler,
switches::kReachedCodeSamplingIntervalUs,
#endif
};
......
......@@ -3443,6 +3443,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
#if defined(OS_ANDROID)
switches::kDisableMediaSessionAPI,
switches::kEnableReachedCodeProfiler,
switches::kReachedCodeSamplingIntervalUs,
switches::kRendererWaitForJavaDebugger,
#endif
#if defined(OS_WIN)
......
......@@ -476,6 +476,7 @@ bool UtilityProcessHost::StartProcess() {
switches::kVModule,
#if defined(OS_ANDROID)
switches::kEnableReachedCodeProfiler,
switches::kReachedCodeSamplingIntervalUs,
#endif
switches::kEnableExperimentalWebPlatformFeatures,
// These flags are used by the audio service:
......
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