You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							189 lines
						
					
					
						
							6.2 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							189 lines
						
					
					
						
							6.2 KiB
						
					
					
				| #include <memory> | |
| #include <cassert> | |
| #include <cstdio> | |
| #include <stdlib.h>  | |
| #include <algorithm>  | |
| #include <vector> | |
|  | |
| // enable debugging code in spp_bitset.h | |
| #define SPP_TEST 1 | |
|  | |
| #include <sparsepp/spp_timer.h> | |
| #include <sparsepp/spp_memory.h> | |
| #include <sparsepp/spp_dlalloc.h> | |
|  | |
| using namespace std; | |
| 
 | |
| static float _to_mb(uint64_t m) { return (float)((double)m / (1024 * 1024)); } | |
| 
 | |
| // ----------------------------------------------------------- | |
| // ----------------------------------------------------------- | |
| template <class T, class A> | |
| class TestAlloc | |
| { | |
| public: | |
|     TestAlloc(size_t num_alloc = 8000000) :  | |
|         _num_alloc(num_alloc) | |
|     { | |
|         _allocated.resize(_num_alloc, nullptr); | |
|         _sizes.resize(_num_alloc, 0); | |
|         _start_mem_usage = spp::GetProcessMemoryUsed(); | |
|     } | |
| 
 | |
|     void run() | |
|     { | |
|         srand(43); // always same sequence of random numbers | |
|  | |
|         for (size_t i=0; i<_num_alloc; ++i) | |
|             _sizes[i] = std::max(2, (rand() % 5) * 2); | |
|                                   | |
|         spp::Timer<std::milli> timer; | |
| 
 | |
|         // allocate small buffers | |
|         // ---------------------- | |
|         for (size_t i=0; i<_num_alloc; ++i) | |
|         { | |
|             _allocated[i] = _allocator.allocate(_sizes[i]); | |
|             _set_buf(_allocated[i], _sizes[i]); | |
|         } | |
|          | |
| #if 1 | |
|         // and grow the buffers to a max size of 24 each | |
|         // --------------------------------------------- | |
|         for (uint32_t j=4; j<26; j += 2) | |
|         { | |
|             for (size_t i=0; i<_num_alloc; ++i) | |
|             { | |
|                 // if ( _sizes[i] < j)                    // windows allocator friendly! | |
|                 if ((rand() % 4) != 3 && _sizes[i] < j)   // really messes up windows allocator | |
|                 { | |
|                     _allocated[i] = _allocator.reallocate(_allocated[i], j); | |
|                     _check_buf(_allocated[i], _sizes[i]); | |
|                     _set_buf(_allocated[i], j); | |
|                     _sizes[i] = j; | |
|                 } | |
|             } | |
|         } | |
| #endif | |
|  | |
| #if 0 | |
|         // test erase (shrinking the buffers) | |
|         // --------------------------------------------- | |
|         for (uint32_t j=28; j>4; j -= 2) | |
|         { | |
|             for (size_t i=0; i<_num_alloc; ++i) | |
|             { | |
|                 // if ( _sizes[i] < j)                    // windows allocator friendly! | |
|                 if ((rand() % 4) != 3 && _sizes[i] > j)   // really messes up windows allocator | |
|                 { | |
|                     _allocated[i] = _allocator.reallocate(_allocated[i], j); | |
|                     _check_buf1(_allocated[i], _sizes[i]); | |
|                     _set_buf(_allocated[i], j); | |
|                     _sizes[i] = j; | |
|                 } | |
|             } | |
|         } | |
| #endif | |
|  | |
| #if 0 | |
|         // and grow the buffers back to a max size of 24 each | |
|         // -------------------------------------------------- | |
|         for (uint32_t j=4; j<26; j += 2) | |
|         { | |
|             for (size_t i=0; i<_num_alloc; ++i) | |
|             { | |
|                 // if ( _sizes[i] < j)                    // windows allocator friendly! | |
|                 if ((rand() % 4) != 3 && _sizes[i] < j)   // really messes up windows allocator | |
|                 { | |
|                     _allocated[i] = _allocator.reallocate(_allocated[i], j); | |
|                     _check_buf(_allocated[i], _sizes[i]); | |
|                     _set_buf(_allocated[i], j); | |
|                     _sizes[i] = j; | |
|                 } | |
|             } | |
|         } | |
| #endif | |
|  | |
|         size_t total_units = 0; | |
|         for (size_t i=0; i<_num_alloc; ++i) | |
|             total_units += _sizes[i]; | |
|          | |
|         uint64_t mem_usage          = spp::GetProcessMemoryUsed(); | |
|         uint64_t alloc_mem_usage    = mem_usage - _start_mem_usage; | |
|         uint64_t expected_mem_usage = total_units * sizeof(T); | |
| 
 | |
|         // finally free the memory | |
|         // ----------------------- | |
|         for (size_t i=0; i<_num_alloc; ++i) | |
|         { | |
|             _check_buf(_allocated[i], _sizes[i]); | |
|             _allocator.deallocate(_allocated[i], _sizes[i]); | |
|         } | |
| 
 | |
|         uint64_t mem_usage_end = spp::GetProcessMemoryUsed(); | |
| 
 | |
|         printf("allocated %zd entities of size %zd\n", total_units, sizeof(T)); | |
|         printf("done in %3.2f seconds, mem_usage %4.1f/%4.1f/%4.1f MB\n",  | |
|                timer.get_total() / 1000, _to_mb(_start_mem_usage),  _to_mb(mem_usage),  _to_mb(mem_usage_end)); | |
|         printf("expected mem usage: %4.1f\n", _to_mb(expected_mem_usage)); | |
|         if (expected_mem_usage <= alloc_mem_usage) | |
|             printf("overhead: %4.1f%%\n",  | |
|                    (float)((double)(alloc_mem_usage - expected_mem_usage) / expected_mem_usage) * 100); | |
|         else | |
|             printf("bug: alloc_mem_usage <= expected_mem_usage\n"); | |
|          | |
|         std::vector<T *>().swap(_allocated); | |
|         std::vector<uint32_t>().swap(_sizes); | |
| 
 | |
|         printf("\nmem usage after freeing vectors: %4.1f\n", _to_mb(spp::GetProcessMemoryUsed())); | |
|     } | |
| 
 | |
| private: | |
| 
 | |
|     void _set_buf(T *buff, uint32_t sz) { *buff = (T)sz; buff[sz - 1] = (T)sz; } | |
|     void _check_buf1(T *buff, uint32_t sz)  | |
|     {  | |
|         assert(*buff == (T)sz);  | |
|         (void)(buff + sz); // silence warning | |
|     } | |
|     void _check_buf(T *buff, uint32_t sz)  | |
|     {  | |
|         assert(*buff == (T)sz &&  buff[sz - 1] == (T)sz);  | |
|         (void)(buff + sz); // silence warning | |
|     } | |
| 
 | |
|     size_t                _num_alloc; | |
|     uint64_t              _start_mem_usage; | |
|     std::vector<T *>      _allocated; | |
|     std::vector<uint32_t> _sizes; | |
|     A                     _allocator; | |
| }; | |
| 
 | |
| // ----------------------------------------------------------- | |
| // ----------------------------------------------------------- | |
| template <class X, class A> | |
| void run_test(const char *alloc_name) | |
| { | |
|     printf("\n---------------- testing %s\n\n", alloc_name); | |
| 
 | |
|     printf("\nmem usage before the alloc test: %4.1f\n",  | |
|            _to_mb(spp::GetProcessMemoryUsed())); | |
|     { | |
|         TestAlloc< X, A >  test_alloc; | |
|         test_alloc.run(); | |
|     } | |
|     printf("mem usage after the alloc test: %4.1f\n", | |
|            _to_mb(spp::GetProcessMemoryUsed())); | |
| 
 | |
|     printf("\n\n"); | |
| } | |
| 
 | |
| // ----------------------------------------------------------- | |
| // ----------------------------------------------------------- | |
| int main() | |
| { | |
|     typedef uint64_t X; | |
| 
 | |
|     run_test<X, spp::libc_allocator<X>>("libc_allocator"); | |
|     run_test<X, spp::spp_allocator<X>>("spp_allocator"); | |
| }
 |