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: 22.7% 25 / 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 778 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 778 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 1040 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 276 DelayedRecycle(MallocApi* malloc, int64 delay_ts)
60
1/2
✓ Branch 2 taken 276 times.
✗ Branch 3 not taken.
276 : malloc_(malloc), delay_ts_(delay_ts) {}
61 552 ~DelayedRecycle() { Clear(); }
62 73182 void Recycle(void* ptr) override {
63 73182 char* data = reinterpret_cast<char*>(ptr);
64
1/2
✓ Branch 0 taken 73182 times.
✗ Branch 1 not taken.
73182 if (ptr) {
65
3/6
✓ Branch 1 taken 73182 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 73182 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 73182 times.
✗ Branch 8 not taken.
73182 recycle_ptr_.push(std::make_pair(base::GetTimestamp(), data));
66 }
67
1/2
✓ Branch 1 taken 73182 times.
✗ Branch 2 not taken.
73182 int64 recyle_ts = base::GetTimestamp() - delay_ts_;
68
5/6
✓ Branch 1 taken 135744 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 62562 times.
✓ Branch 5 taken 73182 times.
✓ Branch 6 taken 62562 times.
✓ Branch 7 taken 73182 times.
135744 while (recycle_ptr_.size() && recycle_ptr_.front().first < recyle_ts) {
69
3/12
✓ Branch 2 taken 62562 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 62562 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 62562 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
62562 CHECK(malloc_->Free(recycle_ptr_.front().second))
70 << recycle_ptr_.front().second;
71 62562 recycle_ptr_.pop();
72 }
73 73182 }
74 276 void Clear() {
75
2/2
✓ Branch 1 taken 10620 times.
✓ Branch 2 taken 276 times.
10896 while (recycle_ptr_.size()) {
76
2/12
✗ Branch 2 not taken.
✓ Branch 3 taken 10620 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 10620 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
10620 CHECK(malloc_->Free(recycle_ptr_.front().second));
77 10620 recycle_ptr_.pop();
78 }
79 276 }
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 764 ThreadSafeDelayedRecycle(MallocApi* malloc, int64 delay_ts)
95 764 : malloc_(malloc), delay_ts_(delay_ts) {}
96 1528 ~ThreadSafeDelayedRecycle() override { LocalRecyclers().erase(this); }
97
98 73182 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 73946 static RecyclerMap& LocalRecyclers() {
120
2/2
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 73714 times.
73946 thread_local RecyclerMap recyclers;
121 73946 return recyclers;
122 }
123
124 73182 DelayedRecycle& LocalRecycle() const {
125 73182 auto& recyclers = LocalRecyclers();
126
1/2
✓ Branch 1 taken 73182 times.
✗ Branch 2 not taken.
73182 auto it = recyclers.find(this);
127
2/2
✓ Branch 2 taken 276 times.
✓ Branch 3 taken 72906 times.
73182 if (it == recyclers.end()) {
128 276 it = recyclers
129
1/2
✓ Branch 1 taken 276 times.
✗ Branch 2 not taken.
276 .emplace(this,
130 276 std::make_unique<DelayedRecycle>(
131
1/2
✓ Branch 2 taken 276 times.
✗ Branch 3 not taken.
828 malloc_, delay_ts_.load(std::memory_order_relaxed)))
132 .first;
133 }
134 146364 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