• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/profiling/memory/bookkeeping.h"
18 
19 #include "gmock/gmock.h"
20 #include "gtest/gtest.h"
21 
22 namespace perfetto {
23 namespace profiling {
24 namespace {
25 
26 using ::testing::AnyOf;
27 using ::testing::Eq;
28 
stack()29 std::vector<FrameData> stack() {
30   std::vector<FrameData> res;
31 
32   unwindstack::FrameData data{};
33   data.function_name = "fun1";
34   data.map_name = "map1";
35   res.emplace_back(std::move(data), "dummy_buildid");
36   data = {};
37   data.function_name = "fun2";
38   data.map_name = "map2";
39   res.emplace_back(std::move(data), "dummy_buildid");
40   return res;
41 }
42 
stack2()43 std::vector<FrameData> stack2() {
44   std::vector<FrameData> res;
45   unwindstack::FrameData data{};
46   data.function_name = "fun1";
47   data.map_name = "map1";
48   res.emplace_back(std::move(data), "dummy_buildid");
49   data = {};
50   data.function_name = "fun3";
51   data.map_name = "map3";
52   res.emplace_back(std::move(data), "dummy_buildid");
53   return res;
54 }
55 
TEST(BookkeepingTest,Basic)56 TEST(BookkeepingTest, Basic) {
57   uint64_t sequence_number = 1;
58   GlobalCallstackTrie c;
59   HeapTracker hd(&c);
60 
61   hd.RecordMalloc(stack(), 1, 5, sequence_number, 100 * sequence_number);
62   sequence_number++;
63   hd.RecordMalloc(stack2(), 2, 2, sequence_number, 100 * sequence_number);
64   sequence_number++;
65   ASSERT_EQ(hd.GetSizeForTesting(stack()), 5);
66   ASSERT_EQ(hd.GetSizeForTesting(stack2()), 2);
67   ASSERT_EQ(hd.GetTimestampForTesting(), 100 * (sequence_number - 1));
68   hd.RecordFree(2, sequence_number, 100 * sequence_number);
69   sequence_number++;
70   ASSERT_EQ(hd.GetSizeForTesting(stack()), 5);
71   ASSERT_EQ(hd.GetSizeForTesting(stack2()), 0);
72   ASSERT_EQ(hd.GetTimestampForTesting(), 100 * (sequence_number - 1));
73   hd.RecordFree(1, sequence_number, 100 * sequence_number);
74   sequence_number++;
75   ASSERT_EQ(hd.GetSizeForTesting(stack()), 0);
76   ASSERT_EQ(hd.GetSizeForTesting(stack2()), 0);
77   ASSERT_EQ(hd.GetTimestampForTesting(), 100 * (sequence_number - 1));
78 }
79 
TEST(BookkeepingTest,TwoHeapTrackers)80 TEST(BookkeepingTest, TwoHeapTrackers) {
81   uint64_t sequence_number = 1;
82   GlobalCallstackTrie c;
83   HeapTracker hd(&c);
84   {
85     HeapTracker hd2(&c);
86 
87     hd.RecordMalloc(stack(), 1, 5, sequence_number, 100 * sequence_number);
88     hd2.RecordMalloc(stack(), 2, 2, sequence_number, 100 * sequence_number);
89     sequence_number++;
90     ASSERT_EQ(hd2.GetSizeForTesting(stack()), 2);
91     ASSERT_EQ(hd.GetSizeForTesting(stack()), 5);
92     ASSERT_EQ(hd.GetTimestampForTesting(), 100 * (sequence_number - 1));
93   }
94   ASSERT_EQ(hd.GetSizeForTesting(stack()), 5);
95 }
96 
TEST(BookkeepingTest,ReplaceAlloc)97 TEST(BookkeepingTest, ReplaceAlloc) {
98   uint64_t sequence_number = 1;
99   GlobalCallstackTrie c;
100   HeapTracker hd(&c);
101 
102   hd.RecordMalloc(stack(), 1, 5, sequence_number, 100 * sequence_number);
103   sequence_number++;
104   hd.RecordMalloc(stack2(), 1, 2, sequence_number, 100 * sequence_number);
105   sequence_number++;
106   EXPECT_EQ(hd.GetSizeForTesting(stack()), 0);
107   EXPECT_EQ(hd.GetSizeForTesting(stack2()), 2);
108   ASSERT_EQ(hd.GetTimestampForTesting(), 100 * (sequence_number - 1));
109 }
110 
TEST(BookkeepingTest,OutOfOrder)111 TEST(BookkeepingTest, OutOfOrder) {
112   GlobalCallstackTrie c;
113   HeapTracker hd(&c);
114 
115   hd.RecordMalloc(stack(), 1, 5, 2, 2);
116   hd.RecordMalloc(stack2(), 1, 2, 1, 1);
117   EXPECT_EQ(hd.GetSizeForTesting(stack()), 5);
118   EXPECT_EQ(hd.GetSizeForTesting(stack2()), 0);
119 }
120 
TEST(BookkeepingTest,ManyAllocations)121 TEST(BookkeepingTest, ManyAllocations) {
122   GlobalCallstackTrie c;
123   HeapTracker hd(&c);
124 
125   std::vector<std::pair<uint64_t, uint64_t>> batch_frees;
126 
127   for (uint64_t sequence_number = 1; sequence_number < 1000;) {
128     if (batch_frees.size() > 10) {
129       for (const auto& p : batch_frees)
130         hd.RecordFree(p.first, p.second, 100 * p.second);
131       batch_frees.clear();
132     }
133 
134     uint64_t addr = sequence_number;
135     hd.RecordMalloc(stack(), addr, 5, sequence_number, sequence_number);
136     sequence_number++;
137     batch_frees.emplace_back(addr, sequence_number++);
138     ASSERT_THAT(hd.GetSizeForTesting(stack()), AnyOf(Eq(0), Eq(5)));
139   }
140 }
141 
TEST(BookkeepingTest,ArbitraryOrder)142 TEST(BookkeepingTest, ArbitraryOrder) {
143   std::vector<FrameData> s = stack();
144   std::vector<FrameData> s2 = stack2();
145 
146   struct Operation {
147     uint64_t sequence_number;
148     uint64_t address;
149     uint64_t bytes;                       // 0 for free
150     const std::vector<FrameData>* stack;  // nullptr for free
151 
152     // For std::next_permutation.
153     bool operator<(const Operation& other) const {
154       return sequence_number < other.sequence_number;
155     }
156   } operations[] = {
157       {1, 1, 5, &s},       //
158       {2, 1, 10, &s2},     //
159       {3, 1, 0, nullptr},  //
160       {4, 2, 0, nullptr},  //
161       {5, 3, 0, nullptr},  //
162       {6, 3, 2, &s},       //
163       {7, 4, 3, &s2},      //
164   };
165 
166   uint64_t s_size = 2;
167   uint64_t s2_size = 3;
168 
169   do {
170     GlobalCallstackTrie c;
171     HeapTracker hd(&c);
172 
173     for (auto it = std::begin(operations); it != std::end(operations); ++it) {
174       const Operation& operation = *it;
175 
176       if (operation.bytes == 0) {
177         hd.RecordFree(operation.address, operation.sequence_number,
178                       100 * operation.sequence_number);
179       } else {
180         hd.RecordMalloc(*operation.stack, operation.address, operation.bytes,
181                         operation.sequence_number,
182                         100 * operation.sequence_number);
183       }
184     }
185     ASSERT_EQ(hd.GetSizeForTesting(s), s_size);
186     ASSERT_EQ(hd.GetSizeForTesting(s2), s2_size);
187   } while (std::next_permutation(std::begin(operations), std::end(operations)));
188 }
189 
190 }  // namespace
191 }  // namespace profiling
192 }  // namespace perfetto
193