@@ -108,6 +108,146 @@ class CompactObjectTest : public ::testing::Test {
108
108
string tmp_;
109
109
};
110
110
111
+ TEST_F (CompactObjectTest, WastedMemoryDetection) {
112
+ mi_option_set (mi_option_decommit_delay, 0 );
113
+
114
+ size_t allocated = 0 , commited = 0 , wasted = 0 ;
115
+ // By setting the threshold to high value we are expecting
116
+ // To find locations where we have wasted memory
117
+ float ratio = 0.8 ;
118
+ zmalloc_get_allocator_wasted_blocks (ratio, &allocated, &commited, &wasted);
119
+ EXPECT_EQ (allocated, 0 );
120
+ EXPECT_EQ (commited, 0 );
121
+ EXPECT_EQ (wasted, (commited - allocated));
122
+
123
+ std::size_t allocated_mem = 64 ;
124
+ auto * myheap = mi_heap_get_backing ();
125
+
126
+ void * p1 = mi_heap_malloc (myheap, 64 );
127
+
128
+ void * ptrs_end[50 ];
129
+ for (size_t i = 0 ; i < 50 ; ++i) {
130
+ ptrs_end[i] = mi_heap_malloc (myheap, 128 );
131
+ allocated_mem += 128 ;
132
+ }
133
+
134
+ allocated = commited = wasted = 0 ;
135
+ zmalloc_get_allocator_wasted_blocks (ratio, &allocated, &commited, &wasted);
136
+ EXPECT_EQ (allocated, allocated_mem);
137
+ EXPECT_GT (commited, allocated_mem);
138
+ EXPECT_EQ (wasted, (commited - allocated));
139
+ void * ptr[50 ];
140
+ // allocate 50
141
+ for (size_t i = 0 ; i < 50 ; ++i) {
142
+ ptr[i] = mi_heap_malloc (myheap, 256 );
143
+ allocated_mem += 256 ;
144
+ }
145
+
146
+ // At this point all the blocks has committed > 0 and used > 0
147
+ // and since we expecting to find these locations, the size of
148
+ // wasted == commited memory - allocated memory.
149
+ allocated = commited = wasted = 0 ;
150
+ zmalloc_get_allocator_wasted_blocks (ratio, &allocated, &commited, &wasted);
151
+ EXPECT_EQ (allocated, allocated_mem);
152
+ EXPECT_GT (commited, allocated_mem);
153
+ EXPECT_EQ (wasted, (commited - allocated));
154
+
155
+ // free 50/50 -
156
+ for (size_t i = 0 ; i < 50 ; ++i) {
157
+ mi_free (ptr[i]);
158
+ allocated_mem -= 256 ;
159
+ }
160
+
161
+ // After all the memory at block size 256 is free, we would have commited there
162
+ // but the used is expected to be 0, so the number now is different from the
163
+ // case above
164
+ allocated = commited = wasted = 0 ;
165
+ zmalloc_get_allocator_wasted_blocks (ratio, &allocated, &commited, &wasted);
166
+ EXPECT_EQ (allocated, allocated_mem);
167
+ EXPECT_GT (commited, allocated_mem);
168
+ // since we release all 256 memory block, it should not be counted
169
+ EXPECT_EQ (wasted, (commited - allocated));
170
+ for (size_t i = 0 ; i < 50 ; ++i) {
171
+ mi_free (ptrs_end[i]);
172
+ }
173
+ mi_free (p1);
174
+
175
+ // Now that its all freed, we are not expecting to have any wasted memory any more
176
+ allocated = commited = wasted = 0 ;
177
+ zmalloc_get_allocator_wasted_blocks (ratio, &allocated, &commited, &wasted);
178
+ EXPECT_EQ (allocated, 0 );
179
+ EXPECT_GT (commited, allocated);
180
+ EXPECT_EQ (wasted, (commited - allocated));
181
+
182
+ mi_collect (false );
183
+ }
184
+
185
+ TEST_F (CompactObjectTest, WastedMemoryDontCount) {
186
+ // The commited memory per blocks are:
187
+ // 64bit => 4K
188
+ // 128bit => 8k
189
+ // 256 => 16k
190
+ // and so on, which mean every n * sizeof(ptr) ^ 2 == 2^11*2*(n-1) (where n starts with 1)
191
+ constexpr std::size_t kExpectedFor256MemWasted = 0x4000 ; // memory block 256
192
+ mi_option_set (mi_option_decommit_delay, 0 );
193
+ auto * myheap = mi_heap_get_backing ();
194
+
195
+ size_t allocated = 0 , commited = 0 , wasted = 0 ;
196
+ // By setting the threshold to a very low number
197
+ // we don't expect to find and locations where memory is wasted
198
+ float ratio = 0.01 ;
199
+ zmalloc_get_allocator_wasted_blocks (ratio, &allocated, &commited, &wasted);
200
+ EXPECT_EQ (allocated, 0 );
201
+ EXPECT_EQ (commited, 0 );
202
+ EXPECT_EQ (wasted, (commited - allocated));
203
+
204
+ std::size_t allocated_mem = 64 ;
205
+
206
+ void * p1 = mi_heap_malloc (myheap, 64 );
207
+
208
+ void * ptrs_end[50 ];
209
+ for (size_t i = 0 ; i < 50 ; ++i) {
210
+ ptrs_end[i] = mi_heap_malloc (myheap, 128 );
211
+ (void )p1;
212
+ allocated_mem += 128 ;
213
+ }
214
+
215
+ void * ptr[50 ];
216
+
217
+ // allocate 50
218
+ for (size_t i = 0 ; i < 50 ; ++i) {
219
+ ptr[i] = mi_heap_malloc (myheap, 256 );
220
+ allocated_mem += 256 ;
221
+ }
222
+ allocated = commited = wasted = 0 ;
223
+ zmalloc_get_allocator_wasted_blocks (ratio, &allocated, &commited, &wasted);
224
+ // Threshold is low so we are not expecting any wasted memory to be found.
225
+ EXPECT_EQ (allocated, allocated_mem);
226
+ EXPECT_GT (commited, allocated_mem);
227
+ EXPECT_EQ (wasted, 0 );
228
+
229
+ // free 50/50 -
230
+ for (size_t i = 0 ; i < 50 ; ++i) {
231
+ mi_free (ptr[i]);
232
+ allocated_mem -= 256 ;
233
+ }
234
+ allocated = commited = wasted = 0 ;
235
+ zmalloc_get_allocator_wasted_blocks (ratio, &allocated, &commited, &wasted);
236
+
237
+ EXPECT_EQ (allocated, allocated_mem);
238
+ EXPECT_GT (commited, allocated_mem);
239
+ // We will detect only wasted memory for block size of
240
+ // 256 - and all of it is wasted.
241
+ EXPECT_EQ (wasted, kExpectedFor256MemWasted );
242
+ // Threshold is low so we are not expecting any wasted memory to be found.
243
+ for (size_t i = 0 ; i < 50 ; ++i) {
244
+ mi_free (ptrs_end[i]);
245
+ }
246
+ mi_free (p1);
247
+
248
+ mi_collect (false );
249
+ }
250
+
111
251
TEST_F (CompactObjectTest, Basic) {
112
252
robj* rv = createRawStringObject (" foo" , 3 );
113
253
cobj_.ImportRObj (rv);
0 commit comments