@@ -269,6 +269,85 @@ TEST_F(test, sharedLimits) {
269269 EXPECT_EQ (MaxSize / SlabMinSize * 2 , numFrees);
270270}
271271
272+ TEST_F (test, disjointPoolTrim) {
273+ struct memory_provider : public umf_test ::provider_base_t {
274+ umf_result_t alloc (size_t size, size_t alignment, void **ptr) noexcept {
275+ *ptr = umf_ba_global_aligned_alloc (size, alignment);
276+ return UMF_RESULT_SUCCESS;
277+ }
278+
279+ umf_result_t free (void *ptr, [[maybe_unused]] size_t size) noexcept {
280+ umf_ba_global_free (ptr);
281+ return UMF_RESULT_SUCCESS;
282+ }
283+ };
284+
285+ umf_memory_provider_ops_t provider_ops =
286+ umf_test::providerMakeCOps<memory_provider, void >();
287+
288+ auto providerUnique =
289+ wrapProviderUnique (createProviderChecked (&provider_ops, nullptr ));
290+
291+ umf_memory_provider_handle_t provider_handle;
292+ provider_handle = providerUnique.get ();
293+
294+ umf_disjoint_pool_params_handle_t params =
295+ (umf_disjoint_pool_params_handle_t )defaultDisjointPoolConfig ();
296+ params->pool_trace = 3 ;
297+ // Set the slab min size to 64 so allocating 64 bytes will use the whole
298+ // slab.
299+ params->slab_min_size = 64 ;
300+ params->capacity = 4 ;
301+
302+ // in "internals" test we use ops interface to directly manipulate the pool
303+ // structure
304+ const umf_memory_pool_ops_t *ops = umfDisjointPoolOps ();
305+ EXPECT_NE (ops, nullptr );
306+
307+ disjoint_pool_t *pool;
308+ umf_result_t res = ops->initialize (provider_handle, params, (void **)&pool);
309+ EXPECT_EQ (res, UMF_RESULT_SUCCESS);
310+ EXPECT_NE (pool, nullptr );
311+
312+ // do 4 allocs, then free all of them
313+ size_t size = 64 ;
314+ void *ptrs[4 ] = {0 };
315+ ptrs[0 ] = ops->malloc (pool, size);
316+ EXPECT_NE (ptrs[0 ], nullptr );
317+ ptrs[1 ] = ops->malloc (pool, size);
318+ EXPECT_NE (ptrs[1 ], nullptr );
319+ ptrs[2 ] = ops->malloc (pool, size);
320+ EXPECT_NE (ptrs[2 ], nullptr );
321+ ptrs[3 ] = ops->malloc (pool, size);
322+ EXPECT_NE (ptrs[3 ], nullptr );
323+
324+ ops->free (pool, ptrs[0 ]);
325+ ops->free (pool, ptrs[1 ]);
326+ ops->free (pool, ptrs[2 ]);
327+ ops->free (pool, ptrs[3 ]);
328+
329+ // Because we set the slab min size to 64, each allocation should go to the
330+ // separate slab. Additionally, because we set the capacity to 4, all slabs
331+ // should still be in the pool available for new allocations.
332+ EXPECT_EQ (pool->buckets [0 ]->available_slabs_num , 4 );
333+ EXPECT_EQ (pool->buckets [0 ]->curr_slabs_in_use , 0 );
334+ EXPECT_EQ (pool->buckets [0 ]->curr_slabs_in_pool , 4 );
335+
336+ // Trim memory - leave only one slab
337+ umfDisjointPoolTrimMemory (pool, 1 );
338+ EXPECT_EQ (pool->buckets [0 ]->available_slabs_num , 1 );
339+ EXPECT_EQ (pool->buckets [0 ]->curr_slabs_in_pool , 1 );
340+
341+ // Trim the rest of memory
342+ umfDisjointPoolTrimMemory (pool, 0 );
343+ EXPECT_EQ (pool->buckets [0 ]->available_slabs_num , 0 );
344+ EXPECT_EQ (pool->buckets [0 ]->curr_slabs_in_pool , 0 );
345+
346+ ops->finalize (pool);
347+ res = umfDisjointPoolParamsDestroy (params);
348+ EXPECT_EQ (res, UMF_RESULT_SUCCESS);
349+ }
350+
272351TEST_F (test, disjointPoolNullParams) {
273352 umf_result_t res = umfDisjointPoolParamsCreate (nullptr );
274353 EXPECT_EQ (res, UMF_RESULT_ERROR_INVALID_ARGUMENT);
0 commit comments