1 /**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <thread>
17 #include <sstream>
18 #include <gtest/gtest.h>
19 #include "mem/alloc_tracker.h"
20
21 namespace panda {
22
23 struct Header {
24 uint32_t num_items = 0;
25 uint32_t num_stacktraces = 0;
26 };
27
28 struct AllocInfo {
29 uint32_t tag = 0;
30 uint32_t id = 0;
31 uint32_t size = 0;
32 uint32_t space = 0;
33 uint32_t stacktrace_id = 0;
34 };
35
36 struct FreeInfo {
37 uint32_t tag = 0;
38 uint32_t alloc_id = 0;
39 };
40
SkipString(std::istream & in)41 static void SkipString(std::istream &in)
42 {
43 uint32_t len = 0;
44 in.read(reinterpret_cast<char *>(&len), sizeof(len));
45 if (!in) {
46 return;
47 }
48 in.seekg(len, std::ios_base::cur);
49 }
50
TEST(DetailAllocTrackerTest,NoAllocs)51 TEST(DetailAllocTrackerTest, NoAllocs)
52 {
53 DetailAllocTracker tracker;
54 std::stringstream out;
55 tracker.Dump(out);
56 out.seekg(0);
57
58 Header hdr;
59 out.read(reinterpret_cast<char *>(&hdr), sizeof(hdr));
60 ASSERT_FALSE(out.eof());
61 ASSERT_EQ(0, hdr.num_items);
62 ASSERT_EQ(0, hdr.num_stacktraces);
63 }
64
TEST(DetailAllocTrackerTest,OneAlloc)65 TEST(DetailAllocTrackerTest, OneAlloc)
66 {
67 DetailAllocTracker tracker;
68 std::stringstream out;
69 tracker.TrackAlloc(reinterpret_cast<void *>(0x15), 20, SpaceType::SPACE_TYPE_INTERNAL);
70 tracker.Dump(out);
71 out.seekg(0);
72
73 Header hdr;
74 out.read(reinterpret_cast<char *>(&hdr), sizeof(hdr));
75 ASSERT_FALSE(out.eof());
76 ASSERT_EQ(1, hdr.num_items);
77 ASSERT_EQ(1, hdr.num_stacktraces);
78
79 // skip stacktrace
80 SkipString(out);
81 ASSERT_FALSE(out.eof());
82 AllocInfo info;
83 out.read(reinterpret_cast<char *>(&info), sizeof(info));
84 ASSERT_FALSE(out.eof());
85 ASSERT_EQ(DetailAllocTracker::ALLOC_TAG, info.tag);
86 ASSERT_EQ(0, info.id);
87 ASSERT_EQ(20, info.size);
88 ASSERT_EQ(static_cast<uint32_t>(SpaceType::SPACE_TYPE_INTERNAL), info.space);
89 ASSERT_EQ(0, info.stacktrace_id);
90 }
91
TEST(DetailAllocTrackerTest,AllocAndFree)92 TEST(DetailAllocTrackerTest, AllocAndFree)
93 {
94 DetailAllocTracker tracker;
95 std::stringstream out;
96 tracker.TrackAlloc(reinterpret_cast<void *>(0x15), 20, SpaceType::SPACE_TYPE_INTERNAL);
97 tracker.TrackFree(reinterpret_cast<void *>(0x15));
98 tracker.Dump(out);
99 out.seekg(0);
100
101 Header hdr;
102 out.read(reinterpret_cast<char *>(&hdr), sizeof(hdr));
103 ASSERT_FALSE(out.eof());
104 ASSERT_EQ(2, hdr.num_items);
105 ASSERT_EQ(1, hdr.num_stacktraces);
106
107 // skip stacktrace
108 SkipString(out);
109 ASSERT_FALSE(out.eof());
110 AllocInfo alloc;
111 FreeInfo free;
112 out.read(reinterpret_cast<char *>(&alloc), sizeof(alloc));
113 out.read(reinterpret_cast<char *>(&free), sizeof(free));
114 ASSERT_FALSE(out.eof());
115 ASSERT_EQ(DetailAllocTracker::ALLOC_TAG, alloc.tag);
116 ASSERT_EQ(0, alloc.id);
117 ASSERT_EQ(20, alloc.size);
118 ASSERT_EQ(static_cast<uint32_t>(SpaceType::SPACE_TYPE_INTERNAL), alloc.space);
119 ASSERT_EQ(0, alloc.stacktrace_id);
120 ASSERT_EQ(DetailAllocTracker::FREE_TAG, free.tag);
121 ASSERT_EQ(0, free.alloc_id);
122 }
123
TEST(DetailAllocTrackerTest,MultithreadedAlloc)124 TEST(DetailAllocTrackerTest, MultithreadedAlloc)
125 {
126 static constexpr size_t NUM_THREADS = 10;
127 static constexpr size_t NUM_ITERS = 100;
128
129 DetailAllocTracker tracker;
130 std::vector<std::thread> threads;
131 for (size_t i = 0; i < NUM_THREADS; ++i) {
132 threads.emplace_back(
133 [&tracker](size_t thread_num) {
134 for (size_t iter = 0; iter < NUM_ITERS; ++iter) {
135 auto addr = reinterpret_cast<void *>(thread_num * NUM_THREADS + iter + 1);
136 tracker.TrackAlloc(addr, 10, SpaceType::SPACE_TYPE_INTERNAL);
137 }
138 },
139 i);
140 }
141
142 for (auto &thread : threads) {
143 thread.join();
144 }
145
146 std::stringstream out;
147 tracker.Dump(out);
148 out.seekg(0);
149
150 Header hdr;
151 out.read(reinterpret_cast<char *>(&hdr), sizeof(hdr));
152 ASSERT_FALSE(out.eof());
153 ASSERT_EQ(NUM_THREADS * NUM_ITERS, hdr.num_items);
154 ASSERT_EQ(1, hdr.num_stacktraces);
155 }
156
157 } // namespace panda
158