Skip to content
This repository has been archived by the owner on Apr 3, 2020. It is now read-only.

Commit

Permalink
[tracing] MemoryDumpManager uses TraceConfig to set the periodic dump…
Browse files Browse the repository at this point in the history
… timers

The memory dump trigger config was added to TraceConfig in
crrev.com/1306753005. This CL updates the MemoryDumpManager to use
the TraceConfig to set the periodic timers for the memory dumps.

BUG=513692

Review URL: https://codereview.chromium.org/1313613002

Cr-Commit-Position: refs/heads/master@{#347570}
  • Loading branch information
ssiddhartha authored and Commit bot committed Sep 5, 2015
1 parent cc7516e commit 08adbe4
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 41 deletions.
66 changes: 48 additions & 18 deletions base/trace_event/memory_dump_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,27 @@ namespace trace_event {

namespace {

// Throttle mmaps at a rate of once every kHeavyMmapsDumpsRate standard dumps.
const int kHeavyDumpsRate = 8; // 250 ms * 8 = 2000 ms.
const int kDumpIntervalMs = 250;
const int kTraceEventNumArgs = 1;
const char* kTraceEventArgNames[] = {"dumps"};
const unsigned char kTraceEventArgTypes[] = {TRACE_VALUE_TYPE_CONVERTABLE};

StaticAtomicSequenceNumber g_next_guid;
uint32 g_periodic_dumps_count = 0;
uint32 g_heavy_dumps_rate = 0;
MemoryDumpManager* g_instance_for_testing = nullptr;

void RequestPeriodicGlobalDump() {
MemoryDumpArgs::LevelOfDetail dump_level_of_detail =
g_periodic_dumps_count == 0 ? MemoryDumpArgs::LevelOfDetail::HIGH
: MemoryDumpArgs::LevelOfDetail::LOW;
if (++g_periodic_dumps_count == kHeavyDumpsRate)
g_periodic_dumps_count = 0;
MemoryDumpArgs::LevelOfDetail dump_level_of_detail;
if (g_heavy_dumps_rate == 0) {
dump_level_of_detail = MemoryDumpArgs::LevelOfDetail::LOW;
} else {
dump_level_of_detail = g_periodic_dumps_count == 0
? MemoryDumpArgs::LevelOfDetail::HIGH
: MemoryDumpArgs::LevelOfDetail::LOW;

if (++g_periodic_dumps_count == g_heavy_dumps_rate)
g_periodic_dumps_count = 0;
}

MemoryDumpArgs dump_args = {dump_level_of_detail};
MemoryDumpManager::GetInstance()->RequestGlobalDump(
Expand Down Expand Up @@ -412,18 +416,44 @@ void MemoryDumpManager::OnTraceLogEnabled() {
subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);

// TODO(primiano): This is a temporary hack to disable periodic memory dumps
// when running memory benchmarks until they can be enabled/disabled in
// base::trace_event::TraceConfig. See https://goo.gl/5Hj3o0.
// when running memory benchmarks until telemetry uses TraceConfig to
// enable/disable periodic dumps.
// The same mechanism should be used to disable periodic dumps in tests.
if (delegate_->IsCoordinatorProcess() &&
!CommandLine::ForCurrentProcess()->HasSwitch(
"enable-memory-benchmarking") &&
!disable_periodic_dumps_for_testing_) {
g_periodic_dumps_count = 0;
periodic_dump_timer_.Start(FROM_HERE,
TimeDelta::FromMilliseconds(kDumpIntervalMs),
base::Bind(&RequestPeriodicGlobalDump));
if (!delegate_->IsCoordinatorProcess() ||
CommandLine::ForCurrentProcess()->HasSwitch(
"enable-memory-benchmarking") ||
disable_periodic_dumps_for_testing_) {
return;
}

// Enable periodic dumps. At the moment the periodic support is limited to at
// most one low-detail periodic dump and at most one high-detail periodic
// dump. If both are specified the high-detail period must be an integer
// multiple of the low-level one.
g_periodic_dumps_count = 0;
const TraceConfig trace_config =
TraceLog::GetInstance()->GetCurrentTraceConfig();
const TraceConfig::MemoryDumpConfig& config_list =
trace_config.memory_dump_config();
if (config_list.empty())
return;

uint32 min_timer_period_ms = std::numeric_limits<uint32>::max();
uint32 heavy_dump_period_ms = 0;
DCHECK_LE(config_list.size(), 2u);
for (const TraceConfig::MemoryDumpTriggerConfig& config : config_list) {
DCHECK(config.periodic_interval_ms);
if (config.level_of_detail == MemoryDumpArgs::LevelOfDetail::HIGH)
heavy_dump_period_ms = config.periodic_interval_ms;
min_timer_period_ms =
std::min(min_timer_period_ms, config.periodic_interval_ms);
}
DCHECK_EQ(0u, heavy_dump_period_ms % min_timer_period_ms);
g_heavy_dumps_rate = heavy_dump_period_ms / min_timer_period_ms;

periodic_dump_timer_.Start(FROM_HERE,
TimeDelta::FromMilliseconds(min_timer_period_ms),
base::Bind(&RequestPeriodicGlobalDump));
}

void MemoryDumpManager::OnTraceLogDisabled() {
Expand Down
125 changes: 102 additions & 23 deletions base/trace_event/memory_dump_manager_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ using testing::Return;
namespace base {
namespace trace_event {
namespace {
MemoryDumpArgs high_detail_args = {MemoryDumpArgs::LevelOfDetail::HIGH};
MemoryDumpArgs low_detail_args = {MemoryDumpArgs::LevelOfDetail::LOW};
MemoryDumpArgs g_high_detail_args = {MemoryDumpArgs::LevelOfDetail::HIGH};
MemoryDumpArgs g_low_detail_args = {MemoryDumpArgs::LevelOfDetail::LOW};
}

// Testing MemoryDumpManagerDelegate which short-circuits dump requests locally
Expand All @@ -44,6 +44,16 @@ class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
}
};

class MemoryDumpManagerDelegateForPeriodicDumpTest
: public MemoryDumpManagerDelegateForTesting {
public:
MOCK_METHOD2(RequestGlobalMemoryDump,
void(const MemoryDumpRequestArgs& args,
const MemoryDumpCallback& callback));

bool IsCoordinatorProcess() const override { return true; }
};

class MemoryDumpManagerTest : public testing::Test {
public:
void SetUp() override {
Expand All @@ -53,7 +63,6 @@ class MemoryDumpManagerTest : public testing::Test {
MemoryDumpManager::SetInstanceForTesting(mdm_.get());
ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance());
MemoryDumpManager::GetInstance()->Initialize();
MemoryDumpManager::GetInstance()->SetDelegate(&delegate_);
}

void TearDown() override {
Expand All @@ -72,19 +81,35 @@ class MemoryDumpManagerTest : public testing::Test {
}

protected:
void SetDelegate(scoped_ptr<MemoryDumpManagerDelegateForTesting> delegate) {
delegate_ = delegate.Pass();
MemoryDumpManager::GetInstance()->SetDelegate(delegate_.get());
}

// This enalbes tracing using the legacy category filter string.
void EnableTracing(const char* category) {
if (!delegate_) {
delegate_.reset(new MemoryDumpManagerDelegateForTesting());
MemoryDumpManager::GetInstance()->SetDelegate(delegate_.get());
}
TraceLog::GetInstance()->SetEnabled(
TraceConfig(category, ""), TraceLog::RECORDING_MODE);
}

void EnableTracingWithTraceConfig(const char* trace_config) {
DCHECK(delegate_);
TraceConfig tc(trace_config);
TraceLog::GetInstance()->SetEnabled(tc, TraceLog::RECORDING_MODE);
}

void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }

scoped_ptr<MemoryDumpManager> mdm_;
bool last_callback_success_;
scoped_ptr<MemoryDumpManagerDelegateForTesting> delegate_;

private:
scoped_ptr<MessageLoop> message_loop_;
MemoryDumpManagerDelegateForTesting delegate_;

// We want our singleton torn down after each test.
ShadowingAtExitManager at_exit_manager_;
Expand Down Expand Up @@ -170,7 +195,7 @@ TEST_F(MemoryDumpManagerTest, SingleDumper) {
EnableTracing("foo-and-bar-but-not-memory");
EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
high_detail_args);
g_high_detail_args);
DisableTracing();

// Now repeat enabling the memory category and check that the dumper is
Expand All @@ -179,7 +204,7 @@ TEST_F(MemoryDumpManagerTest, SingleDumper) {
EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3).WillRepeatedly(Return(true));
for (int i = 0; i < 3; ++i)
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
high_detail_args);
g_high_detail_args);
DisableTracing();

mdm_->UnregisterDumpProvider(&mdp);
Expand All @@ -188,7 +213,7 @@ TEST_F(MemoryDumpManagerTest, SingleDumper) {
EnableTracing(MemoryDumpManager::kTraceCategory);
EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
high_detail_args);
g_high_detail_args);
TraceLog::GetInstance()->SetDisabled();
}

Expand All @@ -205,7 +230,7 @@ TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgs) {
Invoke(&mdp_high_detail,
&MockDumpProvider::OnMemoryDump_CheckMemoryDumpArgs));
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
high_detail_args);
g_high_detail_args);
DisableTracing();
mdm_->UnregisterDumpProvider(&mdp_high_detail);

Expand All @@ -221,7 +246,7 @@ TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgs) {
Invoke(&mdp_low_detail,
&MockDumpProvider::OnMemoryDump_CheckMemoryDumpArgs));
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
low_detail_args);
g_low_detail_args);
DisableTracing();
mdm_->UnregisterDumpProvider(&mdp_low_detail);
}
Expand All @@ -244,7 +269,7 @@ TEST_F(MemoryDumpManagerTest, SharedSessionState) {

for (int i = 0; i < 2; ++i)
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
high_detail_args);
g_high_detail_args);

DisableTracing();
}
Expand All @@ -259,7 +284,7 @@ TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0);
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
high_detail_args);
g_high_detail_args);
DisableTracing();

// Invert: enable mdp1 and disable mdp2.
Expand All @@ -269,7 +294,7 @@ TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
high_detail_args);
g_high_detail_args);
DisableTracing();

// Enable both mdp1 and mdp2.
Expand All @@ -278,7 +303,7 @@ TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
high_detail_args);
g_high_detail_args);
DisableTracing();
}

Expand All @@ -293,7 +318,7 @@ TEST_F(MemoryDumpManagerTest, RegistrationConsistency) {
EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1);
EnableTracing(MemoryDumpManager::kTraceCategory);
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
high_detail_args);
g_high_detail_args);
DisableTracing();
}

Expand All @@ -303,7 +328,7 @@ TEST_F(MemoryDumpManagerTest, RegistrationConsistency) {
EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
EnableTracing(MemoryDumpManager::kTraceCategory);
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
high_detail_args);
g_high_detail_args);
DisableTracing();
}

Expand All @@ -314,7 +339,7 @@ TEST_F(MemoryDumpManagerTest, RegistrationConsistency) {
EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
EnableTracing(MemoryDumpManager::kTraceCategory);
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
high_detail_args);
g_high_detail_args);
DisableTracing();
}

Expand All @@ -326,7 +351,7 @@ TEST_F(MemoryDumpManagerTest, RegistrationConsistency) {
EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1);
EnableTracing(MemoryDumpManager::kTraceCategory);
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
high_detail_args);
g_high_detail_args);
DisableTracing();
}
}
Expand Down Expand Up @@ -366,7 +391,7 @@ TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) {
Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
MessageLoop::current()->task_runner(), run_loop.QuitClosure());
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
high_detail_args, callback);
g_high_detail_args, callback);
// This nested message loop (|run_loop|) will be quit if and only if
// the RequestGlobalDump callback is invoked.
run_loop.Run();
Expand Down Expand Up @@ -414,7 +439,7 @@ TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) {
for (int i = 0; i < 1 + MemoryDumpManager::kMaxConsecutiveFailuresCount;
i++) {
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
high_detail_args);
g_high_detail_args);
}

DisableTracing();
Expand Down Expand Up @@ -445,7 +470,7 @@ TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) {

for (int i = 0; i < 4; i++) {
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
high_detail_args);
g_high_detail_args);
}

DisableTracing();
Expand Down Expand Up @@ -476,7 +501,7 @@ TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) {

for (int i = 0; i < 4; i++) {
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
high_detail_args);
g_high_detail_args);
}

DisableTracing();
Expand Down Expand Up @@ -526,7 +551,7 @@ TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) {

EnableTracing(MemoryDumpManager::kTraceCategory);
MemoryDumpRequestArgs request_args = {0, MemoryDumpType::EXPLICITLY_TRIGGERED,
high_detail_args};
g_high_detail_args};
mdm_->CreateProcessDump(request_args, callback);

run_loop.Run();
Expand All @@ -552,11 +577,65 @@ TEST_F(MemoryDumpManagerTest, CallbackCalledOnFailure) {
Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
MessageLoop::current()->task_runner(), run_loop.QuitClosure());
mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
high_detail_args, callback);
g_high_detail_args, callback);
run_loop.Run();
}
EXPECT_FALSE(last_callback_success_);
}

MATCHER(IsHighDetail, "") {
return arg.dump_args.level_of_detail == MemoryDumpArgs::LevelOfDetail::HIGH;
}

MATCHER(IsLowDetail, "") {
return arg.dump_args.level_of_detail == MemoryDumpArgs::LevelOfDetail::LOW;
}

TEST_F(MemoryDumpManagerTest, SchedulePeriodicDumpsFromTraceConfig) {
const char kMemoryDumpTraceConfigString[] =
"{"
"\"included_categories\":["
"\"disabled-by-default-memory-infra\""
"],"
"\"memory_dump_config\":{"
"\"triggers\":["
"{"
"\"mode\":\"light\","
"\"periodic_interval_ms\":1"
"},"
"{"
"\"mode\":\"detailed\","
"\"periodic_interval_ms\":3"
"}"
"]"
"}"
"}";

RunLoop run_loop;
scoped_ptr<MemoryDumpManagerDelegateForPeriodicDumpTest> delegate(
new MemoryDumpManagerDelegateForPeriodicDumpTest());

auto quit_closure = run_loop.QuitClosure();
testing::InSequence sequence;
EXPECT_CALL(*delegate.get(), RequestGlobalMemoryDump(IsHighDetail(), _))
.Times(1);
EXPECT_CALL(*delegate.get(), RequestGlobalMemoryDump(IsLowDetail(), _))
.Times(2);
EXPECT_CALL(*delegate.get(), RequestGlobalMemoryDump(IsHighDetail(), _))
.Times(1);
EXPECT_CALL(*delegate.get(), RequestGlobalMemoryDump(IsLowDetail(), _))
.Times(1)
.WillOnce(Invoke([quit_closure](const MemoryDumpRequestArgs& args,
const MemoryDumpCallback& callback) {
TraceLog::GetInstance()->SetDisabled();
ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure);
}));

SetDelegate(delegate.Pass());
EnableTracingWithTraceConfig(kMemoryDumpTraceConfigString);

run_loop.Run();
}

} // namespace trace_event
} // namespace base

0 comments on commit 08adbe4

Please sign in to comment.