Revert "Remove "--enable-heap-profiling""
This reverts commit 51e2344126
.
Reason for revert: Sid points out:
"""
We just figured that memlog doesn't work in WebView. WebView does not build chrome/ folders and we used to have the legacy heap profiling working on it. We might have to revert this change that removes the old flag while we figure out webview case.
Sorry about this late finding..
"""
Original change's description:
> Remove "--enable-heap-profiling"
>
> The flag is deprecated and replaced by --memlog and co. See
> https://chromium.googlesource.com/chromium/src/+/lkcr/docs/memory/debugging_memory_issues.md#taking-a-heap-dump
> for more details.
>
> Bug: 758739
> Change-Id: I8f7ac614298334a90103cd5b4c9667468d662845
> Reviewed-on: https://chromium-review.googlesource.com/970852
> Reviewed-by: Tommy Martino <tmartino@chromium.org>
> Reviewed-by: Avi Drissman <avi@chromium.org>
> Reviewed-by: Daniel Cheng <dcheng@chromium.org>
> Reviewed-by: Juan Antonio Navarro Pérez <perezju@chromium.org>
> Reviewed-by: Primiano Tucci <primiano@chromium.org>
> Reviewed-by: Siddhartha S <ssid@chromium.org>
> Reviewed-by: Dmitry Skiba <dskiba@chromium.org>
> Commit-Queue: Erik Chen <erikchen@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#545929}
TBR=avi@chromium.org,dcheng@chromium.org,primiano@chromium.org,erikchen@chromium.org,perezju@chromium.org,ssid@chromium.org,dskiba@chromium.org,tmartino@chromium.org
Change-Id: Iaac5d628ff248d70830b0c19403780df9ec0cdef
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 758739
Reviewed-on: https://chromium-review.googlesource.com/982693
Reviewed-by: Erik Chen <erikchen@chromium.org>
Commit-Queue: Erik Chen <erikchen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#546308}
This commit is contained in:
base
chrome
app
browser
components/tracing
content
browser
child
docs
tools
metrics
histograms
perf
benchmarks
contrib
@ -21,6 +21,25 @@ const char kEnableCrashReporter[] = "enable-crash-reporter";
|
||||
// Comma-separated list of feature names to enable. See also kDisableFeatures.
|
||||
const char kEnableFeatures[] = "enable-features";
|
||||
|
||||
// Makes memory allocators keep track of their allocations and context, so a
|
||||
// detailed breakdown of memory usage can be presented in chrome://tracing when
|
||||
// the memory-infra category is enabled.
|
||||
const char kEnableHeapProfiling[] = "enable-heap-profiling";
|
||||
|
||||
// Report pseudo allocation traces. Pseudo traces are derived from currently
|
||||
// active trace events.
|
||||
const char kEnableHeapProfilingModePseudo[] = "";
|
||||
|
||||
// Report native (walk the stack) allocation traces. By default pseudo stacks
|
||||
// derived from trace events are reported.
|
||||
const char kEnableHeapProfilingModeNative[] = "native";
|
||||
|
||||
// Report per-task heap usage and churn in the task profiler.
|
||||
// Does not keep track of individual allocations unlike the default and native
|
||||
// mode. Keeps only track of summarized churn stats in the task profiler
|
||||
// (chrome://profiler).
|
||||
const char kEnableHeapProfilingTaskProfiler[] = "task-profiler";
|
||||
|
||||
// Generates full memory crash dump.
|
||||
const char kFullMemoryCrashReport[] = "full-memory-crash-report";
|
||||
|
||||
|
@ -16,6 +16,10 @@ extern const char kDisableFeatures[];
|
||||
extern const char kDisableLowEndDeviceMode[];
|
||||
extern const char kEnableCrashReporter[];
|
||||
extern const char kEnableFeatures[];
|
||||
extern const char kEnableHeapProfiling[];
|
||||
extern const char kEnableHeapProfilingModePseudo[];
|
||||
extern const char kEnableHeapProfilingModeNative[];
|
||||
extern const char kEnableHeapProfilingTaskProfiler[];
|
||||
extern const char kEnableLowEndDeviceMode[];
|
||||
extern const char kForceFieldTrials[];
|
||||
extern const char kFullMemoryCrashReport[];
|
||||
|
@ -15,25 +15,11 @@
|
||||
namespace base {
|
||||
namespace trace_event {
|
||||
|
||||
// AllocationContextTracker is a thread-local object. Its main purpose is to
|
||||
// keep track of a pseudo stack of trace events. Chrome has been instrumented
|
||||
// with lots of `TRACE_EVENT` macros. These trace events push their name to a
|
||||
// thread-local stack when they go into scope, and pop when they go out of
|
||||
// scope, if all of the following conditions have been met:
|
||||
//
|
||||
// * A trace is being recorded.
|
||||
// * The category of the event is enabled in the trace config.
|
||||
// * Heap profiling is enabled (with the `--enable-heap-profiling` flag).
|
||||
//
|
||||
// This means that allocations that occur before tracing is started will not
|
||||
// have backtrace information in their context.
|
||||
//
|
||||
// AllocationContextTracker also keeps track of some thread state not related to
|
||||
// trace events. See |AllocationContext|.
|
||||
//
|
||||
// A thread-local instance of the context tracker is initialized lazily when it
|
||||
// is first accessed. This might be because a trace event pushed or popped, or
|
||||
// because `GetContextSnapshot()` was called when an allocation occurred
|
||||
// The allocation context tracker keeps track of thread-local context for heap
|
||||
// profiling. It includes a pseudo stack of trace events. On every allocation
|
||||
// the tracker provides a snapshot of its context in the form of an
|
||||
// |AllocationContext| that is to be stored together with the allocation
|
||||
// details.
|
||||
class BASE_EXPORT AllocationContextTracker {
|
||||
public:
|
||||
enum class CaptureMode : int32_t {
|
||||
|
@ -201,6 +201,44 @@ MemoryDumpManager::~MemoryDumpManager() {
|
||||
g_memory_dump_manager_for_testing = nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
HeapProfilingMode MemoryDumpManager::GetHeapProfilingModeFromCommandLine() {
|
||||
if (!CommandLine::InitializedForCurrentProcess() ||
|
||||
!CommandLine::ForCurrentProcess()->HasSwitch(
|
||||
switches::kEnableHeapProfiling)) {
|
||||
return kHeapProfilingModeDisabled;
|
||||
}
|
||||
#if BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
|
||||
std::string profiling_mode =
|
||||
CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
|
||||
switches::kEnableHeapProfiling);
|
||||
if (profiling_mode == switches::kEnableHeapProfilingTaskProfiler)
|
||||
return kHeapProfilingModeTaskProfiler;
|
||||
if (profiling_mode == switches::kEnableHeapProfilingModePseudo)
|
||||
return kHeapProfilingModePseudo;
|
||||
if (profiling_mode == switches::kEnableHeapProfilingModeNative)
|
||||
return kHeapProfilingModeNative;
|
||||
#endif // BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
|
||||
return kHeapProfilingModeInvalid;
|
||||
}
|
||||
|
||||
void MemoryDumpManager::EnableHeapProfilingIfNeeded() {
|
||||
#if BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
|
||||
HeapProfilingMode profiling_mode = GetHeapProfilingModeFromCommandLine();
|
||||
if (IsHeapProfilingModeEnabled(profiling_mode)) {
|
||||
EnableHeapProfiling(profiling_mode);
|
||||
} else {
|
||||
if (profiling_mode == kHeapProfilingModeInvalid) {
|
||||
// Heap profiling is misconfigured, disable it permanently.
|
||||
EnableHeapProfiling(kHeapProfilingModeDisabled);
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Heap profiling is unsupported, disable it permanently.
|
||||
EnableHeapProfiling(kHeapProfilingModeDisabled);
|
||||
#endif // BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
|
||||
}
|
||||
|
||||
bool MemoryDumpManager::EnableHeapProfiling(HeapProfilingMode profiling_mode) {
|
||||
AutoLock lock(lock_);
|
||||
#if BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
|
||||
@ -291,6 +329,7 @@ void MemoryDumpManager::Initialize(
|
||||
request_dump_function_ = request_dump_function;
|
||||
is_coordinator_ = is_coordinator;
|
||||
}
|
||||
EnableHeapProfilingIfNeeded();
|
||||
|
||||
// Enable the core dump providers.
|
||||
#if defined(MALLOC_MEMORY_TRACING_SUPPORTED)
|
||||
|
@ -131,6 +131,15 @@ class BASE_EXPORT MemoryDumpManager {
|
||||
void CreateProcessDump(const MemoryDumpRequestArgs& args,
|
||||
const ProcessMemoryDumpCallback& callback);
|
||||
|
||||
// Returns the heap profiling mode configured on the command-line, if any.
|
||||
// If heap profiling is configured but not supported by this binary, or if an
|
||||
// invalid mode is specified, then kHeapProfilingInvalid is returned.
|
||||
static HeapProfilingMode GetHeapProfilingModeFromCommandLine();
|
||||
|
||||
// Enable heap profiling if supported, and kEnableHeapProfiling command line
|
||||
// is specified.
|
||||
void EnableHeapProfilingIfNeeded();
|
||||
|
||||
// Enable heap profiling with specified |profiling_mode|.
|
||||
// Use kHeapProfilingModeDisabled to disable, but it can't be re-enabled then.
|
||||
// Returns true if mode has been *changed* to the desired |profiling_mode|.
|
||||
|
@ -961,6 +961,54 @@ TEST_F(MemoryDumpManagerTestAsCoordinator, EnableHeapProfilingDisableDisabled) {
|
||||
}
|
||||
#endif // BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
|
||||
|
||||
TEST_F(MemoryDumpManagerTest, EnableHeapProfilingIfNeeded) {
|
||||
MockMemoryDumpProvider mdp1;
|
||||
MemoryDumpProvider::Options supported_options;
|
||||
supported_options.supports_heap_profiling = true;
|
||||
RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get(), supported_options);
|
||||
|
||||
// Should be noop.
|
||||
mdm_->EnableHeapProfilingIfNeeded();
|
||||
ASSERT_EQ(AllocationContextTracker::CaptureMode::DISABLED,
|
||||
AllocationContextTracker::capture_mode());
|
||||
mdm_->EnableHeapProfilingIfNeeded();
|
||||
ASSERT_EQ(AllocationContextTracker::CaptureMode::DISABLED,
|
||||
AllocationContextTracker::capture_mode());
|
||||
|
||||
#if BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
|
||||
testing::InSequence sequence;
|
||||
EXPECT_CALL(mdp1, OnHeapProfilingEnabled(true)).Times(1);
|
||||
EXPECT_CALL(mdp1, OnHeapProfilingEnabled(false)).Times(1);
|
||||
|
||||
CommandLine* cmdline = CommandLine::ForCurrentProcess();
|
||||
cmdline->AppendSwitchASCII(switches::kEnableHeapProfiling, "");
|
||||
mdm_->EnableHeapProfilingIfNeeded();
|
||||
RunLoop().RunUntilIdle();
|
||||
ASSERT_EQ(AllocationContextTracker::CaptureMode::PSEUDO_STACK,
|
||||
AllocationContextTracker::capture_mode());
|
||||
EXPECT_TRUE(mdm_->EnableHeapProfiling(kHeapProfilingModeDisabled));
|
||||
RunLoop().RunUntilIdle();
|
||||
ASSERT_EQ(AllocationContextTracker::CaptureMode::DISABLED,
|
||||
AllocationContextTracker::capture_mode());
|
||||
EXPECT_FALSE(mdm_->EnableHeapProfiling(kHeapProfilingModeBackground));
|
||||
ASSERT_EQ(AllocationContextTracker::CaptureMode::DISABLED,
|
||||
AllocationContextTracker::capture_mode());
|
||||
#endif // BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
|
||||
}
|
||||
|
||||
TEST_F(MemoryDumpManagerTest, EnableHeapProfilingIfNeededUnsupported) {
|
||||
#if BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
|
||||
ASSERT_EQ(mdm_->GetHeapProfilingMode(), kHeapProfilingModeDisabled);
|
||||
CommandLine* cmdline = CommandLine::ForCurrentProcess();
|
||||
cmdline->AppendSwitchASCII(switches::kEnableHeapProfiling, "unsupported");
|
||||
mdm_->EnableHeapProfilingIfNeeded();
|
||||
EXPECT_EQ(mdm_->GetHeapProfilingMode(), kHeapProfilingModeInvalid);
|
||||
#else
|
||||
mdm_->EnableHeapProfilingIfNeeded();
|
||||
EXPECT_EQ(mdm_->GetHeapProfilingMode(), kHeapProfilingModeInvalid);
|
||||
#endif // BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
|
||||
}
|
||||
|
||||
// Mock MDP class that tests if the number of OnMemoryDump() calls are expected.
|
||||
// It is implemented without gmocks since EXPECT_CALL implementation is slow
|
||||
// when there are 1000s of instances, as required in
|
||||
|
@ -4884,6 +4884,11 @@ Keep your key file in a safe place. You will need it to create new versions of y
|
||||
usage statistics
|
||||
</message>
|
||||
|
||||
<!-- Unimplemented Flags Infobar-->
|
||||
<message name="IDS_UNIMPLEMENTED_FLAGS_WARNING_MESSAGE" desc="Message shown when a command-line flag is used that is not implemented by this build. [Keep it short so it fits in the infobar.]">
|
||||
<ph name="BAD_FLAG">$1<ex>--enable-heap-profiling</ex></ph> is not implemented in this build
|
||||
</message>
|
||||
|
||||
<!-- Bad Flags Infobar-->
|
||||
<message name="IDS_BAD_FLAGS_WARNING_MESSAGE" desc="Message shown when an unsupported command-line flag is used. [Keep it short so it fits in the infobar.]">
|
||||
You are using an unsupported command-line flag: <ph name="BAD_FLAG">$1<ex>--no-sandbox</ex></ph>. Stability and security will suffer.
|
||||
|
@ -959,6 +959,16 @@ const FeatureEntry::FeatureVariation kDataReductionMainMenuFeatureVariations[] =
|
||||
arraysize(kPersistentMenuItemEnabled), nullptr}};
|
||||
#endif // OS_ANDROID
|
||||
|
||||
const FeatureEntry::Choice kEnableHeapProfilingChoices[] = {
|
||||
{flags_ui::kGenericExperimentChoiceDisabled, "", ""},
|
||||
{flag_descriptions::kEnableHeapProfilingModePseudo,
|
||||
switches::kEnableHeapProfiling, switches::kEnableHeapProfilingModePseudo},
|
||||
{flag_descriptions::kEnableHeapProfilingModeNative,
|
||||
switches::kEnableHeapProfiling, switches::kEnableHeapProfilingModeNative},
|
||||
{flag_descriptions::kEnableHeapProfilingTaskProfiler,
|
||||
switches::kEnableHeapProfiling,
|
||||
switches::kEnableHeapProfilingTaskProfiler}};
|
||||
|
||||
const FeatureEntry::Choice kEnableOutOfProcessHeapProfilingChoices[] = {
|
||||
{flags_ui::kGenericExperimentChoiceDisabled, "", ""},
|
||||
{flag_descriptions::kEnableOutOfProcessHeapProfilingModeMinimal,
|
||||
@ -3146,6 +3156,10 @@ const FeatureEntry kFeatureEntries[] = {
|
||||
flag_descriptions::kSamplingHeapProfilerDescription, kOsAll,
|
||||
SINGLE_VALUE_TYPE(switches::kSamplingHeapProfiler)},
|
||||
|
||||
{"enable-heap-profiling", flag_descriptions::kEnableHeapProfilingName,
|
||||
flag_descriptions::kEnableHeapProfilingDescription, kOsAll,
|
||||
MULTI_VALUE_TYPE(kEnableHeapProfilingChoices)},
|
||||
|
||||
{"memlog", flag_descriptions::kEnableOutOfProcessHeapProfilingName,
|
||||
flag_descriptions::kEnableOutOfProcessHeapProfilingDescription, kOsAll,
|
||||
MULTI_VALUE_TYPE(kEnableOutOfProcessHeapProfilingChoices)},
|
||||
|
@ -390,6 +390,12 @@ const char kEnableHDRName[] = "HDR mode";
|
||||
const char kEnableHDRDescription[] =
|
||||
"Enables HDR support on compatible displays.";
|
||||
|
||||
const char kEnableHeapProfilingName[] = "Heap profiling";
|
||||
const char kEnableHeapProfilingDescription[] = "Enables heap profiling.";
|
||||
const char kEnableHeapProfilingModePseudo[] = "Enabled (pseudo mode)";
|
||||
const char kEnableHeapProfilingModeNative[] = "Enabled (native mode)";
|
||||
const char kEnableHeapProfilingTaskProfiler[] = "Enabled (task mode)";
|
||||
|
||||
const char kEnableHttpFormWarningName[] =
|
||||
"Show in-form warnings for sensitive fields when the top-level page is not "
|
||||
"HTTPS";
|
||||
|
@ -271,6 +271,12 @@ extern const char kEnableGenericSensorExtraClassesDescription[];
|
||||
extern const char kEnableHDRName[];
|
||||
extern const char kEnableHDRDescription[];
|
||||
|
||||
extern const char kEnableHeapProfilingName[];
|
||||
extern const char kEnableHeapProfilingDescription[];
|
||||
extern const char kEnableHeapProfilingModePseudo[];
|
||||
extern const char kEnableHeapProfilingModeNative[];
|
||||
extern const char kEnableHeapProfilingTaskProfiler[];
|
||||
|
||||
extern const char kEnableHttpFormWarningName[];
|
||||
extern const char kEnableHttpFormWarningDescription[];
|
||||
|
||||
|
@ -273,15 +273,16 @@ void ProfilingProcessHost::AddClientToProfilingService(
|
||||
ProfilingProcessHost::Mode ProfilingProcessHost::GetModeForStartup() {
|
||||
const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
|
||||
#if BUILDFLAG(USE_ALLOCATOR_SHIM)
|
||||
if (cmdline->HasSwitch("enable-heap-profiling")) {
|
||||
LOG(ERROR) << "--enable-heap-profiling is no longer supported. Use "
|
||||
"--memlog instead. See documentation at "
|
||||
"docs/memory/debugging_memory_issues.md";
|
||||
return Mode::kNone;
|
||||
}
|
||||
|
||||
if (cmdline->HasSwitch(switches::kMemlog) ||
|
||||
base::FeatureList::IsEnabled(kOOPHeapProfilingFeature)) {
|
||||
if (cmdline->HasSwitch(switches::kEnableHeapProfiling)) {
|
||||
// PartitionAlloc doesn't support chained allocation hooks so we can't
|
||||
// run both heap profilers at the same time.
|
||||
LOG(ERROR) << "--" << switches::kEnableHeapProfiling
|
||||
<< " specified with --" << switches::kMemlog
|
||||
<< "which are not compatible. Memlog will be disabled.";
|
||||
return Mode::kNone;
|
||||
}
|
||||
|
||||
std::string mode;
|
||||
// Respect the commandline switch above the field trial.
|
||||
|
@ -119,6 +119,25 @@ void ShowBadFeatureFlagsInfoBar(content::WebContents* web_contents,
|
||||
} // namespace
|
||||
|
||||
void ShowBadFlagsPrompt(content::WebContents* web_contents) {
|
||||
// Flags only available in specific builds, for which to display a warning
|
||||
// "the flag is not implemented in this build", if necessary.
|
||||
struct {
|
||||
const char* name;
|
||||
bool is_invalid;
|
||||
} conditional_flags[] = {
|
||||
{switches::kEnableHeapProfiling,
|
||||
base::trace_event::MemoryDumpManager::
|
||||
GetHeapProfilingModeFromCommandLine() ==
|
||||
base::trace_event::kHeapProfilingModeInvalid},
|
||||
};
|
||||
for (auto conditional_flag : conditional_flags) {
|
||||
if (conditional_flag.is_invalid) {
|
||||
ShowBadFlagsInfoBar(web_contents, IDS_UNIMPLEMENTED_FLAGS_WARNING_MESSAGE,
|
||||
conditional_flag.name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (const char* flag : kBadFlags) {
|
||||
if (base::CommandLine::ForCurrentProcess()->HasSwitch(flag)) {
|
||||
ShowBadFlagsInfoBar(web_contents, IDS_BAD_FLAGS_WARNING_MESSAGE, flag);
|
||||
|
@ -22,6 +22,10 @@ void EnableStartupTracingIfNeeded() {
|
||||
// https://crbug.com/764357
|
||||
base::trace_event::TraceLog::GetInstance();
|
||||
|
||||
// Enables heap profiling if "--enable-heap-profiling" flag is passed.
|
||||
base::trace_event::MemoryDumpManager::GetInstance()
|
||||
->EnableHeapProfilingIfNeeded();
|
||||
|
||||
if (command_line.HasSwitch(switches::kTraceStartup)) {
|
||||
base::trace_event::TraceConfig trace_config(
|
||||
command_line.GetSwitchValueASCII(switches::kTraceStartup),
|
||||
|
2
components/tracing/docs/heap_profiler_internals.md
Normal file
2
components/tracing/docs/heap_profiler_internals.md
Normal file
@ -0,0 +1,2 @@
|
||||
This document has moved to [//docs/memory-infra/heap_profiler_internals.md](/docs/memory-infra/heap_profiler_internals.md).
|
||||
|
@ -167,6 +167,7 @@
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#include "base/allocator/allocator_interception_mac.h"
|
||||
#include "base/memory/memory_pressure_monitor_mac.h"
|
||||
#include "content/browser/cocoa/system_hotkey_helper_mac.h"
|
||||
#include "content/browser/mach_broker_mac.h"
|
||||
@ -267,6 +268,7 @@ pid_t LaunchZygoteHelper(base::CommandLine* cmd_line,
|
||||
// to the zygote/renderers.
|
||||
static const char* const kForwardSwitches[] = {
|
||||
switches::kAndroidFontsPath, switches::kClearKeyCdmPathForTesting,
|
||||
switches::kEnableHeapProfiling,
|
||||
switches::kEnableLogging, // Support, e.g., --enable-logging=stderr.
|
||||
// Need to tell the zygote that it is headless so that we don't try to use
|
||||
// the wrong type of main delegate.
|
||||
@ -841,6 +843,14 @@ int BrowserMainLoop::PreCreateThreads() {
|
||||
|
||||
InitializeMemoryManagementComponent();
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
if (base::CommandLine::InitializedForCurrentProcess() &&
|
||||
base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||
switches::kEnableHeapProfiling)) {
|
||||
base::allocator::PeriodicallyShimNewMallocZones();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(ENABLE_PLUGINS)
|
||||
// Prior to any processing happening on the IO thread, we create the
|
||||
// plugin service as it is predominantly used from the IO thread,
|
||||
|
@ -142,6 +142,7 @@ static const char* const kSwitchNames[] = {
|
||||
switches::kEnableAcceleratedVpxDecode,
|
||||
#endif
|
||||
switches::kEnableGpuRasterization,
|
||||
switches::kEnableHeapProfiling,
|
||||
switches::kEnableLogging,
|
||||
switches::kEnableOOPRasterization,
|
||||
switches::kEnableVizDevTools,
|
||||
|
@ -2647,6 +2647,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
|
||||
switches::kDomAutomationController,
|
||||
switches::kEnableAutomation,
|
||||
switches::kEnableExperimentalWebPlatformFeatures,
|
||||
switches::kEnableHeapProfiling,
|
||||
switches::kEnableGPUClientLogging,
|
||||
switches::kEnableGpuClientTracing,
|
||||
switches::kEnableGpuMemoryBufferVideoFrames,
|
||||
|
@ -75,6 +75,10 @@
|
||||
#include "content/public/common/content_descriptors.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#include "base/allocator/allocator_interception_mac.h"
|
||||
#endif
|
||||
|
||||
namespace content {
|
||||
namespace {
|
||||
|
||||
@ -553,6 +557,14 @@ void ChildThreadImpl::Init(const Options& options) {
|
||||
connection_timeout = temp;
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
if (base::CommandLine::InitializedForCurrentProcess() &&
|
||||
base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||
switches::kEnableHeapProfiling)) {
|
||||
base::allocator::PeriodicallyShimNewMallocZones();
|
||||
}
|
||||
#endif
|
||||
|
||||
message_loop_->task_runner()->PostDelayedTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(&ChildThreadImpl::EnsureConnected,
|
||||
|
@ -287,9 +287,6 @@ used when committed.
|
||||
* [VoiceOver](ios/voiceover.md) - Using Apple's VoiceOver feature with
|
||||
Chromium on iOS.
|
||||
|
||||
### Memory
|
||||
* [Memory Overview](memory/README.md)
|
||||
|
||||
### Memory Infrastructure Timeline Profiling (MemoryInfra)
|
||||
* [Overview](memory-infra/README.md)
|
||||
* [GPU Profiling](memory-infra/probe-gpu.md)
|
||||
@ -298,6 +295,7 @@ used when committed.
|
||||
* [Memory Usage in CC](memory-infra/probe-cc.md)
|
||||
* [Memory Benchmarks](memory-infra/memory_benchmarks.md)
|
||||
* [Heap Profiling](memory-infra/heap_profiler.md)
|
||||
* [Heap Profiling Internals](memory-infra/heap_profiler_internals.md)
|
||||
|
||||
### Misc
|
||||
* [Useful URLs](useful_urls.md) - A collection of links to various tools and
|
||||
|
@ -114,6 +114,7 @@ amount of memory used.
|
||||
|
||||
* [Adding MemoryInfra Tracing to a Component](adding_memory_infra_tracing.md)
|
||||
* [GPU Memory Tracing](probe-gpu.md)
|
||||
* [Heap Profiler Internals](heap_profiler_internals.md)
|
||||
* [Heap Profiling with MemoryInfra](heap_profiler.md)
|
||||
* [Startup Tracing with MemoryInfra](memory_infra_startup_tracing.md)
|
||||
|
||||
|
184
docs/memory-infra/heap_profiler_internals.md
Normal file
184
docs/memory-infra/heap_profiler_internals.md
Normal file
@ -0,0 +1,184 @@
|
||||
# Heap Profiler Internals
|
||||
|
||||
This document describes how the heap profiler works and how to add heap
|
||||
profiling support to your allocator. If you just want to know how to use it,
|
||||
see [Heap Profiling with MemoryInfra](heap_profiler.md)
|
||||
|
||||
[TOC]
|
||||
|
||||
## Overview
|
||||
|
||||
The heap profiler consists of tree main components:
|
||||
|
||||
* **The Context Tracker**: Responsible for providing context (pseudo stack
|
||||
backtrace) when an allocation occurs.
|
||||
* **The Allocation Register**: A specialized hash table that stores allocation
|
||||
details by address.
|
||||
* **The Heap Dump Writer**: Extracts the most important information from a set
|
||||
of recorded allocations and converts it into a format that can be dumped into
|
||||
the trace log.
|
||||
|
||||
These components are designed to work well together, but to be usable
|
||||
independently as well.
|
||||
|
||||
When there is a way to get notified of all allocations and frees, this is the
|
||||
normal flow:
|
||||
|
||||
1. When an allocation occurs, call
|
||||
[`AllocationContextTracker::GetInstanceForCurrentThread()->GetContextSnapshot()`][context-tracker]
|
||||
to get an [`AllocationContext`][alloc-context].
|
||||
2. Insert that context together with the address and size into an
|
||||
[`AllocationRegister`][alloc-register] by calling `Insert()`.
|
||||
3. When memory is freed, remove it from the register with `Remove()`.
|
||||
4. On memory dump, collect the allocations from the register, call
|
||||
[`ExportHeapDump()`][export-heap-dump], and add the generated heap dump to
|
||||
the memory dump.
|
||||
|
||||
[context-tracker]: https://chromium.googlesource.com/chromium/src/+/master/base/trace_event/heap_profiler_allocation_context_tracker.h
|
||||
[alloc-context]: https://chromium.googlesource.com/chromium/src/+/master/base/trace_event/heap_profiler_allocation_context.h
|
||||
[alloc-register]: https://chromium.googlesource.com/chromium/src/+/master/base/trace_event/heap_profiler_allocation_register.h
|
||||
[export-heap-dump]: https://chromium.googlesource.com/chromium/src/+/master/base/trace_event/heap_profiler_heap_dump_writer.h
|
||||
|
||||
*** aside
|
||||
An allocator can skip step 2 and 3 if it is able to store the context itself,
|
||||
and if it is able to enumerate all allocations for step 4.
|
||||
***
|
||||
|
||||
When heap profiling is enabled (the `--enable-heap-profiling` flag is passed),
|
||||
the memory dump manager calls `OnHeapProfilingEnabled()` on every
|
||||
`MemoryDumpProvider` as early as possible, so allocators can start recording
|
||||
allocations. This should be done even when tracing has not been started,
|
||||
because these allocations might still be around when a heap dump happens during
|
||||
tracing.
|
||||
|
||||
## Context Tracker
|
||||
|
||||
The [`AllocationContextTracker`][context-tracker] is a thread-local object. Its
|
||||
main purpose is to keep track of a pseudo stack of trace events. Chrome has
|
||||
been instrumented with lots of `TRACE_EVENT` macros. These trace events push
|
||||
their name to a thread-local stack when they go into scope, and pop when they
|
||||
go out of scope, if all of the following conditions have been met:
|
||||
|
||||
* A trace is being recorded.
|
||||
* The category of the event is enabled in the trace config.
|
||||
* Heap profiling is enabled (with the `--enable-heap-profiling` flag).
|
||||
|
||||
This means that allocations that occur before tracing is started will not have
|
||||
backtrace information in their context.
|
||||
|
||||
A thread-local instance of the context tracker is initialized lazily when it is
|
||||
first accessed. This might be because a trace event pushed or popped, or because
|
||||
`GetContextSnapshot()` was called when an allocation occurred.
|
||||
|
||||
[`AllocationContext`][alloc-context] is what is used to group and break down
|
||||
allocations. Currently `AllocationContext` has the following fields:
|
||||
|
||||
* Backtrace: filled by the context tracker, obtained from the thread-local
|
||||
pseudo stack.
|
||||
* Type name: to be filled in at a point where the type of a pointer is known,
|
||||
set to _[unknown]_ by default.
|
||||
|
||||
It is possible to modify this context after insertion into the register, for
|
||||
instance to set the type name if it was not known at the time of allocation.
|
||||
|
||||
## Allocation Register
|
||||
|
||||
The [`AllocationRegister`][alloc-register] is a hash table specialized for
|
||||
storing `(size, AllocationContext)` pairs by address. It has been optimized for
|
||||
Chrome's typical number of unfreed allocations, and it is backed by `mmap`
|
||||
memory directly so there are no reentrancy issues when using it to record
|
||||
`malloc` allocations.
|
||||
|
||||
The allocation register is threading-agnostic. Access must be synchronised
|
||||
properly.
|
||||
|
||||
## Heap Dump Writer
|
||||
|
||||
Dumping every single allocation in the allocation register straight into the
|
||||
trace log is not an option due to the sheer volume (~300k unfreed allocations).
|
||||
The role of the [`ExportHeapDump()`][export-heap-dump] function is to group
|
||||
allocations, striking a balance between trace log size and detail.
|
||||
|
||||
See the [Heap Dump Format][heap-dump-format] document for more details about the
|
||||
structure of the heap dump in the trace log.
|
||||
|
||||
[heap-dump-format]: https://docs.google.com/document/d/1NqBg1MzVnuMsnvV1AKLdKaPSPGpd81NaMPVk5stYanQ
|
||||
|
||||
## Instrumenting an Allocator
|
||||
|
||||
Below is an example of adding heap profiling support to an allocator that has
|
||||
an existing memory dump provider.
|
||||
|
||||
```cpp
|
||||
class FooDumpProvider : public MemoryDumpProvider {
|
||||
|
||||
// Kept as pointer because |AllocationRegister| allocates a lot of virtual
|
||||
// address space when constructed, so only construct it when heap profiling is
|
||||
// enabled.
|
||||
scoped_ptr<AllocationRegister> allocation_register_;
|
||||
Lock allocation_register_lock_;
|
||||
|
||||
static FooDumpProvider* GetInstance();
|
||||
|
||||
void InsertAllocation(void* address, size_t size) {
|
||||
AllocationContext context = AllocationContextTracker::GetInstanceForCurrentThread()->GetContextSnapshot();
|
||||
AutoLock lock(allocation_register_lock_);
|
||||
allocation_register_->Insert(address, size, context);
|
||||
}
|
||||
|
||||
void RemoveAllocation(void* address) {
|
||||
AutoLock lock(allocation_register_lock_);
|
||||
allocation_register_->Remove(address);
|
||||
}
|
||||
|
||||
// Will be called as early as possible by the memory dump manager.
|
||||
void OnHeapProfilingEnabled(bool enabled) override {
|
||||
AutoLock lock(allocation_register_lock_);
|
||||
allocation_register_.reset(new AllocationRegister());
|
||||
|
||||
// At this point, make sure that from now on, for every allocation and
|
||||
// free, |FooDumpProvider::GetInstance()->InsertAllocation()| and
|
||||
// |RemoveAllocation| are called.
|
||||
}
|
||||
|
||||
bool OnMemoryDump(const MemoryDumpArgs& args,
|
||||
ProcessMemoryDump& pmd) override {
|
||||
// Do regular dumping here.
|
||||
|
||||
// Dump the heap only for detailed dumps.
|
||||
if (args.level_of_detail == MemoryDumpLevelOfDetail::DETAILED) {
|
||||
TraceEventMemoryOverhead overhead;
|
||||
hash_map<AllocationContext, size_t> bytes_by_context;
|
||||
|
||||
{
|
||||
AutoLock lock(allocation_register_lock_);
|
||||
if (allocation_register_) {
|
||||
// Group allocations in the register into |bytes_by_context|, but do
|
||||
// no additional processing inside the lock.
|
||||
for (const auto& alloc_size : *allocation_register_)
|
||||
bytes_by_context[alloc_size.context] += alloc_size.size;
|
||||
|
||||
allocation_register_->EstimateTraceMemoryOverhead(&overhead);
|
||||
}
|
||||
}
|
||||
|
||||
if (!bytes_by_context.empty()) {
|
||||
scoped_refptr<TracedValue> heap_dump = ExportHeapDump(
|
||||
bytes_by_context,
|
||||
pmd->session_state()->stack_frame_deduplicator(),
|
||||
pmb->session_state()->type_name_deduplicator());
|
||||
pmd->AddHeapDump("foo_allocator", heap_dump);
|
||||
overhead.DumpInto("tracing/heap_profiler", pmd);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
*** aside
|
||||
The implementation for `malloc` is more complicated because it needs to deal
|
||||
with reentrancy.
|
||||
***
|
@ -26232,6 +26232,7 @@ from previous Chrome versions.
|
||||
<int value="-886912558" label="ChromeHomePromo:enabled"/>
|
||||
<int value="-885601782" label="enable-contextual-search"/>
|
||||
<int value="-884864731" label="WebPaymentsSingleAppUiSkip:enabled"/>
|
||||
<int value="-881854123" label="enable-heap-profiling"/>
|
||||
<int value="-881447505" label="ash-disable-shelf-model-synchronization"/>
|
||||
<int value="-881054479" label="WebAssemblyStreaming:disabled"/>
|
||||
<int value="-879055117" label="ClipboardContentSetting:enabled"/>
|
||||
|
@ -89,6 +89,14 @@ class MemoryBenchmarkTrivialSitesDesktop(_MemoryInfra):
|
||||
return page_sets.TrivialSitesStorySet(wait_in_seconds=0,
|
||||
measure_memory=True)
|
||||
|
||||
def SetExtraBrowserOptions(self, options):
|
||||
super(MemoryBenchmarkTrivialSitesDesktop, self).SetExtraBrowserOptions(
|
||||
options)
|
||||
# Heap profiling is disabled because of crbug.com/757847.
|
||||
#options.AppendExtraBrowserArgs([
|
||||
# '--enable-heap-profiling=native',
|
||||
#])
|
||||
|
||||
@classmethod
|
||||
def Name(cls):
|
||||
return 'memory.desktop'
|
||||
|
@ -126,6 +126,14 @@ class DesktopMemorySystemHealth(_MemorySystemHealthBenchmark):
|
||||
def Name(cls):
|
||||
return 'system_health.memory_desktop'
|
||||
|
||||
def SetExtraBrowserOptions(self, options):
|
||||
super(DesktopMemorySystemHealth, self).SetExtraBrowserOptions(
|
||||
options)
|
||||
# Heap profiling is disabled because of crbug.com/757847.
|
||||
#options.AppendExtraBrowserArgs([
|
||||
# '--enable-heap-profiling=native',
|
||||
#])
|
||||
|
||||
|
||||
@benchmark.Owner(emails=['perezju@chromium.org'])
|
||||
class MobileMemorySystemHealth(_MemorySystemHealthBenchmark):
|
||||
|
@ -63,12 +63,9 @@ class _HeapProfilingBenchmark(perf_benchmark.PerfBenchmark):
|
||||
super(_HeapProfilingBenchmark, self).SetExtraBrowserOptions(options)
|
||||
args = []
|
||||
if self.PROFILING_MODE == 'pseudo':
|
||||
args += [
|
||||
'--memlog=all', '--memlog-stack-mode=pseudo', '--memlog-sampling']
|
||||
args += ['--enable-heap-profiling']
|
||||
elif self.PROFILING_MODE == 'native':
|
||||
args += [
|
||||
'--memlog=all', '--memlog-stack-mode=native-with-thread-names',
|
||||
'--memlog-sampling']
|
||||
args += ['--enable-heap-profiling=native']
|
||||
options.AppendExtraBrowserArgs(args)
|
||||
|
||||
|
||||
|
@ -82,9 +82,7 @@ class LongRunningMemoryBenchmarkSitesDesktop(memory._MemoryInfra):
|
||||
def SetExtraBrowserOptions(self, options):
|
||||
super(LongRunningMemoryBenchmarkSitesDesktop, self).SetExtraBrowserOptions(
|
||||
options)
|
||||
options.AppendExtraBrowserArgs([
|
||||
'--memlog=all', '--memlog-sampling',
|
||||
'--memlog-stack-mode=native-with-thread-names'])
|
||||
options.AppendExtraBrowserArgs(['--enable-heap-profiling=native'])
|
||||
# Disable taking screenshot on failing pages.
|
||||
options.take_screenshot_for_failed_page = False
|
||||
|
||||
|
Reference in New Issue
Block a user