@@ -9,7 +9,9 @@ terms of the MIT license. A copy of the license can be found in the file
99#include "mimalloc/atomic.h"
1010#include "mimalloc/prim.h"
1111
12- #define os_stats (&_mi_stats_main)
12+ #define mi_os_stat_increase (stat ,amount ) _mi_stat_increase(&_mi_stats_main.stat, amount)
13+ #define mi_os_stat_decrease (stat ,amount ) _mi_stat_decrease(&_mi_stats_main.stat, amount)
14+ #define mi_os_stat_counter_increase (stat ,inc ) _mi_stat_counter_increase(&_mi_stats_main.stat, inc)
1315
1416/* -----------------------------------------------------------
1517 Initialization.
@@ -157,42 +159,50 @@ void* _mi_os_get_aligned_hint(size_t try_alignment, size_t size) {
157159}
158160#endif
159161
160-
161162/* -----------------------------------------------------------
162163 Free memory
163164-------------------------------------------------------------- */
164165
165166static void mi_os_free_huge_os_pages (void * p , size_t size );
166167
167- static void mi_os_prim_free (void * addr , size_t size , bool still_committed ) {
168+ static void mi_os_prim_free (void * addr , size_t size , size_t commit_size ) {
168169 mi_assert_internal ((size % _mi_os_page_size ()) == 0 );
169170 if (addr == NULL || size == 0 ) return ; // || _mi_os_is_huge_reserved(addr)
170171 int err = _mi_prim_free (addr , size );
171172 if (err != 0 ) {
172173 _mi_warning_message ("unable to free OS memory (error: %d (0x%x), size: 0x%zx bytes, address: %p)\n" , err , err , size , addr );
173174 }
174- if (still_committed ) { _mi_stat_decrease (& os_stats -> committed , size ); }
175- _mi_stat_decrease (& os_stats -> reserved , size );
175+ if (commit_size > 0 ) {
176+ mi_os_stat_decrease (committed , commit_size );
177+ }
178+ mi_os_stat_decrease (reserved , size );
176179}
177180
178181void _mi_os_free_ex (void * addr , size_t size , bool still_committed , mi_memid_t memid ) {
179182 if (mi_memkind_is_os (memid .memkind )) {
180- size_t csize = _mi_os_good_alloc_size (size );
183+ size_t csize = memid .mem .os .size ;
184+ if (csize == 0 ) { _mi_os_good_alloc_size (size ); }
185+ size_t commit_size = (still_committed ? csize : 0 );
181186 void * base = addr ;
182187 // different base? (due to alignment)
183- if (memid .mem .os .base != NULL ) {
184- mi_assert (memid .mem .os .base <= addr );
185- mi_assert ((uint8_t * )memid .mem .os .base + memid .mem .os .alignment >= (uint8_t * )addr );
188+ if (memid .mem .os .base != base ) {
189+ mi_assert (memid .mem .os .base <= addr );
186190 base = memid .mem .os .base ;
187- csize += ((uint8_t * )addr - (uint8_t * )memid .mem .os .base );
191+ const size_t diff = (uint8_t * )addr - (uint8_t * )memid .mem .os .base ;
192+ if (memid .mem .os .size == 0 ) {
193+ csize += diff ;
194+ }
195+ if (still_committed ) {
196+ commit_size -= diff ; // the (addr-base) part was already un-committed
197+ }
188198 }
189199 // free it
190200 if (memid .memkind == MI_MEM_OS_HUGE ) {
191201 mi_assert (memid .is_pinned );
192202 mi_os_free_huge_os_pages (base , csize );
193203 }
194204 else {
195- mi_os_prim_free (base , csize , still_committed );
205+ mi_os_prim_free (base , csize , ( still_committed ? commit_size : 0 ) );
196206 }
197207 }
198208 else {
@@ -228,11 +238,11 @@ static void* mi_os_prim_alloc_at(void* hint_addr, size_t size, size_t try_alignm
228238
229239
230240
231- mi_stat_counter_increase ( os_stats -> mmap_calls , 1 );
241+ mi_os_stat_counter_increase ( mmap_calls , 1 );
232242 if (p != NULL ) {
233- _mi_stat_increase ( & os_stats -> reserved , size );
243+ mi_os_stat_increase ( reserved , size );
234244 if (commit ) {
235- _mi_stat_increase ( & os_stats -> committed , size );
245+ mi_os_stat_increase ( committed , size );
236246 // seems needed for asan (or `mimalloc-test-api` fails)
237247 #ifdef MI_TRACK_ASAN
238248 if (* is_zero ) { mi_track_mem_defined (p ,size ); }
@@ -273,7 +283,7 @@ static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit
273283 #if !MI_TRACK_ASAN
274284 _mi_warning_message ("unable to allocate aligned OS memory directly, fall back to over-allocation (size: 0x%zx bytes, address: %p, alignment: 0x%zx, commit: %d)\n" , size , p , alignment , commit );
275285 #endif
276- mi_os_prim_free (p , size , commit );
286+ if ( p != NULL ) { mi_os_prim_free (p , size , ( commit ? size : 0 )); }
277287 if (size >= (SIZE_MAX - alignment )) return NULL ; // overflow
278288 const size_t over_size = size + alignment ;
279289
@@ -304,8 +314,8 @@ static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit
304314 size_t mid_size = _mi_align_up (size , _mi_os_page_size ());
305315 size_t post_size = over_size - pre_size - mid_size ;
306316 mi_assert_internal (pre_size < over_size && post_size < over_size && mid_size >= size );
307- if (pre_size > 0 ) { mi_os_prim_free (p , pre_size , commit ); }
308- if (post_size > 0 ) { mi_os_prim_free ((uint8_t * )aligned_p + mid_size , post_size , commit ); }
317+ if (pre_size > 0 ) { mi_os_prim_free (p , pre_size , ( commit ? pre_size : 0 ) ); }
318+ if (post_size > 0 ) { mi_os_prim_free ((uint8_t * )aligned_p + mid_size , post_size , ( commit ? post_size : 0 ) ); }
309319 // we can return the aligned pointer on `mmap` systems
310320 p = aligned_p ;
311321 * base = aligned_p ; // since we freed the pre part, `*base == p`.
@@ -349,7 +359,8 @@ void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool allo
349359 if (p != NULL ) {
350360 * memid = _mi_memid_create_os (commit , os_is_zero , os_is_large );
351361 memid -> mem .os .base = os_base ;
352- memid -> mem .os .alignment = alignment ;
362+ // memid->mem.os.alignment = alignment;
363+ memid -> mem .os .size += ((uint8_t * )p - (uint8_t * )os_base ); // todo: return from prim_alloc_aligned
353364 }
354365 return p ;
355366}
@@ -417,10 +428,10 @@ static void* mi_os_page_align_area_conservative(void* addr, size_t size, size_t*
417428 return mi_os_page_align_areax (true, addr , size , newsize );
418429}
419430
420- bool _mi_os_commit (void * addr , size_t size , bool * is_zero ) {
431+ bool _mi_os_commit_ex (void * addr , size_t size , bool * is_zero , size_t stat_size ) {
421432 if (is_zero != NULL ) { * is_zero = false; }
422- _mi_stat_increase ( & os_stats -> committed , size ); // use size for precise commit vs. decommit
423- _mi_stat_counter_increase ( & os_stats -> commit_calls , 1 );
433+ mi_os_stat_increase ( committed , stat_size ); // use size for precise commit vs. decommit
434+ mi_os_stat_counter_increase ( commit_calls , 1 );
424435
425436 // page align range
426437 size_t csize ;
@@ -446,8 +457,13 @@ bool _mi_os_commit(void* addr, size_t size, bool* is_zero) {
446457 return true;
447458}
448459
449- static bool mi_os_decommit_ex (void * addr , size_t size , bool * needs_recommit ) { mi_assert_internal (needs_recommit != NULL );
450- _mi_stat_decrease (& os_stats -> committed , size );
460+ bool _mi_os_commit (void * addr , size_t size , bool * is_zero ) {
461+ return _mi_os_commit_ex (addr , size , is_zero , size );
462+ }
463+
464+ static bool mi_os_decommit_ex (void * addr , size_t size , bool * needs_recommit , size_t stat_size ) {
465+ mi_assert_internal (needs_recommit != NULL );
466+ mi_os_stat_decrease (committed , stat_size );
451467
452468 // page align
453469 size_t csize ;
@@ -466,7 +482,7 @@ static bool mi_os_decommit_ex(void* addr, size_t size, bool* needs_recommit) {
466482
467483bool _mi_os_decommit (void * addr , size_t size ) {
468484 bool needs_recommit ;
469- return mi_os_decommit_ex (addr , size , & needs_recommit );
485+ return mi_os_decommit_ex (addr , size , & needs_recommit , size );
470486}
471487
472488
@@ -479,8 +495,8 @@ bool _mi_os_reset(void* addr, size_t size) {
479495 size_t csize ;
480496 void * start = mi_os_page_align_area_conservative (addr , size , & csize );
481497 if (csize == 0 ) return true; // || _mi_os_is_huge_reserved(addr)
482- _mi_stat_increase ( & os_stats -> reset , csize );
483- _mi_stat_counter_increase ( & os_stats -> reset_calls , 1 );
498+ mi_os_stat_increase ( reset , csize );
499+ mi_os_stat_counter_increase ( reset_calls , 1 );
484500
485501 #if (MI_DEBUG > 1 ) && !MI_SECURE && !MI_TRACK_ENABLED // && !MI_TSAN
486502 memset (start , 0 , csize ); // pretend it is eagerly reset
@@ -496,17 +512,17 @@ bool _mi_os_reset(void* addr, size_t size) {
496512
497513// either resets or decommits memory, returns true if the memory needs
498514// to be recommitted if it is to be re-used later on.
499- bool _mi_os_purge_ex (void * p , size_t size , bool allow_reset )
515+ bool _mi_os_purge_ex (void * p , size_t size , bool allow_reset , size_t stat_size )
500516{
501517 if (mi_option_get (mi_option_purge_delay ) < 0 ) return false; // is purging allowed?
502- _mi_stat_counter_increase ( & os_stats -> purge_calls , 1 );
503- _mi_stat_increase ( & os_stats -> purged , size );
518+ mi_os_stat_counter_increase ( purge_calls , 1 );
519+ mi_os_stat_increase ( purged , size );
504520
505521 if (mi_option_is_enabled (mi_option_purge_decommits ) && // should decommit?
506522 !_mi_preloading ()) // don't decommit during preloading (unsafe)
507523 {
508524 bool needs_recommit = true;
509- mi_os_decommit_ex (p , size , & needs_recommit );
525+ mi_os_decommit_ex (p , size , & needs_recommit , stat_size );
510526 return needs_recommit ;
511527 }
512528 else {
@@ -520,7 +536,7 @@ bool _mi_os_purge_ex(void* p, size_t size, bool allow_reset)
520536// either resets or decommits memory, returns true if the memory needs
521537// to be recommitted if it is to be re-used later on.
522538bool _mi_os_purge (void * p , size_t size ) {
523- return _mi_os_purge_ex (p , size , true);
539+ return _mi_os_purge_ex (p , size , true, size );
524540}
525541
526542
@@ -628,15 +644,15 @@ void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_mse
628644 // no success, issue a warning and break
629645 if (p != NULL ) {
630646 _mi_warning_message ("could not allocate contiguous huge OS page %zu at %p\n" , page , addr );
631- mi_os_prim_free (p , MI_HUGE_OS_PAGE_SIZE , true );
647+ mi_os_prim_free (p , MI_HUGE_OS_PAGE_SIZE , MI_HUGE_OS_PAGE_SIZE );
632648 }
633649 break ;
634650 }
635651
636652 // success, record it
637653 page ++ ; // increase before timeout check (see issue #711)
638- _mi_stat_increase ( & os_stats -> committed , MI_HUGE_OS_PAGE_SIZE );
639- _mi_stat_increase ( & os_stats -> reserved , MI_HUGE_OS_PAGE_SIZE );
654+ mi_os_stat_increase ( committed , MI_HUGE_OS_PAGE_SIZE );
655+ mi_os_stat_increase ( reserved , MI_HUGE_OS_PAGE_SIZE );
640656
641657 // check for timeout
642658 if (max_msecs > 0 ) {
@@ -674,7 +690,7 @@ static void mi_os_free_huge_os_pages(void* p, size_t size) {
674690 if (p == NULL || size == 0 ) return ;
675691 uint8_t * base = (uint8_t * )p ;
676692 while (size >= MI_HUGE_OS_PAGE_SIZE ) {
677- mi_os_prim_free (base , MI_HUGE_OS_PAGE_SIZE , true );
693+ mi_os_prim_free (base , MI_HUGE_OS_PAGE_SIZE , MI_HUGE_OS_PAGE_SIZE );
678694 size -= MI_HUGE_OS_PAGE_SIZE ;
679695 base += MI_HUGE_OS_PAGE_SIZE ;
680696 }
0 commit comments