Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(359)

Unified Diff: base/trace_event/memory_dump_scheduler_unittest.cc

Issue 2799023002: memory-infra: Switch to MemoryPeakDetector and simplify MemoryDumpScheduler (Closed)
Patch Set: rebase bind -> bindonce Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/trace_event/memory_dump_scheduler.cc ('k') | base/trace_event/memory_peak_detector.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/trace_event/memory_dump_scheduler_unittest.cc
diff --git a/base/trace_event/memory_dump_scheduler_unittest.cc b/base/trace_event/memory_dump_scheduler_unittest.cc
index 9af2a3b4306bf1b6ecf08b3cf66a417b61659ee5..17fb74361f5f47a4889a5c1cf5ead8598067b53a 100644
--- a/base/trace_event/memory_dump_scheduler_unittest.cc
+++ b/base/trace_event/memory_dump_scheduler_unittest.cc
@@ -6,95 +6,195 @@
#include <memory>
+#include "base/bind.h"
#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using ::testing::Invoke;
+using ::testing::_;
+
namespace base {
namespace trace_event {
-class MemoryDumpSchedulerPollingTest : public testing::Test {
+namespace {
+
+// Wrapper to use gmock on a callback.
+struct CallbackWrapper {
+ MOCK_METHOD1(OnTick, void(MemoryDumpLevelOfDetail));
+};
+
+} // namespace
+
+class MemoryDumpSchedulerTest : public testing::Test {
public:
- static const uint32_t kMinPollsToDump = 5;
+ struct FriendDeleter {
+ void operator()(MemoryDumpScheduler* inst) { delete inst; }
+ };
- MemoryDumpSchedulerPollingTest()
- : testing::Test(),
- num_samples_tracked_(
- MemoryDumpScheduler::PollingTriggerState::kMaxNumMemorySamples) {}
+ MemoryDumpSchedulerTest() : testing::Test() {}
void SetUp() override {
- MemoryDumpScheduler::SetPollingIntervalForTesting(1);
- uint32_t kMinPollsToDump = 5;
- mds_ = MemoryDumpScheduler::GetInstance();
- mds_->Setup(nullptr, nullptr);
- mds_->AddTrigger(MemoryDumpType::PEAK_MEMORY_USAGE,
- MemoryDumpLevelOfDetail::LIGHT, kMinPollsToDump);
- mds_->polling_state_->ResetTotals();
- mds_->polling_state_->current_state =
- MemoryDumpScheduler::PollingTriggerState::ENABLED;
+ bg_thread_.reset(new Thread("MemoryDumpSchedulerTest Thread"));
+ bg_thread_->Start();
+ scheduler_.reset(new MemoryDumpScheduler());
}
void TearDown() override {
- mds_->polling_state_->current_state =
- MemoryDumpScheduler::PollingTriggerState::DISABLED;
+ bg_thread_.reset();
+ scheduler_.reset();
}
protected:
- bool ShouldTriggerDump(uint64_t total) {
- return mds_->ShouldTriggerDump(total);
- }
-
- uint32_t num_samples_tracked_;
- MemoryDumpScheduler* mds_;
+ std::unique_ptr<MemoryDumpScheduler, FriendDeleter> scheduler_;
+ std::unique_ptr<Thread> bg_thread_;
+ CallbackWrapper on_tick_;
};
-TEST_F(MemoryDumpSchedulerPollingTest, PeakDetection) {
- for (uint32_t i = 0; i < num_samples_tracked_ * 6; ++i) {
- // Memory is increased in steps and dumps must be triggered at every step.
- uint64_t total = (2 + (i / (2 * num_samples_tracked_))) * 1024 * 1204;
- bool did_trigger = ShouldTriggerDump(total);
- // Dumps must be triggered only at specific iterations.
- bool should_have_triggered = i == 0;
- should_have_triggered |=
- (i > num_samples_tracked_) && (i % (2 * num_samples_tracked_) == 1);
- if (should_have_triggered) {
- ASSERT_TRUE(did_trigger) << "Dump wasn't triggered at " << i;
- } else {
- ASSERT_FALSE(did_trigger) << "Unexpected dump at " << i;
- }
- }
+TEST_F(MemoryDumpSchedulerTest, SingleTrigger) {
+ const uint32_t kPeriodMs = 1;
+ const auto kLevelOfDetail = MemoryDumpLevelOfDetail::DETAILED;
+ const uint32_t kTicks = 5;
+ WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL,
+ WaitableEvent::InitialState::NOT_SIGNALED);
+ MemoryDumpScheduler::Config config;
+ config.triggers.push_back({kLevelOfDetail, kPeriodMs});
+ config.callback = Bind(&CallbackWrapper::OnTick, Unretained(&on_tick_));
+
+ testing::InSequence sequence;
+ EXPECT_CALL(on_tick_, OnTick(_)).Times(kTicks - 1);
+ EXPECT_CALL(on_tick_, OnTick(_))
+ .WillRepeatedly(Invoke(
+ [&evt, kLevelOfDetail](MemoryDumpLevelOfDetail level_of_detail) {
+ EXPECT_EQ(kLevelOfDetail, level_of_detail);
+ evt.Signal();
+ }));
+
+ // Check that Stop() before Start() doesn't cause any error.
+ scheduler_->Stop();
+
+ const TimeTicks tstart = TimeTicks::Now();
+ scheduler_->Start(config, bg_thread_->task_runner());
+ evt.Wait();
+ const double time_ms = (TimeTicks::Now() - tstart).InMillisecondsF();
+
+ // It takes N-1 ms to perform N ticks of 1ms each.
+ EXPECT_GE(time_ms, kPeriodMs * (kTicks - 1));
+
+ // Check that stopping twice doesn't cause any problems.
+ scheduler_->Stop();
+ scheduler_->Stop();
}
-TEST_F(MemoryDumpSchedulerPollingTest, SlowGrowthDetection) {
- for (uint32_t i = 0; i < 15; ++i) {
- // Record 1GiB of increase in each call. Dumps are triggered with 1% w.r.t
- // system's total memory.
- uint64_t total = static_cast<uint64_t>(i + 1) * 1024 * 1024 * 1024;
- bool did_trigger = ShouldTriggerDump(total);
- bool should_have_triggered = i % kMinPollsToDump == 0;
- if (should_have_triggered) {
- ASSERT_TRUE(did_trigger) << "Dump wasn't triggered at " << i;
- } else {
- ASSERT_FALSE(did_trigger) << "Unexpected dump at " << i;
- }
- }
+TEST_F(MemoryDumpSchedulerTest, MultipleTriggers) {
+ const uint32_t kPeriodLightMs = 3;
+ const uint32_t kPeriodDetailedMs = 9;
+ WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL,
+ WaitableEvent::InitialState::NOT_SIGNALED);
+ MemoryDumpScheduler::Config config;
+ const MemoryDumpLevelOfDetail kLight = MemoryDumpLevelOfDetail::LIGHT;
+ const MemoryDumpLevelOfDetail kDetailed = MemoryDumpLevelOfDetail::DETAILED;
+ config.triggers.push_back({kLight, kPeriodLightMs});
+ config.triggers.push_back({kDetailed, kPeriodDetailedMs});
+ config.callback = Bind(&CallbackWrapper::OnTick, Unretained(&on_tick_));
+
+ TimeTicks t1, t2, t3;
+
+ testing::InSequence sequence;
+ EXPECT_CALL(on_tick_, OnTick(kDetailed))
+ .WillOnce(
+ Invoke([&t1](MemoryDumpLevelOfDetail) { t1 = TimeTicks::Now(); }));
+ EXPECT_CALL(on_tick_, OnTick(kLight)).Times(1);
+ EXPECT_CALL(on_tick_, OnTick(kLight)).Times(1);
+ EXPECT_CALL(on_tick_, OnTick(kDetailed))
+ .WillOnce(
+ Invoke([&t2](MemoryDumpLevelOfDetail) { t2 = TimeTicks::Now(); }));
+ EXPECT_CALL(on_tick_, OnTick(kLight))
+ .WillOnce(
+ Invoke([&t3](MemoryDumpLevelOfDetail) { t3 = TimeTicks::Now(); }));
+
+ // Rationale for WillRepeatedly and not just WillOnce: Extra ticks might
+ // happen if the Stop() takes time. Not an interesting case, but we need to
+ // avoid gmock to shout in that case.
+ EXPECT_CALL(on_tick_, OnTick(_))
+ .WillRepeatedly(
+ Invoke([&evt](MemoryDumpLevelOfDetail) { evt.Signal(); }));
+
+ scheduler_->Start(config, bg_thread_->task_runner());
+ evt.Wait();
+ scheduler_->Stop();
+ EXPECT_GE((t2 - t1).InMillisecondsF(), kPeriodDetailedMs);
+ EXPECT_GE((t3 - t2).InMillisecondsF(), kPeriodLightMs);
}
-TEST_F(MemoryDumpSchedulerPollingTest, NotifyDumpTriggered) {
- for (uint32_t i = 0; i < num_samples_tracked_ * 6; ++i) {
- uint64_t total = (2 + (i / (2 * num_samples_tracked_))) * 1024 * 1204;
- if (i % num_samples_tracked_ == 0)
- mds_->NotifyDumpTriggered();
- bool did_trigger = ShouldTriggerDump(total);
- // Dumps should never be triggered since NotifyDumpTriggered() is called
- // frequently.
- EXPECT_NE(0u, mds_->polling_state_->last_dump_memory_total);
- EXPECT_GT(num_samples_tracked_ - 1,
- mds_->polling_state_->last_memory_totals_kb_index);
- EXPECT_LT(static_cast<int64_t>(
- total - mds_->polling_state_->last_dump_memory_total),
- mds_->polling_state_->memory_increase_threshold);
- ASSERT_FALSE(did_trigger && i) << "Unexpected dump at " << i;
+TEST_F(MemoryDumpSchedulerTest, StartStopQuickly) {
+ const uint32_t kPeriodMs = 1;
+ const uint32_t kTicks = 10;
+ WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL,
+ WaitableEvent::InitialState::NOT_SIGNALED);
+ MemoryDumpScheduler::Config config;
+ config.triggers.push_back({MemoryDumpLevelOfDetail::DETAILED, kPeriodMs});
+ config.callback = Bind(&CallbackWrapper::OnTick, Unretained(&on_tick_));
+
+ testing::InSequence sequence;
+ EXPECT_CALL(on_tick_, OnTick(_)).Times(kTicks - 1);
+ EXPECT_CALL(on_tick_, OnTick(_))
+ .WillRepeatedly(
+ Invoke([&evt](MemoryDumpLevelOfDetail) { evt.Signal(); }));
+
+ const TimeTicks tstart = TimeTicks::Now();
+ for (int i = 0; i < 5; i++) {
+ scheduler_->Stop();
+ scheduler_->Start(config, bg_thread_->task_runner());
}
+ evt.Wait();
+ const double time_ms = (TimeTicks::Now() - tstart).InMillisecondsF();
+ scheduler_->Stop();
+
+ // It takes N-1 ms to perform N ticks of 1ms each.
+ EXPECT_GE(time_ms, kPeriodMs * (kTicks - 1));
+}
+
+TEST_F(MemoryDumpSchedulerTest, StopAndStartOnAnotherThread) {
+ const uint32_t kPeriodMs = 1;
+ const uint32_t kTicks = 3;
+ WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL,
+ WaitableEvent::InitialState::NOT_SIGNALED);
+ MemoryDumpScheduler::Config config;
+ config.triggers.push_back({MemoryDumpLevelOfDetail::DETAILED, kPeriodMs});
+ config.callback = Bind(&CallbackWrapper::OnTick, Unretained(&on_tick_));
+
+ scoped_refptr<TaskRunner> expected_task_runner = bg_thread_->task_runner();
+ testing::InSequence sequence;
+ EXPECT_CALL(on_tick_, OnTick(_)).Times(kTicks - 1);
+ EXPECT_CALL(on_tick_, OnTick(_))
+ .WillRepeatedly(
+ Invoke([&evt, expected_task_runner](MemoryDumpLevelOfDetail) {
+ EXPECT_TRUE(expected_task_runner->RunsTasksOnCurrentThread());
+ evt.Signal();
+ }));
+
+ scheduler_->Start(config, bg_thread_->task_runner());
+ evt.Wait();
+ scheduler_->Stop();
+ bg_thread_->Stop();
+
+ bg_thread_.reset(new Thread("MemoryDumpSchedulerTest Thread 2"));
+ bg_thread_->Start();
+ evt.Reset();
+ expected_task_runner = bg_thread_->task_runner();
+ scheduler_->Start(config, bg_thread_->task_runner());
+ EXPECT_CALL(on_tick_, OnTick(_)).Times(kTicks - 1);
+ EXPECT_CALL(on_tick_, OnTick(_))
+ .WillRepeatedly(
+ Invoke([&evt, expected_task_runner](MemoryDumpLevelOfDetail) {
+ EXPECT_TRUE(expected_task_runner->RunsTasksOnCurrentThread());
+ evt.Signal();
+ }));
+ evt.Wait();
+ scheduler_->Stop();
}
} // namespace trace_event
« no previous file with comments | « base/trace_event/memory_dump_scheduler.cc ('k') | base/trace_event/memory_peak_detector.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698