1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/trace_event/memory_dump_scheduler.h"
6 
7 #include <memory>
8 
9 #include "base/single_thread_task_runner.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 
12 namespace base {
13 namespace trace_event {
14 
15 class MemoryDumpSchedulerPollingTest : public testing::Test {
16  public:
17   static const uint32_t kMinPollsToDump = 5;
18 
19   MemoryDumpSchedulerPollingTest()
20       : testing::Test(),
21         num_samples_tracked_(
22             MemoryDumpScheduler::PollingTriggerState::kMaxNumMemorySamples) {}
23 
24   void SetUp() override {
25     MemoryDumpScheduler::SetPollingIntervalForTesting(1);
26     uint32_t kMinPollsToDump = 5;
27     mds_ = MemoryDumpScheduler::GetInstance();
28     mds_->Setup(nullptr, nullptr);
29     mds_->AddTrigger(MemoryDumpType::PEAK_MEMORY_USAGE,
30                      MemoryDumpLevelOfDetail::LIGHT, kMinPollsToDump);
31     mds_->polling_state_->ResetTotals();
32     mds_->polling_state_->current_state =
33         MemoryDumpScheduler::PollingTriggerState::ENABLED;
34   }
35 
36   void TearDown() override {
37     mds_->polling_state_->current_state =
38         MemoryDumpScheduler::PollingTriggerState::DISABLED;
39   }
40 
41  protected:
42   bool ShouldTriggerDump(uint64_t total) {
43     return mds_->ShouldTriggerDump(total);
44   }
45 
46   uint32_t num_samples_tracked_;
47   MemoryDumpScheduler* mds_;
48 };
49 
50 TEST_F(MemoryDumpSchedulerPollingTest, PeakDetection) {
51   for (uint32_t i = 0; i < num_samples_tracked_ * 6; ++i) {
52     // Memory is increased in steps and dumps must be triggered at every step.
53     uint64_t total = (2 + (i / (2 * num_samples_tracked_))) * 1024 * 1204;
54     bool did_trigger = ShouldTriggerDump(total);
55     // Dumps must be triggered only at specific iterations.
56     bool should_have_triggered = i == 0;
57     should_have_triggered |=
58         (i > num_samples_tracked_) && (i % (2 * num_samples_tracked_) == 1);
59     if (should_have_triggered) {
60       ASSERT_TRUE(did_trigger) << "Dump wasn't triggered at " << i;
61     } else {
62       ASSERT_FALSE(did_trigger) << "Unexpected dump at " << i;
63     }
64   }
65 }
66 
67 TEST_F(MemoryDumpSchedulerPollingTest, SlowGrowthDetection) {
68   for (uint32_t i = 0; i < 15; ++i) {
69     // Record 1GiB of increase in each call. Dumps are triggered with 1% w.r.t
70     // system's total memory.
71     uint64_t total = static_cast<uint64_t>(i + 1) * 1024 * 1024 * 1024;
72     bool did_trigger = ShouldTriggerDump(total);
73     bool should_have_triggered = i % kMinPollsToDump == 0;
74     if (should_have_triggered) {
75       ASSERT_TRUE(did_trigger) << "Dump wasn't triggered at " << i;
76     } else {
77       ASSERT_FALSE(did_trigger) << "Unexpected dump at " << i;
78     }
79   }
80 }
81 
82 TEST_F(MemoryDumpSchedulerPollingTest, NotifyDumpTriggered) {
83   for (uint32_t i = 0; i < num_samples_tracked_ * 6; ++i) {
84     uint64_t total = (2 + (i / (2 * num_samples_tracked_))) * 1024 * 1204;
85     if (i % num_samples_tracked_ == 0)
86       mds_->NotifyDumpTriggered();
87     bool did_trigger = ShouldTriggerDump(total);
88     // Dumps should never be triggered since NotifyDumpTriggered() is called
89     // frequently.
90     EXPECT_NE(0u, mds_->polling_state_->last_dump_memory_total);
91     EXPECT_GT(num_samples_tracked_ - 1,
92               mds_->polling_state_->last_memory_totals_kb_index);
93     EXPECT_LT(static_cast<int64_t>(
94                   total - mds_->polling_state_->last_dump_memory_total),
95               mds_->polling_state_->memory_increase_threshold);
96     ASSERT_FALSE(did_trigger && i) << "Unexpected dump at " << i;
97   }
98 }
99 
100 }  // namespace trace_event
101 }  // namespace base
102