GCC Code Coverage Report


Directory: src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 56.2% 36 / 0 / 64
Functions: 60.0% 12 / 0 / 20
Branches: 23.6% 26 / 0 / 110

memory/malloc.h
Line Branch Exec Source
1 #pragma once
2 #include <atomic>
3 #include <memory>
4 #include <queue>
5 #include <string>
6 #include <unordered_map>
7 #include <vector>
8
9 #include "base/base.h"
10 #include "epoch_manager.h"
11
12 namespace base {
13 class MallocApi {
14 public:
15 virtual char* New(int memory_size) = 0;
16 virtual bool Free(void* memory_data) = 0;
17 virtual void GetMallocsAppend(std::vector<char*>* mallocs_data) const = 0;
18 virtual void GetMallocsAppend(std::vector<int64>* mallocs_offset) const = 0;
19 virtual void Initialize() = 0;
20 virtual char* GetMallocData(int64 offset) const = 0;
21 virtual int GetMallocSize(int64 offset) const = 0;
22 virtual int64 GetMallocOffset(const char* data) const = 0;
23 virtual int GetMallocSize(const char* data) const = 0;
24 virtual int64 DataBaseOffset() const { return 0; }
25 virtual char* BackingData() const { return nullptr; }
26 virtual int64 BackingSize() const { return 0; }
27 virtual std::string GetInfo() const { return ""; }
28 728 virtual ~MallocApi() {}
29 virtual uint64_t total_malloc() const = 0;
30 virtual bool Healthy() const = 0;
31 virtual void AddMallocs4Recovery(int64_t shm_offset) = 0;
32
33 protected:
34 728 MallocApi() {}
35
36 private:
37 DISALLOW_COPY_AND_ASSIGN(MallocApi);
38 };
39
40 class ShmBaseRecycle {
41 public:
42 virtual void Recycle(void* ptr) = 0;
43 994 virtual ~ShmBaseRecycle() {}
44 };
45
46 class DirectRecycle : public ShmBaseRecycle {
47 public:
48 explicit DirectRecycle(MallocApi* malloc) : malloc_(malloc) {}
49 void Recycle(void* ptr) override { malloc_->Free(ptr); }
50
51 private:
52 MallocApi* malloc_;
53 };
54
55 class DelayedRecycle : public ShmBaseRecycle {
56 public:
57 explicit DelayedRecycle(MallocApi* malloc)
58 : malloc_(malloc), delay_ts_(1000000) {}
59 280 DelayedRecycle(MallocApi* malloc, int64 delay_ts)
60
1/2
✓ Branch 2 taken 280 times.
✗ Branch 3 not taken.
280 : malloc_(malloc), delay_ts_(delay_ts) {}
61 560 ~DelayedRecycle() { Clear(); }
62 73040 void Recycle(void* ptr) override {
63 73040 char* data = reinterpret_cast<char*>(ptr);
64
1/2
✓ Branch 0 taken 73040 times.
✗ Branch 1 not taken.
73040 if (ptr) {
65
3/6
✓ Branch 1 taken 73040 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 73040 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 73040 times.
✗ Branch 8 not taken.
73040 recycle_ptr_.push(std::make_pair(base::GetTimestamp(), data));
66 }
67
1/2
✓ Branch 1 taken 73040 times.
✗ Branch 2 not taken.
73040 int64 recyle_ts = base::GetTimestamp() - delay_ts_;
68
6/6
✓ Branch 1 taken 135938 times.
✓ Branch 2 taken 8 times.
✓ Branch 4 taken 62906 times.
✓ Branch 5 taken 73032 times.
✓ Branch 6 taken 62906 times.
✓ Branch 7 taken 73040 times.
135946 while (recycle_ptr_.size() && recycle_ptr_.front().first < recyle_ts) {
69
3/12
✓ Branch 2 taken 62906 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 62906 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 62906 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
62906 CHECK(malloc_->Free(recycle_ptr_.front().second))
70 << recycle_ptr_.front().second;
71 62906 recycle_ptr_.pop();
72 }
73 73040 }
74 280 void Clear() {
75
2/2
✓ Branch 1 taken 10134 times.
✓ Branch 2 taken 280 times.
10414 while (recycle_ptr_.size()) {
76
2/12
✗ Branch 2 not taken.
✓ Branch 3 taken 10134 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 10134 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
10134 CHECK(malloc_->Free(recycle_ptr_.front().second));
77 10134 recycle_ptr_.pop();
78 }
79 280 }
80 int64 GetPendingNum() const { return recycle_ptr_.size(); }
81
82 void SetDelayTs(int delay_ts) { delay_ts_ = delay_ts; }
83
84 private:
85 std::queue<std::pair<int64, char*>> recycle_ptr_;
86 MallocApi* malloc_;
87 int64 delay_ts_;
88 };
89
90 class ThreadSafeDelayedRecycle : public ShmBaseRecycle {
91 public:
92 explicit ThreadSafeDelayedRecycle(MallocApi* malloc)
93 : malloc_(malloc), delay_ts_(1000000) {}
94 714 ThreadSafeDelayedRecycle(MallocApi* malloc, int64 delay_ts)
95 714 : malloc_(malloc), delay_ts_(delay_ts) {}
96 1428 ~ThreadSafeDelayedRecycle() override { LocalRecyclers().erase(this); }
97
98 73040 void Recycle(void* ptr) override { LocalRecycle().Recycle(ptr); }
99
100 int64 GetPendingNum() const {
101 auto& recyclers = LocalRecyclers();
102 auto it = recyclers.find(this);
103 return it == recyclers.end() ? 0 : it->second->GetPendingNum();
104 }
105
106 void SetDelayTs(int delay_ts) {
107 delay_ts_.store(delay_ts, std::memory_order_relaxed);
108 auto& recyclers = LocalRecyclers();
109 auto it = recyclers.find(this);
110 if (it != recyclers.end()) {
111 it->second->SetDelayTs(delay_ts);
112 }
113 }
114
115 private:
116 using RecyclerMap = std::unordered_map<const ThreadSafeDelayedRecycle*,
117 std::unique_ptr<DelayedRecycle>>;
118
119 73754 static RecyclerMap& LocalRecyclers() {
120
2/2
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 73520 times.
73754 thread_local RecyclerMap recyclers;
121 73754 return recyclers;
122 }
123
124 73040 DelayedRecycle& LocalRecycle() const {
125 73040 auto& recyclers = LocalRecyclers();
126
1/2
✓ Branch 1 taken 73040 times.
✗ Branch 2 not taken.
73040 auto it = recyclers.find(this);
127
2/2
✓ Branch 2 taken 280 times.
✓ Branch 3 taken 72760 times.
73040 if (it == recyclers.end()) {
128 280 it = recyclers
129
1/2
✓ Branch 1 taken 280 times.
✗ Branch 2 not taken.
280 .emplace(this,
130 280 std::make_unique<DelayedRecycle>(
131
1/2
✓ Branch 2 taken 280 times.
✗ Branch 3 not taken.
840 malloc_, delay_ts_.load(std::memory_order_relaxed)))
132 .first;
133 }
134 146080 return *it->second;
135 }
136
137 MallocApi* malloc_;
138 std::atomic<int64> delay_ts_;
139 };
140
141 class StdDelayedRecycle : public ShmBaseRecycle {
142 public:
143 explicit StdDelayedRecycle() : delay_ts_(1000000) {}
144 StdDelayedRecycle(int64 delay_ts) : delay_ts_(delay_ts) {}
145 ~StdDelayedRecycle() { Clear(); }
146 void Recycle(void* ptr) override {
147 char* data = reinterpret_cast<char*>(ptr);
148 if (ptr) {
149 recycle_ptr_.push(std::make_pair(base::GetTimestamp(), data));
150 }
151 int64 recyle_ts = base::GetTimestamp() - delay_ts_;
152 while (recycle_ptr_.size() && recycle_ptr_.front().first < recyle_ts) {
153 delete recycle_ptr_.front().second;
154 recycle_ptr_.pop();
155 }
156 }
157 void Clear() {
158 while (recycle_ptr_.size()) {
159 delete recycle_ptr_.front().second;
160 recycle_ptr_.pop();
161 }
162 }
163 int64 GetPendingNum() const { return recycle_ptr_.size(); }
164
165 void SetDelayTs(int delay_ts) { delay_ts_ = delay_ts; }
166
167 private:
168 std::queue<std::pair<int64, char*>> recycle_ptr_;
169 int64 delay_ts_;
170 };
171
172 class ShmEpochRecycle : public ShmBaseRecycle {
173 public:
174 explicit ShmEpochRecycle(MallocApi* malloc) : malloc_(malloc) {
175 epoch_manager_ = epoch::EpochManager::GetInstance();
176 }
177 ~ShmEpochRecycle() { Clear(); }
178 void Recycle(void* ptr) {
179 recycled_count++;
180 epoch::Epoch removal_epoch = epoch_manager_->GetCurrentEpoch();
181 char* data = reinterpret_cast<char*>(ptr);
182 if (ptr) {
183 recycle_ptr_.push(std::make_pair(removal_epoch, data));
184 }
185
186 if (recycled_count % 1000 == 0)
187 epoch_manager_->BumpCurrentEpoch();
188 while (recycle_ptr_.size() &&
189 epoch_manager_->IsSafeToReclaim(recycle_ptr_.front().first)) {
190 CHECK(malloc_->Free(recycle_ptr_.front().second))
191 << recycle_ptr_.front().second;
192 recycle_ptr_.pop();
193 }
194 }
195 void Clear() {
196 while (recycle_ptr_.size()) {
197 CHECK(malloc_->Free(recycle_ptr_.front().second));
198 recycle_ptr_.pop();
199 }
200 }
201 int64 GetPendingNum() const { return recycle_ptr_.size(); }
202
203 private:
204 MallocApi* malloc_;
205 epoch::EpochManager* epoch_manager_;
206 std::queue<std::pair<epoch::Epoch, char*>> recycle_ptr_;
207 int64_t recycled_count = 0;
208 };
209
210 } // namespace base
211