From d1f708af595cf0a99b8bb5f8b16a3cfd29e34bce Mon Sep 17 00:00:00 2001 From: daan Date: Fri, 26 Jul 2019 13:01:43 -0700 Subject: [PATCH 01/92] add MIMALLOC_OVERRIDE setting to disable redirection at runtime --- bin/mimalloc-redirect.dll | Bin 34816 -> 35840 bytes test/main-override.cpp | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/mimalloc-redirect.dll b/bin/mimalloc-redirect.dll index d3427e9548492d44174d12a5c8144fd62b5d2bfe..14ed46ec2c3aebed56614e50a464803f4644b397 100644 GIT binary patch delta 2663 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 ZR)mfiRtM`F8VVuuw`FlEn>ODx`~zw1Jd*$b diff --git a/test/main-override.cpp b/test/main-override.cpp index 6c7fc0d5..58d06c6a 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -30,12 +30,12 @@ int main() { free(p1); p1 = malloc(8); char* s = mi_strdup("hello\n"); - free(p2); + mi_free(p2); p2 = malloc(16); p1 = realloc(p1, 32); free(p1); free(p2); - free(s); + mi_free(s); Test* t = new Test(42); delete t; t = new (std::nothrow) Test(42); From 3d9d70bce09c7fdae64eee070ab87e493722de52 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 10 Aug 2019 09:39:36 -0700 Subject: [PATCH 02/92] add new redirection module; fix environment reading at preloading --- bin/mimalloc-redirect.dll | Bin 35840 -> 46080 bytes bin/mimalloc-redirect.lib | Bin 3050 -> 3050 bytes bin/mimalloc-redirect32.dll | Bin 0 -> 28672 bytes bin/mimalloc-redirect32.lib | Bin 0 -> 3126 bytes ide/vs2017/mimalloc-override-test.vcxproj | 12 ++++-- ide/vs2017/mimalloc-override.vcxproj | 29 +++++++++------ ide/vs2017/mimalloc-override.vcxproj.filters | 3 -- src/init.c | 6 +-- src/options.c | 37 +++++++++++++++---- test/main-override.cpp | 5 ++- 10 files changed, 61 insertions(+), 31 deletions(-) create mode 100644 bin/mimalloc-redirect32.dll create mode 100644 bin/mimalloc-redirect32.lib diff --git a/bin/mimalloc-redirect.dll b/bin/mimalloc-redirect.dll index 14ed46ec2c3aebed56614e50a464803f4644b397..aaecc653b849bea38fcace1c2b12a0842d41fc28 100644 GIT binary patch delta 6299 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 Ezi8}CX#fBK delta 5219 zcmbtYeQ;CPmA~)V0?A1B^M`EN2KxzQ5H<$I5Y`D!5y54ZtqBUa#ZAZ{0>$E^jY!Pm z5`vTxx~2|0hLf^P!er%d;ZG4|Q#Z|a+l?1;WGg zQMWxRW1gi??AX?_4KoE?xixhWM!xZst3YD)I)B2oLI(EUwWupEQZa3Lo0nx zE;nEW+GL066s#yL-uDCgxm=R{BwzCcgb!S6&JV=kIzGnyJbnoC7! zYD>_Zx1#w&Hkx}lXVanCprZL)Li0`D_z-#O3*Hpwp&7TJIh28>zZlIEe2zzFqe*b> z13uAV?s88i?|ucVnetTULhb~LW`Mw`pk-e7Ykdg;qq_miVcp=hQO@yvEg^rFrTqZDHcq^)#Czf5wG*`P|_ zjjS{bNOZWO2Hn}D&iPcjMT*fc{RedzS7({90j~B~LZ_$yHdYxXv2<=ukjb3xqHEnu*Lk{}U7epT_*u8{Yjg#c^KZ{Qu49ch#dWN~re7XCPrp_cP|}!{3mqQQ zG*o&~KVR8!6UWB07Ng0OyHI}MCgm2CQXqGMd{0_U=H|<1)2fj(Hi_VmPET^t$Wgk>)<$){oKk9wbMzUDl^3_V(XRV~5 zwSkgWM@bvz;^*sg9jTL0eKBtD!ZO?F-uWedJIguxBB<#C!qGc2pDuH4NA+lBfnpeU zuoffM=ScC|aa{f1v{N(B7O#uK{k(}^e2^|57cU<+EAKSakD*yZgX&`%cJZHsMBC!i)Szc1e1{bp25bcVn5J}I`s z6|=rfrLHbTPw!06%NTJqy1y7?P>@ZDjUf3o83AIO)=|(_E;%S_b4Yf&W~-1gsi`T>2qw-&aq`FKSM_wc@`JSw{UqbUM98Cn#E;kId$qLwJttsxs*N#7bhma2GOYfowIX{~)hYtLxyOIjN|6zMD&l_KuyhMdSt zbvq?eGE6l)n$kbk_?!MXr2ZkuDkylS`;5@>>xI37zE@U7##d)c=8c=`H`V^^KiB{G z_jf%w{Q5VR{r=q>U(1Mmd-W$0J-Viq{sm5=cT@W242l681NytI;9fAB9(hvC=c7IyDm6A-Sw?SlA?{ZY)j8(*SN68IRxj_xPZpF z1?SbcxW=^#u0!LTbn%hRQjpF)ybQ6S8zx16QtS6|jsja8@Zr6+kELgBqJ57plHwZY z6I_SJskCqFW<1_X8p3<@tdk7Wo6c8nf+!cR&| zE?wJyAXjZp&*u?NjP13moMJNB+XV81op;UV2`$c5T@R~h> z2?z{wBq`%bQ%o>%!8}Fk(+WyL@*l``?@Gt<3iNT7l7|&3to6qP9~a2zV&H&5-JKqV z7d7C|^$05<5HDrmfH@|tgg|9adOcs9bQ!4gXt{p<1MAl`G;CN)tw+^J^r&4QiJnn1 z{7!t@{SdNb6F!82Mfjkb3q1;~%xBC9-3>esxw(uqAN)hf@$S2?fz}Fyk;3t5E7UpL*7;b!8o`S4^9tOSxsfQj1&c+9419S!W z50FOaPT*e17U%&W|7P6*Jq(*=fvx~+Acvqkfsa9+h3+fyGxl#Vo`Vqt zz72UEdK{Qr%Gep`DzE|41Kk5W0U6@{z>APqpgZR>wiEIObRX~x4P-QfN}(;^%P_Xl2r)IsO}b{U7%Lsu7Ln;~1E2Z4WvJO^E=L=4FDjchCPK>2nR zwv0Og&n>~0LTA;C{RZ*|AF!0M4}m4%dV0ORt-bNyM6b8c*O%uu=$>F$`$n{~*h*wJ{Fp?Naj(B-S`cdC#>*#f!Q2@0AU_pH_ z5NtzE`c9?O(%I2@8aY|I)UIGx2pQSC9o@Cv;qI~S+8$?*t0&qMLr$(72s0|N+ieS+c&AYCyrr)P2&BhTbGM#ah6%>0ve7}X~8Fmg;{l${*R rB{+Ek<25?D0|OX;0@6Utodd!Xb9yF6F{)11X6B#V#VkD8ol$tQ9wXbtf9jKi qxdbOqV4TNQ!NtJv35avJCtEPd@v|_nGO#glFt9U#S({UtS~&p$7#4*9 diff --git a/bin/mimalloc-redirect32.dll b/bin/mimalloc-redirect32.dll new file mode 100644 index 0000000000000000000000000000000000000000..89b9625d107ccc203d64447d44852fd3fe1be166 GIT binary patch literal 28672 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 literal 0 HcmV?d00001 diff --git a/bin/mimalloc-redirect32.lib b/bin/mimalloc-redirect32.lib new file mode 100644 index 0000000000000000000000000000000000000000..aed3b67fb2fb832cd97d8f35a76ae692ef7ede33 GIT binary patch literal 3126 zcmcgu-A)rh6#lj?AdAsPP4q@nBSww#*FP~aq$m&x%TG$VUP`yhnr%y#^};J(z$>1B zS1{pFmqi zv}ojWMbX;U0o(>sOTh3UFmeWr9f>?kHD&!+Twh?}RHqC&CkeFoF19teZgxw%!Z<(hWW_PBPpNTF-Bn*Pe6t}j|} zoW-W+el5)~$8po6qJhslAD;Ip9r#iTI2;DfMu4L+V3zVRF=3AKDJd9~i4+)xh6I&2 zFoIzWAr)yQVMe!fX&NZZ3=h5AKMG&^eh&r$n)IGkFyu2xI`}+pb>ow6C<;zISUAA! zU9*!&Q4aSN2UA@~e^I1o^D_3gbw!*_T8@J$c`XRli`FdU<@K_y8(I==N>4NpH+a$} zt@_TFPve_@7g(jnci9nj3F&u}wpI12<5@X$j~c%y{}qBH)g?@y2)&{Z;{i3s2v6!U zc?p@51l5m-tt{P-G4>hmrit`mYqN9)IL9&)Gku4aGi=gL*JG9rd6en|}zvCxY68=fq|~I*rkl#bz``Vlyx0 zOz*esi2B+*-H&%)&?fpK>!6-4ybf;E$ V@~rqqZTSpg52>;JKXKd!^naKH*GK>W literal 0 HcmV?d00001 diff --git a/ide/vs2017/mimalloc-override-test.vcxproj b/ide/vs2017/mimalloc-override-test.vcxproj index 7df1e79a..b8e2648b 100644 --- a/ide/vs2017/mimalloc-override-test.vcxproj +++ b/ide/vs2017/mimalloc-override-test.vcxproj @@ -100,7 +100,8 @@ - COPY /Y $(SolutionDir)..\..\bin\mimalloc-redirect32.dll $(OutputPath) + + @@ -123,7 +124,8 @@ - COPY /Y $(SolutionDir)..\..\bin\mimalloc-redirect.dll $(OutputPath) + + @@ -145,7 +147,8 @@ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - COPY /Y $(SolutionDir)..\..\bin\mimalloc-redirect32.dll $(OutputPath) + + @@ -169,7 +172,8 @@ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - COPY /Y $(SolutionDir)..\..\bin\mimalloc-redirect.dll $(OutputPath) + + diff --git a/ide/vs2017/mimalloc-override.vcxproj b/ide/vs2017/mimalloc-override.vcxproj index 7d452b55..6847e388 100644 --- a/ide/vs2017/mimalloc-override.vcxproj +++ b/ide/vs2017/mimalloc-override.vcxproj @@ -101,15 +101,20 @@ Default - %(AdditionalDependencies) + $(ProjectDir)\..\..\bin\mimalloc-redirect32.lib;%(AdditionalDependencies) Default - DllEntry false + + COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect32.dll $(OutputPath) + + + Copy mimalloc-redirect32.dll to the output directory + @@ -124,17 +129,16 @@ Default - %(AdditionalDependencies) + $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) Default - DllEntry false - COPY /Y $(SolutionDir)..\..\bin\mimalloc-redirect.dll $(OutputPath) + COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect.dll $(OutputPath) copy mimalloc-redirect.dll to the output directory @@ -159,13 +163,18 @@ true true - %(AdditionalDependencies) + $(ProjectDir)\..\..\bin\mimalloc-redirect32.lib;%(AdditionalDependencies) Default - DllEntry false + + COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect32.dll $(OutputPath) + + + Copy mimalloc-redirect32.dll to the output directory + @@ -186,15 +195,14 @@ true true - %(AdditionalDependencies) + $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) Default - DllEntry false - COPY /Y $(SolutionDir)..\..\bin\mimalloc-redirect.dll $(OutputPath) + COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect.dll $(OutputPath) copy mimalloc-redirect.dll to the output directory @@ -214,7 +222,6 @@ false false - true true diff --git a/ide/vs2017/mimalloc-override.vcxproj.filters b/ide/vs2017/mimalloc-override.vcxproj.filters index df0bf5ed..ffabddac 100644 --- a/ide/vs2017/mimalloc-override.vcxproj.filters +++ b/ide/vs2017/mimalloc-override.vcxproj.filters @@ -67,8 +67,5 @@ Source Files - - Source Files - \ No newline at end of file diff --git a/src/init.c b/src/init.c index f807d74a..7215e4fb 100644 --- a/src/init.c +++ b/src/init.c @@ -388,7 +388,7 @@ bool _mi_preloading() { } // Communicate with the redirection module on Windows -#if 0 +#if defined(_WIN32) && defined(MI_SHARED_LIB) #ifdef __cplusplus extern "C" { #endif @@ -475,9 +475,7 @@ static void mi_process_done(void) { #if defined(_WIN32) && defined(MI_SHARED_LIB) - // Windows DLL: easy to hook into process_init and thread_done - #include - + // Windows DLL: easy to hook into process_init and thread_done __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) { UNUSED(reserved); UNUSED(inst); diff --git a/src/options.c b/src/options.c index 01620e75..9f045905 100644 --- a/src/options.c +++ b/src/options.c @@ -208,8 +208,25 @@ static void mi_strlcat(char* dest, const char* src, size_t dest_size) { dest[dest_size - 1] = 0; } -static const char* mi_getenv(const char* name) { - if (_mi_preloading()) return NULL; // don't call getenv too early +#if defined _WIN32 +#include +static bool mi_getenv(const char* name, char* result, size_t result_size) { + result[0] = 0; + bool ok = (GetEnvironmentVariableA(name, result, (DWORD)result_size) > 0); + if (!ok) { + char buf[64+1]; + size_t len = strlen(name); + if (len >= sizeof(buf)) len = sizeof(buf) - 1; + for (size_t i = 0; i < len; i++) { + buf[i] = toupper(name[i]); + } + buf[len] = 0; + ok = (GetEnvironmentVariableA(name, result, (DWORD)result_size) > 0); + } + return ok; +} +#else +static bool mi_getenv(const char* name, char* result, size_t result_size) { #pragma warning(suppress:4996) const char* s = getenv(name); if (s == NULL) { @@ -223,17 +240,23 @@ static const char* mi_getenv(const char* name) { #pragma warning(suppress:4996) s = getenv(buf); } - return s; + if (s != NULL && strlen(s) < result_size) { + mi_strlcpy(result,s,result_size); + return true; + } + else { + return false; + } } - +#endif static void mi_option_init(mi_option_desc_t* desc) { - if (!_mi_preloading()) desc->init = DEFAULTED; + desc->init = DEFAULTED; // Read option value from the environment char buf[64+1]; mi_strlcpy(buf, "mimalloc_", sizeof(buf)); mi_strlcat(buf, desc->name, sizeof(buf)); - const char* s = mi_getenv(buf); - if (s != NULL) { + char s[64+1]; + if (mi_getenv(buf, s, sizeof(s))) { size_t len = strlen(s); if (len >= sizeof(buf)) len = sizeof(buf) - 1; for (size_t i = 0; i < len; i++) { diff --git a/test/main-override.cpp b/test/main-override.cpp index 58d06c6a..385778c7 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -23,11 +23,11 @@ public: int main() { - mi_stats_reset(); // ignore earlier allocations + //mi_stats_reset(); // ignore earlier allocations atexit(free_p); void* p1 = malloc(78); void* p2 = mi_malloc_aligned(16,24); - free(p1); + free(p1); p1 = malloc(8); char* s = mi_strdup("hello\n"); mi_free(p2); @@ -40,6 +40,7 @@ int main() { delete t; t = new (std::nothrow) Test(42); delete t; + mi_stats_print(NULL); return 0; } From f35c2c5201ff762effd9d37e3858ac552c9a2983 Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 11 Aug 2019 16:38:58 -0700 Subject: [PATCH 03/92] improve message printing from redirection module --- include/mimalloc-internal.h | 1 + src/init.c | 4 +++- src/options.c | 35 ++++++++++++++++++++++------------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 151cd001..42720386 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -22,6 +22,7 @@ terms of the MIT license. A copy of the license can be found in the file // "options.c" +void _mi_fputs(FILE* out, const char* prefix, const char* message); void _mi_fprintf(FILE* out, const char* fmt, ...); void _mi_error_message(const char* fmt, ...); void _mi_warning_message(const char* fmt, ...); diff --git a/src/init.c b/src/init.c index b8bc2221..d66c875f 100644 --- a/src/init.c +++ b/src/init.c @@ -421,7 +421,9 @@ static void mi_process_load(void) { // show message from the redirector (if present) const char* msg = NULL; mi_allocator_init(&msg); - if (msg != NULL) _mi_verbose_message(msg); + if (msg != NULL && (mi_option_is_enabled(mi_option_verbose) || mi_option_is_enabled(mi_option_show_errors))) { + _mi_fputs(stderr,NULL,msg); + } } // Initialize the process; called by thread_init or the process loader diff --git a/src/options.c b/src/options.c index cd7e5da1..7e6e1a06 100644 --- a/src/options.c +++ b/src/options.c @@ -115,32 +115,41 @@ static uintptr_t error_count = 0; // when MAX_ERROR_COUNT stop emitting errors // inside the C runtime causes another message. static mi_decl_thread bool recurse = false; -// Define our own limited `fprintf` that avoids memory allocation. -// We do this using `snprintf` with a limited buffer. -static void mi_vfprintf( FILE* out, const char* prefix, const char* fmt, va_list args ) { - char buf[256]; - if (fmt==NULL) return; + +void _mi_fputs(FILE* out, const char* prefix, const char* message) { + if (out==NULL) out = stdout; if (_mi_preloading() || recurse) return; recurse = true; - if (out==NULL) out = stdout; - vsnprintf(buf,sizeof(buf)-1,fmt,args); #ifdef _WIN32 // on windows with redirection, the C runtime cannot handle locale dependent output // after the main thread closes so use direct console output. if (out==stderr) { if (prefix != NULL) _cputs(prefix); - _cputs(buf); + _cputs(message); } - else - #endif - { - if (prefix != NULL) fputs(prefix,out); - fputs(buf,out); + else + #endif + { + if (prefix != NULL) fputs(prefix, out); + fputs(message, out); } recurse = false; return; } +// Define our own limited `fprintf` that avoids memory allocation. +// We do this using `snprintf` with a limited buffer. +static void mi_vfprintf( FILE* out, const char* prefix, const char* fmt, va_list args ) { + char buf[512]; + if (fmt==NULL) return; + if (_mi_preloading() || recurse) return; + recurse = true; + vsnprintf(buf,sizeof(buf)-1,fmt,args); + recurse = false; + _mi_fputs(out,prefix,buf); +} + + void _mi_fprintf( FILE* out, const char* fmt, ... ) { va_list args; va_start(args,fmt); From 0061e883602737a2768d3eba542f03e6300b8532 Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 11 Aug 2019 16:45:20 -0700 Subject: [PATCH 04/92] updated redirection module --- bin/mimalloc-redirect.dll | Bin 46080 -> 46080 bytes bin/mimalloc-redirect32.dll | Bin 28672 -> 30720 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/mimalloc-redirect.dll b/bin/mimalloc-redirect.dll index aaecc653b849bea38fcace1c2b12a0842d41fc28..db15bfc1d5f0edee462ff81ee4295caf2c875364 100644 GIT binary patch delta 8046 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 bdWV8T14E&qj$!|B*KlCCH@xfER`I_9NV^U4 delta 5469 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 RT>IAdI(oPCV$Plu{{s*R!pHys diff --git a/bin/mimalloc-redirect32.dll b/bin/mimalloc-redirect32.dll index 89b9625d107ccc203d64447d44852fd3fe1be166..0639152572a437cc6a1a13dc5a14aca1055b0d45 100644 GIT binary patch delta 5834 zcma)A3s6*7nm*k$&_V+jX%H2mQScq@Cy#zf44pAsc5OFfZ=4J&L{LOj3c6jANWf_y z4XqiRLu#CfnZg;%Wu}~2Bb4hzW3`V#GGir}vNk5mBus|NUP4bzyG2bprlI#c_x3fW zW@>A@>O1%R-+%u9{O3Qfd%Jr=)*X@cO{{hdy0($TZ-U5+(`A_)DFfjW$utg61{Y0} z70JfvYT1fhHz5UbPy>XlWX&!TVpW_f&QXO3se*zTSI`^swTc1MPZckwV=`sgbrUqq z6?3lup7?19sax09Q17iLBsm!hcpxc&nP$otWnQtMS_iBKs%V+KXx;#7%tUby6s4Mx>sj$O;+lGWDGI^iE3D1P0zzoL<~(&J=cFp?2*(en(&pqH^xAytBdW?^F_>eER!$ z95FN})ANFkm_H=zam0d7Ws)0(`ZRsK#D@ur~U4whtHcOWirM%HB~=jL}IVE=7JvzD(F zYg17~6wGBVdpr?ley|#y8$S5brwVxDu#Wqq^SV@7*PU_y4Q-DzJe`(x-4plUEbsAz zvo1TrEHBvaEJ~I*XViZ~*5ix@Ju~;dsPshJZ3&mr-oWkv(Q*OjoH&{_ zo@me!Npe8JG8E{AnhSa&NuFr0V=f@f*Yri?t%`;e1++CwQT90hZSv_=g5O@JG9Z|X zKK(akJwmDkWnwX4p7UrVd9UW5zK+K+MsaNJphs1MjJWvsA2C{WG(@-OZ5(MJ^%T3TfLifNQs2ma0&@fHOgQCHBZf@!RVmwz?%v~s?jwr6K|g*9wOeaTaQ!Ct@P zm|@Ad!j|6AP}Y&V;J!&>Tk_OZ5O9;^oaxQR6h6))o5G{-!pl$5K$ycvrQZ3N!nlk7 zPa#Of)XV?KwhKdgY`h&UMjW%6JB|noW5n@j&xm6V *LdfNt48Bn(d&$}3Gt|s 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 delta 4106 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 gp% Date: Sat, 24 Aug 2019 21:24:56 +0800 Subject: [PATCH 05/92] Link with -lrt for older glibc Quoted from Linux Programmer's Manual (2017-09-15): #include int clock_gettime(clockid_t clk_id, struct timespec *tp); Link with -lrt (only for glibc versions before 2.17). This patch adds additional checks for librt availability and append target_link_libraries accordingly. librt is absent on macOS. Fixed #139 --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index c9de8618..d44b3408 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,6 +108,10 @@ if(WIN32) list(APPEND mi_libraries psapi shell32 user32) else() list(APPEND mi_libraries pthread) + find_library(LIBRT rt) + if(LIBRT) + list(APPEND mi_libraries ${LIBRT}) + endif() endif() # ----------------------------------------------------------------------------- From eea093000a30b2e069b77f803217622e3901b0b9 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 26 Aug 2019 13:47:52 -0700 Subject: [PATCH 06/92] graceful fallback for huge page allocation on Linux --- src/os.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/os.c b/src/os.c index 5d1b7576..7648c010 100644 --- a/src/os.c +++ b/src/os.c @@ -369,6 +369,13 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro if (large_only || lflags != flags) { // try large OS page allocation p = mi_unix_mmapx(addr, size, try_alignment, protect_flags, lflags, lfd); + #ifdef MAP_HUGE_1GB + if (p == NULL && (lflags & MAP_HUGE_1GB) != 0) { + _mi_warning_message("unable to allocate huge (1GiB) page, trying large (2MiB) pages instead (error %i)\n", errno); + lflags = ((lflags & ~MAP_HUGE_1GB) | MAP_HUGE_2MB); + p = mi_unix_mmapx(addr, size, try_alignment, protect_flags, lflags, lfd); + } + #endif if (large_only) return p; if (p == NULL) { mi_atomic_write(&large_page_try_ok, 10); // on error, don't try again for the next N allocations From db8d443ae661870af5c0815b7cdb0e3bdcb0f13b Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 26 Aug 2019 22:45:26 -0700 Subject: [PATCH 07/92] track more precisely if memory is fixed or committed --- include/mimalloc-internal.h | 4 +- include/mimalloc-types.h | 11 +++- src/memory.c | 128 +++++++++++++++++++++--------------- src/options.c | 2 +- src/os.c | 98 +++++++++++++++++---------- src/segment.c | 55 ++++++++-------- 6 files changed, 176 insertions(+), 122 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 447df7df..9b3a3907 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -45,8 +45,8 @@ void* _mi_os_alloc(size_t size, mi_stats_t* stats); // to allocat void _mi_os_free(void* p, size_t size, mi_stats_t* stats); // to free thread local data // memory.c -void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool commit, size_t* id, mi_os_tld_t* tld); -void* _mi_mem_alloc(size_t size, bool commit, size_t* id, mi_os_tld_t* tld); +void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, size_t* id, mi_os_tld_t* tld); +void* _mi_mem_alloc(size_t size, bool commit, bool* large, size_t* id, mi_os_tld_t* tld); void _mi_mem_free(void* p, size_t size, size_t id, mi_stats_t* stats); bool _mi_mem_reset(void* p, size_t size, mi_stats_t* stats); diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index 0b2334b8..4bf51d1d 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -167,7 +167,7 @@ typedef struct mi_page_s { bool is_committed:1; // `true` if the page virtual memory is committed // layout like this to optimize access in `mi_malloc` and `mi_free` - uint16_t capacity; // number of blocks committed + uint16_t capacity; // number of blocks committed, must be the first field, see `segment.c:page_clear` uint16_t reserved; // number of blocks reserved in memory mi_page_flags_t flags; // `in_full` and `has_aligned` flags (16 bits) @@ -207,7 +207,13 @@ typedef enum mi_page_kind_e { // the OS. Inside segments we allocated fixed size _pages_ that // contain blocks. typedef struct mi_segment_s { - struct mi_segment_s* next; + // memory fields + size_t memid; // id for the os-level memory manager + bool mem_is_fixed; // `true` if we cannot decommit/reset/protect in this memory (i.e. when allocated using large OS pages) + bool mem_is_committed; // `true` if the whole segment is eagerly committed + + // segment fields + struct mi_segment_s* next; // must be the first segment field -- see `segment.c:segment_alloc` struct mi_segment_s* prev; volatile _Atomic(struct mi_segment_s*) abandoned_next; size_t abandoned; // abandoned pages (i.e. the original owning thread stopped) (`abandoned <= used`) @@ -216,7 +222,6 @@ typedef struct mi_segment_s { size_t segment_size;// for huge pages this may be different from `MI_SEGMENT_SIZE` size_t segment_info_size; // space we are using from the first page for segment meta-data and possible guard pages. uintptr_t cookie; // verify addresses in debug mode: `mi_ptr_cookie(segment) == segment->cookie` - size_t memid; // id for the os-level memory manager // layout like this to optimize access in `mi_free` size_t page_shift; // `1 << page_shift` == the page sizes == `page->block_size * page->reserved` (unless the first page, then `-segment_info_size`). diff --git a/src/memory.c b/src/memory.c index 222b87c2..a9b87b8e 100644 --- a/src/memory.c +++ b/src/memory.c @@ -39,14 +39,14 @@ Possible issues: // Internal raw OS interface size_t _mi_os_large_page_size(); -bool _mi_os_protect(void* addr, size_t size); -bool _mi_os_unprotect(void* addr, size_t size); -bool _mi_os_commit(void* p, size_t size, mi_stats_t* stats); -bool _mi_os_decommit(void* p, size_t size, mi_stats_t* stats); -bool _mi_os_reset(void* p, size_t size, mi_stats_t* stats); -bool _mi_os_unreset(void* p, size_t size, mi_stats_t* stats); -void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, mi_os_tld_t* tld); - +bool _mi_os_protect(void* addr, size_t size); +bool _mi_os_unprotect(void* addr, size_t size); +bool _mi_os_commit(void* p, size_t size, mi_stats_t* stats); +bool _mi_os_decommit(void* p, size_t size, mi_stats_t* stats); +bool _mi_os_reset(void* p, size_t size, mi_stats_t* stats); +bool _mi_os_unreset(void* p, size_t size, mi_stats_t* stats); +void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, mi_os_tld_t* tld); +bool _mi_os_is_huge_reserved(void* p); // Constants #if (MI_INTPTR_SIZE==8) @@ -66,11 +66,24 @@ void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, mi_os_tld #define MI_REGION_MAP_FULL UINTPTR_MAX +typedef uintptr_t mi_region_info_t; + +static inline mi_region_info_t mi_region_info_create(void* start, bool is_large, bool is_committed) { + return ((uintptr_t)start | ((is_large?1:0) << 1) | (is_committed?1:0)); +} + +static inline void* mi_region_info_read(mi_region_info_t info, bool* is_large, bool* is_committed) { + if (is_large) *is_large = ((info&0x02) != 0); + if (is_committed) *is_committed = ((info&0x01) != 0); + return (void*)(info & ~0x03); +} + + // A region owns a chunk of REGION_SIZE (256MiB) (virtual) memory with // a bit map with one bit per MI_SEGMENT_SIZE (4MiB) block. typedef struct mem_region_s { - volatile _Atomic(uintptr_t) map; // in-use bit per MI_SEGMENT_SIZE block - volatile _Atomic(void*) start; // start of virtual memory area + volatile _Atomic(uintptr_t) map; // in-use bit per MI_SEGMENT_SIZE block + volatile _Atomic(mi_region_info_t) info; // start of virtual memory area, and flags } mem_region_t; @@ -108,7 +121,7 @@ bool mi_is_in_heap_region(const void* p) mi_attr_noexcept { if (p==NULL) return false; size_t count = mi_atomic_read_relaxed(®ions_count); for (size_t i = 0; i < count; i++) { - uint8_t* start = (uint8_t*)mi_atomic_read_ptr_relaxed(®ions[i].start); + uint8_t* start = (uint8_t*)mi_region_info_read( mi_atomic_read_relaxed(®ions[i].info), NULL, NULL); if (start != NULL && (uint8_t*)p >= start && (uint8_t*)p < start + MI_REGION_SIZE) return true; } return false; @@ -123,7 +136,7 @@ Commit from a region // Returns `false` on an error (OOM); `true` otherwise. `p` and `id` are only written // if the blocks were successfully claimed so ensure they are initialized to NULL/SIZE_MAX before the call. // (not being able to claim is not considered an error so check for `p != NULL` afterwards). -static bool mi_region_commit_blocks(mem_region_t* region, size_t idx, size_t bitidx, size_t blocks, size_t size, bool commit, void** p, size_t* id, mi_os_tld_t* tld) +static bool mi_region_commit_blocks(mem_region_t* region, size_t idx, size_t bitidx, size_t blocks, size_t size, bool commit, bool* large, void** p, size_t* id, mi_os_tld_t* tld) { size_t mask = mi_region_block_mask(blocks,bitidx); mi_assert_internal(mask != 0); @@ -131,10 +144,14 @@ static bool mi_region_commit_blocks(mem_region_t* region, size_t idx, size_t bit mi_assert_internal(®ions[idx] == region); // ensure the region is reserved - void* start = mi_atomic_read_ptr(®ion->start); - if (start == NULL) + mi_region_info_t info = mi_atomic_read(®ion->info); + if (info == 0) { - start = _mi_os_alloc_aligned(MI_REGION_SIZE, MI_SEGMENT_ALIGN, mi_option_is_enabled(mi_option_eager_region_commit), tld); + bool region_commit = mi_option_is_enabled(mi_option_eager_region_commit); + bool region_large = region_commit && *large; + void* start = _mi_os_alloc_aligned(MI_REGION_SIZE, MI_SEGMENT_ALIGN, region_commit, ®ion_large, tld); + *large = region_large; + if (start == NULL) { // failure to allocate from the OS! unclaim the blocks and fail size_t map; @@ -145,7 +162,8 @@ static bool mi_region_commit_blocks(mem_region_t* region, size_t idx, size_t bit } // set the newly allocated region - if (mi_atomic_cas_ptr_strong(®ion->start, start, NULL)) { + info = mi_region_info_create(start,region_large,region_commit); + if (mi_atomic_cas_strong(®ion->info, info, 0)) { // update the region count mi_atomic_increment(®ions_count); } @@ -154,12 +172,9 @@ static bool mi_region_commit_blocks(mem_region_t* region, size_t idx, size_t bit // we assign it to a later slot instead (up to 4 tries). // note: we don't need to increment the region count, this will happen on another allocation for(size_t i = 1; i <= 4 && idx + i < MI_REGION_MAX; i++) { - void* s = mi_atomic_read_ptr(®ions[idx+i].start); - if (s == NULL) { // quick test - if (mi_atomic_cas_ptr_strong(®ions[idx+i].start, start, NULL)) { - start = NULL; - break; - } + if (mi_atomic_cas_strong(®ions[idx+i].info, info, 0)) { + start = NULL; + break; } } if (start != NULL) { @@ -167,15 +182,17 @@ static bool mi_region_commit_blocks(mem_region_t* region, size_t idx, size_t bit _mi_os_free(start, MI_REGION_SIZE, tld->stats); } // and continue with the memory at our index - start = mi_atomic_read_ptr(®ion->start); + info = mi_atomic_read(®ion->info); } } - mi_assert_internal(start == mi_atomic_read_ptr(®ion->start)); - mi_assert_internal(start != NULL); + mi_assert_internal(info == mi_atomic_read(®ion->info)); + mi_assert_internal(info != 0); // Commit the blocks to memory + bool region_is_committed = false; + void* start = mi_region_info_read(info,large,®ion_is_committed); void* blocks_start = (uint8_t*)start + (bitidx * MI_SEGMENT_SIZE); - if (commit && !mi_option_is_enabled(mi_option_eager_region_commit)) { + if (commit && !region_is_committed) { _mi_os_commit(blocks_start, mi_good_commit_size(size), tld->stats); // only commit needed size (unless using large OS pages) } @@ -223,7 +240,7 @@ static inline size_t mi_bsr(uintptr_t x) { // Returns `false` on an error (OOM); `true` otherwise. `p` and `id` are only written // if the blocks were successfully claimed so ensure they are initialized to NULL/SIZE_MAX before the call. // (not being able to claim is not considered an error so check for `p != NULL` afterwards). -static bool mi_region_alloc_blocks(mem_region_t* region, size_t idx, size_t blocks, size_t size, bool commit, void** p, size_t* id, mi_os_tld_t* tld) +static bool mi_region_alloc_blocks(mem_region_t* region, size_t idx, size_t blocks, size_t size, bool commit, bool* large, void** p, size_t* id, mi_os_tld_t* tld) { mi_assert_internal(p != NULL && id != NULL); mi_assert_internal(blocks < MI_REGION_MAP_BITS); @@ -253,7 +270,7 @@ static bool mi_region_alloc_blocks(mem_region_t* region, size_t idx, size_t bloc else { // success, we claimed the bits // now commit the block memory -- this can still fail - return mi_region_commit_blocks(region, idx, bitidx, blocks, size, commit, p, id, tld); + return mi_region_commit_blocks(region, idx, bitidx, blocks, size, commit, large, p, id, tld); } } else { @@ -276,14 +293,14 @@ static bool mi_region_alloc_blocks(mem_region_t* region, size_t idx, size_t bloc // Returns `false` on an error (OOM); `true` otherwise. `p` and `id` are only written // if the blocks were successfully claimed so ensure they are initialized to NULL/0 before the call. // (not being able to claim is not considered an error so check for `p != NULL` afterwards). -static bool mi_region_try_alloc_blocks(size_t idx, size_t blocks, size_t size, bool commit, void** p, size_t* id, mi_os_tld_t* tld) +static bool mi_region_try_alloc_blocks(size_t idx, size_t blocks, size_t size, bool commit, bool* large, void** p, size_t* id, mi_os_tld_t* tld) { // check if there are available blocks in the region.. mi_assert_internal(idx < MI_REGION_MAX); mem_region_t* region = ®ions[idx]; uintptr_t m = mi_atomic_read_relaxed(®ion->map); if (m != MI_REGION_MAP_FULL) { // some bits are zero - return mi_region_alloc_blocks(region, idx, blocks, size, commit, p, id, tld); + return mi_region_alloc_blocks(region, idx, blocks, size, commit, large, p, id, tld); } else { return true; // no error, but no success either @@ -296,15 +313,17 @@ static bool mi_region_try_alloc_blocks(size_t idx, size_t blocks, size_t size, b // Allocate `size` memory aligned at `alignment`. Return non NULL on success, with a given memory `id`. // (`id` is abstract, but `id = idx*MI_REGION_MAP_BITS + bitidx`) -void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool commit, size_t* id, mi_os_tld_t* tld) +void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, size_t* id, mi_os_tld_t* tld) { mi_assert_internal(id != NULL && tld != NULL); mi_assert_internal(size > 0); *id = SIZE_MAX; + bool default_large = false; + if (large==NULL) large = &default_large; // ensure `large != NULL` // use direct OS allocation for huge blocks or alignment (with `id = SIZE_MAX`) if (size > MI_REGION_MAX_ALLOC_SIZE || alignment > MI_SEGMENT_ALIGN) { - return _mi_os_alloc_aligned(mi_good_commit_size(size), alignment, true, tld); // round up size + return _mi_os_alloc_aligned(mi_good_commit_size(size), alignment, commit, large, tld); // round up size } // always round size to OS page size multiple (so commit/decommit go over the entire range) @@ -318,27 +337,27 @@ void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool commit, size_t* // find a range of free blocks void* p = NULL; size_t count = mi_atomic_read(®ions_count); - size_t idx = 0; // tld->region_idx; // start index is per-thread to reduce contention + size_t idx = 0; // tld->region_idx; // start at 0 to reuse low addresses? Or, use tld->region_idx to reduce contention? for (size_t visited = 0; visited < count; visited++, idx++) { if (idx >= count) idx = 0; // wrap around - if (!mi_region_try_alloc_blocks(idx, blocks, size, commit, &p, id, tld)) return NULL; // error + if (!mi_region_try_alloc_blocks(idx, blocks, size, commit, large, &p, id, tld)) return NULL; // error if (p != NULL) break; } if (p == NULL) { // no free range in existing regions -- try to extend beyond the count.. but at most 4 regions for (idx = count; idx < count + 4 && idx < MI_REGION_MAX; idx++) { - if (!mi_region_try_alloc_blocks(idx, blocks, size, commit, &p, id, tld)) return NULL; // error + if (!mi_region_try_alloc_blocks(idx, blocks, size, commit, large, &p, id, tld)) return NULL; // error if (p != NULL) break; } } if (p == NULL) { // we could not find a place to allocate, fall back to the os directly - p = _mi_os_alloc_aligned(size, alignment, commit, tld); + p = _mi_os_alloc_aligned(size, alignment, commit, large, tld); } else { - tld->region_idx = idx; // next start of search + tld->region_idx = idx; // next start of search? } mi_assert_internal( p == NULL || (uintptr_t)p % alignment == 0); @@ -347,8 +366,8 @@ void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool commit, size_t* // Allocate `size` memory. Return non NULL on success, with a given memory `id`. -void* _mi_mem_alloc(size_t size, bool commit, size_t* id, mi_os_tld_t* tld) { - return _mi_mem_alloc_aligned(size,0,commit,id,tld); +void* _mi_mem_alloc(size_t size, bool commit, bool* large, size_t* id, mi_os_tld_t* tld) { + return _mi_mem_alloc_aligned(size,0,commit,large,id,tld); } /* ---------------------------------------------------------------------------- @@ -377,7 +396,10 @@ void _mi_mem_free(void* p, size_t size, size_t id, mi_stats_t* stats) { mi_assert_internal(idx < MI_REGION_MAX); if (idx >= MI_REGION_MAX) return; // or `abort`? mem_region_t* region = ®ions[idx]; mi_assert_internal((mi_atomic_read_relaxed(®ion->map) & mask) == mask ); // claimed? - void* start = mi_atomic_read_ptr(®ion->start); + mi_region_info_t info = mi_atomic_read(®ion->info); + bool is_large; + bool is_eager_committed; + void* start = mi_region_info_read(info,&is_large,&is_eager_committed); mi_assert_internal(start != NULL); void* blocks_start = (uint8_t*)start + (bitidx * MI_SEGMENT_SIZE); mi_assert_internal(blocks_start == p); // not a pointer in our area? @@ -388,18 +410,13 @@ void _mi_mem_free(void* p, size_t size, size_t id, mi_stats_t* stats) { // TODO: implement delayed decommit/reset as these calls are too expensive // if the memory is reused soon. // reset: 10x slowdown on malloc-large, decommit: 17x slowdown on malloc-large - if (!mi_option_is_enabled(mi_option_large_os_pages)) { - if (mi_option_is_enabled(mi_option_eager_region_commit)) { - //_mi_os_reset(p, size, stats); - } - else { - //_mi_os_decommit(p, size, stats); - } - } + if (!is_large) { + // _mi_os_reset(p,size,stats); + // _mi_os_decommit(p,size,stats); // if !is_committed + } // TODO: should we free empty regions? currently only done _mi_mem_collect. - // this frees up virtual address space which - // might be useful on 32-bit systems? + // this frees up virtual address space which might be useful on 32-bit systems? // and unclaim uintptr_t map; @@ -419,17 +436,20 @@ void _mi_mem_collect(mi_stats_t* stats) { // free every region that has no segments in use. for (size_t i = 0; i < regions_count; i++) { mem_region_t* region = ®ions[i]; - if (mi_atomic_read_relaxed(®ion->map) == 0 && region->start != NULL) { + if (mi_atomic_read_relaxed(®ion->map) == 0) { // if no segments used, try to claim the whole region uintptr_t m; do { m = mi_atomic_read_relaxed(®ion->map); } while(m == 0 && !mi_atomic_cas_weak(®ion->map, ~((uintptr_t)0), 0 )); if (m == 0) { - // on success, free the whole region - if (region->start != NULL) _mi_os_free((void*)region->start, MI_REGION_SIZE, stats); + // on success, free the whole region (unless it was huge reserved) + void* start = mi_region_info_read(mi_atomic_read(®ion->info), NULL, NULL); + if (start != NULL && !_mi_os_is_huge_reserved(start)) { + _mi_os_free(start, MI_REGION_SIZE, stats); + } // and release - mi_atomic_write_ptr(®ion->start,NULL); + mi_atomic_write(®ion->info,0); mi_atomic_write(®ion->map,0); } } diff --git a/src/options.c b/src/options.c index 11bb78d8..41bf33a0 100644 --- a/src/options.c +++ b/src/options.c @@ -58,7 +58,7 @@ static mi_option_desc_t options[_mi_option_last] = #endif // the following options are experimental and not all combinations make sense. - { 1, UNINIT, MI_OPTION(eager_commit) }, // note: if eager_region_commit is on, this should be on too. + { 1, UNINIT, MI_OPTION(eager_commit) }, // note: needs to be on when eager_region_commit is enabled #ifdef _WIN32 // and BSD? { 1, UNINIT, MI_OPTION(eager_region_commit) }, // don't commit too eagerly on windows (just for looks...) #else diff --git a/src/os.c b/src/os.c index 7648c010..e1306722 100644 --- a/src/os.c +++ b/src/os.c @@ -35,10 +35,9 @@ terms of the MIT license. A copy of the license can be found in the file On windows initializes support for aligned allocation and large OS pages (if MIMALLOC_LARGE_OS_PAGES is true). ----------------------------------------------------------- */ -bool _mi_os_decommit(void* addr, size_t size, mi_stats_t* stats); - -static bool mi_os_is_huge_reserved(void* p); -static void* mi_os_alloc_from_huge_reserved(size_t size, size_t try_alignment, bool commit); +bool _mi_os_decommit(void* addr, size_t size, mi_stats_t* stats); +bool _mi_os_is_huge_reserved(void* p); +static void* mi_os_alloc_from_huge_reserved(size_t size, size_t try_alignment, bool commit); static void* mi_align_up_ptr(void* p, size_t alignment) { return (void*)_mi_align_up((uintptr_t)p, alignment); @@ -173,7 +172,7 @@ void _mi_os_init() { static bool mi_os_mem_free(void* addr, size_t size, mi_stats_t* stats) { - if (addr == NULL || size == 0 || mi_os_is_huge_reserved(addr)) return true; + if (addr == NULL || size == 0 || _mi_os_is_huge_reserved(addr)) return true; bool err = false; #if defined(_WIN32) err = (VirtualFree(addr, 0, MEM_RELEASE) == 0); @@ -199,7 +198,7 @@ static void* mi_win_virtual_allocx(void* addr, size_t size, size_t try_alignment #if defined(MEM_EXTENDED_PARAMETER_TYPE_BITS) // on modern Windows try use NtAllocateVirtualMemoryEx for 1GiB huge pages if ((size % ((uintptr_t)1 << 30)) == 0 /* 1GiB multiple */ - && (flags & MEM_LARGE_PAGES) != 0 && (flags & MEM_COMMIT) != 0 + && (flags & MEM_LARGE_PAGES) != 0 && (flags & MEM_COMMIT) != 0 && (flags & MEM_RESERVE) != 0 && (addr != NULL || try_alignment == 0 || try_alignment % _mi_os_page_size() == 0) && pNtAllocateVirtualMemoryEx != NULL) { @@ -211,7 +210,7 @@ static void* mi_win_virtual_allocx(void* addr, size_t size, size_t try_alignment param.ULong64 = MEM_EXTENDED_PARAMETER_NONPAGED_HUGE; SIZE_T psize = size; void* base = addr; - NTSTATUS err = (*pNtAllocateVirtualMemoryEx)(GetCurrentProcess(), &base, &psize, flags | MEM_RESERVE, PAGE_READWRITE, ¶m, 1); + NTSTATUS err = (*pNtAllocateVirtualMemoryEx)(GetCurrentProcess(), &base, &psize, flags, PAGE_READWRITE, ¶m, 1); if (err == 0) { return base; } @@ -247,10 +246,12 @@ static void* mi_win_virtual_allocx(void* addr, size_t size, size_t try_alignment return VirtualAlloc(addr, size, flags, PAGE_READWRITE); } -static void* mi_win_virtual_alloc(void* addr, size_t size, size_t try_alignment, DWORD flags, bool large_only) { +static void* mi_win_virtual_alloc(void* addr, size_t size, size_t try_alignment, DWORD flags, bool large_only, bool allow_large, bool* is_large) { + mi_assert_internal(!(large_only && !allow_large)); static volatile _Atomic(uintptr_t) large_page_try_ok; // = 0; void* p = NULL; - if (large_only || use_large_os_page(size, try_alignment)) { + if ((large_only || use_large_os_page(size, try_alignment)) + && allow_large && (flags&MEM_COMMIT)!=0 && (flags&MEM_RESERVE)!=0) { uintptr_t try_ok = mi_atomic_read(&large_page_try_ok); if (!large_only && try_ok > 0) { // if a large page allocation fails, it seems the calls to VirtualAlloc get very expensive. @@ -259,7 +260,8 @@ static void* mi_win_virtual_alloc(void* addr, size_t size, size_t try_alignment, } else { // large OS pages must always reserve and commit. - p = mi_win_virtual_allocx(addr, size, try_alignment, MEM_LARGE_PAGES | MEM_COMMIT | MEM_RESERVE | flags); + *is_large = true; + p = mi_win_virtual_allocx(addr, size, try_alignment, flags | MEM_LARGE_PAGES); if (large_only) return p; // fall back to non-large page allocation on error (`p == NULL`). if (p == NULL) { @@ -268,6 +270,7 @@ static void* mi_win_virtual_alloc(void* addr, size_t size, size_t try_alignment, } } if (p == NULL) { + *is_large = ((flags&MEM_LARGE_PAGES) != 0); p = mi_win_virtual_allocx(addr, size, try_alignment, flags); } if (p == NULL) { @@ -311,7 +314,7 @@ static void* mi_unix_mmapx(void* addr, size_t size, size_t try_alignment, int pr return p; } -static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int protect_flags, bool large_only) { +static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int protect_flags, bool large_only, bool allow_large, bool* is_large) { void* p = NULL; #if !defined(MAP_ANONYMOUS) #define MAP_ANONYMOUS MAP_ANON @@ -333,7 +336,7 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro // macOS: tracking anonymous page with a specific ID. (All up to 98 are taken officially but LLVM sanitizers had taken 99) fd = VM_MAKE_TAG(100); #endif - if (large_only || use_large_os_page(size, try_alignment)) { + if ((large_only || use_large_os_page(size, try_alignment)) && allow_large) { static volatile _Atomic(uintptr_t) large_page_try_ok; // = 0; uintptr_t try_ok = mi_atomic_read(&large_page_try_ok); if (!large_only && try_ok > 0) { @@ -368,6 +371,7 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro #endif if (large_only || lflags != flags) { // try large OS page allocation + *is_large = true; p = mi_unix_mmapx(addr, size, try_alignment, protect_flags, lflags, lfd); #ifdef MAP_HUGE_1GB if (p == NULL && (lflags & MAP_HUGE_1GB) != 0) { @@ -384,6 +388,7 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro } } if (p == NULL) { + *is_large = false; p = mi_unix_mmapx(addr, size, try_alignment, protect_flags, flags, fd); #if defined(MADV_HUGEPAGE) // Many Linux systems don't allow MAP_HUGETLB but they support instead @@ -392,8 +397,10 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro // in that case -- in particular for our large regions (in `memory.c`). // However, some systems only allow TPH if called with explicit `madvise`, so // when large OS pages are enabled for mimalloc, we call `madvice` anyways. - if (use_large_os_page(size, try_alignment)) { - madvise(p, size, MADV_HUGEPAGE); + if (allow_large && use_large_os_page(size, try_alignment)) { + if (madvise(p, size, MADV_HUGEPAGE) == 0) { + *is_large = true; // possibly + }; } #endif } @@ -403,27 +410,35 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro // Primitive allocation from the OS. // Note: the `try_alignment` is just a hint and the returned pointer is not guaranteed to be aligned. -static void* mi_os_mem_alloc(size_t size, size_t try_alignment, bool commit, mi_stats_t* stats) { +static void* mi_os_mem_alloc(size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, mi_stats_t* stats) { mi_assert_internal(size > 0 && (size % _mi_os_page_size()) == 0); if (size == 0) return NULL; + if (!commit) allow_large = false; - void* p = mi_os_alloc_from_huge_reserved(size, try_alignment, commit); - if (p != NULL) return p; + void* p = NULL; + if (allow_large) { + p = mi_os_alloc_from_huge_reserved(size, try_alignment, commit); + if (p != NULL) { + *is_large = true; + return p; + } + } #if defined(_WIN32) int flags = MEM_RESERVE; if (commit) flags |= MEM_COMMIT; - p = mi_win_virtual_alloc(NULL, size, try_alignment, flags, false); + p = mi_win_virtual_alloc(NULL, size, try_alignment, flags, false, allow_large, is_large); #elif defined(__wasi__) + *is_large = false; p = mi_wasm_heap_grow(size, try_alignment); #else int protect_flags = (commit ? (PROT_WRITE | PROT_READ) : PROT_NONE); - p = mi_unix_mmap(NULL, size, try_alignment, protect_flags, false); + p = mi_unix_mmap(NULL, size, try_alignment, protect_flags, false, allow_large, is_large); #endif _mi_stat_increase(&stats->mmap_calls, 1); if (p != NULL) { _mi_stat_increase(&stats->reserved, size); - if (commit) _mi_stat_increase(&stats->committed, size); + if (commit) { _mi_stat_increase(&stats->committed, size); } } return p; } @@ -431,14 +446,15 @@ static void* mi_os_mem_alloc(size_t size, size_t try_alignment, bool commit, mi_ // Primitive aligned allocation from the OS. // This function guarantees the allocated memory is aligned. -static void* mi_os_mem_alloc_aligned(size_t size, size_t alignment, bool commit, mi_stats_t* stats) { +static void* mi_os_mem_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, bool* is_large, mi_stats_t* stats) { mi_assert_internal(alignment >= _mi_os_page_size() && ((alignment & (alignment - 1)) == 0)); mi_assert_internal(size > 0 && (size % _mi_os_page_size()) == 0); + if (!commit) allow_large = false; if (!(alignment >= _mi_os_page_size() && ((alignment & (alignment - 1)) == 0))) return NULL; size = _mi_align_up(size, _mi_os_page_size()); // try first with a hint (this will be aligned directly on Win 10+ or BSD) - void* p = mi_os_mem_alloc(size, alignment, commit, stats); + void* p = mi_os_mem_alloc(size, alignment, commit, allow_large, is_large, stats); if (p == NULL) return NULL; // if not aligned, free it, overallocate, and unmap around it @@ -457,7 +473,7 @@ static void* mi_os_mem_alloc_aligned(size_t size, size_t alignment, bool commit, if (commit) flags |= MEM_COMMIT; for (int tries = 0; tries < 3; tries++) { // over-allocate to determine a virtual memory range - p = mi_os_mem_alloc(over_size, alignment, commit, stats); + p = mi_os_mem_alloc(over_size, alignment, commit, false, is_large, stats); if (p == NULL) return NULL; // error if (((uintptr_t)p % alignment) == 0) { // if p happens to be aligned, just decommit the left-over area @@ -468,7 +484,7 @@ static void* mi_os_mem_alloc_aligned(size_t size, size_t alignment, bool commit, // otherwise free and allocate at an aligned address in there mi_os_mem_free(p, over_size, stats); void* aligned_p = mi_align_up_ptr(p, alignment); - p = mi_win_virtual_alloc(aligned_p, size, alignment, flags, false); + p = mi_win_virtual_alloc(aligned_p, size, alignment, flags, false, allow_large, is_large); if (p == aligned_p) break; // success! if (p != NULL) { // should not happen? mi_os_mem_free(p, size, stats); @@ -478,7 +494,7 @@ static void* mi_os_mem_alloc_aligned(size_t size, size_t alignment, bool commit, } #else // overallocate... - p = mi_os_mem_alloc(over_size, alignment, commit, stats); + p = mi_os_mem_alloc(over_size, alignment, commit, false, is_large, stats); if (p == NULL) return NULL; // and selectively unmap parts around the over-allocated area. void* aligned_p = mi_align_up_ptr(p, alignment); @@ -504,7 +520,8 @@ static void* mi_os_mem_alloc_aligned(size_t size, size_t alignment, bool commit, void* _mi_os_alloc(size_t size, mi_stats_t* stats) { if (size == 0) return NULL; size = mi_os_good_alloc_size(size, 0); - return mi_os_mem_alloc(size, 0, true, stats); + bool is_large = false; + return mi_os_mem_alloc(size, 0, true, false, &is_large, stats); } void _mi_os_free(void* p, size_t size, mi_stats_t* stats) { @@ -513,12 +530,17 @@ void _mi_os_free(void* p, size_t size, mi_stats_t* stats) { mi_os_mem_free(p, size, stats); } -void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, mi_os_tld_t* tld) +void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, mi_os_tld_t* tld) { if (size == 0) return NULL; size = mi_os_good_alloc_size(size, alignment); alignment = _mi_align_up(alignment, _mi_os_page_size()); - return mi_os_mem_alloc_aligned(size, alignment, commit, tld->stats); + bool allow_large = false; + if (large != NULL) { + allow_large = *large; + *large = false; + } + return mi_os_mem_alloc_aligned(size, alignment, commit, allow_large, (large!=NULL?large:&allow_large), tld->stats); } @@ -559,7 +581,7 @@ static bool mi_os_commitx(void* addr, size_t size, bool commit, bool conservativ // page align in the range, commit liberally, decommit conservative size_t csize; void* start = mi_os_page_align_areax(conservative, addr, size, &csize); - if (csize == 0 || mi_os_is_huge_reserved(addr)) return true; + if (csize == 0 || _mi_os_is_huge_reserved(addr)) return true; int err = 0; if (commit) { _mi_stat_increase(&stats->committed, csize); @@ -611,7 +633,7 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats) // page align conservatively within the range size_t csize; void* start = mi_os_page_align_area_conservative(addr, size, &csize); - if (csize == 0 || mi_os_is_huge_reserved(addr)) return true; + if (csize == 0 || _mi_os_is_huge_reserved(addr)) return true; if (reset) _mi_stat_increase(&stats->reset, csize); else _mi_stat_decrease(&stats->reset, csize); if (!reset) return true; // nothing to do on unreset! @@ -626,6 +648,11 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats) // Testing shows that for us (on `malloc-large`) MEM_RESET is 2x faster than DiscardVirtualMemory void* p = VirtualAlloc(start, csize, MEM_RESET, PAGE_READWRITE); mi_assert_internal(p == start); + #if 0 + if (p == start) { + VirtualUnlock(start,csize); // VirtualUnlock after MEM_RESET removes the memory from the working set + } + #endif if (p != start) return false; #else #if defined(MADV_FREE) @@ -679,8 +706,8 @@ static bool mi_os_protectx(void* addr, size_t size, bool protect) { size_t csize = 0; void* start = mi_os_page_align_area_conservative(addr, size, &csize); if (csize == 0) return false; - if (mi_os_is_huge_reserved(addr)) { - _mi_warning_message("cannot mprotect memory allocated in huge OS pages\n"); + if (_mi_os_is_huge_reserved(addr)) { + _mi_warning_message("cannot mprotect memory allocated in huge OS pages\n"); } int err = 0; #ifdef _WIN32 @@ -742,7 +769,7 @@ typedef struct mi_huge_info_s { static mi_huge_info_t os_huge_reserved = { NULL, 0, ATOMIC_VAR_INIT(0) }; -static bool mi_os_is_huge_reserved(void* p) { +bool _mi_os_is_huge_reserved(void* p) { return (mi_atomic_read_ptr(&os_huge_reserved.start) != NULL && p >= mi_atomic_read_ptr(&os_huge_reserved.start) && (uint8_t*)p < (uint8_t*)mi_atomic_read_ptr(&os_huge_reserved.start) + mi_atomic_read(&os_huge_reserved.reserved)); @@ -806,10 +833,11 @@ int mi_reserve_huge_os_pages( size_t pages, double max_secs ) mi_attr_noexcept for (size_t page = 0; page < pages; page++, addr += MI_HUGE_OS_PAGE_SIZE ) { // allocate lorgu pages void* p = NULL; + bool is_large = true; #ifdef _WIN32 - p = mi_win_virtual_alloc(addr, MI_HUGE_OS_PAGE_SIZE, 0, MEM_LARGE_PAGES | MEM_COMMIT | MEM_RESERVE, true); + p = mi_win_virtual_alloc(addr, MI_HUGE_OS_PAGE_SIZE, 0, MEM_LARGE_PAGES | MEM_COMMIT | MEM_RESERVE, true, true, &is_large); #elif defined(MI_OS_USE_MMAP) - p = mi_unix_mmap(addr, MI_HUGE_OS_PAGE_SIZE, 0, PROT_READ | PROT_WRITE, true); + p = mi_unix_mmap(addr, MI_HUGE_OS_PAGE_SIZE, 0, PROT_READ | PROT_WRITE, true, true, &is_large); #else // always fail #endif diff --git a/src/segment.c b/src/segment.c index 9a744ea6..020d53e8 100644 --- a/src/segment.c +++ b/src/segment.c @@ -229,6 +229,7 @@ static void mi_segment_os_free(mi_segment_t* segment, size_t segment_size, mi_se segment->thread_id = 0; mi_segments_track_size(-((long)segment_size),tld); if (mi_option_is_enabled(mi_option_secure)) { + mi_assert_internal(!segment->mem_is_fixed); _mi_mem_unprotect(segment, segment->segment_size); // ensure no more guard pages are set } _mi_mem_free(segment, segment_size, segment->memid, tld->stats); @@ -277,7 +278,7 @@ static bool mi_segment_cache_push(mi_segment_t* segment, mi_segments_tld_t* tld) return false; } mi_assert_internal(segment->segment_size == MI_SEGMENT_SIZE); - if (mi_option_is_enabled(mi_option_cache_reset)) { + if (!segment->mem_is_fixed && mi_option_is_enabled(mi_option_cache_reset)) { _mi_mem_reset((uint8_t*)segment + segment->segment_info_size, segment->segment_size - segment->segment_info_size, tld->stats); } segment->next = tld->cache; @@ -325,11 +326,13 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, size_t page_size = (page_kind == MI_PAGE_HUGE ? segment_size : (size_t)1 << page_shift); // Try to get it from our thread local cache first - bool commit = mi_option_is_enabled(mi_option_eager_commit) || (page_kind > MI_PAGE_MEDIUM); + bool eager = mi_option_is_enabled(mi_option_eager_commit); + bool commit = eager || (page_kind > MI_PAGE_MEDIUM); bool protection_still_good = false; mi_segment_t* segment = mi_segment_cache_pop(segment_size, tld); if (segment != NULL) { if (mi_option_is_enabled(mi_option_secure)) { + mi_assert_internal(!segment->mem_is_fixed); if (segment->page_kind != page_kind) { _mi_mem_unprotect(segment, segment->segment_size); // reset protection if the page kind differs } @@ -337,37 +340,38 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, protection_still_good = true; // otherwise, the guard pages are still in place } } - if (!mi_option_is_enabled(mi_option_eager_commit)) { - if (page_kind > MI_PAGE_MEDIUM) { - _mi_mem_commit(segment, segment->segment_size, tld->stats); - } - else { - // ok, commit (and unreset) on demand again - } + if (!segment->mem_is_committed && page_kind > MI_PAGE_MEDIUM) { + mi_assert_internal(!segment->mem_is_fixed); + _mi_mem_commit(segment, segment->segment_size, tld->stats); + segment->mem_is_committed = true; } - else if (mi_option_is_enabled(mi_option_cache_reset) || mi_option_is_enabled(mi_option_page_reset)) { + if (!segment->mem_is_fixed && + (mi_option_is_enabled(mi_option_cache_reset) || mi_option_is_enabled(mi_option_page_reset))) { _mi_mem_unreset(segment, segment->segment_size, tld->stats); } } else { // Allocate the segment from the OS size_t memid; - segment = (mi_segment_t*)_mi_mem_alloc_aligned(segment_size, MI_SEGMENT_SIZE, commit, &memid, os_tld); + bool mem_large = (eager && !mi_option_is_enabled(mi_option_secure)); // only allow large OS pages once we are no longer lazy + segment = (mi_segment_t*)_mi_mem_alloc_aligned(segment_size, MI_SEGMENT_SIZE, commit, &mem_large, &memid, os_tld); if (segment == NULL) return NULL; // failed to allocate if (!commit) { + // ensure the initial info is committed _mi_mem_commit(segment, info_size, tld->stats); } segment->memid = memid; + segment->mem_is_fixed = mem_large; + segment->mem_is_committed = commit; mi_segments_track_size((long)segment_size, tld); } mi_assert_internal(segment != NULL && (uintptr_t)segment % MI_SEGMENT_SIZE == 0); - // zero the segment info - { size_t memid = segment->memid; - memset(segment, 0, info_size); - segment->memid = memid; - } + // zero the segment info (but not the `mem` fields) + ptrdiff_t ofs = offsetof(mi_segment_t,next); + memset((uint8_t*)segment + ofs, 0, info_size - ofs); + // guard pages if (mi_option_is_enabled(mi_option_secure) && !protection_still_good) { // in secure mode, we set up a protected page in between the segment info // and the page data @@ -386,6 +390,7 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, } } + // initialize segment->page_kind = page_kind; segment->capacity = capacity; segment->page_shift = page_shift; @@ -453,13 +458,14 @@ static mi_page_t* mi_segment_find_free(mi_segment_t* segment, mi_stats_t* stats) if (!page->segment_in_use) { if (page->is_reset || !page->is_committed) { size_t psize; - uint8_t* start = _mi_page_start(segment, page, &psize); - mi_assert_internal(!(page->is_reset && !page->is_committed)); + uint8_t* start = _mi_page_start(segment, page, &psize); if (!page->is_committed) { + mi_assert_internal(!segment->mem_is_fixed); page->is_committed = true; _mi_mem_commit(start,psize,stats); } if (page->is_reset) { + mi_assert_internal(!segment->mem_is_fixed); page->is_reset = false; _mi_mem_unreset(start, psize, stats); } @@ -488,22 +494,17 @@ static void mi_segment_page_clear(mi_segment_t* segment, mi_page_t* page, mi_sta _mi_stat_decrease(&stats->pages, 1); // reset the page memory to reduce memory pressure? - if (!page->is_reset && mi_option_is_enabled(mi_option_page_reset)) { + if (!segment->mem_is_fixed && !page->is_reset && mi_option_is_enabled(mi_option_page_reset)) { size_t psize; uint8_t* start = _mi_page_start(segment, page, &psize); page->is_reset = true; _mi_mem_reset(start, psize, stats); } - // zero the page data - uint8_t idx = page->segment_idx; // don't clear the index - bool is_reset = page->is_reset; // don't clear the reset flag - bool is_committed = page->is_committed; // don't clear the commit flag - memset(page, 0, sizeof(*page)); - page->segment_idx = idx; + // zero the page data, but not the segment fields + ptrdiff_t ofs = offsetof(mi_page_t,capacity); + memset((uint8_t*)page + ofs, 0, sizeof(*page) - ofs); page->segment_in_use = false; - page->is_reset = is_reset; - page->is_committed = is_committed; segment->used--; } From b72a2d9659216dcf352a69287f39fec7798d305d Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 27 Aug 2019 18:43:50 +0100 Subject: [PATCH 08/92] macOS: anonymous page ID make it as env var. --- include/mimalloc.h | 1 + src/options.c | 3 ++- src/os.c | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 4f13bc1f..41514d3e 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -232,6 +232,7 @@ typedef enum mi_option_e { mi_option_page_reset, mi_option_cache_reset, mi_option_reset_decommits, + mi_option_os_tag, _mi_option_last } mi_option_t; diff --git a/src/options.c b/src/options.c index 16c50f11..5f2ad896 100644 --- a/src/options.c +++ b/src/options.c @@ -68,7 +68,8 @@ static mi_option_desc_t options[_mi_option_last] = { 0, UNINIT, MI_OPTION(segment_cache) }, // cache N segments per thread { 0, UNINIT, MI_OPTION(page_reset) }, { 0, UNINIT, MI_OPTION(cache_reset) }, - { 0, UNINIT, MI_OPTION(reset_decommits) } // note: cannot enable this if secure is on + { 0, UNINIT, MI_OPTION(reset_decommits) }, // note: cannot enable this if secure is on + { 100, UNINIT, MI_OPTION(os_tag) } // only apple specific for now but might serve more or less related purpose }; static void mi_option_init(mi_option_desc_t* desc); diff --git a/src/os.c b/src/os.c index fb36f3fc..0a733aa3 100644 --- a/src/os.c +++ b/src/os.c @@ -288,7 +288,9 @@ static void* mi_unix_mmap(size_t size, size_t try_alignment, int protect_flags) #endif #if defined(VM_MAKE_TAG) // macOS: tracking anonymous page with a specific ID. (All up to 98 are taken officially but LLVM sanitizers had taken 99) - fd = VM_MAKE_TAG(100); + int os_tag = (int)mi_option_get(mi_option_os_tag); + if (os_tag < 100 || os_tag > 255) os_tag = 100; + fd = VM_MAKE_TAG(os_tag); #endif if (use_large_os_page(size, try_alignment)) { static volatile _Atomic(uintptr_t) large_page_try_ok; // = 0; From 61e4b83f3695271a8d771655de8d8896c8111f34 Mon Sep 17 00:00:00 2001 From: Jim Huang Date: Wed, 28 Aug 2019 06:44:40 +0800 Subject: [PATCH 09/92] Clarify LD_PRELOAD on dynamically-linked ELF LD_PRELOAD is an environment variable that can be set to load ELF shared objects before all others. Linux and BSD are known to fit. This change also unifies the use of command line, ensuring the prefix "> " prompt. --- readme.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/readme.md b/readme.md index c2efcc19..9352199d 100644 --- a/readme.md +++ b/readme.md @@ -13,7 +13,7 @@ Initially developed by Daan Leijen for the run-time systems of the [Koka](https://github.com/koka-lang/koka) and [Lean](https://github.com/leanprover/lean) languages. It is a drop-in replacement for `malloc` and can be used in other programs -without code changes, for example, on Unix you can use it as: +without code changes, for example, on dynamically linked ELF-based systems (Linux, BSD, etc.) you can use it as: ``` > LD_PRELOAD=/usr/bin/libmimalloc.so myprogram ``` @@ -117,7 +117,7 @@ Notes: The preferred usage is including ``, linking with the shared- or static library, and using the `mi_malloc` API exclusively for allocation. For example, ``` -gcc -o myprogram -lmimalloc myfile.c +> gcc -o myprogram -lmimalloc myfile.c ``` mimalloc uses only safe OS calls (`mmap` and `VirtualAlloc`) and can co-exist @@ -207,20 +207,21 @@ This is the recommended way to override the standard malloc interface. ### Linux, BSD -On these systems we preload the mimalloc shared +On these ELF-based systems we preload the mimalloc shared library so all calls to the standard `malloc` interface are resolved to the _mimalloc_ library. - -- `env LD_PRELOAD=/usr/lib/libmimalloc.so myprogram` +``` +> env LD_PRELOAD=/usr/lib/libmimalloc.so myprogram +``` You can set extra environment variables to check that mimalloc is running, like: ``` -env MIMALLOC_VERBOSE=1 LD_PRELOAD=/usr/lib/libmimalloc.so myprogram +> env MIMALLOC_VERBOSE=1 LD_PRELOAD=/usr/lib/libmimalloc.so myprogram ``` or run with the debug version to get detailed statistics: ``` -env MIMALLOC_SHOW_STATS=1 LD_PRELOAD=/usr/lib/libmimalloc-debug.so myprogram +> env MIMALLOC_SHOW_STATS=1 LD_PRELOAD=/usr/lib/libmimalloc-debug.so myprogram ``` ### MacOS @@ -228,8 +229,9 @@ env MIMALLOC_SHOW_STATS=1 LD_PRELOAD=/usr/lib/libmimalloc-debug.so myprogram On macOS we can also preload the mimalloc shared library so all calls to the standard `malloc` interface are resolved to the _mimalloc_ library. - -- `env DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=/usr/lib/libmimalloc.dylib myprogram` +``` +> env DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=/usr/lib/libmimalloc.dylib myprogram +``` Note that certain security restrictions may apply when doing this from the [shell](https://stackoverflow.com/questions/43941322/dyld-insert-libraries-ignored-when-calling-application-through-bash). @@ -257,16 +259,15 @@ robust; try this out if you experience troubles. ## Static override -On Unix systems, you can also statically link with _mimalloc_ to override the standard +On Unix-like systems, you can also statically link with _mimalloc_ to override the standard malloc interface. The recommended way is to link the final program with the _mimalloc_ single object file (`mimalloc-override.o`). We use an object file instead of a library file as linkers give preference to that over archives to resolve symbols. To ensure that the standard malloc interface resolves to the _mimalloc_ library, link it as the first object file. For example: - ``` -gcc -o myprogram mimalloc-override.o myfile1.c ... +> gcc -o myprogram mimalloc-override.o myfile1.c ... ``` From 18e02c3766d9fd8fc47fef2f0346645487d967ff Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 27 Aug 2019 17:02:56 -0700 Subject: [PATCH 10/92] try allocating non-eager segments in non-fixed memory --- src/memory.c | 24 ++++++++++++++++++------ src/options.c | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/memory.c b/src/memory.c index a9b87b8e..f53b1ec3 100644 --- a/src/memory.c +++ b/src/memory.c @@ -262,7 +262,7 @@ static bool mi_region_alloc_blocks(mem_region_t* region, size_t idx, size_t bloc mi_assert_internal((m >> bitidx) == mask); // no overflow? uintptr_t newmap = map | m; mi_assert_internal((newmap^map) >> bitidx == mask); - if (!mi_atomic_cas_weak(®ion->map, newmap, map)) { + if (!mi_atomic_cas_weak(®ion->map, newmap, map)) { // TODO: use strong cas here? // no success, another thread claimed concurrently.. keep going map = mi_atomic_read(®ion->map); continue; @@ -299,12 +299,24 @@ static bool mi_region_try_alloc_blocks(size_t idx, size_t blocks, size_t size, b mi_assert_internal(idx < MI_REGION_MAX); mem_region_t* region = ®ions[idx]; uintptr_t m = mi_atomic_read_relaxed(®ion->map); - if (m != MI_REGION_MAP_FULL) { // some bits are zero - return mi_region_alloc_blocks(region, idx, blocks, size, commit, large, p, id, tld); - } - else { - return true; // no error, but no success either + if (m != MI_REGION_MAP_FULL) { // some bits are zero + bool ok = (commit || *large); // committing or allow-large is always ok + if (!ok) { + // otherwise skip incompatible regions if possible. + // this is not guaranteed due to multiple threads allocating at the same time but + // that's ok. In secure mode, large is never allowed so that works out; otherwise + // we might just not be able to reset/decommit individual pages sometimes. + mi_region_info_t info = mi_atomic_read_relaxed(®ion->info); + bool is_large; + bool is_committed; + void* start = mi_region_info_read(info,&is_large,&is_committed); + ok = (start == NULL || (commit || !is_committed) || (*large || !is_large)); // Todo: test with one bitmap operation? + } + if (ok) { + return mi_region_alloc_blocks(region, idx, blocks, size, commit, large, p, id, tld); + } } + return true; // no error, but no success either } /* ---------------------------------------------------------------------------- diff --git a/src/options.c b/src/options.c index 1d030830..1076ce1e 100644 --- a/src/options.c +++ b/src/options.c @@ -60,7 +60,7 @@ static mi_option_desc_t options[_mi_option_last] = // the following options are experimental and not all combinations make sense. { 1, UNINIT, MI_OPTION(eager_commit) }, // note: needs to be on when eager_region_commit is enabled #ifdef _WIN32 // and BSD? - { 1, UNINIT, MI_OPTION(eager_region_commit) }, // don't commit too eagerly on windows (just for looks...) + { 0, UNINIT, MI_OPTION(eager_region_commit) }, // don't commit too eagerly on windows (just for looks...) #else { 1, UNINIT, MI_OPTION(eager_region_commit) }, #endif From a551f3abc470695335bf7368012fe401260bde56 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 27 Aug 2019 18:08:03 -0700 Subject: [PATCH 11/92] more precise commit statistics --- src/memory.c | 12 +++++++++--- src/os.c | 26 +++++++++++++++----------- src/stats.c | 1 + 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/memory.c b/src/memory.c index f53b1ec3..3a465d86 100644 --- a/src/memory.c +++ b/src/memory.c @@ -47,6 +47,7 @@ bool _mi_os_reset(void* p, size_t size, mi_stats_t* stats); bool _mi_os_unreset(void* p, size_t size, mi_stats_t* stats); void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, mi_os_tld_t* tld); bool _mi_os_is_huge_reserved(void* p); +void _mi_os_free_ex(void* p, size_t size, bool was_committed, mi_stats_t* stats); // Constants #if (MI_INTPTR_SIZE==8) @@ -179,7 +180,7 @@ static bool mi_region_commit_blocks(mem_region_t* region, size_t idx, size_t bit } if (start != NULL) { // free it if we didn't succeed to save it to some other region - _mi_os_free(start, MI_REGION_SIZE, tld->stats); + _mi_os_free_ex(start, MI_REGION_SIZE, region_commit, tld->stats); } // and continue with the memory at our index info = mi_atomic_read(®ion->info); @@ -426,6 +427,10 @@ void _mi_mem_free(void* p, size_t size, size_t id, mi_stats_t* stats) { // _mi_os_reset(p,size,stats); // _mi_os_decommit(p,size,stats); // if !is_committed } + if (!is_eager_committed) { + // adjust commit statistics as we commit again when re-using the same slot + _mi_stat_decrease(&stats->committed, mi_good_commit_size(size)); + } // TODO: should we free empty regions? currently only done _mi_mem_collect. // this frees up virtual address space which might be useful on 32-bit systems? @@ -456,9 +461,10 @@ void _mi_mem_collect(mi_stats_t* stats) { } while(m == 0 && !mi_atomic_cas_weak(®ion->map, ~((uintptr_t)0), 0 )); if (m == 0) { // on success, free the whole region (unless it was huge reserved) - void* start = mi_region_info_read(mi_atomic_read(®ion->info), NULL, NULL); + bool is_eager_committed; + void* start = mi_region_info_read(mi_atomic_read(®ion->info), NULL, &is_eager_committed); if (start != NULL && !_mi_os_is_huge_reserved(start)) { - _mi_os_free(start, MI_REGION_SIZE, stats); + _mi_os_free_ex(start, MI_REGION_SIZE, is_eager_committed, stats); } // and release mi_atomic_write(®ion->info,0); diff --git a/src/os.c b/src/os.c index 566d204d..76778123 100644 --- a/src/os.c +++ b/src/os.c @@ -170,7 +170,7 @@ void _mi_os_init() { Raw allocation on Windows (VirtualAlloc) and Unix's (mmap). ----------------------------------------------------------- */ -static bool mi_os_mem_free(void* addr, size_t size, mi_stats_t* stats) +static bool mi_os_mem_free(void* addr, size_t size, bool was_committed, mi_stats_t* stats) { if (addr == NULL || size == 0 || _mi_os_is_huge_reserved(addr)) return true; bool err = false; @@ -181,7 +181,7 @@ static bool mi_os_mem_free(void* addr, size_t size, mi_stats_t* stats) #else err = (munmap(addr, size) == -1); #endif - _mi_stat_decrease(&stats->committed, size); // TODO: what if never committed? + if (was_committed) _mi_stat_decrease(&stats->committed, size); _mi_stat_decrease(&stats->reserved, size); if (err) { #pragma warning(suppress:4996) @@ -461,7 +461,7 @@ static void* mi_os_mem_alloc_aligned(size_t size, size_t alignment, bool commit, // if not aligned, free it, overallocate, and unmap around it if (((uintptr_t)p % alignment != 0)) { - mi_os_mem_free(p, size, stats); + mi_os_mem_free(p, size, commit, stats); if (size >= (SIZE_MAX - alignment)) return NULL; // overflow size_t over_size = size + alignment; @@ -484,12 +484,12 @@ static void* mi_os_mem_alloc_aligned(size_t size, size_t alignment, bool commit, } else { // otherwise free and allocate at an aligned address in there - mi_os_mem_free(p, over_size, stats); + mi_os_mem_free(p, over_size, commit, stats); void* aligned_p = mi_align_up_ptr(p, alignment); p = mi_win_virtual_alloc(aligned_p, size, alignment, flags, false, allow_large, is_large); if (p == aligned_p) break; // success! if (p != NULL) { // should not happen? - mi_os_mem_free(p, size, stats); + mi_os_mem_free(p, size, commit, stats); p = NULL; } } @@ -504,8 +504,8 @@ static void* mi_os_mem_alloc_aligned(size_t size, size_t alignment, bool commit, size_t mid_size = _mi_align_up(size, _mi_os_page_size()); size_t post_size = over_size - pre_size - mid_size; mi_assert_internal(pre_size < over_size && post_size < over_size && mid_size >= size); - if (pre_size > 0) mi_os_mem_free(p, pre_size, stats); - if (post_size > 0) mi_os_mem_free((uint8_t*)aligned_p + mid_size, post_size, stats); + if (pre_size > 0) mi_os_mem_free(p, pre_size, commit, stats); + if (post_size > 0) mi_os_mem_free((uint8_t*)aligned_p + mid_size, post_size, commit, stats); // we can return the aligned pointer on `mmap` systems p = aligned_p; #endif @@ -526,10 +526,14 @@ void* _mi_os_alloc(size_t size, mi_stats_t* stats) { return mi_os_mem_alloc(size, 0, true, false, &is_large, stats); } -void _mi_os_free(void* p, size_t size, mi_stats_t* stats) { +void _mi_os_free_ex(void* p, size_t size, bool was_committed, mi_stats_t* stats) { if (size == 0 || p == NULL) return; size = mi_os_good_alloc_size(size, 0); - mi_os_mem_free(p, size, stats); + mi_os_mem_free(p, size, was_committed, stats); +} + +void _mi_os_free(void* p, size_t size, mi_stats_t* stats) { + _mi_os_free_ex(p, size, true, stats); } void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, mi_os_tld_t* tld) @@ -650,7 +654,7 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats) // Testing shows that for us (on `malloc-large`) MEM_RESET is 2x faster than DiscardVirtualMemory void* p = VirtualAlloc(start, csize, MEM_RESET, PAGE_READWRITE); mi_assert_internal(p == start); - #if 0 + #if 1 if (p == start) { VirtualUnlock(start,csize); // VirtualUnlock after MEM_RESET removes the memory from the working set } @@ -753,7 +757,7 @@ bool _mi_os_shrink(void* p, size_t oldsize, size_t newsize, mi_stats_t* stats) { // we cannot shrink on windows, but we can decommit return _mi_os_decommit(start, size, stats); #else - return mi_os_mem_free(start, size, stats); + return mi_os_mem_free(start, size, true, stats); #endif } diff --git a/src/stats.c b/src/stats.c index 075234b8..292bc84b 100644 --- a/src/stats.c +++ b/src/stats.c @@ -85,6 +85,7 @@ static void mi_stat_add(mi_stat_count_t* stat, const mi_stat_count_t* src, int64 mi_atomic_add64( &stat->allocated, src->allocated * unit); mi_atomic_add64( &stat->current, src->current * unit); mi_atomic_add64( &stat->freed, src->freed * unit); + // peak scores do not work across threads.. mi_atomic_add64( &stat->peak, src->peak * unit); } From 3903a10e93a3bc13976d6f84b1fc4cc1a4deecb4 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Wed, 28 Aug 2019 07:17:58 +0000 Subject: [PATCH 12/92] FreeBSD (and possibly NetBSD) build fix. --- src/os.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/os.c b/src/os.c index 0a733aa3..ee3c360a 100644 --- a/src/os.c +++ b/src/os.c @@ -261,6 +261,8 @@ static void* mi_unix_mmapx(size_t size, size_t try_alignment, int protect_flags, if (p==MAP_FAILED) p = NULL; // fall back to regular mmap } } + #else + UNUSED(try_alignment); #endif if (p==NULL) { p = mmap(NULL,size,protect_flags,flags,fd,0); From cbc392434c0fe482aebbe0163374122d94fcc4a8 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Wed, 28 Aug 2019 17:26:56 +0200 Subject: [PATCH 13/92] Add an option to disable building tests --- CMakeLists.txt | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d44b3408..0600ed5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,12 +4,13 @@ include("cmake/mimalloc-config-version.cmake") set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) -option(MI_OVERRIDE "Override the standard malloc interface" ON) -option(MI_INTERPOSE "Use interpose to override standard malloc on macOS" ON) -option(MI_SEE_ASM "Generate assembly files" OFF) -option(MI_CHECK_FULL "Use full internal invariant checking in DEBUG mode" OFF) -option(MI_USE_CXX "Use the C++ compiler to compile the library" OFF) -option(MI_SECURE "Use security mitigations (like guard pages and randomization)" OFF) +option(MI_OVERRIDE "Override the standard malloc interface" ON) +option(MI_INTERPOSE "Use interpose to override standard malloc on macOS" ON) +option(MI_SEE_ASM "Generate assembly files" OFF) +option(MI_CHECK_FULL "Use full internal invariant checking in DEBUG mode" OFF) +option(MI_USE_CXX "Use the C++ compiler to compile the library" OFF) +option(MI_SECURE "Use security mitigations (like guard pages and randomization)" OFF) +option(MI_BUILD_TESTS "Build test executables" ON) set(mi_install_dir "lib/mimalloc-${mi_version}") @@ -179,21 +180,24 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/mimalloc-obj.dir/src/static # ----------------------------------------------------------------------------- # API surface testing # ----------------------------------------------------------------------------- -add_executable(mimalloc-test-api test/test-api.c) -target_compile_definitions(mimalloc-test-api PRIVATE ${mi_defines}) -target_compile_options(mimalloc-test-api PRIVATE ${mi_cflags}) -target_include_directories(mimalloc-test-api PRIVATE include) -target_link_libraries(mimalloc-test-api PRIVATE mimalloc-static) -add_executable(mimalloc-test-stress test/test-stress.c) -target_compile_definitions(mimalloc-test-stress PRIVATE ${mi_defines}) -target_compile_options(mimalloc-test-stress PRIVATE ${mi_cflags}) -target_include_directories(mimalloc-test-stress PRIVATE include) -target_link_libraries(mimalloc-test-stress PRIVATE mimalloc-static) +if (MI_BUILD_TESTS MATCHES "ON") + add_executable(mimalloc-test-api test/test-api.c) + target_compile_definitions(mimalloc-test-api PRIVATE ${mi_defines}) + target_compile_options(mimalloc-test-api PRIVATE ${mi_cflags}) + target_include_directories(mimalloc-test-api PRIVATE include) + target_link_libraries(mimalloc-test-api PRIVATE mimalloc-static ${mi_libraries}) -enable_testing() -add_test(test_api, mimalloc-test-api) -add_test(test_stress, mimalloc-test-stress) + add_executable(mimalloc-test-stress test/test-stress.c) + target_compile_definitions(mimalloc-test-stress PRIVATE ${mi_defines}) + target_compile_options(mimalloc-test-stress PRIVATE ${mi_cflags}) + target_include_directories(mimalloc-test-stress PRIVATE include) + target_link_libraries(mimalloc-test-stress PRIVATE mimalloc-static ${mi_libraries}) + + enable_testing() + add_test(test_api, mimalloc-test-api) + add_test(test_stress, mimalloc-test-stress) +endif() # ----------------------------------------------------------------------------- # Set override properties From 9af51506a65f3597ca2b183ebcde1491e3271ed8 Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 28 Aug 2019 11:58:30 -0700 Subject: [PATCH 14/92] track commit and is_large status more precisely --- include/mimalloc-internal.h | 3 +- include/mimalloc.h | 2 ++ src/memory.c | 65 +++++++++++++++++++++++-------------- src/options.c | 2 ++ src/os.c | 15 ++++----- src/segment.c | 8 ++--- 6 files changed, 57 insertions(+), 38 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 9b3a3907..97619765 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -45,8 +45,7 @@ void* _mi_os_alloc(size_t size, mi_stats_t* stats); // to allocat void _mi_os_free(void* p, size_t size, mi_stats_t* stats); // to free thread local data // memory.c -void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, size_t* id, mi_os_tld_t* tld); -void* _mi_mem_alloc(size_t size, bool commit, bool* large, size_t* id, mi_os_tld_t* tld); +void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, size_t* id, mi_os_tld_t* tld); void _mi_mem_free(void* p, size_t size, size_t id, mi_stats_t* stats); bool _mi_mem_reset(void* p, size_t size, mi_stats_t* stats); diff --git a/include/mimalloc.h b/include/mimalloc.h index 0357d633..5cec05fa 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -225,11 +225,13 @@ typedef enum mi_option_e { mi_option_verbose, // the following options are experimental mi_option_secure, + mi_option_lazy_commit, mi_option_eager_commit, mi_option_eager_region_commit, mi_option_large_os_pages, // implies eager commit mi_option_reserve_huge_os_pages, mi_option_segment_cache, + mi_option_segment_reset, mi_option_page_reset, mi_option_cache_reset, mi_option_reset_decommits, diff --git a/src/memory.c b/src/memory.c index 3a465d86..d8cb204e 100644 --- a/src/memory.c +++ b/src/memory.c @@ -46,8 +46,9 @@ bool _mi_os_decommit(void* p, size_t size, mi_stats_t* stats); bool _mi_os_reset(void* p, size_t size, mi_stats_t* stats); bool _mi_os_unreset(void* p, size_t size, mi_stats_t* stats); void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, mi_os_tld_t* tld); -bool _mi_os_is_huge_reserved(void* p); void _mi_os_free_ex(void* p, size_t size, bool was_committed, mi_stats_t* stats); +void* _mi_os_try_alloc_from_huge_reserved(size_t size, size_t try_alignment); +bool _mi_os_is_huge_reserved(void* p); // Constants #if (MI_INTPTR_SIZE==8) @@ -137,7 +138,7 @@ Commit from a region // Returns `false` on an error (OOM); `true` otherwise. `p` and `id` are only written // if the blocks were successfully claimed so ensure they are initialized to NULL/SIZE_MAX before the call. // (not being able to claim is not considered an error so check for `p != NULL` afterwards). -static bool mi_region_commit_blocks(mem_region_t* region, size_t idx, size_t bitidx, size_t blocks, size_t size, bool commit, bool* large, void** p, size_t* id, mi_os_tld_t* tld) +static bool mi_region_commit_blocks(mem_region_t* region, size_t idx, size_t bitidx, size_t blocks, size_t size, bool* commit, bool* allow_large, void** p, size_t* id, mi_os_tld_t* tld) { size_t mask = mi_region_block_mask(blocks,bitidx); mi_assert_internal(mask != 0); @@ -149,9 +150,16 @@ static bool mi_region_commit_blocks(mem_region_t* region, size_t idx, size_t bit if (info == 0) { bool region_commit = mi_option_is_enabled(mi_option_eager_region_commit); - bool region_large = region_commit && *large; - void* start = _mi_os_alloc_aligned(MI_REGION_SIZE, MI_SEGMENT_ALIGN, region_commit, ®ion_large, tld); - *large = region_large; + bool region_large = *allow_large; + void* start = NULL; + if (region_large) { + start = _mi_os_try_alloc_from_huge_reserved(MI_REGION_SIZE, MI_SEGMENT_ALIGN); + if (start != NULL) { region_commit = true; } + } + if (start == NULL) { + start = _mi_os_alloc_aligned(MI_REGION_SIZE, MI_SEGMENT_ALIGN, region_commit, ®ion_large, tld); + } + mi_assert_internal(!(region_large && !*allow_large)); if (start == NULL) { // failure to allocate from the OS! unclaim the blocks and fail @@ -191,13 +199,22 @@ static bool mi_region_commit_blocks(mem_region_t* region, size_t idx, size_t bit // Commit the blocks to memory bool region_is_committed = false; - void* start = mi_region_info_read(info,large,®ion_is_committed); + bool region_is_large = false; + void* start = mi_region_info_read(info,®ion_is_large,®ion_is_committed); + mi_assert_internal(!(region_is_large && !*allow_large)); + void* blocks_start = (uint8_t*)start + (bitidx * MI_SEGMENT_SIZE); - if (commit && !region_is_committed) { + if (*commit && !region_is_committed) { + // ensure commit _mi_os_commit(blocks_start, mi_good_commit_size(size), tld->stats); // only commit needed size (unless using large OS pages) } + else if (!*commit && region_is_committed) { + // but even when no commit is requested, we might have committed anyway (in a huge OS page for example) + *commit = true; + } - // and return the allocation + // and return the allocation + *allow_large = region_is_large; *p = blocks_start; *id = (idx*MI_REGION_MAP_BITS) + bitidx; return true; @@ -241,7 +258,7 @@ static inline size_t mi_bsr(uintptr_t x) { // Returns `false` on an error (OOM); `true` otherwise. `p` and `id` are only written // if the blocks were successfully claimed so ensure they are initialized to NULL/SIZE_MAX before the call. // (not being able to claim is not considered an error so check for `p != NULL` afterwards). -static bool mi_region_alloc_blocks(mem_region_t* region, size_t idx, size_t blocks, size_t size, bool commit, bool* large, void** p, size_t* id, mi_os_tld_t* tld) +static bool mi_region_alloc_blocks(mem_region_t* region, size_t idx, size_t blocks, size_t size, bool* commit, bool* allow_large, void** p, size_t* id, mi_os_tld_t* tld) { mi_assert_internal(p != NULL && id != NULL); mi_assert_internal(blocks < MI_REGION_MAP_BITS); @@ -271,7 +288,7 @@ static bool mi_region_alloc_blocks(mem_region_t* region, size_t idx, size_t bloc else { // success, we claimed the bits // now commit the block memory -- this can still fail - return mi_region_commit_blocks(region, idx, bitidx, blocks, size, commit, large, p, id, tld); + return mi_region_commit_blocks(region, idx, bitidx, blocks, size, commit, allow_large, p, id, tld); } } else { @@ -294,27 +311,27 @@ static bool mi_region_alloc_blocks(mem_region_t* region, size_t idx, size_t bloc // Returns `false` on an error (OOM); `true` otherwise. `p` and `id` are only written // if the blocks were successfully claimed so ensure they are initialized to NULL/0 before the call. // (not being able to claim is not considered an error so check for `p != NULL` afterwards). -static bool mi_region_try_alloc_blocks(size_t idx, size_t blocks, size_t size, bool commit, bool* large, void** p, size_t* id, mi_os_tld_t* tld) +static bool mi_region_try_alloc_blocks(size_t idx, size_t blocks, size_t size, bool* commit, bool* allow_large, void** p, size_t* id, mi_os_tld_t* tld) { // check if there are available blocks in the region.. mi_assert_internal(idx < MI_REGION_MAX); mem_region_t* region = ®ions[idx]; uintptr_t m = mi_atomic_read_relaxed(®ion->map); if (m != MI_REGION_MAP_FULL) { // some bits are zero - bool ok = (commit || *large); // committing or allow-large is always ok + bool ok = (*commit || *allow_large); // committing or allow-large is always ok if (!ok) { // otherwise skip incompatible regions if possible. // this is not guaranteed due to multiple threads allocating at the same time but - // that's ok. In secure mode, large is never allowed so that works out; otherwise - // we might just not be able to reset/decommit individual pages sometimes. + // that's ok. In secure mode, large is never allowed for any thread, so that works out; + // otherwise we might just not be able to reset/decommit individual pages sometimes. mi_region_info_t info = mi_atomic_read_relaxed(®ion->info); bool is_large; bool is_committed; void* start = mi_region_info_read(info,&is_large,&is_committed); - ok = (start == NULL || (commit || !is_committed) || (*large || !is_large)); // Todo: test with one bitmap operation? + ok = (start == NULL || (*commit || !is_committed) || (*allow_large || !is_large)); // Todo: test with one bitmap operation? } if (ok) { - return mi_region_alloc_blocks(region, idx, blocks, size, commit, large, p, id, tld); + return mi_region_alloc_blocks(region, idx, blocks, size, commit, allow_large, p, id, tld); } } return true; // no error, but no success either @@ -326,7 +343,7 @@ static bool mi_region_try_alloc_blocks(size_t idx, size_t blocks, size_t size, b // Allocate `size` memory aligned at `alignment`. Return non NULL on success, with a given memory `id`. // (`id` is abstract, but `id = idx*MI_REGION_MAP_BITS + bitidx`) -void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, size_t* id, mi_os_tld_t* tld) +void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, size_t* id, mi_os_tld_t* tld) { mi_assert_internal(id != NULL && tld != NULL); mi_assert_internal(size > 0); @@ -336,7 +353,7 @@ void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool commit, bool* la // use direct OS allocation for huge blocks or alignment (with `id = SIZE_MAX`) if (size > MI_REGION_MAX_ALLOC_SIZE || alignment > MI_SEGMENT_ALIGN) { - return _mi_os_alloc_aligned(mi_good_commit_size(size), alignment, commit, large, tld); // round up size + return _mi_os_alloc_aligned(mi_good_commit_size(size), alignment, *commit, large, tld); // round up size } // always round size to OS page size multiple (so commit/decommit go over the entire range) @@ -371,6 +388,7 @@ void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool commit, bool* la } else { tld->region_idx = idx; // next start of search? + } mi_assert_internal( p == NULL || (uintptr_t)p % alignment == 0); @@ -378,10 +396,6 @@ void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool commit, bool* la } -// Allocate `size` memory. Return non NULL on success, with a given memory `id`. -void* _mi_mem_alloc(size_t size, bool commit, bool* large, size_t* id, mi_os_tld_t* tld) { - return _mi_mem_alloc_aligned(size,0,commit,large,id,tld); -} /* ---------------------------------------------------------------------------- Free @@ -424,8 +438,11 @@ void _mi_mem_free(void* p, size_t size, size_t id, mi_stats_t* stats) { // if the memory is reused soon. // reset: 10x slowdown on malloc-large, decommit: 17x slowdown on malloc-large if (!is_large) { - // _mi_os_reset(p,size,stats); - // _mi_os_decommit(p,size,stats); // if !is_committed + if (mi_option_is_enabled(mi_option_segment_reset)) { + _mi_os_reset(p, size, stats); + // _mi_os_decommit(p,size,stats); // if !is_eager_committed + } + // else { _mi_os_reset(p,size,stats); } } if (!is_eager_committed) { // adjust commit statistics as we commit again when re-using the same slot diff --git a/src/options.c b/src/options.c index 1076ce1e..e5c0c96a 100644 --- a/src/options.c +++ b/src/options.c @@ -58,6 +58,7 @@ static mi_option_desc_t options[_mi_option_last] = #endif // the following options are experimental and not all combinations make sense. + { 0, UNINIT, MI_OPTION(lazy_commit) }, // the first N segments per thread are lazily committed { 1, UNINIT, MI_OPTION(eager_commit) }, // note: needs to be on when eager_region_commit is enabled #ifdef _WIN32 // and BSD? { 0, UNINIT, MI_OPTION(eager_region_commit) }, // don't commit too eagerly on windows (just for looks...) @@ -67,6 +68,7 @@ static mi_option_desc_t options[_mi_option_last] = { 0, UNINIT, MI_OPTION(large_os_pages) }, // use large OS pages, use only with eager commit to prevent fragmentation of VMA's { 0, UNINIT, MI_OPTION(reserve_huge_os_pages) }, { 0, UNINIT, MI_OPTION(segment_cache) }, // cache N segments per thread + { 0, UNINIT, MI_OPTION(segment_reset) }, // reset segment memory on free { 0, UNINIT, MI_OPTION(page_reset) }, { 0, UNINIT, MI_OPTION(cache_reset) }, { 0, UNINIT, MI_OPTION(reset_decommits) }, // note: cannot enable this if secure is on diff --git a/src/os.c b/src/os.c index 76778123..58abafe0 100644 --- a/src/os.c +++ b/src/os.c @@ -35,9 +35,9 @@ terms of the MIT license. A copy of the license can be found in the file On windows initializes support for aligned allocation and large OS pages (if MIMALLOC_LARGE_OS_PAGES is true). ----------------------------------------------------------- */ -bool _mi_os_decommit(void* addr, size_t size, mi_stats_t* stats); -bool _mi_os_is_huge_reserved(void* p); -static void* mi_os_alloc_from_huge_reserved(size_t size, size_t try_alignment, bool commit); +bool _mi_os_decommit(void* addr, size_t size, mi_stats_t* stats); +bool _mi_os_is_huge_reserved(void* p); +void* _mi_os_try_alloc_from_huge_reserved(size_t size, size_t try_alignment); static void* mi_align_up_ptr(void* p, size_t alignment) { return (void*)_mi_align_up((uintptr_t)p, alignment); @@ -418,8 +418,8 @@ static void* mi_os_mem_alloc(size_t size, size_t try_alignment, bool commit, boo if (!commit) allow_large = false; void* p = NULL; - if (allow_large) { - p = mi_os_alloc_from_huge_reserved(size, try_alignment, commit); + if (commit && allow_large) { + p = _mi_os_try_alloc_from_huge_reserved(size, try_alignment); if (p != NULL) { *is_large = true; return p; @@ -781,12 +781,11 @@ bool _mi_os_is_huge_reserved(void* p) { (uint8_t*)p < (uint8_t*)mi_atomic_read_ptr(&os_huge_reserved.start) + mi_atomic_read(&os_huge_reserved.reserved)); } -static void* mi_os_alloc_from_huge_reserved(size_t size, size_t try_alignment, bool commit) +void* _mi_os_try_alloc_from_huge_reserved(size_t size, size_t try_alignment) { // only allow large aligned allocations if (size < MI_SEGMENT_SIZE || (size % MI_SEGMENT_SIZE) != 0) return NULL; - if (try_alignment > MI_SEGMENT_SIZE) return NULL; - if (!commit) return NULL; + if (try_alignment > MI_SEGMENT_SIZE) return NULL; if (mi_atomic_read_ptr(&os_huge_reserved.start)==NULL) return NULL; if (mi_atomic_read(&os_huge_reserved.used) >= mi_atomic_read(&os_huge_reserved.reserved)) return NULL; // already full diff --git a/src/segment.c b/src/segment.c index 020d53e8..441d79b8 100644 --- a/src/segment.c +++ b/src/segment.c @@ -326,8 +326,8 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, size_t page_size = (page_kind == MI_PAGE_HUGE ? segment_size : (size_t)1 << page_shift); // Try to get it from our thread local cache first - bool eager = mi_option_is_enabled(mi_option_eager_commit); - bool commit = eager || (page_kind > MI_PAGE_MEDIUM); + bool lazy = (tld->count < mi_option_get(mi_option_lazy_commit)); + bool commit = (!lazy && mi_option_is_enabled(mi_option_eager_commit)) || (page_kind > MI_PAGE_MEDIUM); bool protection_still_good = false; mi_segment_t* segment = mi_segment_cache_pop(segment_size, tld); if (segment != NULL) { @@ -353,8 +353,8 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, else { // Allocate the segment from the OS size_t memid; - bool mem_large = (eager && !mi_option_is_enabled(mi_option_secure)); // only allow large OS pages once we are no longer lazy - segment = (mi_segment_t*)_mi_mem_alloc_aligned(segment_size, MI_SEGMENT_SIZE, commit, &mem_large, &memid, os_tld); + bool mem_large = (!lazy && !mi_option_is_enabled(mi_option_secure)); // only allow large OS pages once we are no longer lazy + segment = (mi_segment_t*)_mi_mem_alloc_aligned(segment_size, MI_SEGMENT_SIZE, &commit, &mem_large, &memid, os_tld); if (segment == NULL) return NULL; // failed to allocate if (!commit) { // ensure the initial info is committed From d381fcd9fa3b70778cda8894476886645778e3da Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 28 Aug 2019 12:09:23 -0700 Subject: [PATCH 15/92] rename lazy to eager_commit_delay --- include/mimalloc.h | 4 ++-- src/options.c | 4 ++-- src/segment.c | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 5cec05fa..15d06bef 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -225,16 +225,16 @@ typedef enum mi_option_e { mi_option_verbose, // the following options are experimental mi_option_secure, - mi_option_lazy_commit, mi_option_eager_commit, mi_option_eager_region_commit, mi_option_large_os_pages, // implies eager commit mi_option_reserve_huge_os_pages, mi_option_segment_cache, - mi_option_segment_reset, mi_option_page_reset, mi_option_cache_reset, mi_option_reset_decommits, + mi_option_eager_commit_delay, + mi_option_segment_reset, mi_option_os_tag, _mi_option_last } mi_option_t; diff --git a/src/options.c b/src/options.c index e5c0c96a..8654550e 100644 --- a/src/options.c +++ b/src/options.c @@ -58,7 +58,6 @@ static mi_option_desc_t options[_mi_option_last] = #endif // the following options are experimental and not all combinations make sense. - { 0, UNINIT, MI_OPTION(lazy_commit) }, // the first N segments per thread are lazily committed { 1, UNINIT, MI_OPTION(eager_commit) }, // note: needs to be on when eager_region_commit is enabled #ifdef _WIN32 // and BSD? { 0, UNINIT, MI_OPTION(eager_region_commit) }, // don't commit too eagerly on windows (just for looks...) @@ -68,10 +67,11 @@ static mi_option_desc_t options[_mi_option_last] = { 0, UNINIT, MI_OPTION(large_os_pages) }, // use large OS pages, use only with eager commit to prevent fragmentation of VMA's { 0, UNINIT, MI_OPTION(reserve_huge_os_pages) }, { 0, UNINIT, MI_OPTION(segment_cache) }, // cache N segments per thread - { 0, UNINIT, MI_OPTION(segment_reset) }, // reset segment memory on free { 0, UNINIT, MI_OPTION(page_reset) }, { 0, UNINIT, MI_OPTION(cache_reset) }, { 0, UNINIT, MI_OPTION(reset_decommits) }, // note: cannot enable this if secure is on + { 0, UNINIT, MI_OPTION(eager_commit_delay) }, // the first N segments per thread are not eagerly committed + { 0, UNINIT, MI_OPTION(segment_reset) }, // reset segment memory on free { 100, UNINIT, MI_OPTION(os_tag) } // only apple specific for now but might serve more or less related purpose }; diff --git a/src/segment.c b/src/segment.c index 441d79b8..3777e060 100644 --- a/src/segment.c +++ b/src/segment.c @@ -326,8 +326,8 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, size_t page_size = (page_kind == MI_PAGE_HUGE ? segment_size : (size_t)1 << page_shift); // Try to get it from our thread local cache first - bool lazy = (tld->count < mi_option_get(mi_option_lazy_commit)); - bool commit = (!lazy && mi_option_is_enabled(mi_option_eager_commit)) || (page_kind > MI_PAGE_MEDIUM); + bool eager = mi_option_is_enabled(mi_option_eager_commit) && (tld->count < mi_option_get(mi_option_eager_commit_delay)); + bool commit = eager || (page_kind > MI_PAGE_MEDIUM); bool protection_still_good = false; mi_segment_t* segment = mi_segment_cache_pop(segment_size, tld); if (segment != NULL) { @@ -353,7 +353,7 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, else { // Allocate the segment from the OS size_t memid; - bool mem_large = (!lazy && !mi_option_is_enabled(mi_option_secure)); // only allow large OS pages once we are no longer lazy + bool mem_large = (eager && !mi_option_is_enabled(mi_option_secure)); // only allow large OS pages once we are no longer lazy segment = (mi_segment_t*)_mi_mem_alloc_aligned(segment_size, MI_SEGMENT_SIZE, &commit, &mem_large, &memid, os_tld); if (segment == NULL) return NULL; // failed to allocate if (!commit) { From 154fd471a111baec5afd36a66b49d9b0850d392c Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 29 Aug 2019 07:48:15 -0700 Subject: [PATCH 16/92] fix comparison warning --- src/segment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/segment.c b/src/segment.c index 3777e060..d442d521 100644 --- a/src/segment.c +++ b/src/segment.c @@ -326,7 +326,7 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, size_t page_size = (page_kind == MI_PAGE_HUGE ? segment_size : (size_t)1 << page_shift); // Try to get it from our thread local cache first - bool eager = mi_option_is_enabled(mi_option_eager_commit) && (tld->count < mi_option_get(mi_option_eager_commit_delay)); + bool eager = mi_option_is_enabled(mi_option_eager_commit) && (tld->count < (size_t)mi_option_get(mi_option_eager_commit_delay)); bool commit = eager || (page_kind > MI_PAGE_MEDIUM); bool protection_still_good = false; mi_segment_t* segment = mi_segment_cache_pop(segment_size, tld); From e8c750585390c3da5bc71f60c9ca7339bb77e20f Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 29 Aug 2019 07:49:40 -0700 Subject: [PATCH 17/92] only set has_aligned flag if really necessary --- src/alloc-aligned.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index 24f6c440..97f4319f 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -43,10 +43,10 @@ static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* heap, size_t size, size_t if (p == NULL) return NULL; // .. and align within the allocation - mi_page_set_has_aligned( _mi_ptr_page(p), true ); uintptr_t adjust = alignment - (((uintptr_t)p + offset) % alignment); mi_assert_internal(adjust % sizeof(uintptr_t) == 0); void* aligned_p = (adjust == alignment ? p : (void*)((uintptr_t)p + adjust)); + if (aligned_p != p) mi_page_set_has_aligned(_mi_ptr_page(p), true); mi_assert_internal(((uintptr_t)aligned_p + offset) % alignment == 0); mi_assert_internal( p == _mi_page_ptr_unalign(_mi_ptr_segment(aligned_p),_mi_ptr_page(aligned_p),aligned_p) ); return aligned_p; From 64c1d6de8688c5d53165a6eed5d2ed3613191863 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 29 Aug 2019 07:50:35 -0700 Subject: [PATCH 18/92] fix mi_likely branch that was marked as unlikely --- src/page.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/page.c b/src/page.c index f45f43e3..74c3d88e 100644 --- a/src/page.c +++ b/src/page.c @@ -180,7 +180,7 @@ void _mi_page_free_collect(mi_page_t* page, bool force) { // and the local free list if (page->local_free != NULL) { - if (mi_unlikely(page->free == NULL)) { + if (mi_likely(page->free == NULL)) { // usual case page->free = page->local_free; page->local_free = NULL; From 4b39c0b06edae29ca9b0bc0ca9e3938538a76a13 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 29 Aug 2019 07:55:57 -0700 Subject: [PATCH 19/92] fix eager_delay test, and allow large OS pages even without eager commit enabled --- src/segment.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/segment.c b/src/segment.c index d442d521..b03547b3 100644 --- a/src/segment.c +++ b/src/segment.c @@ -326,7 +326,8 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, size_t page_size = (page_kind == MI_PAGE_HUGE ? segment_size : (size_t)1 << page_shift); // Try to get it from our thread local cache first - bool eager = mi_option_is_enabled(mi_option_eager_commit) && (tld->count < (size_t)mi_option_get(mi_option_eager_commit_delay)); + bool eager_delay = (tld->count < (size_t)mi_option_get(mi_option_eager_commit_delay)); + bool eager = !eager_delay && mi_option_is_enabled(mi_option_eager_commit); bool commit = eager || (page_kind > MI_PAGE_MEDIUM); bool protection_still_good = false; mi_segment_t* segment = mi_segment_cache_pop(segment_size, tld); @@ -353,7 +354,7 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, else { // Allocate the segment from the OS size_t memid; - bool mem_large = (eager && !mi_option_is_enabled(mi_option_secure)); // only allow large OS pages once we are no longer lazy + bool mem_large = (!eager_delay && !mi_option_is_enabled(mi_option_secure)); // only allow large OS pages once we are no longer lazy segment = (mi_segment_t*)_mi_mem_alloc_aligned(segment_size, MI_SEGMENT_SIZE, &commit, &mem_large, &memid, os_tld); if (segment == NULL) return NULL; // failed to allocate if (!commit) { From 4819d3f78f5c803961faa94b51fbe6e7179365f7 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 29 Aug 2019 09:01:00 -0700 Subject: [PATCH 20/92] expose mi_stats_merge function --- include/mimalloc.h | 1 + src/stats.c | 34 +++++++++++++++++----------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 15d06bef..9fd455da 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -110,6 +110,7 @@ mi_decl_export size_t mi_good_size(size_t size) mi_attr_noexcept; mi_decl_export void mi_collect(bool force) mi_attr_noexcept; mi_decl_export void mi_stats_print(FILE* out) mi_attr_noexcept; mi_decl_export void mi_stats_reset(void) mi_attr_noexcept; +mi_decl_export void mi_stats_merge(void) mi_attr_noexcept; mi_decl_export int mi_version(void) mi_attr_noexcept; mi_decl_export void mi_process_init(void) mi_attr_noexcept; diff --git a/src/stats.c b/src/stats.c index 292bc84b..1ecc8b3a 100644 --- a/src/stats.c +++ b/src/stats.c @@ -11,19 +11,6 @@ terms of the MIT license. A copy of the license can be found in the file #include // memset -/* ----------------------------------------------------------- - Merge thread statistics with the main one. ------------------------------------------------------------ */ - -static void mi_stats_add(mi_stats_t* stats, const mi_stats_t* src); - -void _mi_stats_done(mi_stats_t* stats) { - if (stats == &_mi_stats_main) return; - mi_stats_add(&_mi_stats_main, stats); - memset(stats,0,sizeof(*stats)); -} - - /* ----------------------------------------------------------- Statistics operations ----------------------------------------------------------- */ @@ -294,6 +281,13 @@ static mi_stats_t* mi_stats_get_default(void) { return &heap->tld->stats; } +static void mi_stats_merge_from(mi_stats_t* stats) { + if (stats != &_mi_stats_main) { + mi_stats_add(&_mi_stats_main, stats); + memset(stats, 0, sizeof(mi_stats_t)); + } +} + void mi_stats_reset(void) mi_attr_noexcept { mi_stats_t* stats = mi_stats_get_default(); if (stats != &_mi_stats_main) { memset(stats, 0, sizeof(mi_stats_t)); } @@ -301,11 +295,17 @@ void mi_stats_reset(void) mi_attr_noexcept { mi_time_start = _mi_clock_start(); } +void mi_stats_merge(void) mi_attr_noexcept { + mi_stats_merge_from( mi_stats_get_default() ); +} + +void _mi_stats_done(mi_stats_t* stats) { // called from `mi_thread_done` + mi_stats_merge_from(stats); +} + + static void mi_stats_print_ex(mi_stats_t* stats, double secs, FILE* out) { - if (stats != &_mi_stats_main) { - mi_stats_add(&_mi_stats_main,stats); - memset(stats,0,sizeof(mi_stats_t)); - } + mi_stats_merge_from(stats); _mi_stats_print(&_mi_stats_main, secs, out); } From 7bf12c7b5fbb2aa7c156360a145545c7a45be90f Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 29 Aug 2019 09:42:50 -0700 Subject: [PATCH 21/92] make output function configurable; remove from standard includes --- include/mimalloc-internal.h | 2 +- include/mimalloc.h | 16 +++++++---- src/alloc-override-win.c | 1 + src/options.c | 57 +++++++++++++++++++++++-------------- src/stats.c | 26 ++++++++--------- 5 files changed, 61 insertions(+), 41 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 97619765..3ddb734d 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -22,7 +22,7 @@ terms of the MIT license. A copy of the license can be found in the file // "options.c" -void _mi_fprintf(FILE* out, const char* fmt, ...); +void _mi_fprintf(mi_output_fun* out, const char* fmt, ...); void _mi_error_message(const char* fmt, ...); void _mi_warning_message(const char* fmt, ...); void _mi_verbose_message(const char* fmt, ...); diff --git a/include/mimalloc.h b/include/mimalloc.h index 9fd455da..ed75f617 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -69,8 +69,8 @@ terms of the MIT license. A copy of the license can be found in the file // Includes // ------------------------------------------------------ +#include // size_t #include // bool -#include // FILE #ifdef __cplusplus extern "C" { @@ -107,19 +107,23 @@ mi_decl_export mi_decl_allocator void* mi_reallocf(void* p, size_t newsize) mi_decl_export size_t mi_usable_size(const void* p) mi_attr_noexcept; mi_decl_export size_t mi_good_size(size_t size) mi_attr_noexcept; +typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat); +mi_decl_export void mi_register_deferred_free(mi_deferred_free_fun* deferred_free) mi_attr_noexcept; + +typedef void (mi_output_fun)(const char* msg); +mi_decl_export void mi_register_output(mi_output_fun* out) mi_attr_noexcept; + mi_decl_export void mi_collect(bool force) mi_attr_noexcept; -mi_decl_export void mi_stats_print(FILE* out) mi_attr_noexcept; +mi_decl_export int mi_version(void) mi_attr_noexcept; mi_decl_export void mi_stats_reset(void) mi_attr_noexcept; mi_decl_export void mi_stats_merge(void) mi_attr_noexcept; -mi_decl_export int mi_version(void) mi_attr_noexcept; +mi_decl_export void mi_stats_print(mi_output_fun* out) mi_attr_noexcept; mi_decl_export void mi_process_init(void) mi_attr_noexcept; mi_decl_export void mi_thread_init(void) mi_attr_noexcept; mi_decl_export void mi_thread_done(void) mi_attr_noexcept; -mi_decl_export void mi_thread_stats_print(FILE* out) mi_attr_noexcept; +mi_decl_export void mi_thread_stats_print(mi_output_fun* out) mi_attr_noexcept; -typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat); -mi_decl_export void mi_register_deferred_free(mi_deferred_free_fun* deferred_free) mi_attr_noexcept; // ------------------------------------------------------ // Aligned allocation diff --git a/src/alloc-override-win.c b/src/alloc-override-win.c index 0bd05deb..dc4796ab 100644 --- a/src/alloc-override-win.c +++ b/src/alloc-override-win.c @@ -16,6 +16,7 @@ terms of the MIT license. A copy of the license can be found in the file #include #include // getenv +#include // _setmaxstdio #include // strstr diff --git a/src/options.c b/src/options.c index 8654550e..cd9b4e48 100644 --- a/src/options.c +++ b/src/options.c @@ -134,6 +134,32 @@ void mi_option_disable(mi_option_t option) { } +static void mi_out_stderr(const char* msg) { + #ifdef _WIN32 + // on windows with redirection, the C runtime cannot handle locale dependent output + // after the main thread closes so we use direct console output. + _cputs(msg); + #else + fputs(msg, stderr); + #endif +} + +// -------------------------------------------------------- +// Default output handler +// -------------------------------------------------------- + +static volatile _Atomic(mi_output_fun*) mi_out_default; // = NULL + +static mi_output_fun* mi_out_get_default(void) { + mi_output_fun* out = (mi_output_fun*)mi_atomic_read_ptr(mi_atomic_cast(void*, &mi_out_default)); + return (out == NULL ? &mi_out_stderr : out); +} + +void mi_register_output(mi_output_fun* out) mi_attr_noexcept { + mi_atomic_write_ptr(mi_atomic_cast(void*,&mi_out_default),out); +} + + // -------------------------------------------------------- // Messages // -------------------------------------------------------- @@ -146,31 +172,20 @@ static mi_decl_thread bool recurse = false; // Define our own limited `fprintf` that avoids memory allocation. // We do this using `snprintf` with a limited buffer. -static void mi_vfprintf( FILE* out, const char* prefix, const char* fmt, va_list args ) { +static void mi_vfprintf( mi_output_fun* out, const char* prefix, const char* fmt, va_list args ) { char buf[256]; if (fmt==NULL) return; if (_mi_preloading() || recurse) return; recurse = true; - if (out==NULL) out = stdout; + if (out==NULL) out = mi_out_get_default(); vsnprintf(buf,sizeof(buf)-1,fmt,args); - #ifdef _WIN32 - // on windows with redirection, the C runtime cannot handle locale dependent output - // after the main thread closes so use direct console output. - if (out==stderr) { - if (prefix != NULL) _cputs(prefix); - _cputs(buf); - } - else - #endif - { - if (prefix != NULL) fputs(prefix,out); - fputs(buf,out); - } + if (prefix != NULL) out(prefix); + out(buf); recurse = false; return; } -void _mi_fprintf( FILE* out, const char* fmt, ... ) { +void _mi_fprintf( mi_output_fun* out, const char* fmt, ... ) { va_list args; va_start(args,fmt); mi_vfprintf(out,NULL,fmt,args); @@ -181,7 +196,7 @@ void _mi_trace_message(const char* fmt, ...) { if (mi_option_get(mi_option_verbose) <= 1) return; // only with verbose level 2 or higher va_list args; va_start(args, fmt); - mi_vfprintf(stderr, "mimalloc: ", fmt, args); + mi_vfprintf(NULL, "mimalloc: ", fmt, args); va_end(args); } @@ -189,7 +204,7 @@ void _mi_verbose_message(const char* fmt, ...) { if (!mi_option_is_enabled(mi_option_verbose)) return; va_list args; va_start(args,fmt); - mi_vfprintf(stderr, "mimalloc: ", fmt, args); + mi_vfprintf(NULL, "mimalloc: ", fmt, args); va_end(args); } @@ -198,7 +213,7 @@ void _mi_error_message(const char* fmt, ...) { if (mi_atomic_increment(&error_count) > MAX_ERROR_COUNT) return; va_list args; va_start(args,fmt); - mi_vfprintf(stderr, "mimalloc: error: ", fmt, args); + mi_vfprintf(NULL, "mimalloc: error: ", fmt, args); va_end(args); mi_assert(false); } @@ -208,14 +223,14 @@ void _mi_warning_message(const char* fmt, ...) { if (mi_atomic_increment(&error_count) > MAX_ERROR_COUNT) return; va_list args; va_start(args,fmt); - mi_vfprintf(stderr, "mimalloc: warning: ", fmt, args); + mi_vfprintf(NULL, "mimalloc: warning: ", fmt, args); va_end(args); } #if MI_DEBUG void _mi_assert_fail(const char* assertion, const char* fname, unsigned line, const char* func ) { - _mi_fprintf(stderr,"mimalloc: assertion failed: at \"%s\":%u, %s\n assertion: \"%s\"\n", fname, line, (func==NULL?"":func), assertion); + _mi_fprintf(NULL,"mimalloc: assertion failed: at \"%s\":%u, %s\n assertion: \"%s\"\n", fname, line, (func==NULL?"":func), assertion); abort(); } #endif diff --git a/src/stats.c b/src/stats.c index 1ecc8b3a..37a7bde4 100644 --- a/src/stats.c +++ b/src/stats.c @@ -8,6 +8,7 @@ terms of the MIT license. A copy of the license can be found in the file #include "mimalloc-internal.h" #include "mimalloc-atomic.h" +#include // fputs, stderr #include // memset @@ -120,7 +121,7 @@ static void mi_stats_add(mi_stats_t* stats, const mi_stats_t* src) { Display statistics ----------------------------------------------------------- */ -static void mi_printf_amount(int64_t n, int64_t unit, FILE* out, const char* fmt) { +static void mi_printf_amount(int64_t n, int64_t unit, mi_output_fun* out, const char* fmt) { char buf[32]; int len = 32; const char* suffix = (unit <= 0 ? " " : "b"); @@ -141,16 +142,16 @@ static void mi_printf_amount(int64_t n, int64_t unit, FILE* out, const char* fmt } -static void mi_print_amount(int64_t n, int64_t unit, FILE* out) { +static void mi_print_amount(int64_t n, int64_t unit, mi_output_fun* out) { mi_printf_amount(n,unit,out,NULL); } -static void mi_print_count(int64_t n, int64_t unit, FILE* out) { +static void mi_print_count(int64_t n, int64_t unit, mi_output_fun* out) { if (unit==1) _mi_fprintf(out,"%11s"," "); else mi_print_amount(n,0,out); } -static void mi_stat_print(const mi_stat_count_t* stat, const char* msg, int64_t unit, FILE* out ) { +static void mi_stat_print(const mi_stat_count_t* stat, const char* msg, int64_t unit, mi_output_fun* out ) { _mi_fprintf(out,"%10s:", msg); if (unit>0) { mi_print_amount(stat->peak, unit, out); @@ -179,24 +180,24 @@ static void mi_stat_print(const mi_stat_count_t* stat, const char* msg, int64_t } } -static void mi_stat_counter_print(const mi_stat_counter_t* stat, const char* msg, FILE* out ) { +static void mi_stat_counter_print(const mi_stat_counter_t* stat, const char* msg, mi_output_fun* out ) { _mi_fprintf(out, "%10s:", msg); mi_print_amount(stat->total, -1, out); _mi_fprintf(out, "\n"); } -static void mi_stat_counter_print_avg(const mi_stat_counter_t* stat, const char* msg, FILE* out) { +static void mi_stat_counter_print_avg(const mi_stat_counter_t* stat, const char* msg, mi_output_fun* out) { double avg = (stat->count == 0 ? 0.0 : (double)stat->total / (double)stat->count); _mi_fprintf(out, "%10s: %7.1f avg\n", msg, avg); } -static void mi_print_header( FILE* out ) { +static void mi_print_header(mi_output_fun* out ) { _mi_fprintf(out,"%10s: %10s %10s %10s %10s %10s\n", "heap stats", "peak ", "total ", "freed ", "unit ", "count "); } #if MI_STAT>1 -static void mi_stats_print_bins(mi_stat_count_t* all, const mi_stat_count_t* bins, size_t max, const char* fmt, FILE* out) { +static void mi_stats_print_bins(mi_stat_count_t* all, const mi_stat_count_t* bins, size_t max, const char* fmt, mi_output_fun* out) { bool found = false; char buf[64]; for (size_t i = 0; i <= max; i++) { @@ -220,8 +221,7 @@ static void mi_stats_print_bins(mi_stat_count_t* all, const mi_stat_count_t* bin static void mi_process_info(double* utime, double* stime, size_t* peak_rss, size_t* page_faults, size_t* page_reclaim, size_t* peak_commit); -static void _mi_stats_print(mi_stats_t* stats, double secs, FILE* out) mi_attr_noexcept { - if (out == NULL) out = stderr; +static void _mi_stats_print(mi_stats_t* stats, double secs, mi_output_fun* out) mi_attr_noexcept { mi_print_header(out); #if MI_STAT>1 mi_stat_count_t normal = { 0,0,0,0 }; @@ -304,16 +304,16 @@ void _mi_stats_done(mi_stats_t* stats) { // called from `mi_thread_done` } -static void mi_stats_print_ex(mi_stats_t* stats, double secs, FILE* out) { +static void mi_stats_print_ex(mi_stats_t* stats, double secs, mi_output_fun* out) { mi_stats_merge_from(stats); _mi_stats_print(&_mi_stats_main, secs, out); } -void mi_stats_print(FILE* out) mi_attr_noexcept { +void mi_stats_print(mi_output_fun* out) mi_attr_noexcept { mi_stats_print_ex(mi_stats_get_default(),_mi_clock_end(mi_time_start),out); } -void mi_thread_stats_print(FILE* out) mi_attr_noexcept { +void mi_thread_stats_print(mi_output_fun* out) mi_attr_noexcept { _mi_stats_print(mi_stats_get_default(), _mi_clock_end(mi_time_start), out); } From 0aed30b387d55b20287943b25f8e53ead5022738 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 29 Aug 2019 23:37:51 -0700 Subject: [PATCH 22/92] update redirection modules; more robust and works on older windows versions --- bin/mimalloc-redirect.dll | Bin 46080 -> 38912 bytes bin/mimalloc-redirect.lib | Bin 3050 -> 2874 bytes bin/mimalloc-redirect32.dll | Bin 30720 -> 27136 bytes bin/mimalloc-redirect32.lib | Bin 3126 -> 2928 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/mimalloc-redirect.dll b/bin/mimalloc-redirect.dll index db15bfc1d5f0edee462ff81ee4295caf2c875364..184c71321766641c3eda60acf195611bb12178ad 100644 GIT binary patch delta 6255 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 Sb;9!o`~wqw&iDhvCH@~3OeQ)2 delta 7090 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 CdH2}> delta 5071 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 nxzIE+SpkZh8O2P3j%Fw%S@&dt04JjO1_ delta 320 zcmew$woPJ!g^!7`nF0hPa4|42@G~&5xG^xWEnr|^f5gDRy# Date: Fri, 30 Aug 2019 14:34:46 -0700 Subject: [PATCH 23/92] in verbose mode, list all options at startup --- src/options.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/options.c b/src/options.c index cd9b4e48..06d876fc 100644 --- a/src/options.c +++ b/src/options.c @@ -80,7 +80,12 @@ static void mi_option_init(mi_option_desc_t* desc); void _mi_options_init(void) { // called on process load for(int i = 0; i < _mi_option_last; i++ ) { - mi_option_get((mi_option_t)i); // initialize + mi_option_t option = (mi_option_t)i; + mi_option_get(option); // initialize + if (option != mi_option_verbose) { + mi_option_desc_t* desc = &options[option]; + _mi_verbose_message("option '%s': %ld\n", desc->name, desc->value); + } } } @@ -89,10 +94,7 @@ long mi_option_get(mi_option_t option) { mi_option_desc_t* desc = &options[option]; mi_assert(desc->option == option); // index should match the option if (mi_unlikely(desc->init == UNINIT)) { - mi_option_init(desc); - if (option != mi_option_verbose) { - _mi_verbose_message("option '%s': %ld\n", desc->name, desc->value); - } + mi_option_init(desc); } return desc->value; } From 9fc726619a182744362f07ff4f51b7660133c4d4 Mon Sep 17 00:00:00 2001 From: daan Date: Fri, 30 Aug 2019 14:37:04 -0700 Subject: [PATCH 24/92] guard against passing stdin/stderr as output --- src/options.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/options.c b/src/options.c index 06d876fc..ff0c4e03 100644 --- a/src/options.c +++ b/src/options.c @@ -150,6 +150,7 @@ static void mi_out_stderr(const char* msg) { // Default output handler // -------------------------------------------------------- +#pragma warning(suppress:4180) static volatile _Atomic(mi_output_fun*) mi_out_default; // = NULL static mi_output_fun* mi_out_get_default(void) { @@ -179,7 +180,7 @@ static void mi_vfprintf( mi_output_fun* out, const char* prefix, const char* fmt if (fmt==NULL) return; if (_mi_preloading() || recurse) return; recurse = true; - if (out==NULL) out = mi_out_get_default(); + if (out==NULL || (FILE*)out==stdout || (FILE*)out==stderr) out = mi_out_get_default(); vsnprintf(buf,sizeof(buf)-1,fmt,args); if (prefix != NULL) out(prefix); out(buf); From 0e35ec3879f885c8f5b72e96232d2d76bca93c8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlo=20Marcelo=20Arenas=20Bel=C3=B3n?= Date: Sun, 1 Sep 2019 01:06:01 -0700 Subject: [PATCH 25/92] avoid deadlock with OpenBSD --- include/mimalloc-internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 26251878..df04c1b8 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -10,7 +10,7 @@ terms of the MIT license. A copy of the license can be found in the file #include "mimalloc-types.h" -#if defined(MI_MALLOC_OVERRIDE) && defined(__APPLE__) +#if defined(MI_MALLOC_OVERRIDE) && (defined(__APPLE__) || defined(__OpenBSD__)) #define MI_TLS_RECURSE_GUARD #endif From e874844562f5176bd97c3c483ee0d1f521e5afe8 Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 1 Sep 2019 12:18:29 -0700 Subject: [PATCH 26/92] update redirection to include fixes for x86 --- bin/mimalloc-redirect.dll | Bin 38912 -> 42496 bytes bin/mimalloc-redirect32.dll | Bin 27136 -> 30720 bytes src/memory.c | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/mimalloc-redirect.dll b/bin/mimalloc-redirect.dll index 184c71321766641c3eda60acf195611bb12178ad..2f1d942d6a4db503af7cf46d61d26d44e278ffb8 100644 GIT binary patch delta 8013 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 F{}+H3dbt1q delta 6000 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 diff --git a/bin/mimalloc-redirect32.dll b/bin/mimalloc-redirect32.dll index a95be026decc91a6d86c0861433c87f9838816ac..837e96ba0b67c4f4f743e2697060afb73c1440c7 100644 GIT binary patch delta 7096 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 delta 4827 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 diff --git a/src/memory.c b/src/memory.c index d8cb204e..d6689c7a 100644 --- a/src/memory.c +++ b/src/memory.c @@ -17,7 +17,7 @@ We need this memory layer between the raw OS calls because of: to reuse memory effectively. 2. It turns out that for large objects, between 1MiB and 32MiB (?), the cost of an OS allocation/free is still (much) too expensive relative to the accesses in that - object :-( (`mallloc-large` tests this). This means we need a cheaper way to + object :-( (`malloc-large` tests this). This means we need a cheaper way to reuse memory. 3. This layer can help with a NUMA aware allocation in the future. From 136e120d51b01ffebc9752b90b9305ddb0e17a7e Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 1 Sep 2019 17:21:58 -0700 Subject: [PATCH 27/92] update redirection modules --- bin/mimalloc-redirect.dll | Bin 42496 -> 43008 bytes bin/mimalloc-redirect32.dll | Bin 30720 -> 31232 bytes test/main-override.cpp | 9 ++++++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/bin/mimalloc-redirect.dll b/bin/mimalloc-redirect.dll index 2f1d942d6a4db503af7cf46d61d26d44e278ffb8..cc3bf22f5359a77a1e3b0021d07d9ee848a62855 100644 GIT binary patch delta 6392 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 delta 6971 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 b&eIYqj+~AvRmV@ey4+oA?V(Mpo#OuhSQb+F diff --git a/bin/mimalloc-redirect32.dll b/bin/mimalloc-redirect32.dll index 837e96ba0b67c4f4f743e2697060afb73c1440c7..f82a8f5678608156dcf9abc9a4658cf3677f5ff9 100644 GIT binary patch delta 4673 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 delta 4885 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 ZYwLCOW%bSVE%omD_WG^$Bkb-V`)?)d>g50c diff --git a/test/main-override.cpp b/test/main-override.cpp index 385778c7..2cafd2cd 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -30,11 +30,18 @@ int main() { free(p1); p1 = malloc(8); char* s = mi_strdup("hello\n"); + /* + char* s = _strdup("hello\n"); + char* buf = NULL; + size_t len; + _dupenv_s(&buf,&len,"MIMALLOC_VERBOSE"); + mi_free(buf); + */ mi_free(p2); p2 = malloc(16); p1 = realloc(p1, 32); free(p1); - free(p2); + mi_free(p2); mi_free(s); Test* t = new Test(42); delete t; From e60174e836deceeaa3db533ce84a6eea66b7df2e Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 2 Sep 2019 08:51:31 -0700 Subject: [PATCH 28/92] add more targets for redirection --- bin/mimalloc-redirect.dll | Bin 43008 -> 43520 bytes bin/mimalloc-redirect32.dll | Bin 31232 -> 31232 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/mimalloc-redirect.dll b/bin/mimalloc-redirect.dll index cc3bf22f5359a77a1e3b0021d07d9ee848a62855..428ffbab718b79502f475baab1539689ea92f00b 100644 GIT binary patch delta 2565 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 R4>t*kK8h+ei!UF`{Xb&63zGl< diff --git a/bin/mimalloc-redirect32.dll b/bin/mimalloc-redirect32.dll index f82a8f5678608156dcf9abc9a4658cf3677f5ff9..84a23962437420d94356c4c8eb71710d1dddac76 100644 GIT binary patch delta 1935 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 Date: Mon, 2 Sep 2019 09:57:39 -0700 Subject: [PATCH 29/92] make output name not depend on build type capitalization (issue #144) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index eb679771..d9b6d62f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,7 +96,7 @@ if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU") endif() endif() -if(NOT(CMAKE_BUILD_TYPE MATCHES "Release|RelWithDebInfo")) +if(NOT(CMAKE_BUILD_TYPE MATCHES "Release|release|RelWithDebInfo|relwithdebinfo")) string(TOLOWER "${CMAKE_BUILD_TYPE}" build_type) set(mi_basename "mimalloc-${build_type}") else() From 31726c6554e6d0fd64411708773a61b15f4932bd Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 2 Sep 2019 10:18:34 -0700 Subject: [PATCH 30/92] fix type; fix comment --- src/alloc-override.c | 2 +- src/os.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/alloc-override.c b/src/alloc-override.c index e5eeaab2..002374bb 100644 --- a/src/alloc-override.c +++ b/src/alloc-override.c @@ -10,7 +10,7 @@ terms of the MIT license. A copy of the license can be found in the file #endif #if defined(MI_MALLOC_OVERRIDE) && defined(_WIN32) && !(defined(MI_SHARED_LIB) && defined(_DLL)) -#error "It is only possible to override "malloc" on Windows when building as a 64-bit DLL (and linking the C runtime as a DLL)" +#error "It is only possible to override "malloc" on Windows when building as a DLL (and linking the C runtime as a DLL)" #endif #if defined(MI_MALLOC_OVERRIDE) && !defined(_WIN32) diff --git a/src/os.c b/src/os.c index cd634869..2b1ed4f4 100644 --- a/src/os.c +++ b/src/os.c @@ -822,7 +822,7 @@ static void mi_os_free_huge_reserved() { */ #if !(MI_INTPTR_SIZE >= 8 && (defined(_WIN32) || defined(MI_OS_USE_MMAP))) -int mi_reserve_huge_os_pages(size_t pages, size_t max_secs) { +int mi_reserve_huge_os_pages(size_t pages, double max_secs) { return -2; // cannot allocate } #else From 6e6e8ef800e2f639f0ba0069153573eb2618d55e Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 2 Sep 2019 10:22:52 -0700 Subject: [PATCH 31/92] Update readme.md --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 9352199d..3720e5b6 100644 --- a/readme.md +++ b/readme.md @@ -57,6 +57,7 @@ Enjoy! ### Releases * 2019-08-10, `v1.0.6`: pre-release 6: various performance improvements. +* 2019-09-01, `v1.0.8`: pre-release 8: more robust windows dynamic overriding, initial huge page support. # Building From 216d75a222f8ab8aced84ca892e85fd4bab67da9 Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 2 Sep 2019 10:48:49 -0700 Subject: [PATCH 32/92] Update readme.md --- readme.md | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/readme.md b/readme.md index 3720e5b6..6da3cf76 100644 --- a/readme.md +++ b/readme.md @@ -189,11 +189,17 @@ or via environment variables. - `MIMALLOC_SHOW_ERRORS=1`: show error and warning messages. - `MIMALLOC_LARGE_OS_PAGES=1`: use large OS pages when available; for some workloads this can significantly improve performance. Use `MIMALLOC_VERBOSE` to check if the large OS pages are enabled -- usually one needs - to explicitly allow large OS pages (as on [Windows][windows-huge] and [Linux][linux-huge]). + to explicitly allow large OS pages (as on [Windows][windows-huge] and [Linux][linux-huge]). However, sometimes + the OS is very slow to reserve contiguous physical memory for large OS pages so use with care on systems that + can have fragmented memory. - `MIMALLOC_EAGER_REGION_COMMIT=1`: on Windows, commit large (256MiB) regions eagerly. On Windows, these regions show in the working set even though usually just a small part is committed to physical memory. This is why it turned off by default on Windows as it looks not good in the task manager. However, in reality it is always better to turn it on as it improves performance and has no other drawbacks. +- `MIMALLOC_RESERVE_HUGE_OS_PAGES=N`: where N is the number of 1GiB huge OS pages. This reserves the huge pages at + startup and can give quite a performance improvement on long running workloads. Usually it is better to not use + `MIMALLOC_LARGE_OS_PAGES` in combination with this setting. Just like large OS pages, use with care as reserving + contiguous physical memory can take a long time when memory is fragmented. Still experimental. [linux-huge]: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/5/html/tuning_and_optimizing_red_hat_enterprise_linux_for_oracle_9i_and_10g_databases/sect-oracle_9i_and_10g_tuning_guide-large_memory_optimization_big_pages_and_huge_pages-configuring_huge_pages_in_red_hat_enterprise_linux_4_or_5 [windows-huge]: https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/enable-the-lock-pages-in-memory-option-windows?view=sql-server-2017 @@ -243,19 +249,23 @@ Note: unfortunately, at this time, dynamic overriding on macOS seems broken but ### Windows On Windows you need to link your program explicitly with the mimalloc -DLL, and use the C-runtime library as a DLL (the `/MD` or `/MDd` switch). -To ensure the mimalloc DLL gets loaded it is easiest to insert some +DLL and use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch). +Moreover, you need to ensure the `mimalloc-redirect.dll` (or `mimalloc-redirect32.dll`) is available +in the same folder as the mimalloc DLL at runtime (as it as referred to by the mimalloc DLL). +The redirection DLL's ensure all calls to the C runtime malloc API get redirected to mimalloc. + +To ensure the mimalloc DLL is loaded at run-time it is easiest to insert some call to the mimalloc API in the `main` function, like `mi_version()` -(or use the `/INCLUDE:mi_version` switch on the linker) +(or use the `/INCLUDE:mi_version` switch on the linker). See the `mimalloc-override-test` project +for an example on how to use this. -Due to the way mimalloc intercepts the standard malloc at runtime, it is best -to link to the mimalloc import library first on the command line so it gets -loaded right after the universal C runtime DLL (`ucrtbase`). See -the `mimalloc-override-test` project for an example. +The environment variable `MIMALLOC_DISABLE_REDIRECT=1` can be used to disable dynamic +overriding at run-time. Use `MIMALLOC_VERBOSE=1` to check if mimalloc successfully redirected. -Note: the current overriding on Windows works for most programs but some programs still have -trouble -- the `dev-exp` branch contains a newer way of overriding that is more -robust; try this out if you experience troubles. +(Note: in principle, it should be possible to patch existing executables +that are linked with the dynamic C runtime (`ucrtbase.dll`) by just putting the mimalloc DLL into +the import table (and putting `mimalloc-redirect.dll` in the same folder) +Such patching can be done for example with [CFF Explorer](https://ntcore.com/?page_id=388)). ## Static override From d1bd1644d567ea48976caa151a935c1ad1cc8866 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 2 Sep 2019 13:16:52 -0700 Subject: [PATCH 33/92] support zero-initialized memory detection --- include/mimalloc-internal.h | 7 +++-- include/mimalloc-types.h | 9 ++++-- src/alloc-aligned.c | 2 +- src/alloc.c | 30 +++++++++++++++++-- src/init.c | 6 ++-- src/memory.c | 57 ++++++++++++++++++++++++------------- src/os.c | 20 +++++++------ src/page.c | 15 +++++++++- src/segment.c | 25 +++++++++++----- 9 files changed, 123 insertions(+), 48 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 3921de3a..2ef0839e 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -46,12 +46,12 @@ void* _mi_os_alloc(size_t size, mi_stats_t* stats); // to allocat void _mi_os_free(void* p, size_t size, mi_stats_t* stats); // to free thread local data // memory.c -void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, size_t* id, mi_os_tld_t* tld); +void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, bool* is_zero, size_t* id, mi_os_tld_t* tld); void _mi_mem_free(void* p, size_t size, size_t id, mi_stats_t* stats); bool _mi_mem_reset(void* p, size_t size, mi_stats_t* stats); -bool _mi_mem_unreset(void* p, size_t size, mi_stats_t* stats); -bool _mi_mem_commit(void* p, size_t size, mi_stats_t* stats); +bool _mi_mem_unreset(void* p, size_t size, bool* is_zero, mi_stats_t* stats); +bool _mi_mem_commit(void* p, size_t size, bool* is_zero, mi_stats_t* stats); bool _mi_mem_protect(void* addr, size_t size); bool _mi_mem_unprotect(void* addr, size_t size); @@ -101,6 +101,7 @@ void* _mi_heap_malloc_zero(mi_heap_t* heap, size_t size, bool zero); void* _mi_heap_realloc_zero(mi_heap_t* heap, void* p, size_t newsize, bool zero); mi_block_t* _mi_page_ptr_unalign(const mi_segment_t* segment, const mi_page_t* page, const void* p); bool _mi_free_delayed_block(mi_block_t* block); +void _mi_block_zero_init(void* p, size_t size); #if MI_DEBUG>1 bool _mi_page_is_valid(mi_page_t* page); diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index 4bf51d1d..9928f12d 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -131,9 +131,11 @@ typedef enum mi_delayed_e { // test if both are false (`value == 0`) in the `mi_free` routine. typedef union mi_page_flags_u { uint16_t value; + uint8_t full_aligned; struct { - bool in_full; - bool has_aligned; + bool in_full:1; + bool has_aligned:1; + bool is_zero; // `true` if the blocks in the free list are zero initialized }; } mi_page_flags_t; @@ -165,7 +167,8 @@ typedef struct mi_page_s { bool segment_in_use:1; // `true` if the segment allocated this page bool is_reset:1; // `true` if the page memory was reset bool is_committed:1; // `true` if the page virtual memory is committed - + bool is_zero_init:1; // `true` if the page was zero initialized + // layout like this to optimize access in `mi_malloc` and `mi_free` uint16_t capacity; // number of blocks committed, must be the first field, see `segment.c:page_clear` uint16_t reserved; // number of blocks reserved in memory diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index 97f4319f..a18ae7a5 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -33,7 +33,7 @@ static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* heap, size_t size, size_t void* p = _mi_page_malloc(heap,page,size); mi_assert_internal(p != NULL); mi_assert_internal(((uintptr_t)p + offset) % alignment == 0); - if (zero) memset(p,0,size); + if (zero) _mi_block_zero_init(p,size); return p; } } diff --git a/src/alloc.c b/src/alloc.c index afc181dd..f9bbf66c 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -33,7 +33,7 @@ extern inline void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t siz page->used++; mi_assert_internal(page->free == NULL || _mi_ptr_page(page->free) == page); #if (MI_DEBUG) - memset(block, MI_DEBUG_UNINIT, size); + if (!page->flags.is_zero) { memset(block, MI_DEBUG_UNINIT, size); } #elif (MI_SECURE) block->next = 0; #endif @@ -89,9 +89,32 @@ extern inline void* mi_malloc(size_t size) mi_attr_noexcept { return mi_heap_malloc(mi_get_default_heap(), size); } +void _mi_block_zero_init(void* p, size_t size) { + mi_assert_internal(p != NULL); + // already zero initialized memory? + if (size > 4*sizeof(void*)) { // don't bother for small sizes + mi_page_t* page = _mi_ptr_page(p); + if (page->flags.is_zero) { + ((mi_block_t*)p)->next = 0; + #if MI_DEBUG>0 + for (size_t i = 0; i < size; i++) { + if (((uint8_t*)p)[i] != 0) { + _mi_assert_fail("page not zero", __FILE__, __LINE__, "_mi_block_zero_init"); + } + } + #endif + return; // and done + } + } + // otherwise memset + memset(p, 0, size); +} + void* _mi_heap_malloc_zero(mi_heap_t* heap, size_t size, bool zero) { void* p = mi_heap_malloc(heap,size); - if (zero && p != NULL) memset(p,0,size); + if (zero && p != NULL) { + _mi_block_zero_init(p,size); + } return p; } @@ -127,6 +150,7 @@ static mi_decl_noinline void _mi_free_block_mt(mi_page_t* page, mi_block_t* bloc mi_block_set_next(page, block, page->free); page->free = block; page->used--; + page->flags.is_zero = false; _mi_segment_page_free(page,true,&heap->tld->segments); } return; @@ -254,7 +278,7 @@ void mi_free(void* p) mi_attr_noexcept // huge page stat is accounted for in `_mi_page_retire` #endif - if (mi_likely(tid == segment->thread_id && page->flags.value == 0)) { // the thread id matches and it is not a full page, nor has aligned blocks + if (mi_likely(tid == segment->thread_id && page->flags.full_aligned == 0)) { // the thread id matches and it is not a full page, nor has aligned blocks // local, and not full or aligned mi_block_t* block = (mi_block_t*)p; mi_block_set_next(page, block, page->local_free); diff --git a/src/init.c b/src/init.c index bd594378..cb5901aa 100644 --- a/src/init.c +++ b/src/init.c @@ -12,7 +12,7 @@ terms of the MIT license. A copy of the license can be found in the file // Empty page used to initialize the small free pages array const mi_page_t _mi_page_empty = { - 0, false, false, false, 0, 0, + 0, false, false, false, false, 0, 0, { 0 }, NULL, // free #if MI_SECURE @@ -352,7 +352,7 @@ void mi_thread_init(void) mi_attr_noexcept pthread_setspecific(mi_pthread_key, (void*)(_mi_thread_id()|1)); // set to a dummy value so that `mi_pthread_done` is called #endif - #if (MI_DEBUG>0) && !defined(NDEBUG) // not in release mode as that leads to crashes on Windows dynamic override + #if (MI_DEBUG>0 && !defined(_WIN32)) _mi_verbose_message("thread init: 0x%zx\n", _mi_thread_id()); #endif } @@ -367,7 +367,7 @@ void mi_thread_done(void) mi_attr_noexcept { // abandon the thread local heap if (_mi_heap_done()) return; // returns true if already ran - #if (MI_DEBUG>0) + #if (MI_DEBUG>0 && !defined(_WIN32)) if (!_mi_is_main_thread()) { _mi_verbose_message("thread done: 0x%zx\n", _mi_thread_id()); } diff --git a/src/memory.c b/src/memory.c index d6689c7a..c8b3b138 100644 --- a/src/memory.c +++ b/src/memory.c @@ -41,10 +41,10 @@ Possible issues: size_t _mi_os_large_page_size(); bool _mi_os_protect(void* addr, size_t size); bool _mi_os_unprotect(void* addr, size_t size); -bool _mi_os_commit(void* p, size_t size, mi_stats_t* stats); +bool _mi_os_commit(void* p, size_t size, bool* is_zero, mi_stats_t* stats); bool _mi_os_decommit(void* p, size_t size, mi_stats_t* stats); bool _mi_os_reset(void* p, size_t size, mi_stats_t* stats); -bool _mi_os_unreset(void* p, size_t size, mi_stats_t* stats); +bool _mi_os_unreset(void* p, size_t size, bool* is_zero, mi_stats_t* stats); void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, mi_os_tld_t* tld); void _mi_os_free_ex(void* p, size_t size, bool was_committed, mi_stats_t* stats); void* _mi_os_try_alloc_from_huge_reserved(size_t size, size_t try_alignment); @@ -86,6 +86,7 @@ static inline void* mi_region_info_read(mi_region_info_t info, bool* is_large, b typedef struct mem_region_s { volatile _Atomic(uintptr_t) map; // in-use bit per MI_SEGMENT_SIZE block volatile _Atomic(mi_region_info_t) info; // start of virtual memory area, and flags + volatile _Atomic(uintptr_t) dirty_mask; // bit per block if the contents are not zero'd } mem_region_t; @@ -138,7 +139,8 @@ Commit from a region // Returns `false` on an error (OOM); `true` otherwise. `p` and `id` are only written // if the blocks were successfully claimed so ensure they are initialized to NULL/SIZE_MAX before the call. // (not being able to claim is not considered an error so check for `p != NULL` afterwards). -static bool mi_region_commit_blocks(mem_region_t* region, size_t idx, size_t bitidx, size_t blocks, size_t size, bool* commit, bool* allow_large, void** p, size_t* id, mi_os_tld_t* tld) +static bool mi_region_commit_blocks(mem_region_t* region, size_t idx, size_t bitidx, size_t blocks, + size_t size, bool* commit, bool* allow_large, bool* is_zero, void** p, size_t* id, mi_os_tld_t* tld) { size_t mask = mi_region_block_mask(blocks,bitidx); mi_assert_internal(mask != 0); @@ -203,10 +205,19 @@ static bool mi_region_commit_blocks(mem_region_t* region, size_t idx, size_t bit void* start = mi_region_info_read(info,®ion_is_large,®ion_is_committed); mi_assert_internal(!(region_is_large && !*allow_large)); + // set dirty bits + uintptr_t m; + do { + m = mi_atomic_read(®ion->dirty_mask); + } while (!mi_atomic_cas_weak(®ion->dirty_mask, m | mask, m)); + *is_zero = ((m & mask) == 0); // no dirty bit set in our claimed range? + void* blocks_start = (uint8_t*)start + (bitidx * MI_SEGMENT_SIZE); if (*commit && !region_is_committed) { - // ensure commit - _mi_os_commit(blocks_start, mi_good_commit_size(size), tld->stats); // only commit needed size (unless using large OS pages) + // ensure commit + bool commit_zero = false; + _mi_os_commit(blocks_start, mi_good_commit_size(size), &commit_zero, tld->stats); // only commit needed size (unless using large OS pages) + if (commit_zero) *is_zero = true; } else if (!*commit && region_is_committed) { // but even when no commit is requested, we might have committed anyway (in a huge OS page for example) @@ -258,7 +269,8 @@ static inline size_t mi_bsr(uintptr_t x) { // Returns `false` on an error (OOM); `true` otherwise. `p` and `id` are only written // if the blocks were successfully claimed so ensure they are initialized to NULL/SIZE_MAX before the call. // (not being able to claim is not considered an error so check for `p != NULL` afterwards). -static bool mi_region_alloc_blocks(mem_region_t* region, size_t idx, size_t blocks, size_t size, bool* commit, bool* allow_large, void** p, size_t* id, mi_os_tld_t* tld) +static bool mi_region_alloc_blocks(mem_region_t* region, size_t idx, size_t blocks, size_t size, + bool* commit, bool* allow_large, bool* is_zero, void** p, size_t* id, mi_os_tld_t* tld) { mi_assert_internal(p != NULL && id != NULL); mi_assert_internal(blocks < MI_REGION_MAP_BITS); @@ -288,7 +300,8 @@ static bool mi_region_alloc_blocks(mem_region_t* region, size_t idx, size_t bloc else { // success, we claimed the bits // now commit the block memory -- this can still fail - return mi_region_commit_blocks(region, idx, bitidx, blocks, size, commit, allow_large, p, id, tld); + return mi_region_commit_blocks(region, idx, bitidx, blocks, + size, commit, allow_large, is_zero, p, id, tld); } } else { @@ -311,7 +324,9 @@ static bool mi_region_alloc_blocks(mem_region_t* region, size_t idx, size_t bloc // Returns `false` on an error (OOM); `true` otherwise. `p` and `id` are only written // if the blocks were successfully claimed so ensure they are initialized to NULL/0 before the call. // (not being able to claim is not considered an error so check for `p != NULL` afterwards). -static bool mi_region_try_alloc_blocks(size_t idx, size_t blocks, size_t size, bool* commit, bool* allow_large, void** p, size_t* id, mi_os_tld_t* tld) +static bool mi_region_try_alloc_blocks(size_t idx, size_t blocks, size_t size, + bool* commit, bool* allow_large, bool* is_zero, + void** p, size_t* id, mi_os_tld_t* tld) { // check if there are available blocks in the region.. mi_assert_internal(idx < MI_REGION_MAX); @@ -331,7 +346,7 @@ static bool mi_region_try_alloc_blocks(size_t idx, size_t blocks, size_t size, b ok = (start == NULL || (*commit || !is_committed) || (*allow_large || !is_large)); // Todo: test with one bitmap operation? } if (ok) { - return mi_region_alloc_blocks(region, idx, blocks, size, commit, allow_large, p, id, tld); + return mi_region_alloc_blocks(region, idx, blocks, size, commit, allow_large, is_zero, p, id, tld); } } return true; // no error, but no success either @@ -343,16 +358,19 @@ static bool mi_region_try_alloc_blocks(size_t idx, size_t blocks, size_t size, b // Allocate `size` memory aligned at `alignment`. Return non NULL on success, with a given memory `id`. // (`id` is abstract, but `id = idx*MI_REGION_MAP_BITS + bitidx`) -void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, size_t* id, mi_os_tld_t* tld) +void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, bool* is_zero, + size_t* id, mi_os_tld_t* tld) { mi_assert_internal(id != NULL && tld != NULL); mi_assert_internal(size > 0); *id = SIZE_MAX; + *is_zero = false; bool default_large = false; - if (large==NULL) large = &default_large; // ensure `large != NULL` + if (large==NULL) large = &default_large; // ensure `large != NULL` // use direct OS allocation for huge blocks or alignment (with `id = SIZE_MAX`) if (size > MI_REGION_MAX_ALLOC_SIZE || alignment > MI_SEGMENT_ALIGN) { + *is_zero = true; return _mi_os_alloc_aligned(mi_good_commit_size(size), alignment, *commit, large, tld); // round up size } @@ -370,20 +388,21 @@ void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* l size_t idx = 0; // tld->region_idx; // start at 0 to reuse low addresses? Or, use tld->region_idx to reduce contention? for (size_t visited = 0; visited < count; visited++, idx++) { if (idx >= count) idx = 0; // wrap around - if (!mi_region_try_alloc_blocks(idx, blocks, size, commit, large, &p, id, tld)) return NULL; // error + if (!mi_region_try_alloc_blocks(idx, blocks, size, commit, large, is_zero, &p, id, tld)) return NULL; // error if (p != NULL) break; } if (p == NULL) { // no free range in existing regions -- try to extend beyond the count.. but at most 4 regions for (idx = count; idx < count + 4 && idx < MI_REGION_MAX; idx++) { - if (!mi_region_try_alloc_blocks(idx, blocks, size, commit, large, &p, id, tld)) return NULL; // error + if (!mi_region_try_alloc_blocks(idx, blocks, size, commit, large, is_zero, &p, id, tld)) return NULL; // error if (p != NULL) break; } } if (p == NULL) { // we could not find a place to allocate, fall back to the os directly + *is_zero = true; p = _mi_os_alloc_aligned(size, alignment, commit, large, tld); } else { @@ -439,8 +458,8 @@ void _mi_mem_free(void* p, size_t size, size_t id, mi_stats_t* stats) { // reset: 10x slowdown on malloc-large, decommit: 17x slowdown on malloc-large if (!is_large) { if (mi_option_is_enabled(mi_option_segment_reset)) { - _mi_os_reset(p, size, stats); - // _mi_os_decommit(p,size,stats); // if !is_eager_committed + _mi_os_reset(p, size, stats); // + // _mi_os_decommit(p,size,stats); // if !is_eager_committed (and clear dirty bits) } // else { _mi_os_reset(p,size,stats); } } @@ -495,8 +514,8 @@ void _mi_mem_collect(mi_stats_t* stats) { Other -----------------------------------------------------------------------------*/ -bool _mi_mem_commit(void* p, size_t size, mi_stats_t* stats) { - return _mi_os_commit(p, size, stats); +bool _mi_mem_commit(void* p, size_t size, bool* is_zero, mi_stats_t* stats) { + return _mi_os_commit(p, size, is_zero, stats); } bool _mi_mem_decommit(void* p, size_t size, mi_stats_t* stats) { @@ -507,8 +526,8 @@ bool _mi_mem_reset(void* p, size_t size, mi_stats_t* stats) { return _mi_os_reset(p, size, stats); } -bool _mi_mem_unreset(void* p, size_t size, mi_stats_t* stats) { - return _mi_os_unreset(p, size, stats); +bool _mi_mem_unreset(void* p, size_t size, bool* is_zero, mi_stats_t* stats) { + return _mi_os_unreset(p, size, is_zero, stats); } bool _mi_mem_protect(void* p, size_t size) { diff --git a/src/os.c b/src/os.c index 2b1ed4f4..93d84365 100644 --- a/src/os.c +++ b/src/os.c @@ -585,8 +585,9 @@ static void* mi_os_page_align_area_conservative(void* addr, size_t size, size_t* // Commit/Decommit memory. // Usuelly commit is aligned liberal, while decommit is aligned conservative. // (but not for the reset version where we want commit to be conservative as well) -static bool mi_os_commitx(void* addr, size_t size, bool commit, bool conservative, mi_stats_t* stats) { +static bool mi_os_commitx(void* addr, size_t size, bool commit, bool conservative, bool* is_zero, mi_stats_t* stats) { // page align in the range, commit liberally, decommit conservative + *is_zero = false; size_t csize; void* start = mi_os_page_align_areax(conservative, addr, size, &csize); if (csize == 0 || _mi_os_is_huge_reserved(addr)) return true; @@ -600,6 +601,7 @@ static bool mi_os_commitx(void* addr, size_t size, bool commit, bool conservativ } #if defined(_WIN32) + *is_zero = true; if (commit) { void* p = VirtualAlloc(start, csize, MEM_COMMIT, PAGE_READWRITE); err = (p == start ? 0 : GetLastError()); @@ -620,16 +622,17 @@ static bool mi_os_commitx(void* addr, size_t size, bool commit, bool conservativ return (err == 0); } -bool _mi_os_commit(void* addr, size_t size, mi_stats_t* stats) { - return mi_os_commitx(addr, size, true, false /* conservative? */, stats); +bool _mi_os_commit(void* addr, size_t size, bool* is_zero, mi_stats_t* stats) { + return mi_os_commitx(addr, size, true, false /* conservative? */, is_zero, stats); } bool _mi_os_decommit(void* addr, size_t size, mi_stats_t* stats) { - return mi_os_commitx(addr, size, false, true /* conservative? */, stats); + bool is_zero; + return mi_os_commitx(addr, size, false, true /* conservative? */, &is_zero, stats); } -bool _mi_os_commit_unreset(void* addr, size_t size, mi_stats_t* stats) { - return mi_os_commitx(addr, size, true, true /* conservative? */, stats); +bool _mi_os_commit_unreset(void* addr, size_t size, bool* is_zero, mi_stats_t* stats) { + return mi_os_commitx(addr, size, true, true /* conservative? */, is_zero, stats); } @@ -698,11 +701,12 @@ bool _mi_os_reset(void* addr, size_t size, mi_stats_t* stats) { } } -bool _mi_os_unreset(void* addr, size_t size, mi_stats_t* stats) { +bool _mi_os_unreset(void* addr, size_t size, bool* is_zero, mi_stats_t* stats) { if (mi_option_is_enabled(mi_option_reset_decommits)) { - return _mi_os_commit_unreset(addr, size, stats); // re-commit it (conservatively!) + return _mi_os_commit_unreset(addr, size, is_zero, stats); // re-commit it (conservatively!) } else { + *is_zero = false; return mi_os_resetx(addr, size, false, stats); } } diff --git a/src/page.c b/src/page.c index 74c3d88e..f0f43960 100644 --- a/src/page.c +++ b/src/page.c @@ -81,6 +81,14 @@ static bool mi_page_is_valid_init(mi_page_t* page) { mi_assert_internal(mi_page_list_is_valid(page,page->free)); mi_assert_internal(mi_page_list_is_valid(page,page->local_free)); + if (page->flags.is_zero) { + for(mi_block_t* block = page->free; block != NULL; mi_block_next(page,block)) { + for (size_t i = sizeof(mi_block_t); i < page->block_size; i++) { + mi_assert_internal(0 == *((uint8_t*)block + i)); + } + } + } + mi_block_t* tfree = mi_tf_block(page->thread_free); mi_assert_internal(mi_page_list_is_valid(page, tfree)); size_t tfree_count = mi_page_list_count(page, tfree); @@ -184,6 +192,7 @@ void _mi_page_free_collect(mi_page_t* page, bool force) { // usual case page->free = page->local_free; page->local_free = NULL; + page->flags.is_zero = false; } else if (force) { // append -- only on shutdown (force) as this is a linear operation @@ -195,7 +204,8 @@ void _mi_page_free_collect(mi_page_t* page, bool force) { mi_block_set_next(page, tail, page->free); page->free = page->local_free; page->local_free = NULL; - } + page->flags.is_zero = false; + } } mi_assert_internal(!force || page->local_free == NULL); @@ -547,6 +557,8 @@ static void mi_page_extend_free(mi_heap_t* heap, mi_page_t* page, mi_stats_t* st page->capacity += (uint16_t)extend; _mi_stat_increase(&stats->page_committed, extend * page->block_size); + // extension into zero initialized memory preserves the zero'd free list + if (!page->is_zero_init) page->flags.is_zero = false; mi_assert_expensive(mi_page_is_valid_init(page)); } @@ -565,6 +577,7 @@ static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t block_size, mi #if MI_SECURE page->cookie = _mi_heap_random(heap) | 1; #endif + page->flags.is_zero = page->is_zero_init; mi_assert_internal(page->capacity == 0); mi_assert_internal(page->free == NULL); diff --git a/src/segment.c b/src/segment.c index b03547b3..68f3fb05 100644 --- a/src/segment.c +++ b/src/segment.c @@ -330,6 +330,7 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, bool eager = !eager_delay && mi_option_is_enabled(mi_option_eager_commit); bool commit = eager || (page_kind > MI_PAGE_MEDIUM); bool protection_still_good = false; + bool is_zero = false; mi_segment_t* segment = mi_segment_cache_pop(segment_size, tld); if (segment != NULL) { if (mi_option_is_enabled(mi_option_secure)) { @@ -343,23 +344,27 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, } if (!segment->mem_is_committed && page_kind > MI_PAGE_MEDIUM) { mi_assert_internal(!segment->mem_is_fixed); - _mi_mem_commit(segment, segment->segment_size, tld->stats); + _mi_mem_commit(segment, segment->segment_size, &is_zero, tld->stats); segment->mem_is_committed = true; } if (!segment->mem_is_fixed && (mi_option_is_enabled(mi_option_cache_reset) || mi_option_is_enabled(mi_option_page_reset))) { - _mi_mem_unreset(segment, segment->segment_size, tld->stats); + bool reset_zero = false; + _mi_mem_unreset(segment, segment->segment_size, &reset_zero, tld->stats); + if (reset_zero) is_zero = true; } } else { // Allocate the segment from the OS size_t memid; bool mem_large = (!eager_delay && !mi_option_is_enabled(mi_option_secure)); // only allow large OS pages once we are no longer lazy - segment = (mi_segment_t*)_mi_mem_alloc_aligned(segment_size, MI_SEGMENT_SIZE, &commit, &mem_large, &memid, os_tld); + segment = (mi_segment_t*)_mi_mem_alloc_aligned(segment_size, MI_SEGMENT_SIZE, &commit, &mem_large, &is_zero, &memid, os_tld); if (segment == NULL) return NULL; // failed to allocate if (!commit) { // ensure the initial info is committed - _mi_mem_commit(segment, info_size, tld->stats); + bool commit_zero = false; + _mi_mem_commit(segment, info_size, &commit_zero, tld->stats); + if (commit_zero) is_zero = true; } segment->memid = memid; segment->mem_is_fixed = mem_large; @@ -403,6 +408,7 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, segment->pages[i].segment_idx = i; segment->pages[i].is_reset = false; segment->pages[i].is_committed = commit; + segment->pages[i].is_zero_init = is_zero; } _mi_stat_increase(&tld->stats->page_committed, segment->segment_info_size); //fprintf(stderr,"mimalloc: alloc segment at %p\n", (void*)segment); @@ -463,12 +469,16 @@ static mi_page_t* mi_segment_find_free(mi_segment_t* segment, mi_stats_t* stats) if (!page->is_committed) { mi_assert_internal(!segment->mem_is_fixed); page->is_committed = true; - _mi_mem_commit(start,psize,stats); + bool is_zero = false; + _mi_mem_commit(start,psize,&is_zero,stats); + if (is_zero) page->is_zero_init = true; } if (page->is_reset) { mi_assert_internal(!segment->mem_is_fixed); page->is_reset = false; - _mi_mem_unreset(start, psize, stats); + bool is_zero = false; + _mi_mem_unreset(start, psize, &is_zero, stats); + if (is_zero) page->is_zero_init = true; } } return page; @@ -493,7 +503,7 @@ static void mi_segment_page_clear(mi_segment_t* segment, mi_page_t* page, mi_sta size_t inuse = page->capacity * page->block_size; _mi_stat_decrease(&stats->page_committed, inuse); _mi_stat_decrease(&stats->pages, 1); - + // reset the page memory to reduce memory pressure? if (!segment->mem_is_fixed && !page->is_reset && mi_option_is_enabled(mi_option_page_reset)) { size_t psize; @@ -503,6 +513,7 @@ static void mi_segment_page_clear(mi_segment_t* segment, mi_page_t* page, mi_sta } // zero the page data, but not the segment fields + page->is_zero_init = false; ptrdiff_t ofs = offsetof(mi_page_t,capacity); memset((uint8_t*)page + ofs, 0, sizeof(*page) - ofs); page->segment_in_use = false; From 739d11313c12b2cfbc0c31b2d03cbd0333adfbe4 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 2 Sep 2019 14:53:22 -0700 Subject: [PATCH 34/92] fix commit zero on windows --- src/alloc.c | 4 ++-- src/os.c | 3 ++- src/page.c | 14 ++++++++++---- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index f9bbf66c..ecbd58fa 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -97,8 +97,8 @@ void _mi_block_zero_init(void* p, size_t size) { if (page->flags.is_zero) { ((mi_block_t*)p)->next = 0; #if MI_DEBUG>0 - for (size_t i = 0; i < size; i++) { - if (((uint8_t*)p)[i] != 0) { + for (size_t i = 0; i < (page->block_size/sizeof(uintptr_t)); i++) { + if (((uintptr_t*)p)[i] != 0) { _mi_assert_fail("page not zero", __FILE__, __LINE__, "_mi_block_zero_init"); } } diff --git a/src/os.c b/src/os.c index 93d84365..9b5aac35 100644 --- a/src/os.c +++ b/src/os.c @@ -601,8 +601,9 @@ static bool mi_os_commitx(void* addr, size_t size, bool commit, bool conservativ } #if defined(_WIN32) - *is_zero = true; if (commit) { + // if the memory was already committed, the call succeeds but it is not zero'd + // *is_zero = true; void* p = VirtualAlloc(start, csize, MEM_COMMIT, PAGE_READWRITE); err = (p == start ? 0 : GetLastError()); } diff --git a/src/page.c b/src/page.c index f0f43960..ee8a3997 100644 --- a/src/page.c +++ b/src/page.c @@ -81,13 +81,17 @@ static bool mi_page_is_valid_init(mi_page_t* page) { mi_assert_internal(mi_page_list_is_valid(page,page->free)); mi_assert_internal(mi_page_list_is_valid(page,page->local_free)); + #if 0 if (page->flags.is_zero) { for(mi_block_t* block = page->free; block != NULL; mi_block_next(page,block)) { - for (size_t i = sizeof(mi_block_t); i < page->block_size; i++) { - mi_assert_internal(0 == *((uint8_t*)block + i)); + for (size_t i = 1; i < (page->block_size/sizeof(uintptr_t)); i++) { + if (((uintptr_t*)block)[i] != 0) { + return false; + } } } } + #endif mi_block_t* tfree = mi_tf_block(page->thread_free); mi_assert_internal(mi_page_list_is_valid(page, tfree)); @@ -558,7 +562,9 @@ static void mi_page_extend_free(mi_heap_t* heap, mi_page_t* page, mi_stats_t* st _mi_stat_increase(&stats->page_committed, extend * page->block_size); // extension into zero initialized memory preserves the zero'd free list - if (!page->is_zero_init) page->flags.is_zero = false; + if (!page->is_zero_init) { + page->flags.is_zero = false; + } mi_assert_expensive(mi_page_is_valid_init(page)); } @@ -577,7 +583,7 @@ static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t block_size, mi #if MI_SECURE page->cookie = _mi_heap_random(heap) | 1; #endif - page->flags.is_zero = page->is_zero_init; + page->flags.is_zero = page->is_zero_init; mi_assert_internal(page->capacity == 0); mi_assert_internal(page->free == NULL); From 7a9136810823182054764790232a571e3f26126f Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 3 Sep 2019 10:11:24 -0700 Subject: [PATCH 35/92] pass page to block_zero_init and extend to block_size --- include/mimalloc-internal.h | 21 ++++++++++++++++++--- src/alloc-aligned.c | 15 +++++++++++---- src/alloc.c | 33 +++++++++++++++------------------ src/page.c | 8 ++------ 4 files changed, 46 insertions(+), 31 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 2ef0839e..de77f3b5 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -20,7 +20,6 @@ terms of the MIT license. A copy of the license can be found in the file #define mi_trace_message(...) #endif - // "options.c" void _mi_fputs(mi_output_fun* out, const char* prefix, const char* message); void _mi_fprintf(mi_output_fun* out, const char* fmt, ...); @@ -101,7 +100,7 @@ void* _mi_heap_malloc_zero(mi_heap_t* heap, size_t size, bool zero); void* _mi_heap_realloc_zero(mi_heap_t* heap, void* p, size_t newsize, bool zero); mi_block_t* _mi_page_ptr_unalign(const mi_segment_t* segment, const mi_page_t* page, const void* p); bool _mi_free_delayed_block(mi_block_t* block); -void _mi_block_zero_init(void* p, size_t size); +void _mi_block_zero_init(const mi_page_t* page, void* p, size_t size); #if MI_DEBUG>1 bool _mi_page_is_valid(mi_page_t* page); @@ -182,6 +181,14 @@ static inline uintptr_t _mi_align_up(uintptr_t sz, size_t alignment) { } } +// Is memory zero initialized? +static inline bool mi_mem_is_zero(void* p, size_t size) { + for (size_t i = 0; i < size; i++) { + if (((uint8_t*)p)[i] != 0) return false; + } + return true; +} + // Align a byte size to a size in _machine words_, // i.e. byte size == `wsize*sizeof(void*)`. static inline size_t _mi_wsize_from_size(size_t size) { @@ -189,6 +196,11 @@ static inline size_t _mi_wsize_from_size(size_t size) { return (size + sizeof(uintptr_t) - 1) / sizeof(uintptr_t); } + +/* ----------------------------------------------------------- + The thread local default heap +----------------------------------------------------------- */ + extern const mi_heap_t _mi_heap_empty; // read-only empty heap, initial value of the thread local default heap extern mi_heap_t _mi_heap_main; // statically allocated main backing heap extern bool _mi_process_is_initialized; @@ -220,6 +232,10 @@ static inline bool mi_heap_is_initialized(mi_heap_t* heap) { return (heap != &_mi_heap_empty); } +/* ----------------------------------------------------------- + Pages +----------------------------------------------------------- */ + static inline mi_page_t* _mi_heap_get_free_small_page(mi_heap_t* heap, size_t size) { mi_assert_internal(size <= MI_SMALL_SIZE_MAX); return heap->pages_free_direct[_mi_wsize_from_size(size)]; @@ -230,7 +246,6 @@ static inline mi_page_t* _mi_get_free_small_page(size_t size) { return _mi_heap_get_free_small_page(mi_get_default_heap(), size); } - // Segment that contains the pointer static inline mi_segment_t* _mi_ptr_segment(const void* p) { // mi_assert_internal(p != NULL); diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index a18ae7a5..c0ed2ece 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -33,7 +33,7 @@ static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* heap, size_t size, size_t void* p = _mi_page_malloc(heap,page,size); mi_assert_internal(p != NULL); mi_assert_internal(((uintptr_t)p + offset) % alignment == 0); - if (zero) _mi_block_zero_init(p,size); + if (zero) _mi_block_zero_init(page,p,size); return p; } } @@ -117,9 +117,16 @@ static void* mi_heap_realloc_zero_aligned_at(mi_heap_t* heap, void* p, size_t ne void* newp = mi_heap_malloc_aligned_at(heap,newsize,alignment,offset); if (newp != NULL) { if (zero && newsize > size) { - // also set last word in the previous allocation to zero to ensure any padding is zero-initialized - size_t start = (size >= sizeof(intptr_t) ? size - sizeof(intptr_t) : 0); - memset((uint8_t*)newp + start, 0, newsize - start); + const mi_page_t* page = _mi_ptr_page(newp); + if (page->flags.is_zero) { + // already zero initialized + mi_assert_expensive(mi_mem_is_zero(newp,newsize)); + } + else { + // also set last word in the previous allocation to zero to ensure any padding is zero-initialized + size_t start = (size >= sizeof(intptr_t) ? size - sizeof(intptr_t) : 0); + memset((uint8_t*)newp + start, 0, newsize - start); + } } memcpy(newp, p, (newsize > size ? size : newsize)); mi_free(p); // only free if successful diff --git a/src/alloc.c b/src/alloc.c index ecbd58fa..d8387178 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -89,31 +89,28 @@ extern inline void* mi_malloc(size_t size) mi_attr_noexcept { return mi_heap_malloc(mi_get_default_heap(), size); } -void _mi_block_zero_init(void* p, size_t size) { +void _mi_block_zero_init(const mi_page_t* page, void* p, size_t size) { + // note: we need to initialize the whole block to zero, not just size + // or the recalloc/rezalloc functions cannot safely expand in place (see issue #63) + UNUSED(size); mi_assert_internal(p != NULL); - // already zero initialized memory? - if (size > 4*sizeof(void*)) { // don't bother for small sizes - mi_page_t* page = _mi_ptr_page(p); - if (page->flags.is_zero) { - ((mi_block_t*)p)->next = 0; - #if MI_DEBUG>0 - for (size_t i = 0; i < (page->block_size/sizeof(uintptr_t)); i++) { - if (((uintptr_t*)p)[i] != 0) { - _mi_assert_fail("page not zero", __FILE__, __LINE__, "_mi_block_zero_init"); - } - } - #endif - return; // and done - } + mi_assert_internal(size > 0 && page->block_size >= size); + mi_assert_internal(_mi_ptr_page(p)==page); + if (page->flags.is_zero) { + // already zero initialized memory? + ((mi_block_t*)p)->next = 0; // clear the free list pointer + mi_assert_expensive(mi_mem_is_zero(p,page->block_size)); + } + else { + // otherwise memset + memset(p, 0, page->block_size); } - // otherwise memset - memset(p, 0, size); } void* _mi_heap_malloc_zero(mi_heap_t* heap, size_t size, bool zero) { void* p = mi_heap_malloc(heap,size); if (zero && p != NULL) { - _mi_block_zero_init(p,size); + _mi_block_zero_init(_mi_ptr_page(p),p,size); // todo: can we avoid getting the page again? } return p; } diff --git a/src/page.c b/src/page.c index ee8a3997..1288fd83 100644 --- a/src/page.c +++ b/src/page.c @@ -81,14 +81,10 @@ static bool mi_page_is_valid_init(mi_page_t* page) { mi_assert_internal(mi_page_list_is_valid(page,page->free)); mi_assert_internal(mi_page_list_is_valid(page,page->local_free)); - #if 0 + #if MI_DEBUG>3 // generally too expensive to check this if (page->flags.is_zero) { for(mi_block_t* block = page->free; block != NULL; mi_block_next(page,block)) { - for (size_t i = 1; i < (page->block_size/sizeof(uintptr_t)); i++) { - if (((uintptr_t*)block)[i] != 0) { - return false; - } - } + mi_assert_expensive(mi_mem_is_zero(block + 1, page->block_size - sizeof(mi_block_t))); } } #endif From a6a956c5890c3037f261a84d9f2d2bbbb70fc308 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 3 Sep 2019 10:57:39 -0700 Subject: [PATCH 36/92] add back zero initialized re-allocation --- include/mimalloc.h | 55 +++++++++++++++++++++++++++++++++------------ src/alloc-aligned.c | 42 +++++++++++++++++++++++++++------- src/alloc-posix.c | 18 +++++++-------- src/alloc.c | 21 +++++++++++++++++ 4 files changed, 104 insertions(+), 32 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index ed75f617..cd8c33a5 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -100,10 +100,11 @@ mi_decl_export mi_decl_allocator void* mi_malloc_small(size_t size) mi_attr_no mi_decl_export mi_decl_allocator void* mi_zalloc_small(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1); mi_decl_export mi_decl_allocator void* mi_zalloc(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1); -mi_decl_export mi_decl_allocator void* mi_mallocn(size_t count, size_t size) mi_attr_noexcept; -mi_decl_export mi_decl_allocator void* mi_reallocn(void* p, size_t count, size_t size) mi_attr_noexcept; +mi_decl_export mi_decl_allocator void* mi_mallocn(size_t count, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(1,2); +mi_decl_export mi_decl_allocator void* mi_reallocn(void* p, size_t count, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2,3); mi_decl_export mi_decl_allocator void* mi_reallocf(void* p, size_t newsize) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2); + mi_decl_export size_t mi_usable_size(const void* p) mi_attr_noexcept; mi_decl_export size_t mi_good_size(size_t size) mi_attr_noexcept; @@ -125,9 +126,11 @@ mi_decl_export void mi_thread_done(void) mi_attr_noexcept; mi_decl_export void mi_thread_stats_print(mi_output_fun* out) mi_attr_noexcept; -// ------------------------------------------------------ +// ------------------------------------------------------------------------------------- // Aligned allocation -// ------------------------------------------------------ +// Note that `alignment` always follows `size` for consistency with unaligned +// allocation, but unfortunately this differs from `posix_memalign` and `aligned_alloc`. +// ------------------------------------------------------------------------------------- mi_decl_export mi_decl_allocator void* mi_malloc_aligned(size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1); mi_decl_export mi_decl_allocator void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1); @@ -177,6 +180,30 @@ mi_decl_export mi_decl_allocator void* mi_heap_realloc_aligned(mi_heap_t* heap, mi_decl_export mi_decl_allocator void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(3); +// -------------------------------------------------------------------------------- +// Zero initialized re-allocation. +// Only valid on memory that was originally allocated with zero initialization too. +// e.g. `mi_calloc`, `mi_zalloc`, `mi_zalloc_aligned` etc. +// see +// -------------------------------------------------------------------------------- + +mi_decl_export mi_decl_allocator void* mi_rezalloc(void* p, size_t newsize) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2); +mi_decl_export mi_decl_allocator void* mi_recalloc(void* p, size_t newcount, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2,3); + +mi_decl_export mi_decl_allocator void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2); +mi_decl_export mi_decl_allocator void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2); +mi_decl_export mi_decl_allocator void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2,3); +mi_decl_export mi_decl_allocator void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2,3); + +mi_decl_export mi_decl_allocator void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(3); +mi_decl_export mi_decl_allocator void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(3,4); + +mi_decl_export mi_decl_allocator void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(3); +mi_decl_export mi_decl_allocator void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(3); +mi_decl_export mi_decl_allocator void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(3,4); +mi_decl_export mi_decl_allocator void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(3,4); + + // ------------------------------------------------------ // Analysis // ------------------------------------------------------ @@ -211,12 +238,14 @@ mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs) mi_a #define mi_calloc_tp(tp,n) ((tp*)mi_calloc(n,sizeof(tp))) #define mi_mallocn_tp(tp,n) ((tp*)mi_mallocn(n,sizeof(tp))) #define mi_reallocn_tp(p,tp,n) ((tp*)mi_reallocn(p,n,sizeof(tp))) +#define mi_recalloc_tp(p,tp,n) ((tp*)mi_recalloc(p,n,sizeof(tp))) #define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp))) #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp))) #define mi_heap_calloc_tp(hp,tp,n) ((tp*)mi_heap_calloc(hp,n,sizeof(tp))) #define mi_heap_mallocn_tp(hp,tp,n) ((tp*)mi_heap_mallocn(hp,n,sizeof(tp))) #define mi_heap_reallocn_tp(hp,tp,n) ((tp*)mi_heap_reallocn(hp,n,sizeof(tp))) +#define mi_heap_recalloc_tp(hp,tp,n) ((tp*)mi_heap_recalloc(hp,n,sizeof(tp))) // ------------------------------------------------------ @@ -266,18 +295,16 @@ mi_decl_export size_t mi_malloc_usable_size(const void *p) mi_attr_noexcept; mi_decl_export void mi_cfree(void* p) mi_attr_noexcept; mi_decl_export void* mi__expand(void* p, size_t newsize) mi_attr_noexcept; -mi_decl_export int mi_posix_memalign(void** p, size_t alignment, size_t size) mi_attr_noexcept; -mi_decl_export int mi__posix_memalign(void** p, size_t alignment, size_t size) mi_attr_noexcept; -mi_decl_export mi_decl_allocator void* mi_memalign(size_t alignment, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2); -mi_decl_export mi_decl_allocator void* mi_valloc(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1); +mi_decl_export int mi_posix_memalign(void** p, size_t alignment, size_t size) mi_attr_noexcept; +mi_decl_export void* mi_memalign(size_t alignment, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2); +mi_decl_export void* mi_valloc(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1); -mi_decl_export mi_decl_allocator void* mi_pvalloc(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1); -mi_decl_export mi_decl_allocator void* mi_aligned_alloc(size_t alignment, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2); -mi_decl_export mi_decl_allocator void* mi_reallocarray(void* p, size_t count, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2,3); +mi_decl_export void* mi_pvalloc(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1); +mi_decl_export void* mi_aligned_alloc(size_t alignment, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2); +mi_decl_export void* mi_reallocarray(void* p, size_t count, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2,3); -mi_decl_export void* mi_recalloc(void* p, size_t count, size_t size) mi_attr_noexcept; -mi_decl_export void* mi_aligned_recalloc(void* p, size_t size, size_t newcount, size_t alignment) mi_attr_noexcept; -mi_decl_export void* mi_aligned_offset_recalloc(void* p, size_t size, size_t newcount, size_t alignment, size_t offset) mi_attr_noexcept; +mi_decl_export void* mi_aligned_recalloc(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept; +mi_decl_export void* mi_aligned_offset_recalloc(void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept; mi_decl_export unsigned short* mi_wcsdup(const unsigned short* s) mi_attr_noexcept; mi_decl_export unsigned char* mi_mbsdup(const unsigned char* s) mi_attr_noexcept; diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index c0ed2ece..3dc0fb28 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -150,6 +150,26 @@ void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t a return mi_heap_realloc_zero_aligned(heap,p,newsize,alignment,false); } +void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { + return mi_heap_realloc_zero_aligned_at(heap, p, newsize, alignment, offset, true); +} + +void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment) mi_attr_noexcept { + return mi_heap_realloc_zero_aligned(heap, p, newsize, alignment, true); +} + +void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { + size_t total; + if (mi_mul_overflow(newcount, size, &total)) return NULL; + return mi_heap_rezalloc_aligned_at(heap, p, total, alignment, offset); +} + +void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept { + size_t total; + if (mi_mul_overflow(newcount, size, &total)) return NULL; + return mi_heap_rezalloc_aligned(heap, p, total, alignment); +} + void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_realloc_aligned_at(mi_get_default_heap(), p, newsize, alignment, offset); } @@ -158,13 +178,19 @@ void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment) mi_attr_noex return mi_heap_realloc_aligned(mi_get_default_heap(), p, newsize, alignment); } -void* mi_aligned_offset_recalloc(void* p, size_t size, size_t newcount, size_t alignment, size_t offset) mi_attr_noexcept { - size_t newsize; - if (mi_mul_overflow(size,newcount,&newsize)) return NULL; - return mi_heap_realloc_zero_aligned_at(mi_get_default_heap(), p, newsize, alignment, offset, true ); +void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { + return mi_heap_rezalloc_aligned_at(mi_get_default_heap(), p, newsize, alignment, offset); } -void* mi_aligned_recalloc(void* p, size_t size, size_t newcount, size_t alignment) mi_attr_noexcept { - size_t newsize; - if (mi_mul_overflow(size, newcount, &newsize)) return NULL; - return mi_heap_realloc_zero_aligned(mi_get_default_heap(), p, newsize, alignment, true ); + +void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment) mi_attr_noexcept { + return mi_heap_rezalloc_aligned(mi_get_default_heap(), p, newsize, alignment); } + +void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { + return mi_heap_recalloc_aligned_at(mi_get_default_heap(), p, newcount, size, alignment, offset); +} + +void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept { + return mi_heap_recalloc_aligned(mi_get_default_heap(), p, newcount, size, alignment); +} + diff --git a/src/alloc-posix.c b/src/alloc-posix.c index 672b73b3..9ffebe4f 100644 --- a/src/alloc-posix.c +++ b/src/alloc-posix.c @@ -55,10 +55,6 @@ int mi_posix_memalign(void** p, size_t alignment, size_t size) mi_attr_noexcept return 0; } -int mi__posix_memalign(void** p, size_t alignment, size_t size) mi_attr_noexcept { - return mi_posix_memalign(p, alignment, size); -} - void* mi_memalign(size_t alignment, size_t size) mi_attr_noexcept { return mi_malloc_aligned(size, alignment); } @@ -90,12 +86,6 @@ void* mi__expand(void* p, size_t newsize) mi_attr_noexcept { // Microsoft return res; } -void* mi_recalloc(void* p, size_t count, size_t size) mi_attr_noexcept { // Microsoft - size_t total; - if (mi_mul_overflow(count, size, &total)) return NULL; - return _mi_heap_realloc_zero(mi_get_default_heap(), p, total, true); -} - unsigned short* mi_wcsdup(const unsigned short* s) mi_attr_noexcept { if (s==NULL) return NULL; size_t len; @@ -149,3 +139,11 @@ int mi_wdupenv_s(unsigned short** buf, size_t* size, const unsigned short* name) return 0; #endif } + +void* mi_aligned_offset_recalloc(void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { // Microsoft + return mi_recalloc_aligned_at(p, newcount, size, alignment, offset); +} + +void* mi_aligned_recalloc(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept { // Microsoft + return mi_recalloc_aligned(p, newcount, size, alignment); +} diff --git a/src/alloc.c b/src/alloc.c index d8387178..9d50bf9f 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -426,6 +426,17 @@ void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcep return newp; } +void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept { + return _mi_heap_realloc_zero(heap, p, newsize, true); +} + +void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t count, size_t size) mi_attr_noexcept { + size_t total; + if (mi_mul_overflow(count, size, &total)) return NULL; + return mi_heap_rezalloc(heap, p, total); +} + + void* mi_realloc(void* p, size_t newsize) mi_attr_noexcept { return mi_heap_realloc(mi_get_default_heap(),p,newsize); } @@ -439,6 +450,16 @@ void* mi_reallocf(void* p, size_t newsize) mi_attr_noexcept { return mi_heap_reallocf(mi_get_default_heap(),p,newsize); } +void* mi_rezalloc(void* p, size_t newsize) mi_attr_noexcept { + return mi_heap_rezalloc(mi_get_default_heap(), p, newsize); +} + +void* mi_recalloc(void* p, size_t count, size_t size) mi_attr_noexcept { + return mi_heap_recalloc(mi_get_default_heap(), p, count, size); +} + + + // ------------------------------------------------------ // strdup, strndup, and realpath // ------------------------------------------------------ From aea21486ddcaa51afacd09d5491c76304f545c80 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 3 Sep 2019 18:20:56 -0700 Subject: [PATCH 37/92] fix regions_count tracking in case of concurrent region allocations --- src/memory.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/memory.c b/src/memory.c index c8b3b138..9ad49cca 100644 --- a/src/memory.c +++ b/src/memory.c @@ -184,6 +184,7 @@ static bool mi_region_commit_blocks(mem_region_t* region, size_t idx, size_t bit // note: we don't need to increment the region count, this will happen on another allocation for(size_t i = 1; i <= 4 && idx + i < MI_REGION_MAX; i++) { if (mi_atomic_cas_strong(®ions[idx+i].info, info, 0)) { + mi_atomic_increment(®ions_count); start = NULL; break; } @@ -204,6 +205,7 @@ static bool mi_region_commit_blocks(mem_region_t* region, size_t idx, size_t bit bool region_is_large = false; void* start = mi_region_info_read(info,®ion_is_large,®ion_is_committed); mi_assert_internal(!(region_is_large && !*allow_large)); + mi_assert_internal(start!=NULL); // set dirty bits uintptr_t m; @@ -225,6 +227,7 @@ static bool mi_region_commit_blocks(mem_region_t* region, size_t idx, size_t bit } // and return the allocation + mi_assert_internal(blocks_start != NULL); *allow_large = region_is_large; *p = blocks_start; *id = (idx*MI_REGION_MAP_BITS) + bitidx; @@ -278,6 +281,7 @@ static bool mi_region_alloc_blocks(mem_region_t* region, size_t idx, size_t bloc const uintptr_t mask = mi_region_block_mask(blocks, 0); const size_t bitidx_max = MI_REGION_MAP_BITS - blocks; uintptr_t map = mi_atomic_read(®ion->map); + if (map==MI_REGION_MAP_FULL) return true; #ifdef MI_HAVE_BITSCAN size_t bitidx = mi_bsf(~map); // quickly find the first zero bit if possible @@ -393,8 +397,8 @@ void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* l } if (p == NULL) { - // no free range in existing regions -- try to extend beyond the count.. but at most 4 regions - for (idx = count; idx < count + 4 && idx < MI_REGION_MAX; idx++) { + // no free range in existing regions -- try to extend beyond the count.. but at most 8 regions + for (idx = count; idx < count + 8 && idx < MI_REGION_MAX; idx++) { if (!mi_region_try_alloc_blocks(idx, blocks, size, commit, large, is_zero, &p, id, tld)) return NULL; // error if (p != NULL) break; } @@ -402,12 +406,12 @@ void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* l if (p == NULL) { // we could not find a place to allocate, fall back to the os directly + _mi_warning_message("unable to allocate from region: size %zu\n", size); *is_zero = true; p = _mi_os_alloc_aligned(size, alignment, commit, large, tld); } else { - tld->region_idx = idx; // next start of search? - + tld->region_idx = idx; // next start of search? currently not used as we use first-fit } mi_assert_internal( p == NULL || (uintptr_t)p % alignment == 0); From 3c563816c0d13b770bacb4336003e9d9d64ab8b2 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 3 Sep 2019 18:25:01 -0700 Subject: [PATCH 38/92] read regions count on every loop iteration --- src/memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/memory.c b/src/memory.c index 9ad49cca..338b1ba3 100644 --- a/src/memory.c +++ b/src/memory.c @@ -398,7 +398,7 @@ void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* l if (p == NULL) { // no free range in existing regions -- try to extend beyond the count.. but at most 8 regions - for (idx = count; idx < count + 8 && idx < MI_REGION_MAX; idx++) { + for (idx = count; idx < mi_atomic_read_relaxed(®ions_count) + 8 && idx < MI_REGION_MAX; idx++) { if (!mi_region_try_alloc_blocks(idx, blocks, size, commit, large, is_zero, &p, id, tld)) return NULL; // error if (p != NULL) break; } From b69a4b52c02475af35a3b213abb352584fc05009 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Wed, 4 Sep 2019 12:02:16 +0200 Subject: [PATCH 39/92] Fix #147: provide CMake option for alternate TLS mechanism This allows use of dlopen() with mimalloc on Unix. --- CMakeLists.txt | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0600ed5d..8a4f871e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,13 +4,14 @@ include("cmake/mimalloc-config-version.cmake") set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) -option(MI_OVERRIDE "Override the standard malloc interface" ON) -option(MI_INTERPOSE "Use interpose to override standard malloc on macOS" ON) -option(MI_SEE_ASM "Generate assembly files" OFF) -option(MI_CHECK_FULL "Use full internal invariant checking in DEBUG mode" OFF) -option(MI_USE_CXX "Use the C++ compiler to compile the library" OFF) -option(MI_SECURE "Use security mitigations (like guard pages and randomization)" OFF) -option(MI_BUILD_TESTS "Build test executables" ON) +option(MI_OVERRIDE "Override the standard malloc interface" ON) +option(MI_INTERPOSE "Use interpose to override standard malloc on macOS" ON) +option(MI_SEE_ASM "Generate assembly files" OFF) +option(MI_CHECK_FULL "Use full internal invariant checking in DEBUG mode" OFF) +option(MI_USE_CXX "Use the C++ compiler to compile the library" OFF) +option(MI_SECURE "Use security mitigations (like guard pages and randomization)" OFF) +option(MI_LOCAL_DYNAMIC_TLS "Use slightly slower, dlopen-compatible TLS mechanism (Unix)" OFF) +option(MI_BUILD_TESTS "Build test executables" ON) set(mi_install_dir "lib/mimalloc-${mi_version}") @@ -84,7 +85,12 @@ endif() # Compiler flags if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU") - list(APPEND mi_cflags -Wall -Wextra -Wno-unknown-pragmas -ftls-model=initial-exec) + list(APPEND mi_cflags -Wall -Wextra -Wno-unknown-pragmas) + if(MI_LOCAL_DYNAMIC_TLS MATCHES "ON") + list(APPEND mi_cflags -ftls-model=local-dynamic) + else() + list(APPEND mi_cflags -ftls-model=initial-exec) + endif() if(CMAKE_C_COMPILER_ID MATCHES "GNU") list(APPEND mi_cflags -Wno-invalid-memory-model) list(APPEND mi_cflags -fvisibility=hidden) From 6c43ae2bde1c9c0843c77c87feb316e200ac1deb Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 4 Sep 2019 12:00:41 -0700 Subject: [PATCH 40/92] add later thread-done invokation; add mi_is_redirected call --- bin/mimalloc-redirect.dll | Bin 43520 -> 43520 bytes bin/mimalloc-redirect32.dll | Bin 31232 -> 31744 bytes include/mimalloc.h | 2 ++ src/init.c | 20 ++++++++++++++++---- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/bin/mimalloc-redirect.dll b/bin/mimalloc-redirect.dll index 428ffbab718b79502f475baab1539689ea92f00b..45e0fb4843752d1ecaa1cac4c18a485e4caabf56 100644 GIT binary patch delta 3053 zcmbtWeN+_J6@N3Z?k?=IeC>*eu)r*=BDz5MQiw|fI*A~g1TEEAz%07P6eu5!Q4^qw zk!&^*pJ|VYwU8>b+9bqj3F(RH#u$SH6V#AHPfiu>X|sfolC;S&X+7KDn;kI6e>>;g z&-c6c-FM%6Gt>4F-}VuIuz(xyDlDma|KFBJPV~*vePPFYQ)K&iUpnOLK|Q^RvOLi% z$Z}&}K=#S@1KS^Vu~>4)<0v7-xnE7H)D2yqEaI$P-&Se+w-IuSBcz+wa8cYiZQ<6? zp1!z{WzDran-PC;4ZXpoa4%CWpUSyt2Dp>{2>c^G=vGK~4&NYsJlH%I2WyD9x3CT>X^t7h97NpV zC89@P0g&OXV6Ma45}f6oQi~o{k@Ti&oLl?o?|}*@q$vl!O-ETSoglg^1hW`)Npug3 zZetlBh5_vXUAX90*QR-^ zer*DmPDi!BEIIPKK*f#xR6b_ke}u*8pMuvgP$6gzL~BsyPMCo*>zL+IRRv(xuvnXD zO-3~Jh8&I^yXp6{8Zjjpn_Lv#rGnjOlIlYL!Es}By?!}2L_73m?yA(Qf0yUl>7(Jj z+!s<*#CT9t#B=iWk-wg8|GAyWy^4k#uh4K)z0RX&<3qjR^!9;*GSyWYBF^oa>pBO*A^+ zpiftv7RXF`JvN$ob+>SqSWRC;&ejw%q&U5y^b1p(jw+@*fLTbpW8!t|6zA%I(?lm? z7U-fBXXy8lAA|&^I1h;_Omg_MigUl>l)4veQ^#6yA+{C`26Lk4u+WCR#d$5lZS?(^ zCMMdsMRZG|gF8c|#FE%t9O*lu-A#c0ghnPct=-nnf>n9&uq|~!FHrPK=%S)mL$6SD zm-rrzCMHE-1&h$1Ek!;D9Zj;W&lEkz7zV_F5PjnNg|<aB_!*Dub);4F==1lN5~uOLi;?|5VH52^_>y<5%+#>MVVu49F1hH zcu82t1=BBuVm{wUb1hHve~zZ_SpLX=7DacZEaSaV^km9C{E;a7&y**5E{fKtp5nzw z8fQ&2CPw1Yc}j)6QV(uJ*5#}Ve&Z4PkhPIN96?8|*YG;*Upzq_YE7#v&@dF=;5XLe zTA>+cG{a1uP)({)Dtallpdia%0yj)#0hMwu{l>fR2>6)o0B)c|zKcw&WLh56tnAH^ zXV`aI!N6H6w8E<~?8CK_<8X83J(piKFzgx@ZWmFIjWma`G#J9Y7CS`^^V+d5%xhQL zuVDr<-_8PKHj7+DV4LJ%q+E78r&Z25i^-d{^7ItyU0SYw;-~0T{}?r;=khDZr1JC;Ubna&zUMFd{gWy`-IP&+Qxi?wY!+U) zO#5uBY~R#jeE1T&>oI-@ovp;`>w*JE6DM$~{3^vZOfz85C2GnrTRxrx?f?+q1EXO8 z8wa=!$Z>{@xFl`Lc#q@veMp6@-Msok+LN`#_%be6i@Kki{0uF}VjZ2T7uuzmySljS zzdeE|^+k4+ivzDuGrl52zUM~*J8zxpWi7XomT=5*k)eGf^lEmJwud2D=V*;80qcvQ z_MCWLJwmH<;+&!@uqKD^*86g)saWWPic|Cr!wE;G>=^PTDKB#K)E;;X=3?Kz9lLTa z_Sryel8a8{L|e^s;EvniyI0dR`Jw zngzjYR#uixy}3<%<}l69OIACP!>1pnRe6i~zh0nE=dD}TjPH}*@-vz5l=&{1?~(bF zGH;Xl&%q@wKRg2cQqwQ_+ywmMY{sS#cK?x?6xV>tn1`_6A1S%i!i8^G`)Nvx9*);e1@vx{6EP=gkR0@qF?dL2t{7(EWs6f%6 zXFzoz)5YSQd;?|KP_k=rOw9H+v}VqY@1itHx@aajkQfpM2a|eg_FX%zta8> D*dfEO delta 2708 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 diff --git a/include/mimalloc.h b/include/mimalloc.h index cd8c33a5..6610bce6 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -226,8 +226,10 @@ typedef bool (mi_cdecl mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_ mi_decl_export bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg); +// Experimental mi_decl_export bool mi_is_in_heap_region(const void* p) mi_attr_noexcept; mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs) mi_attr_noexcept; +mi_decl_export bool mi_is_redirected() mi_attr_noexcept; // ------------------------------------------------------ // Convenience diff --git a/src/init.c b/src/init.c index cb5901aa..863214cb 100644 --- a/src/init.c +++ b/src/init.c @@ -388,14 +388,26 @@ bool _mi_preloading() { return os_preloading; } +bool mi_is_redirected() mi_attr_noexcept { + return mi_redirected; +} + // Communicate with the redirection module on Windows #if defined(_WIN32) && defined(MI_SHARED_LIB) #ifdef __cplusplus extern "C" { #endif -mi_decl_export void _mi_redirect_init() { - // called on redirection - mi_redirected = true; +mi_decl_export void _mi_redirect_entry(DWORD reason) { + // called on redirection; careful as this may be called before DllMain + if (reason == DLL_PROCESS_ATTACH) { + mi_redirected = true; + } + else if (reason == DLL_PROCESS_DETACH) { + mi_redirected = false; + } + else if (reason == DLL_THREAD_DETACH) { + mi_thread_done(); + } } __declspec(dllimport) bool mi_allocator_init(const char** message); __declspec(dllimport) void mi_allocator_done(); @@ -493,7 +505,7 @@ static void mi_process_done(void) { mi_process_load(); } else if (reason==DLL_THREAD_DETACH) { - mi_thread_done(); + if (!mi_is_redirected()) mi_thread_done(); } return TRUE; } From 3bbc047ba653b08d4730c24584c951f34eab2c0a Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 4 Sep 2019 12:14:59 -0700 Subject: [PATCH 41/92] reserve huge pages returns actual number of pages reserved --- include/mimalloc.h | 2 +- src/init.c | 2 +- src/os.c | 21 +++++++++++++-------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 6610bce6..1d5431ff 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -228,7 +228,7 @@ mi_decl_export bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_b // Experimental mi_decl_export bool mi_is_in_heap_region(const void* p) mi_attr_noexcept; -mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs) mi_attr_noexcept; +mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved) mi_attr_noexcept; mi_decl_export bool mi_is_redirected() mi_attr_noexcept; // ------------------------------------------------------ diff --git a/src/init.c b/src/init.c index 863214cb..480960b0 100644 --- a/src/init.c +++ b/src/init.c @@ -443,7 +443,7 @@ static void mi_process_load(void) { if (mi_option_is_enabled(mi_option_reserve_huge_os_pages)) { size_t pages = mi_option_get(mi_option_reserve_huge_os_pages); double max_secs = (double)pages / 2.0; // 0.5s per page (1GiB) - mi_reserve_huge_os_pages(pages, max_secs); + mi_reserve_huge_os_pages(pages, max_secs, NULL); } } diff --git a/src/os.c b/src/os.c index 9b5aac35..97cf7ef1 100644 --- a/src/os.c +++ b/src/os.c @@ -827,14 +827,17 @@ static void mi_os_free_huge_reserved() { */ #if !(MI_INTPTR_SIZE >= 8 && (defined(_WIN32) || defined(MI_OS_USE_MMAP))) -int mi_reserve_huge_os_pages(size_t pages, double max_secs) { - return -2; // cannot allocate +int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved) mi_attr_noexcept { + UNUSED(pages); UNUSED(max_secs); + if (pages_reserved != NULL) *pages_reserved = 0; + return ENOMEM; // cannot allocate } #else -int mi_reserve_huge_os_pages( size_t pages, double max_secs ) mi_attr_noexcept +int mi_reserve_huge_os_pages( size_t pages, double max_secs, size_t* pages_reserved ) mi_attr_noexcept { - if (max_secs==0) return -1; // timeout - if (pages==0) return 0; // ok + if (pages_reserved != NULL) *pages_reserved = 0; + if (max_secs==0) return ETIMEDOUT; // timeout + if (pages==0) return 0; // ok if (!mi_atomic_cas_ptr_strong(&os_huge_reserved.start,(void*)1,NULL)) return -2; // already reserved // Allocate one page at the time but try to place them contiguously @@ -843,7 +846,7 @@ int mi_reserve_huge_os_pages( size_t pages, double max_secs ) mi_attr_noexcept uint8_t* start = (uint8_t*)((uintptr_t)16 << 40); // 16TiB virtual start address uint8_t* addr = start; // current top of the allocations for (size_t page = 0; page < pages; page++, addr += MI_HUGE_OS_PAGE_SIZE ) { - // allocate lorgu pages + // allocate a page void* p = NULL; bool is_large = true; #ifdef _WIN32 @@ -856,6 +859,7 @@ int mi_reserve_huge_os_pages( size_t pages, double max_secs ) mi_attr_noexcept // Did we succeed at a contiguous address? if (p != addr) { + // no success, issue a warning and return with an error if (p != NULL) { _mi_warning_message("could not allocate contiguous huge page %zu at 0x%p\n", page, addr); _mi_os_free(p, MI_HUGE_OS_PAGE_SIZE, &_mi_stats_main ); @@ -868,7 +872,7 @@ int mi_reserve_huge_os_pages( size_t pages, double max_secs ) mi_attr_noexcept #endif _mi_warning_message("could not allocate huge page %zu at 0x%p, error: %i\n", page, addr, err); } - return -2; + return ENOMEM; } // success, record it if (page==0) { @@ -880,7 +884,8 @@ int mi_reserve_huge_os_pages( size_t pages, double max_secs ) mi_attr_noexcept } _mi_stat_increase(&_mi_stats_main.committed, MI_HUGE_OS_PAGE_SIZE); _mi_stat_increase(&_mi_stats_main.reserved, MI_HUGE_OS_PAGE_SIZE); - + if (pages_reserved != NULL) { *pages_reserved = page + 1; } + // check for timeout double elapsed = _mi_clock_end(start_t); if (elapsed > max_secs) return (-1); // timeout From e73982c4cffa01f1c45d5431df116b068919d713 Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 4 Sep 2019 18:42:37 -0700 Subject: [PATCH 42/92] better alignment for large and huge pages inside a segment --- src/alloc-aligned.c | 2 +- src/segment.c | 32 ++++++++++++++++---------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index 3dc0fb28..c8c19855 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -46,7 +46,7 @@ static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* heap, size_t size, size_t uintptr_t adjust = alignment - (((uintptr_t)p + offset) % alignment); mi_assert_internal(adjust % sizeof(uintptr_t) == 0); void* aligned_p = (adjust == alignment ? p : (void*)((uintptr_t)p + adjust)); - if (aligned_p != p) mi_page_set_has_aligned(_mi_ptr_page(p), true); + if (aligned_p != p) mi_page_set_has_aligned(_mi_ptr_page(p), true); mi_assert_internal(((uintptr_t)aligned_p + offset) % alignment == 0); mi_assert_internal( p == _mi_page_ptr_unalign(_mi_ptr_segment(aligned_p),_mi_ptr_page(aligned_p),aligned_p) ); return aligned_p; diff --git a/src/segment.c b/src/segment.c index 68f3fb05..772f21d5 100644 --- a/src/segment.c +++ b/src/segment.c @@ -151,19 +151,19 @@ uint8_t* _mi_segment_page_start(const mi_segment_t* segment, const mi_page_t* pa size_t psize = (segment->page_kind == MI_PAGE_HUGE ? segment->segment_size : (size_t)1 << segment->page_shift); uint8_t* p = (uint8_t*)segment + page->segment_idx*psize; - if (page->segment_idx == 0) { - // the first page starts after the segment info (and possible guard page) - p += segment->segment_info_size; - psize -= segment->segment_info_size; - // for small and medium objects, ensure the page start is aligned with the block size (PR#66 by kickunderscore) - if (block_size > 0 && segment->page_kind <= MI_PAGE_MEDIUM) { - size_t adjust = block_size - ((uintptr_t)p % block_size); - if (adjust < block_size) { - p += adjust; - psize -= adjust; - } - mi_assert_internal((uintptr_t)p % block_size == 0); - } + if (page->segment_idx == 0) { + // the first page starts after the segment info (and possible guard page) + p += segment->segment_info_size; + psize -= segment->segment_info_size; + // for small and medium objects, ensure the page start is aligned with the block size (PR#66 by kickunderscore) + if (block_size > 0 && segment->page_kind <= MI_PAGE_MEDIUM) { + size_t adjust = block_size - ((uintptr_t)p % block_size); + if (adjust < block_size) { + p += adjust; + psize -= adjust; + } + mi_assert_internal((uintptr_t)p % block_size == 0); + } } long secure = mi_option_get(mi_option_secure); if (secure > 1 || (secure == 1 && page->segment_idx == segment->capacity - 1)) { @@ -186,18 +186,18 @@ static size_t mi_segment_size(size_t capacity, size_t required, size_t* pre_size capacity = MI_SMALL_PAGES_PER_SEGMENT; } */ - size_t minsize = sizeof(mi_segment_t) + ((capacity - 1) * sizeof(mi_page_t)) + 16 /* padding */; + const size_t minsize = sizeof(mi_segment_t) + ((capacity - 1) * sizeof(mi_page_t)) + 16 /* padding */; size_t guardsize = 0; size_t isize = 0; if (!mi_option_is_enabled(mi_option_secure)) { // normally no guard pages - isize = _mi_align_up(minsize, (16 > MI_MAX_ALIGN_SIZE ? 16 : MI_MAX_ALIGN_SIZE)); + isize = _mi_align_up(minsize, 16 * MI_MAX_ALIGN_SIZE); } else { // in secure mode, we set up a protected page in between the segment info // and the page data (and one at the end of the segment) - size_t page_size = _mi_os_page_size(); + const size_t page_size = _mi_os_page_size(); isize = _mi_align_up(minsize, page_size); guardsize = page_size; required = _mi_align_up(required, page_size); From 2be3208734dfdb008d835ea9ecafe73acecae770 Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 4 Sep 2019 21:03:00 -0700 Subject: [PATCH 43/92] add wrap-around for large aligned allocations on Windows and Linux --- src/os.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/os.c b/src/os.c index 97cf7ef1..e9a66b0a 100644 --- a/src/os.c +++ b/src/os.c @@ -221,12 +221,16 @@ static void* mi_win_virtual_allocx(void* addr, size_t size, size_t try_alignment } #endif #if (MI_INTPTR_SIZE >= 8) - // on 64-bit systems, use the virtual address area after 4TiB for 4MiB aligned allocations - static volatile _Atomic(intptr_t) aligned_base = ATOMIC_VAR_INIT((intptr_t)4 << 40); // starting at 4TiB + // on 64-bit systems, use the virtual address area after 4TiB for 4MiB aligned allocations + #define MI_HINT_START ((intptr_t)4 << 40) + static volatile _Atomic(intptr_t) aligned_base = ATOMIC_VAR_INIT(MI_HINT_START); // starting at 4TiB if (addr == NULL && try_alignment > 0 && try_alignment <= MI_SEGMENT_SIZE && (size%MI_SEGMENT_SIZE) == 0) { intptr_t hint = mi_atomic_add(&aligned_base, size); + if (hint > ((intptr_t)30<<40)) { // try to wrap around after 30TiB (area after 32TiB is used for huge OS pages) + mi_atomic_cas_strong(mi_atomic_cast(uintptr_t,&aligned_base),MI_HINT_START,hint + size); + } if (hint%try_alignment == 0) { return VirtualAlloc((void*)hint, size, flags, PAGE_READWRITE); } @@ -298,9 +302,13 @@ static void* mi_unix_mmapx(void* addr, size_t size, size_t try_alignment, int pr void* p = NULL; #if (MI_INTPTR_SIZE >= 8) && !defined(MAP_ALIGNED) // on 64-bit systems, use the virtual address area after 4TiB for 4MiB aligned allocations - static volatile _Atomic(intptr_t) aligned_base = ATOMIC_VAR_INIT((intptr_t)1 << 42); // starting at 4TiB + #define MI_HINT_START ((intptr_t)4 << 40) + static volatile _Atomic(intptr_t) aligned_base = ATOMIC_VAR_INIT(MI_HINT_START); // starting at 4TiB if (addr==NULL && try_alignment <= MI_SEGMENT_SIZE && (size%MI_SEGMENT_SIZE)==0) { intptr_t hint = mi_atomic_add(&aligned_base,size); + if (hint > ((intptr_t)30<<40)) { // try to wrap around after 30TiB (area after 32TiB is used for huge OS pages) + mi_atomic_cas_strong(mi_atomic_cast(uintptr_t,&aligned_base), MI_HINT_START, hint + size); + } if (hint%try_alignment == 0) { p = mmap((void*)hint,size,protect_flags,flags,fd,0); if (p==MAP_FAILED) p = NULL; // fall back to regular mmap @@ -770,14 +778,16 @@ bool _mi_os_shrink(void* p, size_t oldsize, size_t newsize, mi_stats_t* stats) { /* ---------------------------------------------------------------------------- - +Support for huge OS pages (1Gib) that are reserved up-front and never +released. Only regions are allocated in here (see `memory.c`) so the memory +will be reused. -----------------------------------------------------------------------------*/ #define MI_HUGE_OS_PAGE_SIZE ((size_t)1 << 30) // 1GiB typedef struct mi_huge_info_s { - volatile _Atomic(void*) start; - volatile _Atomic(size_t) reserved; - volatile _Atomic(size_t) used; + volatile _Atomic(void*) start; // start of huge page area (32TiB) + volatile _Atomic(size_t) reserved; // total reserved size + volatile _Atomic(size_t) used; // currently allocated } mi_huge_info_t; static mi_huge_info_t os_huge_reserved = { NULL, 0, ATOMIC_VAR_INIT(0) }; @@ -790,7 +800,7 @@ bool _mi_os_is_huge_reserved(void* p) { void* _mi_os_try_alloc_from_huge_reserved(size_t size, size_t try_alignment) { - // only allow large aligned allocations + // only allow large aligned allocations (e.g. regions) if (size < MI_SEGMENT_SIZE || (size % MI_SEGMENT_SIZE) != 0) return NULL; if (try_alignment > MI_SEGMENT_SIZE) return NULL; if (mi_atomic_read_ptr(&os_huge_reserved.start)==NULL) return NULL; @@ -830,7 +840,7 @@ static void mi_os_free_huge_reserved() { int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved) mi_attr_noexcept { UNUSED(pages); UNUSED(max_secs); if (pages_reserved != NULL) *pages_reserved = 0; - return ENOMEM; // cannot allocate + return ENOMEM; } #else int mi_reserve_huge_os_pages( size_t pages, double max_secs, size_t* pages_reserved ) mi_attr_noexcept @@ -838,12 +848,12 @@ int mi_reserve_huge_os_pages( size_t pages, double max_secs, size_t* pages_reser if (pages_reserved != NULL) *pages_reserved = 0; if (max_secs==0) return ETIMEDOUT; // timeout if (pages==0) return 0; // ok - if (!mi_atomic_cas_ptr_strong(&os_huge_reserved.start,(void*)1,NULL)) return -2; // already reserved + if (!mi_atomic_cas_ptr_strong(&os_huge_reserved.start,(void*)1,NULL)) return ETIMEDOUT; // already reserved // Allocate one page at the time but try to place them contiguously // We allocate one page at the time to be able to abort if it takes too long double start_t = _mi_clock_start(); - uint8_t* start = (uint8_t*)((uintptr_t)16 << 40); // 16TiB virtual start address + uint8_t* start = (uint8_t*)((uintptr_t)32 << 40); // 32TiB virtual start address uint8_t* addr = start; // current top of the allocations for (size_t page = 0; page < pages; page++, addr += MI_HUGE_OS_PAGE_SIZE ) { // allocate a page @@ -888,10 +898,10 @@ int mi_reserve_huge_os_pages( size_t pages, double max_secs, size_t* pages_reser // check for timeout double elapsed = _mi_clock_end(start_t); - if (elapsed > max_secs) return (-1); // timeout + if (elapsed > max_secs) return ETIMEDOUT; if (page >= 1) { double estimate = ((elapsed / (double)(page+1)) * (double)pages); - if (estimate > 1.5*max_secs) return (-1); // seems like we are going to timeout + if (estimate > 1.5*max_secs) return ETIMEDOUT; // seems like we are going to timeout } } _mi_verbose_message("reserved %zu huge pages\n", pages); From 1a7b1783fa01ceef1361c4249ec0c3cd082b9dd8 Mon Sep 17 00:00:00 2001 From: Jakub Szymanski Date: Thu, 5 Sep 2019 08:13:52 -0700 Subject: [PATCH 44/92] changed strategy to reduce contention for region search and vs2019 project fix --- ide/vs2019/mimalloc-override.vcxproj | 14 +++++++++++--- src/memory.c | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/ide/vs2019/mimalloc-override.vcxproj b/ide/vs2019/mimalloc-override.vcxproj index 1f3b7ee2..33c9ee55 100644 --- a/ide/vs2019/mimalloc-override.vcxproj +++ b/ide/vs2019/mimalloc-override.vcxproj @@ -135,7 +135,7 @@ DllEntry - kernel32.lib;%(AdditionalDependencies) + kernel32.lib;..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) @@ -180,7 +180,6 @@ MaxSpeed true true - true true ../../include MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;_MBCS;%(PreprocessorDefinitions);NDEBUG @@ -188,14 +187,23 @@ $(IntDir) false MultiThreadedDLL + false + Speed + true + false + AdvancedVectorExtensions + Fast + /Bv /Ob3 /d2FH4 /Gw /fp:fast /GL %(AdditionalOptions) true true DllEntry - kernel32.lib;%(AdditionalDependencies) + kernel32.lib;..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration + /LTCG /USEPROFILE:AGGRESSIVE /d2:-threads16 /d2:-notypeopt %(AdditionalOptions) diff --git a/src/memory.c b/src/memory.c index 338b1ba3..52efbace 100644 --- a/src/memory.c +++ b/src/memory.c @@ -389,7 +389,7 @@ void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* l // find a range of free blocks void* p = NULL; size_t count = mi_atomic_read(®ions_count); - size_t idx = 0; // tld->region_idx; // start at 0 to reuse low addresses? Or, use tld->region_idx to reduce contention? + size_t idx = tld->region_idx; // start at 0 to reuse low addresses? Or, use tld->region_idx to reduce contention? for (size_t visited = 0; visited < count; visited++, idx++) { if (idx >= count) idx = 0; // wrap around if (!mi_region_try_alloc_blocks(idx, blocks, size, commit, large, is_zero, &p, id, tld)) return NULL; // error From f38fcf79eb9f2203a06d7fa60c78ed4b1623a6f8 Mon Sep 17 00:00:00 2001 From: daan Date: Fri, 6 Sep 2019 09:19:26 -0700 Subject: [PATCH 45/92] ensure addresses of large aligned allocations are randomized --- src/os.c | 74 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 26 deletions(-) diff --git a/src/os.c b/src/os.c index e9a66b0a..730b4a60 100644 --- a/src/os.c +++ b/src/os.c @@ -193,6 +193,8 @@ static bool mi_os_mem_free(void* addr, size_t size, bool was_committed, mi_stats } } +static void* mi_os_get_aligned_hint(size_t try_alignment, size_t size); + #ifdef _WIN32 static void* mi_win_virtual_allocx(void* addr, size_t size, size_t try_alignment, DWORD flags) { #if defined(MEM_EXTENDED_PARAMETER_TYPE_BITS) @@ -221,19 +223,10 @@ static void* mi_win_virtual_allocx(void* addr, size_t size, size_t try_alignment } #endif #if (MI_INTPTR_SIZE >= 8) - // on 64-bit systems, use the virtual address area after 4TiB for 4MiB aligned allocations - #define MI_HINT_START ((intptr_t)4 << 40) - static volatile _Atomic(intptr_t) aligned_base = ATOMIC_VAR_INIT(MI_HINT_START); // starting at 4TiB - if (addr == NULL && try_alignment > 0 && - try_alignment <= MI_SEGMENT_SIZE && (size%MI_SEGMENT_SIZE) == 0) - { - intptr_t hint = mi_atomic_add(&aligned_base, size); - if (hint > ((intptr_t)30<<40)) { // try to wrap around after 30TiB (area after 32TiB is used for huge OS pages) - mi_atomic_cas_strong(mi_atomic_cast(uintptr_t,&aligned_base),MI_HINT_START,hint + size); - } - if (hint%try_alignment == 0) { - return VirtualAlloc((void*)hint, size, flags, PAGE_READWRITE); - } + // on 64-bit systems, try to use the virtual address area after 4TiB for 4MiB aligned allocations + void* hint; + if (addr == NULL && (hint = mi_os_get_aligned_hint(try_alignment,size)) != NULL) { + return VirtualAlloc(hint, size, flags, PAGE_READWRITE); } #endif #if defined(MEM_EXTENDED_PARAMETER_TYPE_BITS) @@ -302,17 +295,10 @@ static void* mi_unix_mmapx(void* addr, size_t size, size_t try_alignment, int pr void* p = NULL; #if (MI_INTPTR_SIZE >= 8) && !defined(MAP_ALIGNED) // on 64-bit systems, use the virtual address area after 4TiB for 4MiB aligned allocations - #define MI_HINT_START ((intptr_t)4 << 40) - static volatile _Atomic(intptr_t) aligned_base = ATOMIC_VAR_INIT(MI_HINT_START); // starting at 4TiB - if (addr==NULL && try_alignment <= MI_SEGMENT_SIZE && (size%MI_SEGMENT_SIZE)==0) { - intptr_t hint = mi_atomic_add(&aligned_base,size); - if (hint > ((intptr_t)30<<40)) { // try to wrap around after 30TiB (area after 32TiB is used for huge OS pages) - mi_atomic_cas_strong(mi_atomic_cast(uintptr_t,&aligned_base), MI_HINT_START, hint + size); - } - if (hint%try_alignment == 0) { - p = mmap((void*)hint,size,protect_flags,flags,fd,0); - if (p==MAP_FAILED) p = NULL; // fall back to regular mmap - } + void* hint; + if (addr == NULL && (hint = mi_os_get_aligned_hint(try_alignment, size)) != NULL) { + p = mmap(hint,size,protect_flags,flags,fd,0); + if (p==MAP_FAILED) p = NULL; // fall back to regular mmap } #else UNUSED(try_alignment); @@ -420,6 +406,36 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro } #endif +// On 64-bit systems, we can do efficient aligned allocation by using +// the 4TiB to 30TiB area to allocate them. +#if (MI_INTPTR_SIZE >= 8) && (defined(_WIN32) || (defined(MI_OS_USE_MMAP) && !defined(MAP_ALIGNED))) +static volatile _Atomic(intptr_t) aligned_base; + +// Return a 4MiB aligned address that is probably available +static void* mi_os_get_aligned_hint(size_t try_alignment, size_t size) { + if (try_alignment == 0 || try_alignment > MI_SEGMENT_SIZE) return NULL; + if ((size%MI_SEGMENT_SIZE) != 0) return NULL; + intptr_t hint = mi_atomic_add(&aligned_base, size); + if (hint == 0 || hint > ((intptr_t)30<<40)) { // try to wrap around after 30TiB (area after 32TiB is used for huge OS pages) + intptr_t init = ((intptr_t)4 << 40); // start at 4TiB area + #if (MI_SECURE>0 || MI_DEBUG==0) // security: randomize start of aligned allocations unless in debug mode + uintptr_t r = _mi_random_init((uintptr_t)&mi_os_get_aligned_hint ^ hint); + init = init + (MI_SEGMENT_SIZE * ((r>>17) & 0xFFFF)); // (randomly 0-64k)*4MiB == 0 to 256GiB + #endif + mi_atomic_cas_strong(mi_atomic_cast(uintptr_t, &aligned_base), init, hint + size); + hint = mi_atomic_add(&aligned_base, size); // this may still give 0 or > 30TiB but that is ok, it is a hint after all + } + if (hint%try_alignment != 0) return NULL; + return (void*)hint; +} +#else +static void* mi_os_get_aligned_hint(size_t try_alignment, size_t size) { + UNUSED(try_alignment); UNUSED(size); + return NULL; +} +#endif + + // Primitive allocation from the OS. // Note: the `try_alignment` is just a hint and the returned pointer is not guaranteed to be aligned. static void* mi_os_mem_alloc(size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, mi_stats_t* stats) { @@ -850,10 +866,16 @@ int mi_reserve_huge_os_pages( size_t pages, double max_secs, size_t* pages_reser if (pages==0) return 0; // ok if (!mi_atomic_cas_ptr_strong(&os_huge_reserved.start,(void*)1,NULL)) return ETIMEDOUT; // already reserved + // Set the start address after the 32TiB area + uint8_t* start = (uint8_t*)((uintptr_t)32 << 40); // 32TiB virtual start address + #if (MI_SECURE>0 || MI_DEBUG==0) // security: randomize start of huge pages unless in debug mode + uintptr_t r = _mi_random_init((uintptr_t)&mi_reserve_huge_os_pages); + start = start + ((uintptr_t)MI_SEGMENT_SIZE * ((r>>17) & 0xFFFF)); // (randomly 0-64k)*4MiB == 0 to 256GiB + #endif + // Allocate one page at the time but try to place them contiguously // We allocate one page at the time to be able to abort if it takes too long double start_t = _mi_clock_start(); - uint8_t* start = (uint8_t*)((uintptr_t)32 << 40); // 32TiB virtual start address uint8_t* addr = start; // current top of the allocations for (size_t page = 0; page < pages; page++, addr += MI_HUGE_OS_PAGE_SIZE ) { // allocate a page @@ -886,7 +908,7 @@ int mi_reserve_huge_os_pages( size_t pages, double max_secs, size_t* pages_reser } // success, record it if (page==0) { - mi_atomic_write_ptr(&os_huge_reserved.start, addr); + mi_atomic_write_ptr(&os_huge_reserved.start, addr); // don't switch the order of these writes mi_atomic_write(&os_huge_reserved.reserved, MI_HUGE_OS_PAGE_SIZE); } else { From 47fc73d694f02adc5508a0af1510da63ac14991a Mon Sep 17 00:00:00 2001 From: daan Date: Fri, 6 Sep 2019 11:51:22 -0700 Subject: [PATCH 46/92] fix c++ compilation; make default output non-atomic --- src/options.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/options.c b/src/options.c index 55b9ae5c..38400831 100644 --- a/src/options.c +++ b/src/options.c @@ -150,16 +150,18 @@ static void mi_out_stderr(const char* msg) { // Default output handler // -------------------------------------------------------- +// Should be atomic but gives errors on many platforms as generally we cannot cast a function pointer to a uintptr_t. +// For now, don't register output from multiple threads. #pragma warning(suppress:4180) -static volatile _Atomic(mi_output_fun*) mi_out_default; // = NULL +static volatile mi_output_fun* mi_out_default; // = NULL static mi_output_fun* mi_out_get_default(void) { - mi_output_fun* out = (mi_output_fun*)mi_atomic_read_ptr(mi_atomic_cast(void*, &mi_out_default)); + mi_output_fun* out = mi_out_default; return (out == NULL ? &mi_out_stderr : out); } void mi_register_output(mi_output_fun* out) mi_attr_noexcept { - mi_atomic_write_ptr(mi_atomic_cast(void*,&mi_out_default),out); + mi_out_default = out; } From 89858ab7916fe2a4477b2698e3e3984be1622cfb Mon Sep 17 00:00:00 2001 From: daan Date: Fri, 6 Sep 2019 16:48:48 -0700 Subject: [PATCH 47/92] improve page_free_extend performance slightly; do not maintain expensive statistics in release mode --- src/page.c | 20 ++++++++++---------- test/test-stress.c | 4 +++- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/page.c b/src/page.c index 1288fd83..f1c96a71 100644 --- a/src/page.c +++ b/src/page.c @@ -410,7 +410,7 @@ void _mi_page_retire(mi_page_t* page) { // if its neighbours are almost fully used. if (mi_likely(page->block_size <= (MI_SMALL_SIZE_MAX/4))) { if (mi_page_mostly_used(page->prev) && mi_page_mostly_used(page->next)) { - _mi_stat_counter_increase(&_mi_stats_main.page_no_retire,1); + mi_stat_counter_increase(_mi_stats_main.page_no_retire,1); return; // dont't retire after all } } @@ -482,7 +482,7 @@ static void mi_page_free_list_extend_secure(mi_heap_t* heap, mi_page_t* page, si heap->random = _mi_random_shuffle(rnd); } -static void mi_page_free_list_extend( mi_page_t* page, size_t extend, mi_stats_t* stats) +static mi_decl_noinline void mi_page_free_list_extend( mi_page_t* page, size_t extend, mi_stats_t* stats) { UNUSED(stats); mi_assert_internal(page->free == NULL); @@ -491,15 +491,15 @@ static void mi_page_free_list_extend( mi_page_t* page, size_t extend, mi_stats_t void* page_area = _mi_page_start(_mi_page_segment(page), page, NULL ); size_t bsize = page->block_size; mi_block_t* start = mi_page_block_at(page, page_area, page->capacity); - + // initialize a sequential free list - mi_block_t* last = mi_page_block_at(page, page_area, page->capacity + extend - 1); + mi_block_t* last = mi_page_block_at(page, page_area, page->capacity + extend - 1); mi_block_t* block = start; while(block <= last) { mi_block_t* next = (mi_block_t*)((uint8_t*)block + bsize); mi_block_set_next(page,block,next); block = next; - } + } mi_block_set_next(page, last, NULL); page->free = start; } @@ -530,11 +530,11 @@ static void mi_page_extend_free(mi_heap_t* heap, mi_page_t* page, mi_stats_t* st size_t page_size; _mi_page_start(_mi_page_segment(page), page, &page_size); - _mi_stat_increase(&stats->pages_extended, 1); + mi_stat_increase(stats->pages_extended, 1); // calculate the extend count size_t extend = page->reserved - page->capacity; - size_t max_extend = MI_MAX_EXTEND_SIZE/page->block_size; + size_t max_extend = (page->block_size >= MI_MAX_EXTEND_SIZE ? MI_MIN_EXTEND : MI_MAX_EXTEND_SIZE/(uint32_t)page->block_size); if (max_extend < MI_MIN_EXTEND) max_extend = MI_MIN_EXTEND; if (extend > max_extend) { @@ -547,7 +547,7 @@ static void mi_page_extend_free(mi_heap_t* heap, mi_page_t* page, mi_stats_t* st mi_assert_internal(extend < (1UL<<16)); // and append the extend the free list - if (extend < MI_MIN_SLICES || !mi_option_is_enabled(mi_option_secure)) { + if (extend < MI_MIN_SLICES || MI_SECURE==0) { //!mi_option_is_enabled(mi_option_secure)) { mi_page_free_list_extend(page, extend, stats ); } else { @@ -555,7 +555,7 @@ static void mi_page_extend_free(mi_heap_t* heap, mi_page_t* page, mi_stats_t* st } // enable the new free list page->capacity += (uint16_t)extend; - _mi_stat_increase(&stats->page_committed, extend * page->block_size); + mi_stat_increase(stats->page_committed, extend * page->block_size); // extension into zero initialized memory preserves the zero'd free list if (!page->is_zero_init) { @@ -653,7 +653,7 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p page = next; } // for each page - _mi_stat_counter_increase(&heap->tld->stats.searches,count); + mi_stat_counter_increase(heap->tld->stats.searches,count); if (page == NULL) { page = rpage; diff --git a/test/test-stress.c b/test/test-stress.c index ad487538..354e2b07 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -18,7 +18,7 @@ terms of the MIT license. // argument defaults static int THREADS = 32; // more repeatable if THREADS <= #processors -static int N = 10; // scaling factor +static int N = 20; // scaling factor // static int THREADS = 8; // more repeatable if THREADS <= #processors // static int N = 100; // scaling factor @@ -163,8 +163,10 @@ int main(int argc, char** argv) { for (int i = 0; i < TRANSFERS; i++) { free_items((void*)transfer[i]); } + #ifndef NDEBUG mi_collect(false); mi_collect(true); + #endif mi_stats_print(NULL); //bench_end_program(); return 0; From f2f7c8d0e9271fb3c38a0fc991289d64ab99c21f Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 7 Sep 2019 09:18:29 -0700 Subject: [PATCH 48/92] fix volatile declaration on function pointer --- src/options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/options.c b/src/options.c index 38400831..37a7c025 100644 --- a/src/options.c +++ b/src/options.c @@ -153,7 +153,7 @@ static void mi_out_stderr(const char* msg) { // Should be atomic but gives errors on many platforms as generally we cannot cast a function pointer to a uintptr_t. // For now, don't register output from multiple threads. #pragma warning(suppress:4180) -static volatile mi_output_fun* mi_out_default; // = NULL +static mi_output_fun* volatile mi_out_default; // = NULL static mi_output_fun* mi_out_get_default(void) { mi_output_fun* out = mi_out_default; From b241910810ccfd7c4293afe5f74a48d92a33a88d Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 7 Sep 2019 11:52:21 -0700 Subject: [PATCH 49/92] don't allocate more than PTRDIFF_MAX on aligned allocations --- src/alloc-aligned.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index c8c19855..7caf0dbc 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -19,7 +19,7 @@ static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* heap, size_t size, size_t // the address at offset is aligned regardless of the allocated size. mi_assert(alignment > 0 && alignment % sizeof(uintptr_t) == 0); if (alignment <= sizeof(uintptr_t)) return _mi_heap_malloc_zero(heap,size,zero); - if (size >= (SIZE_MAX - alignment)) return NULL; // overflow + if (mi_unlikely(size > PTRDIFF_MAX)) return NULL; // we don't allocate more than PTRDIFF_MAX (see ) // try if there is a current small block with just the right alignment if (size <= MI_SMALL_SIZE_MAX) { From 0aec6d930277a2a459cb8889b1dc1c60dd13020a Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 7 Sep 2019 12:01:54 -0700 Subject: [PATCH 50/92] don't align to sizes greater than than the allocation size --- src/alloc-aligned.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index 7caf0dbc..cf89e274 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -18,8 +18,9 @@ static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* heap, size_t size, size_t // note: we don't require `size > offset`, we just guarantee that // the address at offset is aligned regardless of the allocated size. mi_assert(alignment > 0 && alignment % sizeof(uintptr_t) == 0); - if (alignment <= sizeof(uintptr_t)) return _mi_heap_malloc_zero(heap,size,zero); if (mi_unlikely(size > PTRDIFF_MAX)) return NULL; // we don't allocate more than PTRDIFF_MAX (see ) + // note: we require that alignment is smaller than `size` + if (mi_unlikely(alignment <= sizeof(uintptr_t) || alignment >= size)) return _mi_heap_malloc_zero(heap,size,zero); // try if there is a current small block with just the right alignment if (size <= MI_SMALL_SIZE_MAX) { From 7b63bc42110bc6efd2094b4b0098fc1007080c1b Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 7 Sep 2019 12:02:22 -0700 Subject: [PATCH 51/92] add alignment check to aligned_alloc for C11 compliance --- src/alloc-posix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/alloc-posix.c b/src/alloc-posix.c index 9ffebe4f..f51aa999 100644 --- a/src/alloc-posix.c +++ b/src/alloc-posix.c @@ -71,6 +71,7 @@ void* mi_pvalloc(size_t size) mi_attr_noexcept { } void* mi_aligned_alloc(size_t alignment, size_t size) mi_attr_noexcept { + if (alignment != 0 && (size%alignment) != 0) return NULL; // C11 required; return mi_malloc_aligned(size, alignment); } From e227341f5b60939fe287bdaf92f084d7ea4bf3c1 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 9 Sep 2019 07:54:36 -0700 Subject: [PATCH 52/92] fix mi_collect being called with empty heap (issue #150) --- src/heap.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/heap.c b/src/heap.c index 417c19da..8465479e 100644 --- a/src/heap.c +++ b/src/heap.c @@ -108,9 +108,8 @@ static bool mi_heap_page_never_delayed_free(mi_heap_t* heap, mi_page_queue_t* pq static void mi_heap_collect_ex(mi_heap_t* heap, mi_collect_t collect) { - _mi_deferred_free(heap,collect > NORMAL); if (!mi_heap_is_initialized(heap)) return; - + _mi_deferred_free(heap, collect > NORMAL); // collect (some) abandoned pages if (collect >= NORMAL && !heap->no_reclaim) { From 23155c5d7102d8667f20b50cbc079210a6d1ed7f Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 9 Sep 2019 08:02:41 -0700 Subject: [PATCH 53/92] add recursion guard to deferred callback --- include/mimalloc-types.h | 1 + src/heap.c | 2 +- src/init.c | 2 +- src/page.c | 6 ++++-- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index 9928f12d..5ce8513d 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -405,6 +405,7 @@ typedef struct mi_os_tld_s { // Thread local data struct mi_tld_s { unsigned long long heartbeat; // monotonic heartbeat count + bool recurse; // true if deferred was called; used to prevent infinite recursion. mi_heap_t* heap_backing; // backing heap of this thread (cannot be deleted) mi_segments_tld_t segments; // segment tld mi_os_tld_t os; // os tld diff --git a/src/heap.c b/src/heap.c index 8465479e..15c5d02a 100644 --- a/src/heap.c +++ b/src/heap.c @@ -110,7 +110,7 @@ static void mi_heap_collect_ex(mi_heap_t* heap, mi_collect_t collect) { if (!mi_heap_is_initialized(heap)) return; _mi_deferred_free(heap, collect > NORMAL); - + // collect (some) abandoned pages if (collect >= NORMAL && !heap->no_reclaim) { if (collect == NORMAL) { diff --git a/src/init.c b/src/init.c index 480960b0..3d9b4842 100644 --- a/src/init.c +++ b/src/init.c @@ -96,7 +96,7 @@ mi_decl_thread mi_heap_t* _mi_heap_default = (mi_heap_t*)&_mi_heap_empty; #define tld_main_stats ((mi_stats_t*)((uint8_t*)&tld_main + offsetof(mi_tld_t,stats))) static mi_tld_t tld_main = { - 0, + 0, false, &_mi_heap_main, { { NULL, NULL }, {NULL ,NULL}, 0, 0, 0, 0, 0, 0, NULL, tld_main_stats }, // segments { 0, tld_main_stats }, // os diff --git a/src/page.c b/src/page.c index f1c96a71..59977f38 100644 --- a/src/page.c +++ b/src/page.c @@ -702,12 +702,14 @@ static inline mi_page_t* mi_find_free_page(mi_heap_t* heap, size_t size) { a certain number of allocations. ----------------------------------------------------------- */ -static mi_deferred_free_fun* deferred_free = NULL; +static volatile mi_deferred_free_fun* deferred_free = NULL; void _mi_deferred_free(mi_heap_t* heap, bool force) { heap->tld->heartbeat++; - if (deferred_free != NULL) { + if (deferred_free != NULL && !heap->tld->recurse) { + heap->tld->recurse = true; deferred_free(force, heap->tld->heartbeat); + heap->tld->recurse = false; } } From b104e434e44da8bc4e2fc50d92d4f9a36c086c72 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 9 Sep 2019 08:07:35 -0700 Subject: [PATCH 54/92] fix volatile declaration on function --- src/page.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/page.c b/src/page.c index 59977f38..62490dd6 100644 --- a/src/page.c +++ b/src/page.c @@ -702,7 +702,7 @@ static inline mi_page_t* mi_find_free_page(mi_heap_t* heap, size_t size) { a certain number of allocations. ----------------------------------------------------------- */ -static volatile mi_deferred_free_fun* deferred_free = NULL; +static mi_deferred_free_fun* volatile deferred_free = NULL; void _mi_deferred_free(mi_heap_t* heap, bool force) { heap->tld->heartbeat++; From ce81af11199b05ade3a1faf9c3dcf53459ee643f Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 9 Sep 2019 08:12:50 -0700 Subject: [PATCH 55/92] use mi_is_power_of_two when possible (pr #118) --- include/mimalloc-internal.h | 6 ++++-- src/alloc-posix.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index de77f3b5..fd97b3ef 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -167,10 +167,12 @@ static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) { #endif } -// Align upwards -static inline uintptr_t _mi_is_power_of_two(uintptr_t x) { +// Is `x` a power of two? +static inline bool _mi_is_power_of_two(uintptr_t x) { return ((x & (x - 1)) == 0); } + +// Align upwards static inline uintptr_t _mi_align_up(uintptr_t sz, size_t alignment) { uintptr_t mask = alignment - 1; if ((alignment & mask) == 0) { // power of two? diff --git a/src/alloc-posix.c b/src/alloc-posix.c index f51aa999..f64cb1f6 100644 --- a/src/alloc-posix.c +++ b/src/alloc-posix.c @@ -48,7 +48,7 @@ int mi_posix_memalign(void** p, size_t alignment, size_t size) mi_attr_noexcept // if (p == NULL) return EINVAL; if (alignment % sizeof(void*) != 0) return EINVAL; // natural alignment - if ((alignment & (alignment - 1)) != 0) return EINVAL; // not a power of 2 + if (!_mi_is_power_of_two(alignment)) return EINVAL; // not a power of 2 void* q = mi_malloc_aligned(size, alignment); if (q==NULL && size != 0) return ENOMEM; *p = q; From 8903d7a5263a7f3ab12d85dd31ea8410ef36f122 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 9 Sep 2019 08:21:35 -0700 Subject: [PATCH 56/92] fix tests for aligned allocation --- test/test-api.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test-api.c b/test/test-api.c index a5f61074..5f3395fb 100644 --- a/test/test-api.c +++ b/test/test-api.c @@ -124,13 +124,13 @@ int main() { void* p = mi_malloc_aligned(32,24); result = (p != NULL && (uintptr_t)(p) % 24 == 0); mi_free(p); }); CHECK_BODY("malloc-aligned2", { - void* p = mi_malloc_aligned(8,24); result = (p != NULL && (uintptr_t)(p) % 24 == 0); mi_free(p); + void* p = mi_malloc_aligned(48,24); result = (p != NULL && (uintptr_t)(p) % 24 == 0); mi_free(p); }); CHECK_BODY("malloc-aligned-at1", { - void* p = mi_malloc_aligned_at(8,24,0); result = (p != NULL && ((uintptr_t)(p) + 0) % 24 == 0); mi_free(p); + void* p = mi_malloc_aligned_at(48,24,0); result = (p != NULL && ((uintptr_t)(p) + 0) % 24 == 0); mi_free(p); }); CHECK_BODY("malloc-aligned-at2", { - void* p = mi_malloc_aligned_at(5,24,8); result = (p != NULL && ((uintptr_t)(p) + 8) % 24 == 0); mi_free(p); + void* p = mi_malloc_aligned_at(50,24,8); result = (p != NULL && ((uintptr_t)(p) + 8) % 24 == 0); mi_free(p); }); // --------------------------------------------------- From e2202f6bbe4e2051014ac20c38b3cf88492e9d2f Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 9 Sep 2019 12:56:15 -0700 Subject: [PATCH 57/92] update vs2019 projects --- .gitignore | 9 ++- ide/vs2019/mimalloc-override-test.vcxproj | 35 +++++++-- ide/vs2019/mimalloc-override.vcxproj | 96 +++++++++++------------ ide/vs2019/mimalloc-test-stress.vcxproj | 12 +-- ide/vs2019/mimalloc-test.vcxproj | 19 ++--- ide/vs2019/mimalloc.vcxproj | 41 ++++------ 6 files changed, 113 insertions(+), 99 deletions(-) diff --git a/.gitignore b/.gitignore index bc3df510..3639d324 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ -ide/vs2017/*.db -ide/vs2017/*.opendb -ide/vs2017/*.user -ide/vs2017/.vs +ide/vs20??/*.db +ide/vs20??/*.opendb +ide/vs20??/*.user +ide/vs20??/*.vcxproj.filters +ide/vs20??/.vs out/ docs/ *.zip diff --git a/ide/vs2019/mimalloc-override-test.vcxproj b/ide/vs2019/mimalloc-override-test.vcxproj index d75a67e1..79adedb0 100644 --- a/ide/vs2019/mimalloc-override-test.vcxproj +++ b/ide/vs2019/mimalloc-override-test.vcxproj @@ -90,10 +90,19 @@ true ..\..\include MultiThreadedDebugDLL + false + Default + false Console + kernel32.lib;%(AdditionalDependencies) + + + + + @@ -103,14 +112,21 @@ true ..\..\include MultiThreadedDebugDLL + false + Default + false Console - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - false + kernel32.lib;%(AdditionalDependencies) + + + + + @@ -128,7 +144,12 @@ true true Console + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + @@ -150,15 +171,19 @@ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + - - - {abb5eae7-b3e6-432e-b636-333449892ea7} + + + diff --git a/ide/vs2019/mimalloc-override.vcxproj b/ide/vs2019/mimalloc-override.vcxproj index 33c9ee55..c651879f 100644 --- a/ide/vs2019/mimalloc-override.vcxproj +++ b/ide/vs2019/mimalloc-override.vcxproj @@ -35,7 +35,6 @@ DynamicLibrary false v142 - true DynamicLibrary @@ -46,7 +45,6 @@ DynamicLibrary false v142 - true @@ -70,21 +68,25 @@ $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ .dll + mimalloc-override $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ .dll + mimalloc-override $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ .dll + mimalloc-override $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ .dll + mimalloc-override @@ -93,26 +95,26 @@ true true ../../include - MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;_MBCS;%(PreprocessorDefinitions); + MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); MultiThreadedDebugDLL false + Default - - - - - - - - - DllEntry - kernel32.lib;%(AdditionalDependencies) + $(ProjectDir)\..\..\bin\mimalloc-redirect32.lib;%(AdditionalDependencies) + Default + false + + COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect32.dll $(OutputPath) + + + Copy mimalloc-redirect32.dll to the output directory + @@ -121,26 +123,26 @@ true true ../../include - MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;_MBCS;%(PreprocessorDefinitions); + MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions); MultiThreadedDebugDLL false + Default - - - - - - - - - DllEntry - kernel32.lib;..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) + $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) + Default + false + + COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect.dll $(OutputPath) + + + copy mimalloc-redirect.dll to the output directory + @@ -148,30 +150,30 @@ MaxSpeed true true - true true ../../include - MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;_MBCS;%(PreprocessorDefinitions);NDEBUG + MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);NDEBUG AssemblyAndSourceCode $(IntDir) false MultiThreadedDLL + Default + false true true - DllEntry - kernel32.lib;%(AdditionalDependencies) + $(ProjectDir)\..\..\bin\mimalloc-redirect32.lib;%(AdditionalDependencies) + Default + false - - + COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect32.dll $(OutputPath) - - + Copy mimalloc-redirect32.dll to the output directory @@ -182,42 +184,35 @@ true true ../../include - MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;_MBCS;%(PreprocessorDefinitions);NDEBUG + MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);NDEBUG AssemblyAndSourceCode $(IntDir) false MultiThreadedDLL + Default false - Speed - true - false - AdvancedVectorExtensions - Fast - /Bv /Ob3 /d2FH4 /Gw /fp:fast /GL %(AdditionalOptions) true true - DllEntry - kernel32.lib;..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) + $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) - UseLinkTimeCodeGeneration - /LTCG /USEPROFILE:AGGRESSIVE /d2:-threads16 /d2:-notypeopt %(AdditionalOptions) + Default + false - - + COPY /Y $(ProjectDir)..\..\bin\mimalloc-redirect.dll $(OutputPath) - - + copy mimalloc-redirect.dll to the output directory + @@ -227,7 +222,12 @@ false false - + + true + true + true + true + diff --git a/ide/vs2019/mimalloc-test-stress.vcxproj b/ide/vs2019/mimalloc-test-stress.vcxproj index 6aed1cc1..afbb6666 100644 --- a/ide/vs2019/mimalloc-test-stress.vcxproj +++ b/ide/vs2019/mimalloc-test-stress.vcxproj @@ -67,19 +67,19 @@ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ @@ -149,8 +149,8 @@ - - {abb5eae7-b3e6-432e-b636-333449892ea6} + + {abb5eae7-b3e6-432e-b636-333449892ea7} diff --git a/ide/vs2019/mimalloc-test.vcxproj b/ide/vs2019/mimalloc-test.vcxproj index 1e901e45..13af6ab4 100644 --- a/ide/vs2019/mimalloc-test.vcxproj +++ b/ide/vs2019/mimalloc-test.vcxproj @@ -67,19 +67,19 @@ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ - $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ @@ -144,19 +144,14 @@ Console - - - AssemblyAndSourceCode - AssemblyAndSourceCode - AssemblyAndSourceCode - AssemblyAndSourceCode - - {abb5eae7-b3e6-432e-b636-333449892ea6} + + + diff --git a/ide/vs2019/mimalloc.vcxproj b/ide/vs2019/mimalloc.vcxproj index 4d9563c2..7e74d881 100644 --- a/ide/vs2019/mimalloc.vcxproj +++ b/ide/vs2019/mimalloc.vcxproj @@ -70,21 +70,25 @@ $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ .lib + mimalloc-static $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ .lib + mimalloc-static $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ .lib + mimalloc-static $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\ $(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\ .lib + mimalloc-static @@ -94,8 +98,9 @@ true ../../include MI_DEBUG=3;%(PreprocessorDefinitions); - Default + CompileAsCpp false + stdcpp17 @@ -112,8 +117,9 @@ true ../../include MI_DEBUG=3;%(PreprocessorDefinitions); - Default + CompileAsCpp false + stdcpp17 @@ -135,8 +141,6 @@ Level3 MaxSpeed true - true - true true ../../include %(PreprocessorDefinitions);NDEBUG @@ -144,11 +148,9 @@ $(IntDir) false false - AnySuitable - Neither - false - false - Default + Default + CompileAsCpp + true true @@ -166,8 +168,6 @@ Level3 MaxSpeed true - true - true true ../../include %(PreprocessorDefinitions);NDEBUG @@ -175,11 +175,9 @@ $(IntDir) false false - AnySuitable - Neither - false - false - Default + Default + CompileAsCpp + true true @@ -211,12 +209,6 @@ true true - - true - true - true - true - true true @@ -243,8 +235,9 @@ - - + + + From d278c26c0ec8fd919ad02b04b7151696942d2084 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Tue, 10 Sep 2019 07:54:31 -0700 Subject: [PATCH 58/92] round huge page sizes into 12.5% increments (issue #153) --- src/page.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/page.c b/src/page.c index 62490dd6..c9226c64 100644 --- a/src/page.c +++ b/src/page.c @@ -727,7 +727,10 @@ void mi_register_deferred_free(mi_deferred_free_fun* fn) mi_attr_noexcept { // just that page, we always treat them as abandoned and any thread // that frees the block can free the whole page and segment directly. static mi_page_t* mi_huge_page_alloc(mi_heap_t* heap, size_t size) { - size_t block_size = _mi_wsize_from_size(size) * sizeof(uintptr_t); + size_t align_size = _mi_os_page_size(); + if (align_size < (size / 8)) align_size = _mi_align_up(size / 8, align_size); + if (align_size > MI_SEGMENT_SIZE) align_size = MI_SEGMENT_SIZE; + size_t block_size = _mi_align_up(size, align_size); mi_assert_internal(_mi_bin(block_size) == MI_BIN_HUGE); mi_page_t* page = mi_page_fresh_alloc(heap,NULL,block_size); if (page != NULL) { From 1909cfb3462a72ef93ae8768e96c9ba07f273389 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Tue, 10 Sep 2019 13:26:51 -0700 Subject: [PATCH 59/92] refine mi_os_good_alloc_size and use it for huge pages (to ensure realloc is bounded as in #153 --- include/mimalloc-internal.h | 1 + include/mimalloc-types.h | 3 +++ src/os.c | 21 +++++++++++++-------- src/page.c | 5 +---- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index fd97b3ef..8a81337b 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -43,6 +43,7 @@ size_t _mi_os_page_size(void); void _mi_os_init(void); // called from process init void* _mi_os_alloc(size_t size, mi_stats_t* stats); // to allocate thread local data void _mi_os_free(void* p, size_t size, mi_stats_t* stats); // to free thread local data +size_t _mi_os_good_alloc_size(size_t size); // memory.c void* _mi_mem_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, bool* is_zero, size_t* id, mi_os_tld_t* tld); diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index 5ce8513d..72fb7e7e 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -68,6 +68,9 @@ terms of the MIT license. A copy of the license can be found in the file #define MI_INTPTR_SIZE (1<= (SIZE_MAX - os_alloc_granularity)) return size; // possible overflow? - return _mi_align_up(size, os_alloc_granularity); +// round to a good OS allocation size (bounded by max 12.5% waste) +size_t _mi_os_good_alloc_size(size_t size) { + size_t align_size; + if (size < 512*KiB) align_size = _mi_os_page_size(); + else if (size < 2*MiB) align_size = 64*KiB; + else if (size < 8*MiB) align_size = 256*KiB; + else if (size < 32*MiB) align_size = 1*MiB; + else align_size = 4*MiB; + if (size >= (SIZE_MAX - align_size)) return size; // possible overflow? + return _mi_align_up(size, align_size); } #if defined(_WIN32) @@ -547,14 +552,14 @@ static void* mi_os_mem_alloc_aligned(size_t size, size_t alignment, bool commit, void* _mi_os_alloc(size_t size, mi_stats_t* stats) { if (size == 0) return NULL; - size = mi_os_good_alloc_size(size, 0); + size = _mi_os_good_alloc_size(size); bool is_large = false; return mi_os_mem_alloc(size, 0, true, false, &is_large, stats); } void _mi_os_free_ex(void* p, size_t size, bool was_committed, mi_stats_t* stats) { if (size == 0 || p == NULL) return; - size = mi_os_good_alloc_size(size, 0); + size = _mi_os_good_alloc_size(size); mi_os_mem_free(p, size, was_committed, stats); } @@ -565,7 +570,7 @@ void _mi_os_free(void* p, size_t size, mi_stats_t* stats) { void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, mi_os_tld_t* tld) { if (size == 0) return NULL; - size = mi_os_good_alloc_size(size, alignment); + size = _mi_os_good_alloc_size(size); alignment = _mi_align_up(alignment, _mi_os_page_size()); bool allow_large = false; if (large != NULL) { diff --git a/src/page.c b/src/page.c index c9226c64..8cbf96ad 100644 --- a/src/page.c +++ b/src/page.c @@ -727,10 +727,7 @@ void mi_register_deferred_free(mi_deferred_free_fun* fn) mi_attr_noexcept { // just that page, we always treat them as abandoned and any thread // that frees the block can free the whole page and segment directly. static mi_page_t* mi_huge_page_alloc(mi_heap_t* heap, size_t size) { - size_t align_size = _mi_os_page_size(); - if (align_size < (size / 8)) align_size = _mi_align_up(size / 8, align_size); - if (align_size > MI_SEGMENT_SIZE) align_size = MI_SEGMENT_SIZE; - size_t block_size = _mi_align_up(size, align_size); + size_t block_size = _mi_os_good_alloc_size(size); mi_assert_internal(_mi_bin(block_size) == MI_BIN_HUGE); mi_page_t* page = mi_page_fresh_alloc(heap,NULL,block_size); if (page != NULL) { From 050e7cedf453e05eb4e498786b467b599a154f9b Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 11 Sep 2019 15:48:44 -0700 Subject: [PATCH 60/92] roll back commit 0aec6d93 on `alignment >= size` as it breaks assertions in tensorflow --- src/alloc-aligned.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index cf89e274..b629d57b 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -17,10 +17,10 @@ terms of the MIT license. A copy of the license can be found in the file static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset, bool zero) mi_attr_noexcept { // note: we don't require `size > offset`, we just guarantee that // the address at offset is aligned regardless of the allocated size. - mi_assert(alignment > 0 && alignment % sizeof(uintptr_t) == 0); + mi_assert(alignment > 0 && alignment % sizeof(void*) == 0); if (mi_unlikely(size > PTRDIFF_MAX)) return NULL; // we don't allocate more than PTRDIFF_MAX (see ) - // note: we require that alignment is smaller than `size` - if (mi_unlikely(alignment <= sizeof(uintptr_t) || alignment >= size)) return _mi_heap_malloc_zero(heap,size,zero); + // use regular allocation if it is guaranteed to fit the alignment constraints + if (mi_unlikely(alignment <= sizeof(void*))) return _mi_heap_malloc_zero(heap, size, zero); // try if there is a current small block with just the right alignment if (size <= MI_SMALL_SIZE_MAX) { From 24777f6a9116d51a1ba6f79e619bedeef3b4d06f Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 11 Sep 2019 17:49:28 -0700 Subject: [PATCH 61/92] limit aligned allocation to power-of-two alignment --- include/mimalloc-internal.h | 2 +- src/alloc-aligned.c | 31 +++++++++++++++++++------------ src/alloc-posix.c | 3 ++- test/test-api.c | 8 ++++---- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 8a81337b..e99e6df6 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -168,7 +168,7 @@ static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) { #endif } -// Is `x` a power of two? +// Is `x` a power of two? (0 is considered a power of two) static inline bool _mi_is_power_of_two(uintptr_t x) { return ((x & (x - 1)) == 0); } diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index b629d57b..352f07b2 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -14,24 +14,24 @@ terms of the MIT license. A copy of the license can be found in the file // Aligned Allocation // ------------------------------------------------------ -static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset, bool zero) mi_attr_noexcept { +static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* const heap, const size_t size, const size_t alignment, const size_t offset, const bool zero) mi_attr_noexcept { // note: we don't require `size > offset`, we just guarantee that // the address at offset is aligned regardless of the allocated size. mi_assert(alignment > 0 && alignment % sizeof(void*) == 0); - if (mi_unlikely(size > PTRDIFF_MAX)) return NULL; // we don't allocate more than PTRDIFF_MAX (see ) - // use regular allocation if it is guaranteed to fit the alignment constraints - if (mi_unlikely(alignment <= sizeof(void*))) return _mi_heap_malloc_zero(heap, size, zero); - - // try if there is a current small block with just the right alignment - if (size <= MI_SMALL_SIZE_MAX) { + if (mi_unlikely(size > PTRDIFF_MAX)) return NULL; // we don't allocate more than PTRDIFF_MAX (see ) + if (mi_unlikely(alignment==0 || !_mi_is_power_of_two(alignment))) return NULL; // require power-of-two (see ) + const uintptr_t align_mask = alignment-1; // for any x, `(x & align_mask) == (x % alignment)` + + // try if there is a small block available with just the right alignment + if (mi_likely(size <= MI_SMALL_SIZE_MAX)) { mi_page_t* page = _mi_heap_get_free_small_page(heap,size); - if (page->free != NULL && - (((uintptr_t)page->free + offset) % alignment) == 0) + const bool is_aligned = (((uintptr_t)page->free+offset) & align_mask)==0; + if (mi_likely(page->free != NULL && is_aligned)) { #if MI_STAT>1 - mi_heap_stat_increase( heap, malloc, size); + mi_heap_stat_increase( heap, malloc, size); #endif - void* p = _mi_page_malloc(heap,page,size); + void* p = _mi_page_malloc(heap,page,size); // TODO: inline _mi_page_malloc mi_assert_internal(p != NULL); mi_assert_internal(((uintptr_t)p + offset) % alignment == 0); if (zero) _mi_block_zero_init(page,p,size); @@ -39,12 +39,19 @@ static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* heap, size_t size, size_t } } + // use regular allocation if it is guaranteed to fit the alignment constraints + if (offset==0 && alignment<=size && size<=MI_MEDIUM_OBJ_SIZE_MAX && (size&align_mask)==0) { + void* p = _mi_heap_malloc_zero(heap, size, zero); + mi_assert_internal(p == NULL || ((uintptr_t)p % alignment) == 0); + return p; + } + // otherwise over-allocate void* p = _mi_heap_malloc_zero(heap, size + alignment - 1, zero); if (p == NULL) return NULL; // .. and align within the allocation - uintptr_t adjust = alignment - (((uintptr_t)p + offset) % alignment); + uintptr_t adjust = alignment - (((uintptr_t)p + offset) & align_mask); mi_assert_internal(adjust % sizeof(uintptr_t) == 0); void* aligned_p = (adjust == alignment ? p : (void*)((uintptr_t)p + adjust)); if (aligned_p != p) mi_page_set_has_aligned(_mi_ptr_page(p), true); diff --git a/src/alloc-posix.c b/src/alloc-posix.c index f64cb1f6..505e42e4 100644 --- a/src/alloc-posix.c +++ b/src/alloc-posix.c @@ -71,7 +71,8 @@ void* mi_pvalloc(size_t size) mi_attr_noexcept { } void* mi_aligned_alloc(size_t alignment, size_t size) mi_attr_noexcept { - if (alignment != 0 && (size%alignment) != 0) return NULL; // C11 required; + if (alignment==0 || !_mi_is_power_of_two(alignment)) return NULL; + if ((size&(alignment-1)) != 0) return NULL; // C11 requires integral multiple, see return mi_malloc_aligned(size, alignment); } diff --git a/test/test-api.c b/test/test-api.c index 5f3395fb..bd2291da 100644 --- a/test/test-api.c +++ b/test/test-api.c @@ -121,16 +121,16 @@ int main() { // Aligned API // --------------------------------------------------- CHECK_BODY("malloc-aligned1", { - void* p = mi_malloc_aligned(32,24); result = (p != NULL && (uintptr_t)(p) % 24 == 0); mi_free(p); + void* p = mi_malloc_aligned(32,32); result = (p != NULL && (uintptr_t)(p) % 32 == 0); mi_free(p); }); CHECK_BODY("malloc-aligned2", { - void* p = mi_malloc_aligned(48,24); result = (p != NULL && (uintptr_t)(p) % 24 == 0); mi_free(p); + void* p = mi_malloc_aligned(48,32); result = (p != NULL && (uintptr_t)(p) % 32 == 0); mi_free(p); }); CHECK_BODY("malloc-aligned-at1", { - void* p = mi_malloc_aligned_at(48,24,0); result = (p != NULL && ((uintptr_t)(p) + 0) % 24 == 0); mi_free(p); + void* p = mi_malloc_aligned_at(48,32,0); result = (p != NULL && ((uintptr_t)(p) + 0) % 32 == 0); mi_free(p); }); CHECK_BODY("malloc-aligned-at2", { - void* p = mi_malloc_aligned_at(50,24,8); result = (p != NULL && ((uintptr_t)(p) + 8) % 24 == 0); mi_free(p); + void* p = mi_malloc_aligned_at(50,32,8); result = (p != NULL && ((uintptr_t)(p) + 8) % 32 == 0); mi_free(p); }); // --------------------------------------------------- From c977a1629d52557e46a0b43985144f267f758c90 Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 11 Sep 2019 20:48:41 -0700 Subject: [PATCH 62/92] update documentation --- doc/mimalloc-doc.h | 150 +++++++++++++--- docs/group__extended.html | 245 ++++++++++++++++++++++---- docs/group__extended.js | 16 +- docs/group__heap.html | 67 ++++++++ docs/group__heap.js | 2 + docs/group__options.html | 32 ++-- docs/group__options.js | 7 +- docs/group__posix.html | 3 + docs/group__typed.html | 45 +++++ docs/group__typed.js | 1 + docs/index.html | 5 +- docs/mimalloc-doc_8h_source.html | 80 +++++---- docs/modules.html | 9 +- docs/modules.js | 1 + docs/navtreedata.js | 1 + docs/navtreeindex0.js | 287 +++++++++++++++++-------------- docs/overrides.html | 7 +- docs/pages.html | 5 +- docs/search/all_4.js | 1 + docs/search/all_6.js | 37 +++- docs/search/enumvalues_1.js | 7 +- docs/search/functions_0.js | 28 ++- docs/search/pages_1.js | 2 +- docs/search/pages_2.js | 2 +- docs/search/pages_3.js | 2 +- docs/search/searchdata.js | 6 +- docs/search/typedefs_0.js | 3 +- docs/using.html | 11 +- 28 files changed, 784 insertions(+), 278 deletions(-) diff --git a/doc/mimalloc-doc.h b/doc/mimalloc-doc.h index e4f8590f..5ad5a1e6 100644 --- a/doc/mimalloc-doc.h +++ b/doc/mimalloc-doc.h @@ -48,20 +48,23 @@ Notable aspects of the design include: - __first-class heaps__: efficiently create and use multiple heaps to allocate across different regions. A heap can be destroyed at once instead of deallocating each object separately. - __bounded__: it does not suffer from _blowup_ \[1\], has bounded worst-case allocation - times (_wcat_), bounded space overhead (~0.2% meta-data, with at most 16.7% waste in allocation sizes), + times (_wcat_), bounded space overhead (~0.2% meta-data, with at most 12.5% waste in allocation sizes), and has no internal points of contention using only atomic operations. - __fast__: In our benchmarks (see [below](#performance)), _mimalloc_ always outperforms all other leading allocators (_jemalloc_, _tcmalloc_, _Hoard_, etc), and usually uses less memory (up to 25% more in the worst case). A nice property is that it does consistently well over a wide range of benchmarks. -You can read more on the design of _mimalloc_ in the upcoming technical report +You can read more on the design of _mimalloc_ in the +[technical report](https://www.microsoft.com/en-us/research/publication/mimalloc-free-list-sharding-in-action) which also has detailed benchmark results. + Further information: - \ref build - \ref using +- \ref environment - \ref overrides - \ref bench - \ref malloc @@ -293,31 +296,34 @@ size_t mi_good_size(size_t size); /// resource usage by calling this every once in a while. void mi_collect(bool force); -/// Print statistics. -/// @param out Output file. Use \a NULL for \a stderr. +/// Print the main statistics. +/// @param out Output function. Use \a NULL for outputting to \a stderr. /// /// Most detailed when using a debug build. -void mi_stats_print(FILE* out); +void mi_stats_print(mi_output_fun* out); /// Reset statistics. -void mi_stats_reset(); +void mi_stats_reset(void); + +/// Merge thread local statistics with the main statistics and reset. +void mi_stats_merge(void); /// Initialize mimalloc on a thread. /// Should not be used as on most systems (pthreads, windows) this is done /// automatically. -void mi_thread_init(); +void mi_thread_init(void); /// Uninitialize mimalloc on a thread. /// Should not be used as on most systems (pthreads, windows) this is done /// automatically. Ensures that any memory that is not freed yet (but will /// be freed by other threads in the future) is properly handled. -void mi_thread_done(); +void mi_thread_done(void); /// Print out heap statistics for this thread. -/// @param out Output file. Use \a NULL for \a stderr. +/// @param out Output function. Use \a NULL for outputting to \a stderr. /// /// Most detailed when using a debug build. -void mi_thread_stats_print(FILE* out); +void mi_thread_stats_print(mi_output_fun* out); /// Type of deferred free functions. /// @param force If \a true all outstanding items should be freed. @@ -342,6 +348,45 @@ typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat); /// At most one \a deferred_free function can be active. void mi_register_deferred_free(mi_deferred_free_fun* deferred_free); +/// Type of output functions. +/// @param msg Message to output. +/// +/// @see mi_register_output() +typedef void (mi_output_fun)(const char* msg); + +/// Register an output function. +/// @param out The output function, use `NULL` to output to stdout. +/// +/// The `out` function is called to output any information from mimalloc, +/// like verbose or warning messages. +void mi_register_output(mi_output_fun* out) mi_attr_noexcept; + +/// Is a pointer part of our heap? +/// @param p The pointer to check. +/// @returns \a true if this is a pointer into our heap. +/// This function is relatively fast. +bool mi_is_in_heap_region(const void* p); + +/// Reserve \a pages of huge OS pages (1GiB) but stops after at most `max_secs` seconds. +/// @param pages The number of 1GiB pages to reserve. +/// @param max_secs Maximum number of seconds to try reserving. +/// @param pages_reserved If not \a NULL, it is set to the actual number of pages that were reserved. +/// @returns 0 if successfull, \a ENOMEM if running out of memory, or \a ETIMEDOUT if timed out. +/// +/// The reserved memory is used by mimalloc to satisfy allocations. +/// May quit before \a max_secs are expired if it estimates it will take more than +/// 1.5 times \a max_secs. The time limit is needed because on some operating systems +/// it can take a long time to reserve contiguous memory if the physical memory is +/// fragmented. +int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved); + +/// Is the C runtime \a malloc API redirected? +/// @returns \a true if all malloc API calls are redirected to mimalloc. +/// +/// Currenty only used on Windows. +bool mi_is_redirected(); + + /// \} // ------------------------------------------------------ @@ -443,10 +488,18 @@ mi_heap_t* mi_heap_get_default(); /// except by exiting the thread. mi_heap_t* mi_heap_get_backing(); +/// Release outstanding resources in a specific heap. +void mi_heap_collect(mi_heap_t* heap, bool force); + /// Allocate in a specific heap. /// @see mi_malloc() void* mi_heap_malloc(mi_heap_t* heap, size_t size); +/// Allocate a small object in a specific heap. +/// \a size must be smaller or equal to MI_SMALL_SIZE_MAX(). +/// @see mi_malloc() +void* mi_heap_malloc_small(mi_heap_t* heap, size_t size); + /// Allocate zero-initialized in a specific heap. /// @see mi_zalloc() void* mi_heap_zalloc(mi_heap_t* heap, size_t size); @@ -486,6 +539,34 @@ void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_ /// \} + +/// \defgroup zeroinit Zero initialized re-allocation +/// +/// The zero-initialized re-allocations are only valid on memory that was +/// originally allocated with zero initialization too. +/// e.g. `mi_calloc`, `mi_zalloc`, `mi_zalloc_aligned` etc. +/// see +/// +/// \{ + +void* mi_rezalloc(void* p, size_t newsize); +void* mi_recalloc(void* p, size_t newcount, size_t size) ; + +void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment); +void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset); +void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment); +void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset); + +void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize); +void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size); + +void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment); +void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset); +void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment); +void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset); + +/// \} + /// \defgroup typed Typed Macros /// /// Typed allocation macros @@ -532,6 +613,9 @@ void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_ /// Re-allocate to \a count blocks of type \a tp in a heap \a hp. #define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp))) +/// Re-allocate to \a count zero initialized blocks of type \a tp in a heap \a hp. +#define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp))) + /// \} /// \defgroup analysis Heap Introspection @@ -614,14 +698,17 @@ typedef enum mi_option_e { mi_option_show_errors, ///< Print error messages to `stderr`. mi_option_verbose, ///< Print verbose messages to `stderr`. // the following options are experimental - mi_option_secure, ///< Experimental mi_option_eager_commit, ///< Eagerly commit segments (4MiB) (enabled by default). - mi_option_eager_region_commit, ///< Eagerly commit large (256MiB) memory regions (enabled by default except on Windows) - mi_option_large_os_pages, ///< Use large OS pages if possible + mi_option_eager_region_commit, ///< Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows) + mi_option_large_os_pages, ///< Use large OS pages (2MiB in size) if possible + mi_option_reserve_huge_os_pages, ///< The number of huge OS pages (1GiB in size) to reserve at the start of the program. + mi_option_segment_cache, ///< The number of segments per thread to keep cached. mi_option_page_reset, ///< Reset page memory when it becomes free. mi_option_cache_reset, ///< Reset segment memory when a segment is cached. mi_option_reset_decommits, ///< Experimental - mi_option_reset_discards, ///< Experimental + mi_option_eager_commit_delay, ///< Experimental + mi_option_segment_reset, ///< Experimental + mi_option_os_tag, ///< OS tag to assign to mimalloc'd memory _mi_option_last } mi_option_t; @@ -647,6 +734,8 @@ void mi_option_set_default(mi_option_t option, long value); void* mi_recalloc(void* p, size_t count, size_t size); size_t mi_malloc_size(const void* p); size_t mi_malloc_usable_size(const void *p); + +/// Just as `free` but also checks if the pointer `p` belongs to our heap. void mi_cfree(void* p); int mi_posix_memalign(void** p, size_t alignment, size_t size); @@ -804,9 +893,12 @@ completely and redirect all calls to the _mimalloc_ library instead. See \ref overrides for more info. -## Environment Options +*/ -You can set further options either programmatically (using [`mi_option_set`](https://microsoft.github.io/mimalloc/group__options.html)), +/*! \page environment Environment Options + +You can set further options either programmatically +(using [`mi_option_set`](https://microsoft.github.io/mimalloc/group__options.html)), or via environment variables. - `MIMALLOC_SHOW_STATS=1`: show statistics when the program terminates. @@ -869,19 +961,23 @@ Note: unfortunately, at this time, dynamic overriding on macOS seems broken but ### Windows On Windows you need to link your program explicitly with the mimalloc -DLL, and use the C-runtime library as a DLL (the `/MD` or `/MDd` switch). -To ensure the mimalloc DLL gets loaded it is easiest to insert some +DLL and use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch). +Moreover, you need to ensure the `mimalloc-redirect.dll` (or `mimalloc-redirect32.dll`) is available +in the same folder as the mimalloc DLL at runtime (as it as referred to by the mimalloc DLL). +The redirection DLL's ensure all calls to the C runtime malloc API get redirected to mimalloc. + +To ensure the mimalloc DLL is loaded at run-time it is easiest to insert some call to the mimalloc API in the `main` function, like `mi_version()` -(or use the `/INCLUDE:mi_version` switch on the linker) +(or use the `/INCLUDE:mi_version` switch on the linker). See the `mimalloc-override-test` project +for an example on how to use this. -Due to the way mimalloc intercepts the standard malloc at runtime, it is best -to link to the mimalloc import library first on the command line so it gets -loaded right after the universal C runtime DLL (`ucrtbase`). See -the `mimalloc-override-test` project for an example. +The environment variable `MIMALLOC_DISABLE_REDIRECT=1` can be used to disable dynamic +overriding at run-time. Use `MIMALLOC_VERBOSE=1` to check if mimalloc successfully redirected. -Note: the current overriding on Windows works for most programs but some programs still have -trouble -- the `dev-exp` branch contains a newer way of overriding that is more -robust; try this out if you experience troubles. +(Note: in principle, it should be possible to patch existing executables +that are linked with the dynamic C runtime (`ucrtbase.dll`) by just putting the mimalloc DLL into +the import table (and putting `mimalloc-redirect.dll` in the same folder) +Such patching can be done for example with [CFF Explorer](https://ntcore.com/?page_id=388)). ## Static override @@ -897,8 +993,6 @@ object file. For example: gcc -o myprogram mimalloc-override.o myfile1.c ... ``` - - ## List of Overrides: The specific functions that get redirected to the _mimalloc_ library are: diff --git a/docs/group__extended.html b/docs/group__extended.html index 8ab087e1..4d07f38d 100644 --- a/docs/group__extended.html +++ b/docs/group__extended.html @@ -121,6 +121,9 @@ Typedefs typedef void() mi_deferred_free_fun(bool force, unsigned long long heartbeat)  Type of deferred free functions. More...
  +typedef void() mi_output_fun(const char *msg) + Type of output functions. More...
+  @@ -139,24 +142,39 @@ Functions - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Functions

void mi_collect (bool force)
 Eagerly free memory. More...
 
void mi_stats_print (FILE *out)
 Print statistics. More...
 
void mi_stats_reset ()
 Reset statistics. More...
 
void mi_thread_init ()
 Initialize mimalloc on a thread. More...
 
void mi_thread_done ()
 Uninitialize mimalloc on a thread. More...
 
void mi_thread_stats_print (FILE *out)
 Print out heap statistics for this thread. More...
 
void mi_stats_print (mi_output_fun *out)
 Print the main statistics. More...
 
void mi_stats_reset (void)
 Reset statistics. More...
 
void mi_stats_merge (void)
 Merge thread local statistics with the main statistics and reset. More...
 
void mi_thread_init (void)
 Initialize mimalloc on a thread. More...
 
void mi_thread_done (void)
 Uninitialize mimalloc on a thread. More...
 
void mi_thread_stats_print (mi_output_fun *out)
 Print out heap statistics for this thread. More...
 
void mi_register_deferred_free (mi_deferred_free_fun *deferred_free)
 Register a deferred free function. More...
 
void mi_register_output (mi_output_fun *out) mi_attr_noexcept
 Register an output function. More...
 
bool mi_is_in_heap_region (const void *p)
 Is a pointer part of our heap? More...
 
int mi_reserve_huge_os_pages (size_t pages, double max_secs, size_t *pages_reserved)
 Reserve pages of huge OS pages (1GiB) but stops after at most max_secs seconds. More...
 
bool mi_is_redirected ()
 Is the C runtime malloc API redirected? More...
 

Detailed Description

Extended functionality.

@@ -200,6 +218,29 @@ Functions
See also
mi_register_deferred_free
+ + + +

◆ mi_output_fun

+ +
+
+ + + + +
typedef void() mi_output_fun(const char *msg)
+
+ +

Type of output functions.

+
Parameters
+ + +
msgMessage to output.
+
+
+
See also
mi_register_output()
+

Function Documentation

@@ -257,6 +298,54 @@ Functions

Generally, mi_usable_size(mi_malloc(size)) == mi_good_size(size). This can be used to reduce internal wasted space when allocating buffers for example.

See also
mi_usable_size()
+ + + +

◆ mi_is_in_heap_region()

+ +
+
+ + + + + + + + +
bool mi_is_in_heap_region (const void * p)
+
+ +

Is a pointer part of our heap?

+
Parameters
+ + +
pThe pointer to check.
+
+
+
Returns
true if this is a pointer into our heap. This function is relatively fast.
+ +
+
+ +

◆ mi_is_redirected()

+ +
+
+ + + + + + + +
bool mi_is_redirected ()
+
+ +

Is the C runtime malloc API redirected?

+
Returns
true if all malloc API calls are redirected to mimalloc.
+

Currenty only used on Windows.

+
@@ -313,8 +402,101 @@ Functions - -

◆ mi_stats_print()

+ +

◆ mi_register_output()

+ +
+
+ + + + + + + + +
void mi_register_output (mi_output_funout)
+
+ +

Register an output function.

+
Parameters
+ + +
outThe output function, use NULL to output to stdout.
+
+
+

The out function is called to output any information from mimalloc, like verbose or warning messages.

+ +
+
+ +

◆ mi_reserve_huge_os_pages()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int mi_reserve_huge_os_pages (size_t pages,
double max_secs,
size_t * pages_reserved 
)
+
+ +

Reserve pages of huge OS pages (1GiB) but stops after at most max_secs seconds.

+
Parameters
+ + + + +
pagesThe number of 1GiB pages to reserve.
max_secsMaximum number of seconds to try reserving.
pages_reservedIf not NULL, it is set to the actual number of pages that were reserved.
+
+
+
Returns
0 if successfull, ENOMEM if running out of memory, or ETIMEDOUT if timed out.
+

The reserved memory is used by mimalloc to satisfy allocations. May quit before max_secs are expired if it estimates it will take more than 1.5 times max_secs. The time limit is needed because on some operating systems it can take a long time to reserve contiguous memory if the physical memory is fragmented.

+ +
+
+ +

◆ mi_stats_merge()

+ +
+
+ + + + + + + + +
void mi_stats_merge (void )
+
+ +

Merge thread local statistics with the main statistics and reset.

+ +
+
+ +

◆ mi_stats_print()

@@ -322,17 +504,17 @@ Functions void mi_stats_print ( - FILE *  + mi_output_funout)
-

Print statistics.

+

Print the main statistics.

Parameters
- +
outOutput file. Use NULL for stderr.
outOutput function. Use NULL for outputting to stderr.
@@ -340,8 +522,8 @@ Functions
- -

◆ mi_stats_reset()

+ +

◆ mi_stats_reset()

@@ -349,6 +531,7 @@ Functions void mi_stats_reset ( + void  ) @@ -359,8 +542,8 @@ Functions
- -

◆ mi_thread_done()

+ +

◆ mi_thread_done()

@@ -368,6 +551,7 @@ Functions void mi_thread_done ( + void  ) @@ -379,8 +563,8 @@ Functions
- -

◆ mi_thread_init()

+ +

◆ mi_thread_init()

@@ -388,6 +572,7 @@ Functions void mi_thread_init ( + void  ) @@ -399,8 +584,8 @@ Functions
- -

◆ mi_thread_stats_print()

+ +

◆ mi_thread_stats_print()

@@ -408,7 +593,7 @@ Functions void mi_thread_stats_print ( - FILE *  + mi_output_funout) @@ -418,7 +603,7 @@ Functions

Print out heap statistics for this thread.

Parameters
- +
outOutput file. Use NULL for stderr.
outOutput function. Use NULL for outputting to stderr.
diff --git a/docs/group__extended.js b/docs/group__extended.js index fd2ce8a5..00c73614 100644 --- a/docs/group__extended.js +++ b/docs/group__extended.js @@ -2,15 +2,21 @@ var group__extended = [ [ "MI_SMALL_SIZE_MAX", "group__extended.html#ga1ea64283508718d9d645c38efc2f4305", null ], [ "mi_deferred_free_fun", "group__extended.html#ga22213691c3ce5ab4d91b24aff1023529", null ], + [ "mi_output_fun", "group__extended.html#ga2bed6d40b74591a67f81daea4b4a246f", null ], [ "mi_collect", "group__extended.html#ga421430e2226d7d468529cec457396756", null ], [ "mi_good_size", "group__extended.html#gac057927cd06c854b45fe7847e921bd47", null ], + [ "mi_is_in_heap_region", "group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6", null ], + [ "mi_is_redirected", "group__extended.html#gaad25050b19f30cd79397b227e0157a3f", null ], [ "mi_malloc_small", "group__extended.html#ga7136c2e55cb22c98ecf95d08d6debb99", null ], [ "mi_register_deferred_free", "group__extended.html#ga24dc9cc6fca8daa2aa30aa8025467ce2", null ], - [ "mi_stats_print", "group__extended.html#ga6bb821ca1b664b452112c0e17b15fcf1", null ], - [ "mi_stats_reset", "group__extended.html#ga9883b8a059aed7eb0888a01ec1461161", null ], - [ "mi_thread_done", "group__extended.html#gac0f4849256aaf677f334690952c6ebbd", null ], - [ "mi_thread_init", "group__extended.html#ga9398517f01a1ec971244aa0db084ea46", null ], - [ "mi_thread_stats_print", "group__extended.html#ga490826cbd7c494acc9fe69be23f018ac", null ], + [ "mi_register_output", "group__extended.html#ga84a0c8b401e42eb5b1bce156852f44c5", null ], + [ "mi_reserve_huge_os_pages", "group__extended.html#ga2664f36a2dd557741c429cb799f04641", null ], + [ "mi_stats_merge", "group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1", null ], + [ "mi_stats_print", "group__extended.html#ga8ca07ccff283956d71f48272f4fd5c01", null ], + [ "mi_stats_reset", "group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99", null ], + [ "mi_thread_done", "group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf", null ], + [ "mi_thread_init", "group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17", null ], + [ "mi_thread_stats_print", "group__extended.html#ga489670a15d1a257ab4639e645ee4612a", null ], [ "mi_usable_size", "group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee", null ], [ "mi_zalloc_small", "group__extended.html#ga220f29f40a44404b0061c15bc1c31152", null ] ]; \ No newline at end of file diff --git a/docs/group__heap.html b/docs/group__heap.html index cc970c7a..753aaba3 100644 --- a/docs/group__heap.html +++ b/docs/group__heap.html @@ -135,9 +135,15 @@ Functions mi_heap_tmi_heap_get_backing ()  Get the backing heap. More...
  +void mi_heap_collect (mi_heap_t *heap, bool force) + Release outstanding resources in a specific heap. More...
+  void * mi_heap_malloc (mi_heap_t *heap, size_t size)  Allocate in a specific heap. More...
  +void * mi_heap_malloc_small (mi_heap_t *heap, size_t size) + Allocate a small object in a specific heap. More...
+  void * mi_heap_zalloc (mi_heap_t *heap, size_t size)  Allocate zero-initialized in a specific heap. More...
  @@ -321,6 +327,36 @@ Functions
+
+
+ +

◆ mi_heap_collect()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void mi_heap_collect (mi_heap_theap,
bool force 
)
+
+ +

Release outstanding resources in a specific heap.

+
@@ -510,6 +546,37 @@ Functions
+
+ + +

◆ mi_heap_malloc_small()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void* mi_heap_malloc_small (mi_heap_theap,
size_t size 
)
+
+ +

Allocate a small object in a specific heap.

+

size must be smaller or equal to MI_SMALL_SIZE_MAX().

See also
mi_malloc()
+
diff --git a/docs/group__heap.js b/docs/group__heap.js index 7e908c04..13d13778 100644 --- a/docs/group__heap.js +++ b/docs/group__heap.js @@ -4,6 +4,7 @@ var group__heap = [ "mi_heap_calloc", "group__heap.html#gaa6702b3c48e9e53e50e81b36f5011d55", null ], [ "mi_heap_calloc_aligned", "group__heap.html#ga4af03a6e2b93fae77424d93f889705c3", null ], [ "mi_heap_calloc_aligned_at", "group__heap.html#ga08ca6419a5c057a4d965868998eef487", null ], + [ "mi_heap_collect", "group__heap.html#ga7922f7495cde30b1984d0e6072419298", null ], [ "mi_heap_delete", "group__heap.html#ga2ab1af8d438819b55319c7ef51d1e409", null ], [ "mi_heap_destroy", "group__heap.html#ga9f9c0844edb9717f4feacd79116b8e0d", null ], [ "mi_heap_get_backing", "group__heap.html#ga5d03fbe062ffcf38f0f417fd968357fc", null ], @@ -11,6 +12,7 @@ var group__heap = [ "mi_heap_malloc", "group__heap.html#ga9cbed01e42c0647907295de92c3fa296", null ], [ "mi_heap_malloc_aligned", "group__heap.html#gab5b87e1805306f70df38789fcfcf6653", null ], [ "mi_heap_malloc_aligned_at", "group__heap.html#ga23acd7680fb0976dde3783254c6c874b", null ], + [ "mi_heap_malloc_small", "group__heap.html#gaa1a1c7a1f4da6826b5a25b70ef878368", null ], [ "mi_heap_mallocn", "group__heap.html#ga851da6c43fe0b71c1376cee8aef90db0", null ], [ "mi_heap_new", "group__heap.html#ga766f672ba56f2fbfeb9d9dbb0b7f6b11", null ], [ "mi_heap_realloc", "group__heap.html#gaaef3395f66be48f37bdc8322509c5d81", null ], diff --git a/docs/group__options.html b/docs/group__options.html index e8a0bbd6..a34a9307 100644 --- a/docs/group__options.html +++ b/docs/group__options.html @@ -115,16 +115,20 @@ Enumerations   mi_option_show_stats, mi_option_show_errors, mi_option_verbose, -mi_option_secure, +mi_option_eager_commit,
-  mi_option_eager_commit, -mi_option_eager_region_commit, +  mi_option_eager_region_commit, mi_option_large_os_pages, -mi_option_page_reset, +mi_option_reserve_huge_os_pages, +mi_option_segment_cache,
-  mi_option_cache_reset, +  mi_option_page_reset, +mi_option_cache_reset, mi_option_reset_decommits, -mi_option_reset_discards, +mi_option_eager_commit_delay, +
+  mi_option_segment_reset, +mi_option_os_tag, _mi_option_last
} @@ -169,13 +173,15 @@ Functions mi_option_verbose 

Print verbose messages to stderr.

-mi_option_secure 

Experimental.

- mi_option_eager_commit 

Eagerly commit segments (4MiB) (enabled by default).

-mi_option_eager_region_commit 

Eagerly commit large (256MiB) memory regions (enabled by default except on Windows)

+mi_option_eager_region_commit 

Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows)

-mi_option_large_os_pages 

Use large OS pages if possible.

+mi_option_large_os_pages 

Use large OS pages (2MiB in size) if possible.

+ +mi_option_reserve_huge_os_pages 

The number of huge OS pages (1GiB in size) to reserve at the start of the program.

+ +mi_option_segment_cache 

The number of segments per thread to keep cached.

mi_option_page_reset 

Reset page memory when it becomes free.

@@ -183,7 +189,11 @@ Functions mi_option_reset_decommits 

Experimental.

-mi_option_reset_discards 

Experimental.

+mi_option_eager_commit_delay 

Experimental.

+ +mi_option_segment_reset 

Experimental.

+ +mi_option_os_tag 

OS tag to assign to mimalloc'd memory.

_mi_option_last  diff --git a/docs/group__options.js b/docs/group__options.js index 485dc83d..4bf52d54 100644 --- a/docs/group__options.js +++ b/docs/group__options.js @@ -4,14 +4,17 @@ var group__options = [ "mi_option_show_stats", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda", null ], [ "mi_option_show_errors", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0", null ], [ "mi_option_verbose", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777", null ], - [ "mi_option_secure", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca083ee20765063fc6d727e11d33cf378f", null ], [ "mi_option_eager_commit", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b", null ], [ "mi_option_eager_region_commit", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca32ce97ece29f69e82579679cf8a307ad", null ], [ "mi_option_large_os_pages", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4192d491200d0055df0554d4cf65054e", null ], + [ "mi_option_reserve_huge_os_pages", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2", null ], + [ "mi_option_segment_cache", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca2ecbe7ef32f5c84de3739aa4f0b805a1", null ], [ "mi_option_page_reset", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cada854dd272c66342f18a93ee254a2968", null ], [ "mi_option_cache_reset", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac2157a0cb79cd996c1db7d9f6a090c07", null ], [ "mi_option_reset_decommits", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac81ee965b130fa81238913a3c239d536", null ], - [ "mi_option_reset_discards", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cab3a837b5ceee250e14e051dbee2a441b", null ], + [ "mi_option_eager_commit_delay", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c", null ], + [ "mi_option_segment_reset", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafb121d30d87591850d5410ccc3a95c6d", null ], + [ "mi_option_os_tag", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf", null ], [ "_mi_option_last", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca5b4357b74be0d87568036c32eb1a2e4a", null ] ] ], [ "mi_option_enable", "group__options.html#ga6d45a20a3131f18bc351b69763b38ce4", null ], diff --git a/docs/group__posix.html b/docs/group__posix.html index 6d0ca57c..b9cf0b52 100644 --- a/docs/group__posix.html +++ b/docs/group__posix.html @@ -115,6 +115,7 @@ Functions size_t mi_malloc_usable_size (const void *p)   void mi_cfree (void *p) + Just as free but also checks if the pointer p belongs to our heap. More...
  int mi_posix_memalign (void **p, size_t alignment, size_t size)   @@ -231,6 +232,8 @@ Functions
+

Just as free but also checks if the pointer p belongs to our heap.

+
diff --git a/docs/group__typed.html b/docs/group__typed.html index c0a52c4b..8ea0f095 100644 --- a/docs/group__typed.html +++ b/docs/group__typed.html @@ -140,6 +140,9 @@ Macros #define mi_heap_reallocn_tp(hp, p, tp, count)  Re-allocate to count blocks of type tp in a heap hp. More...
  +#define mi_heap_recalloc_tp(hp, p, tp, count) + Re-allocate to count zero initialized blocks of type tp in a heap hp. More...

Detailed Description

Typed allocation macros.

@@ -316,6 +319,48 @@ Macros

Re-allocate to count blocks of type tp in a heap hp.

+ + + +

◆ mi_heap_recalloc_tp

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#define mi_heap_recalloc_tp( hp,
 p,
 tp,
 count 
)
+
+ +

Re-allocate to count zero initialized blocks of type tp in a heap hp.

+
diff --git a/docs/group__typed.js b/docs/group__typed.js index 095a5b4a..c6be55d8 100644 --- a/docs/group__typed.js +++ b/docs/group__typed.js @@ -5,6 +5,7 @@ var group__typed = [ "mi_heap_malloc_tp", "group__typed.html#ga653bcb24ac495bc19940ecd6898f9cd7", null ], [ "mi_heap_mallocn_tp", "group__typed.html#ga6b75cb9c4b9c647661d0924552dc6e83", null ], [ "mi_heap_reallocn_tp", "group__typed.html#gaf213d5422ec35e7f6caad827c79bc948", null ], + [ "mi_heap_recalloc_tp", "group__typed.html#ga3e50a1600958fcaf1a7f3560c9174f9e", null ], [ "mi_heap_zalloc_tp", "group__typed.html#gad6e87e86e994aa14416ae9b5d4c188fe", null ], [ "mi_malloc_tp", "group__typed.html#ga0619a62c5fd886f1016030abe91f0557", null ], [ "mi_mallocn_tp", "group__typed.html#gae5cb6e0fafc9f23169c5622e077afe8b", null ], diff --git a/docs/index.html b/docs/index.html index 68127d24..bf758c3c 100644 --- a/docs/index.html +++ b/docs/index.html @@ -110,14 +110,15 @@ $(document).ready(function(){initNavTree('index.html','');});
  • eager page reset: when a "page" becomes empty (with increased chance due to free list sharding) the memory is marked to the OS as unused ("reset" or "purged") reducing (real) memory pressure and fragmentation, especially in long running programs.
  • secure: mimalloc can be build in secure mode, adding guard pages, randomized allocation, encrypted free lists, etc. to protect against various heap vulnerabilities. The performance penalty is only around 3% on average over our benchmarks.
  • first-class heaps: efficiently create and use multiple heaps to allocate across different regions. A heap can be destroyed at once instead of deallocating each object separately.
  • -
  • bounded: it does not suffer from blowup [1], has bounded worst-case allocation times (wcat), bounded space overhead (~0.2% meta-data, with at most 16.7% waste in allocation sizes), and has no internal points of contention using only atomic operations.
  • +
  • bounded: it does not suffer from blowup [1], has bounded worst-case allocation times (wcat), bounded space overhead (~0.2% meta-data, with at most 12.5% waste in allocation sizes), and has no internal points of contention using only atomic operations.
  • fast: In our benchmarks (see below), mimalloc always outperforms all other leading allocators (jemalloc, tcmalloc, Hoard, etc), and usually uses less memory (up to 25% more in the worst case). A nice property is that it does consistently well over a wide range of benchmarks.
  • -

    You can read more on the design of mimalloc in the upcoming technical report which also has detailed benchmark results.

    +

    You can read more on the design of mimalloc in the technical report which also has detailed benchmark results.

    Further information:

    • Building
    • Using the library
    • +
    • Environment Options
    • Overriding Malloc
    • Performance
    • Basic Allocation
    • diff --git a/docs/mimalloc-doc_8h_source.html b/docs/mimalloc-doc_8h_source.html index b4b6e01d..3a235533 100644 --- a/docs/mimalloc-doc_8h_source.html +++ b/docs/mimalloc-doc_8h_source.html @@ -102,31 +102,35 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
      mimalloc-doc.h
      -
      1 /* ----------------------------------------------------------------------------
      2 Copyright (c) 2018, Microsoft Research, Daan Leijen
      3 This is free software; you can redistribute it and/or modify it under the
      4 terms of the MIT license. A copy of the license can be found in the file
      5 "LICENSE" at the root of this distribution.
      6 -----------------------------------------------------------------------------*/
      7 
      8 #error "documentation file only!"
      9 
      10 
      78 
      82 
      86 void mi_free(void* p);
      87 
      92 void* mi_malloc(size_t size);
      93 
      98 void* mi_zalloc(size_t size);
      99 
      109 void* mi_calloc(size_t count, size_t size);
      110 
      123 void* mi_realloc(void* p, size_t newsize);
      124 
      135 void* mi_recalloc(void* p, size_t count, size_t size);
      136 
      150 void* mi_expand(void* p, size_t newsize);
      151 
      161 void* mi_mallocn(size_t count, size_t size);
      162 
      172 void* mi_reallocn(void* p, size_t count, size_t size);
      173 
      190 void* mi_reallocf(void* p, size_t newsize);
      191 
      192 
      201 char* mi_strdup(const char* s);
      202 
      212 char* mi_strndup(const char* s, size_t n);
      213 
      226 char* mi_realpath(const char* fname, char* resolved_name);
      227 
      229 
      230 // ------------------------------------------------------
      231 // Extended functionality
      232 // ------------------------------------------------------
      233 
      237 
      240 #define MI_SMALL_SIZE_MAX (128*sizeof(void*))
      241 
      249 void* mi_malloc_small(size_t size);
      250 
      258 void* mi_zalloc_small(size_t size);
      259 
      274 size_t mi_usable_size(void* p);
      275 
      285 size_t mi_good_size(size_t size);
      286 
      294 void mi_collect(bool force);
      295 
      300 void mi_stats_print(FILE* out);
      301 
      303 void mi_stats_reset();
      304 
      308 void mi_thread_init();
      309 
      314 void mi_thread_done();
      315 
      320 void mi_thread_stats_print(FILE* out);
      321 
      327 typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat);
      328 
      344 
      346 
      347 // ------------------------------------------------------
      348 // Aligned allocation
      349 // ------------------------------------------------------
      350 
      356 
      369 void* mi_malloc_aligned(size_t size, size_t alignment);
      370 void* mi_zalloc_aligned(size_t size, size_t alignment);
      371 void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
      372 void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
      373 
      384 void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
      385 void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
      386 void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
      387 void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
      388 
      390 
      396 
      401 struct mi_heap_s;
      402 
      407 typedef struct mi_heap_s mi_heap_t;
      408 
      411 
      419 void mi_heap_delete(mi_heap_t* heap);
      420 
      428 void mi_heap_destroy(mi_heap_t* heap);
      429 
      434 
      438 
      445 
      448 void* mi_heap_malloc(mi_heap_t* heap, size_t size);
      449 
      452 void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
      453 
      456 void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
      457 
      460 void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
      461 
      464 char* mi_heap_strdup(mi_heap_t* heap, const char* s);
      465 
      468 char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
      469 
      472 char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
      473 
      474 void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
      475 void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
      476 void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
      477 
      478 void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
      479 void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
      480 void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
      481 void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
      482 void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
      483 void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
      484 void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
      485 void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
      486 
      488 
      494 
      506 #define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
      507 
      509 #define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
      510 
      512 #define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
      513 
      515 #define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
      516 
      518 #define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
      519 
      521 #define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
      522 
      524 #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
      525 
      527 #define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
      528 
      530 #define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
      531 
      533 #define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
      534 
      536 
      542 
      549 bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
      550 
      559 bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
      560 
      568 bool mi_check_owned(const void* p);
      569 
      572 typedef struct mi_heap_area_s {
      573  void* blocks;
      574  size_t reserved;
      575  size_t committed;
      576  size_t used;
      577  size_t block_size;
      579 
      587 typedef bool (mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);
      588 
      600 bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
      601 
      603 
      609 
      611 typedef enum mi_option_e {
      612  // stable options
      616  // the following options are experimental
      626 } mi_option_t;
      627 
      628 
      629 bool mi_option_enabled(mi_option_t option);
      630 void mi_option_enable(mi_option_t option, bool enable);
      631 void mi_option_enable_default(mi_option_t option, bool enable);
      632 
      633 long mi_option_get(mi_option_t option);
      634 void mi_option_set(mi_option_t option, long value);
      635 void mi_option_set_default(mi_option_t option, long value);
      636 
      637 
      639 
      646 
      647 void* mi_recalloc(void* p, size_t count, size_t size);
      648 size_t mi_malloc_size(const void* p);
      649 size_t mi_malloc_usable_size(const void *p);
      650 void mi_cfree(void* p);
      651 
      652 int mi_posix_memalign(void** p, size_t alignment, size_t size);
      653 int mi__posix_memalign(void** p, size_t alignment, size_t size);
      654 void* mi_memalign(size_t alignment, size_t size);
      655 void* mi_valloc(size_t size);
      656 
      657 void* mi_pvalloc(size_t size);
      658 void* mi_aligned_alloc(size_t alignment, size_t size);
      659 void* mi_reallocarray(void* p, size_t count, size_t size);
      660 
      661 void mi_free_size(void* p, size_t size);
      662 void mi_free_size_aligned(void* p, size_t size, size_t alignment);
      663 void mi_free_aligned(void* p, size_t alignment);
      664 
      666 void* mi_new(std::size_t n) noexcept(false);
      667 
      669 void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
      670 
      672 void* mi_new_nothrow(size_t n);
      673 ``
      675 void* mi_new_aligned_nothrow(size_t n, size_t alignment);
      676 
      678 
      void mi_stats_print(FILE *out)
      Print statistics.
      -
      void mi_option_enable_default(mi_option_t option, bool enable)
      +
      1 /* ----------------------------------------------------------------------------
      2 Copyright (c) 2018, Microsoft Research, Daan Leijen
      3 This is free software; you can redistribute it and/or modify it under the
      4 terms of the MIT license. A copy of the license can be found in the file
      5 "LICENSE" at the root of this distribution.
      6 -----------------------------------------------------------------------------*/
      7 
      8 #error "documentation file only!"
      9 
      10 
      81 
      85 
      89 void mi_free(void* p);
      90 
      95 void* mi_malloc(size_t size);
      96 
      101 void* mi_zalloc(size_t size);
      102 
      112 void* mi_calloc(size_t count, size_t size);
      113 
      126 void* mi_realloc(void* p, size_t newsize);
      127 
      138 void* mi_recalloc(void* p, size_t count, size_t size);
      139 
      153 void* mi_expand(void* p, size_t newsize);
      154 
      164 void* mi_mallocn(size_t count, size_t size);
      165 
      175 void* mi_reallocn(void* p, size_t count, size_t size);
      176 
      193 void* mi_reallocf(void* p, size_t newsize);
      194 
      195 
      204 char* mi_strdup(const char* s);
      205 
      215 char* mi_strndup(const char* s, size_t n);
      216 
      229 char* mi_realpath(const char* fname, char* resolved_name);
      230 
      232 
      233 // ------------------------------------------------------
      234 // Extended functionality
      235 // ------------------------------------------------------
      236 
      240 
      243 #define MI_SMALL_SIZE_MAX (128*sizeof(void*))
      244 
      252 void* mi_malloc_small(size_t size);
      253 
      261 void* mi_zalloc_small(size_t size);
      262 
      277 size_t mi_usable_size(void* p);
      278 
      288 size_t mi_good_size(size_t size);
      289 
      297 void mi_collect(bool force);
      298 
      303 void mi_stats_print(mi_output_fun* out);
      304 
      306 void mi_stats_reset(void);
      307 
      309 void mi_stats_merge(void);
      310 
      314 void mi_thread_init(void);
      315 
      320 void mi_thread_done(void);
      321 
      327 
      333 typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat);
      334 
      350 
      355 typedef void (mi_output_fun)(const char* msg);
      356 
      362 void mi_register_output(mi_output_fun* out) mi_attr_noexcept;
      363 
      368 bool mi_is_in_heap_region(const void* p);
      369 
      381 int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved);
      382 
      387 bool mi_is_redirected();
      388 
      389 
      391 
      392 // ------------------------------------------------------
      393 // Aligned allocation
      394 // ------------------------------------------------------
      395 
      401 
      414 void* mi_malloc_aligned(size_t size, size_t alignment);
      415 void* mi_zalloc_aligned(size_t size, size_t alignment);
      416 void* mi_calloc_aligned(size_t count, size_t size, size_t alignment);
      417 void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
      418 
      429 void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset);
      430 void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset);
      431 void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset);
      432 void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
      433 
      435 
      441 
      446 struct mi_heap_s;
      447 
      452 typedef struct mi_heap_s mi_heap_t;
      453 
      456 
      464 void mi_heap_delete(mi_heap_t* heap);
      465 
      473 void mi_heap_destroy(mi_heap_t* heap);
      474 
      479 
      483 
      490 
      492 void mi_heap_collect(mi_heap_t* heap, bool force);
      493 
      496 void* mi_heap_malloc(mi_heap_t* heap, size_t size);
      497 
      501 void* mi_heap_malloc_small(mi_heap_t* heap, size_t size);
      502 
      505 void* mi_heap_zalloc(mi_heap_t* heap, size_t size);
      506 
      509 void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size);
      510 
      513 void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size);
      514 
      517 char* mi_heap_strdup(mi_heap_t* heap, const char* s);
      518 
      521 char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n);
      522 
      525 char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name);
      526 
      527 void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize);
      528 void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size);
      529 void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize);
      530 
      531 void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
      532 void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
      533 void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment);
      534 void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset);
      535 void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment);
      536 void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset);
      537 void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
      538 void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
      539 
      541 
      542 
      551 
      552 void* mi_rezalloc(void* p, size_t newsize);
      553 void* mi_recalloc(void* p, size_t newcount, size_t size) ;
      554 
      555 void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
      556 void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset);
      557 void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
      558 void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
      559 
      560 void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize);
      561 void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size);
      562 
      563 void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment);
      564 void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset);
      565 void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment);
      566 void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset);
      567 
      569 
      575 
      587 #define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
      588 
      590 #define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
      591 
      593 #define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp)))
      594 
      596 #define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp)))
      597 
      599 #define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp)))
      600 
      602 #define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
      603 
      605 #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
      606 
      608 #define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp)))
      609 
      611 #define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp)))
      612 
      614 #define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp)))
      615 
      617 #define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp)))
      618 
      620 
      626 
      633 bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
      634 
      643 bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
      644 
      652 bool mi_check_owned(const void* p);
      653 
      656 typedef struct mi_heap_area_s {
      657  void* blocks;
      658  size_t reserved;
      659  size_t committed;
      660  size_t used;
      661  size_t block_size;
      663 
      671 typedef bool (mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);
      672 
      684 bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
      685 
      687 
      693 
      695 typedef enum mi_option_e {
      696  // stable options
      700  // the following options are experimental
      713 } mi_option_t;
      714 
      715 
      716 bool mi_option_enabled(mi_option_t option);
      717 void mi_option_enable(mi_option_t option, bool enable);
      718 void mi_option_enable_default(mi_option_t option, bool enable);
      719 
      720 long mi_option_get(mi_option_t option);
      721 void mi_option_set(mi_option_t option, long value);
      722 void mi_option_set_default(mi_option_t option, long value);
      723 
      724 
      726 
      733 
      734 void* mi_recalloc(void* p, size_t count, size_t size);
      735 size_t mi_malloc_size(const void* p);
      736 size_t mi_malloc_usable_size(const void *p);
      737 
      739 void mi_cfree(void* p);
      740 
      741 int mi_posix_memalign(void** p, size_t alignment, size_t size);
      742 int mi__posix_memalign(void** p, size_t alignment, size_t size);
      743 void* mi_memalign(size_t alignment, size_t size);
      744 void* mi_valloc(size_t size);
      745 
      746 void* mi_pvalloc(size_t size);
      747 void* mi_aligned_alloc(size_t alignment, size_t size);
      748 void* mi_reallocarray(void* p, size_t count, size_t size);
      749 
      750 void mi_free_size(void* p, size_t size);
      751 void mi_free_size_aligned(void* p, size_t size, size_t alignment);
      752 void mi_free_aligned(void* p, size_t alignment);
      753 
      755 void* mi_new(std::size_t n) noexcept(false);
      756 
      758 void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
      759 
      761 void* mi_new_nothrow(size_t n);
      762 ``
      764 void* mi_new_aligned_nothrow(size_t n, size_t alignment);
      765 
      767 
      void mi_option_enable_default(mi_option_t option, bool enable)
      size_t mi_usable_size(void *p)
      Return the available bytes in a memory block.
      -
      Experimental.
      Definition: mimalloc-doc.h:624
      void * mi_reallocn(void *p, size_t count, size_t size)
      Re-allocate memory to count elements of size bytes.
      void * mi_malloc_aligned(size_t size, size_t alignment)
      Allocate size bytes aligned by alignment.
      +
      void * mi_recalloc_aligned_at(void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
      +
      void mi_stats_print(mi_output_fun *out)
      Print the main statistics.
      +
      void mi_stats_reset(void)
      Reset statistics.
      void * mi_heap_realloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
      void * mi_recalloc(void *p, size_t count, size_t size)
      Re-allocate memory to count elements of size bytes, with extra memory initialized to zero.
      void * mi_mallocn(size_t count, size_t size)
      Allocate count elements of size bytes.
      size_t mi_malloc_size(const void *p)
      -
      void mi_thread_done()
      Uninitialize mimalloc on a thread.
      -
      Reset segment memory when a segment is cached.
      Definition: mimalloc-doc.h:622
      +
      Reset segment memory when a segment is cached.
      Definition: mimalloc-doc.h:707
      int mi_posix_memalign(void **p, size_t alignment, size_t size)
      +
      void mi_stats_merge(void)
      Merge thread local statistics with the main statistics and reset.
      +
      void() mi_output_fun(const char *msg)
      Type of output functions.
      Definition: mimalloc-doc.h:355
      +
      void mi_register_output(mi_output_fun *out) mi_attr_noexcept
      Register an output function.
      void mi_option_set_default(mi_option_t option, long value)
      void * mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false)
      raise std::bad_alloc exception on failure.
      -
      Eagerly commit segments (4MiB) (enabled by default).
      Definition: mimalloc-doc.h:618
      +
      void * mi_rezalloc(void *p, size_t newsize)
      +
      Eagerly commit segments (4MiB) (enabled by default).
      Definition: mimalloc-doc.h:701
      void * mi_heap_zalloc(mi_heap_t *heap, size_t size)
      Allocate zero-initialized in a specific heap.
      void mi_option_set(mi_option_t option, long value)
      void mi_register_deferred_free(mi_deferred_free_fun *deferred_free)
      Register a deferred free function.
      -
      Eagerly commit large (256MiB) memory regions (enabled by default except on Windows)
      Definition: mimalloc-doc.h:619
      -
      void mi_cfree(void *p)
      -
      void mi_thread_stats_print(FILE *out)
      Print out heap statistics for this thread.
      -
      Definition: mimalloc-doc.h:625
      +
      Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows)
      Definition: mimalloc-doc.h:702
      +
      void mi_cfree(void *p)
      Just as free but also checks if the pointer p belongs to our heap.
      +
      void * mi_recalloc_aligned(void *p, size_t newcount, size_t size, size_t alignment)
      +
      Definition: mimalloc-doc.h:712
      void * mi_realloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
      -
      void * blocks
      start of the area containing heap blocks
      Definition: mimalloc-doc.h:573
      +
      void * blocks
      start of the area containing heap blocks
      Definition: mimalloc-doc.h:657
      void * mi_realloc_aligned(void *p, size_t newsize, size_t alignment)
      int mi__posix_memalign(void **p, size_t alignment, size_t size)
      void mi_free(void *p)
      Free previously allocated memory.
      @@ -139,55 +143,73 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
      char * mi_strndup(const char *s, size_t n)
      Allocate and duplicate a string up to n bytes.
      void * mi_expand(void *p, size_t newsize)
      Try to re-allocate memory to newsize bytes in place.
      void * mi_pvalloc(size_t size)
      +
      void * mi_heap_rezalloc_aligned_at(mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
      void * mi_zalloc(size_t size)
      Allocate zero-initialized size bytes.
      -
      void mi_thread_init()
      Initialize mimalloc on a thread.
      +
      void * mi_heap_rezalloc(mi_heap_t *heap, void *p, size_t newsize)
      +
      The number of segments per thread to keep cached.
      Definition: mimalloc-doc.h:705
      void * mi_heap_calloc(mi_heap_t *heap, size_t count, size_t size)
      Allocate count zero-initialized elements in a specific heap.
      void * mi_new(std::size_t n) noexcept(false)
      raise std::bad_alloc exception on failure.
      void * mi_heap_calloc_aligned(mi_heap_t *heap, size_t count, size_t size, size_t alignment)
      -
      size_t block_size
      size in bytes of one block
      Definition: mimalloc-doc.h:577
      +
      bool mi_is_redirected()
      Is the C runtime malloc API redirected?
      +
      size_t block_size
      size in bytes of one block
      Definition: mimalloc-doc.h:661
      void * mi_reallocarray(void *p, size_t count, size_t size)
      +
      bool mi_is_in_heap_region(const void *p)
      Is a pointer part of our heap?
      void mi_option_enable(mi_option_t option, bool enable)
      void * mi_realloc(void *p, size_t newsize)
      Re-allocate memory to newsize bytes.
      +
      The number of huge OS pages (1GiB in size) to reserve at the start of the program.
      Definition: mimalloc-doc.h:704
      +
      int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t *pages_reserved)
      Reserve pages of huge OS pages (1GiB) but stops after at most max_secs seconds.
      void * mi_heap_reallocf(mi_heap_t *heap, void *p, size_t newsize)
      void mi_free_size_aligned(void *p, size_t size, size_t alignment)
      -
      Reset page memory when it becomes free.
      Definition: mimalloc-doc.h:621
      +
      void * mi_rezalloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
      +
      Reset page memory when it becomes free.
      Definition: mimalloc-doc.h:706
      +
      void mi_thread_done(void)
      Uninitialize mimalloc on a thread.
      bool mi_heap_visit_blocks(const mi_heap_t *heap, bool visit_all_blocks, mi_block_visit_fun *visitor, void *arg)
      Visit all areas and blocks in a heap.
      +
      void mi_thread_stats_print(mi_output_fun *out)
      Print out heap statistics for this thread.
      void * mi_malloc(size_t size)
      Allocate size bytes.
      bool mi_option_enabled(mi_option_t option)
      -
      Experimental.
      Definition: mimalloc-doc.h:623
      +
      Experimental.
      Definition: mimalloc-doc.h:708
      char * mi_heap_strndup(mi_heap_t *heap, const char *s, size_t n)
      Duplicate a string of at most length n in a specific heap.
      -
      bool() mi_block_visit_fun(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *arg)
      Visitor function passed to mi_heap_visit_blocks()
      Definition: mimalloc-doc.h:587
      +
      bool() mi_block_visit_fun(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *arg)
      Visitor function passed to mi_heap_visit_blocks()
      Definition: mimalloc-doc.h:671
      +
      void * mi_heap_recalloc(mi_heap_t *heap, void *p, size_t newcount, size_t size)
      void * mi_heap_malloc_aligned_at(mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
      char * mi_realpath(const char *fname, char *resolved_name)
      Resolve a file path name.
      -
      Print error messages to stderr.
      Definition: mimalloc-doc.h:614
      +
      Print error messages to stderr.
      Definition: mimalloc-doc.h:698
      +
      Experimental.
      Definition: mimalloc-doc.h:710
      +
      void * mi_heap_rezalloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
      void * mi_memalign(size_t alignment, size_t size)
      void * mi_new_aligned_nothrow(size_t n, size_t alignment)
      return NULL on failure.
      void * mi_new_nothrow(size_t n)
      return NULL on failure.
      +
      void * mi_rezalloc_aligned(void *p, size_t newsize, size_t alignment)
      bool mi_heap_contains_block(mi_heap_t *heap, const void *p)
      Does a heap contain a pointer to a previously allocated block?
      -
      Print verbose messages to stderr.
      Definition: mimalloc-doc.h:615
      +
      void mi_heap_collect(mi_heap_t *heap, bool force)
      Release outstanding resources in a specific heap.
      +
      void * mi_heap_recalloc_aligned_at(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
      +
      Print verbose messages to stderr.
      Definition: mimalloc-doc.h:699
      void * mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset)
      void * mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset)
      Allocate size bytes aligned by alignment at a specified offset.
      void mi_heap_delete(mi_heap_t *heap)
      Delete a previously allocated heap.
      +
      OS tag to assign to mimalloc'd memory.
      Definition: mimalloc-doc.h:711
      mi_heap_t * mi_heap_get_default()
      Get the default heap that is used for mi_malloc() et al.
      void * mi_aligned_alloc(size_t alignment, size_t size)
      void * mi_valloc(size_t size)
      +
      void mi_thread_init(void)
      Initialize mimalloc on a thread.
      size_t mi_good_size(size_t size)
      Return the used allocation size.
      +
      Experimental.
      Definition: mimalloc-doc.h:709
      +
      void * mi_heap_recalloc_aligned(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment)
      void * mi_heap_mallocn(mi_heap_t *heap, size_t count, size_t size)
      Allocate count elements in a specific heap.
      -
      An area of heap space contains blocks of a single size.
      Definition: mimalloc-doc.h:572
      -
      Print statistics to stderr when the program is done.
      Definition: mimalloc-doc.h:613
      +
      An area of heap space contains blocks of a single size.
      Definition: mimalloc-doc.h:656
      +
      Print statistics to stderr when the program is done.
      Definition: mimalloc-doc.h:697
      void * mi_zalloc_aligned(size_t size, size_t alignment)
      -
      size_t reserved
      bytes reserved for this area
      Definition: mimalloc-doc.h:574
      -
      struct mi_heap_s mi_heap_t
      Type of first-class heaps.
      Definition: mimalloc-doc.h:407
      -
      size_t used
      bytes in use by allocated blocks
      Definition: mimalloc-doc.h:576
      -
      void() mi_deferred_free_fun(bool force, unsigned long long heartbeat)
      Type of deferred free functions.
      Definition: mimalloc-doc.h:327
      +
      size_t reserved
      bytes reserved for this area
      Definition: mimalloc-doc.h:658
      +
      struct mi_heap_s mi_heap_t
      Type of first-class heaps.
      Definition: mimalloc-doc.h:452
      +
      size_t used
      bytes in use by allocated blocks
      Definition: mimalloc-doc.h:660
      +
      void() mi_deferred_free_fun(bool force, unsigned long long heartbeat)
      Type of deferred free functions.
      Definition: mimalloc-doc.h:333
      void mi_free_size(void *p, size_t size)
      void mi_collect(bool force)
      Eagerly free memory.
      void mi_heap_destroy(mi_heap_t *heap)
      Destroy a heap, freeing all its still allocated blocks.
      void * mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset)
      -
      Use large OS pages if possible.
      Definition: mimalloc-doc.h:620
      -
      Experimental.
      Definition: mimalloc-doc.h:617
      -
      void mi_stats_reset()
      Reset statistics.
      +
      Use large OS pages (2MiB in size) if possible.
      Definition: mimalloc-doc.h:703
      void * mi_heap_reallocn(mi_heap_t *heap, void *p, size_t count, size_t size)
      +
      void * mi_heap_malloc_small(mi_heap_t *heap, size_t size)
      Allocate a small object in a specific heap.
      void * mi_heap_realloc(mi_heap_t *heap, void *p, size_t newsize)
      size_t mi_malloc_usable_size(const void *p)
      char * mi_strdup(const char *s)
      Allocate and duplicate a string.
      @@ -203,8 +225,8 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
      void mi_free_aligned(void *p, size_t alignment)
      mi_heap_t * mi_heap_new()
      Create a new heap that can be used for allocation.
      void * mi_heap_malloc(mi_heap_t *heap, size_t size)
      Allocate in a specific heap.
      -
      size_t committed
      current committed bytes of this area
      Definition: mimalloc-doc.h:575
      -
      mi_option_t
      Runtime options.
      Definition: mimalloc-doc.h:611
      +
      size_t committed
      current committed bytes of this area
      Definition: mimalloc-doc.h:659
      +
      mi_option_t
      Runtime options.
      Definition: mimalloc-doc.h:695
      bool mi_heap_check_owned(mi_heap_t *heap, const void *p)
      Check safely if any pointer is part of a heap.
      mi_heap_t * mi_heap_set_default(mi_heap_t *heap)
      Set the default heap to use for mi_malloc() et al.
      diff --git a/docs/modules.html b/docs/modules.html index a7693c5c..ca18e1eb 100644 --- a/docs/modules.html +++ b/docs/modules.html @@ -108,10 +108,11 @@ $(document).ready(function(){initNavTree('modules.html','');});  Extended FunctionsExtended functionality  Aligned AllocationAllocating aligned memory blocks  Heap AllocationFirst-class heaps that can be destroyed in one go - Typed MacrosTyped allocation macros - Heap IntrospectionInspect the heap at runtime - Runtime OptionsSet runtime behavior - Posixmi_ prefixed implementations of various Posix, Unix, and C++ allocation functions + Zero initialized re-allocationThe zero-initialized re-allocations are only valid on memory that was originally allocated with zero initialization too + Typed MacrosTyped allocation macros + Heap IntrospectionInspect the heap at runtime + Runtime OptionsSet runtime behavior + Posixmi_ prefixed implementations of various Posix, Unix, and C++ allocation functions
      diff --git a/docs/modules.js b/docs/modules.js index aa1c3642..47e99b42 100644 --- a/docs/modules.js +++ b/docs/modules.js @@ -4,6 +4,7 @@ var modules = [ "Extended Functions", "group__extended.html", "group__extended" ], [ "Aligned Allocation", "group__aligned.html", "group__aligned" ], [ "Heap Allocation", "group__heap.html", "group__heap" ], + [ "Zero initialized re-allocation", "group__zeroinit.html", "group__zeroinit" ], [ "Typed Macros", "group__typed.html", "group__typed" ], [ "Heap Introspection", "group__analysis.html", "group__analysis" ], [ "Runtime Options", "group__options.html", "group__options" ], diff --git a/docs/navtreedata.js b/docs/navtreedata.js index f1be4622..e6dc7bc0 100644 --- a/docs/navtreedata.js +++ b/docs/navtreedata.js @@ -26,6 +26,7 @@ var NAVTREE = [ "mi-malloc", "index.html", [ [ "Building", "build.html", null ], [ "Using the library", "using.html", null ], + [ "Environment Options", "environment.html", null ], [ "Overriding Malloc", "overrides.html", null ], [ "Performance", "bench.html", null ], [ "Modules", "modules.html", "modules" ], diff --git a/docs/navtreeindex0.js b/docs/navtreeindex0.js index f026a1ff..90be7d78 100644 --- a/docs/navtreeindex0.js +++ b/docs/navtreeindex0.js @@ -1,138 +1,163 @@ var NAVTREEINDEX0 = { -"annotated.html":[5,0], -"bench.html":[3], +"annotated.html":[6,0], +"bench.html":[4], "build.html":[0], -"classes.html":[5,1], -"functions.html":[5,2,0], -"functions_vars.html":[5,2,1], -"group__aligned.html":[4,2], -"group__aligned.html#ga08647c4593f3b2eef24a919a73eba3a3":[4,2,1], -"group__aligned.html#ga0cadbcf5b89a7b6fb171bc8df8734819":[4,2,6], -"group__aligned.html#ga4028d1cf4aa4c87c880747044a8322ae":[4,2,4], -"group__aligned.html#ga53dddb4724042a90315b94bc268fb4c9":[4,2,0], -"group__aligned.html#ga5850da130c936bd77db039dcfbc8295d":[4,2,3], -"group__aligned.html#ga5f8c2353766db522565e642fafd8a3f8":[4,2,7], -"group__aligned.html#ga68930196751fa2cca9e1fd0d71bade56":[4,2,2], -"group__aligned.html#gaf66a9ae6c6f08bd6be6fb6ea771faffb":[4,2,5], -"group__analysis.html":[4,5], -"group__analysis.html#a332a6c14d736a99699d5453a1cb04b41":[4,5,0,0], -"group__analysis.html#ab47526df656d8837ec3e97f11b83f835":[4,5,0,2], -"group__analysis.html#ab820302c5cd0df133eb8e51650a008b4":[4,5,0,4], -"group__analysis.html#ae0085e6e1cf059a4eb7767e30e9991b8":[4,5,0,1], -"group__analysis.html#ae848a3e6840414891035423948ca0383":[4,5,0,3], -"group__analysis.html#ga0d67c1789faaa15ff366c024fcaf6377":[4,5,3], -"group__analysis.html#ga628c237489c2679af84a4d0d143b3dd5":[4,5,2], -"group__analysis.html#ga70c46687dc6e9dc98b232b02646f8bed":[4,5,5], -"group__analysis.html#gaa862aa8ed8d57d84cae41fc1022d71af":[4,5,4], -"group__analysis.html#gadfa01e2900f0e5d515ad5506b26f6d65":[4,5,1], -"group__analysis.html#structmi__heap__area__t":[4,5,0], -"group__extended.html":[4,1], -"group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee":[4,1,11], -"group__extended.html#ga1ea64283508718d9d645c38efc2f4305":[4,1,0], -"group__extended.html#ga220f29f40a44404b0061c15bc1c31152":[4,1,12], -"group__extended.html#ga22213691c3ce5ab4d91b24aff1023529":[4,1,1], -"group__extended.html#ga24dc9cc6fca8daa2aa30aa8025467ce2":[4,1,5], -"group__extended.html#ga421430e2226d7d468529cec457396756":[4,1,2], -"group__extended.html#ga490826cbd7c494acc9fe69be23f018ac":[4,1,10], -"group__extended.html#ga6bb821ca1b664b452112c0e17b15fcf1":[4,1,6], -"group__extended.html#ga7136c2e55cb22c98ecf95d08d6debb99":[4,1,4], -"group__extended.html#ga9398517f01a1ec971244aa0db084ea46":[4,1,9], -"group__extended.html#ga9883b8a059aed7eb0888a01ec1461161":[4,1,7], -"group__extended.html#gac057927cd06c854b45fe7847e921bd47":[4,1,3], -"group__extended.html#gac0f4849256aaf677f334690952c6ebbd":[4,1,8], -"group__heap.html":[4,3], -"group__heap.html#ga00e95ba1e01acac3cfd95bb7a357a6f0":[4,3,18], -"group__heap.html#ga08ca6419a5c057a4d965868998eef487":[4,3,3], -"group__heap.html#ga139d6b09dbf50c3c2523d0f4d1cfdeb5":[4,3,20], -"group__heap.html#ga23acd7680fb0976dde3783254c6c874b":[4,3,10], -"group__heap.html#ga2ab1af8d438819b55319c7ef51d1e409":[4,3,4], -"group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2":[4,3,0], -"group__heap.html#ga45fb43a62776fbebbdf1edd99b527954":[4,3,24], -"group__heap.html#ga4a21070eb4e7cce018133c8d5f4b0527":[4,3,16], -"group__heap.html#ga4af03a6e2b93fae77424d93f889705c3":[4,3,2], -"group__heap.html#ga5d03fbe062ffcf38f0f417fd968357fc":[4,3,6], -"group__heap.html#ga766f672ba56f2fbfeb9d9dbb0b7f6b11":[4,3,12], -"group__heap.html#ga851da6c43fe0b71c1376cee8aef90db0":[4,3,11], -"group__heap.html#ga8db4cbb87314a989a9a187464d6b5e05":[4,3,7], -"group__heap.html#ga8e3dbd46650dd26573cf307a2c8f1f5a":[4,3,21], -"group__heap.html#ga903104592c8ed53417a3762da6241133":[4,3,22], -"group__heap.html#ga9cbed01e42c0647907295de92c3fa296":[4,3,8], -"group__heap.html#ga9f9c0844edb9717f4feacd79116b8e0d":[4,3,5], -"group__heap.html#gaa450a59c6c7ae5fdbd1c2b80a8329ef0":[4,3,23], -"group__heap.html#gaa6702b3c48e9e53e50e81b36f5011d55":[4,3,1], -"group__heap.html#gaaef3395f66be48f37bdc8322509c5d81":[4,3,13], -"group__heap.html#gab5b87e1805306f70df38789fcfcf6653":[4,3,9], -"group__heap.html#gab8631ec88c8d26641b68b5d25dcd4422":[4,3,19], -"group__heap.html#gac74e94ad9b0c9b57c1c4d88b8825b7a8":[4,3,17], -"group__heap.html#gaf96c788a1bf553fe2d371de9365e047c":[4,3,15], -"group__heap.html#gafc603b696bd14cae6da28658f950d98c":[4,3,14], -"group__malloc.html":[4,0], -"group__malloc.html#ga08cec32dd5bbe7da91c78d19f1b5bebe":[4,0,8], -"group__malloc.html#ga0b05e2bf0f73e7401ae08597ff782ac6":[4,0,4], -"group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc":[4,0,9], -"group__malloc.html#ga3406e8b168bc74c8637b11571a6da83a":[4,0,3], -"group__malloc.html#ga61d57b4144ba24fba5c1e9b956d13853":[4,0,7], -"group__malloc.html#ga97fedb4f7107c592fd7f0f0a8949a57d":[4,0,0], -"group__malloc.html#gaaabf971c2571891433477e2d21a35266":[4,0,11], -"group__malloc.html#gaaee66a1d483c3e28f585525fb96707e4":[4,0,1], -"group__malloc.html#gac7cffe13f1f458ed16789488bf92b9b2":[4,0,10], -"group__malloc.html#gaf11eb497da57bdfb2de65eb191c69db6":[4,0,5], -"group__malloc.html#gaf2c7b89c327d1f60f59e68b9ea644d95":[4,0,2], -"group__malloc.html#gafdd9d8bb2986e668ba9884f28af38000":[4,0,12], -"group__malloc.html#gafe68ac7c5e24a65cd55c9d6b152211a0":[4,0,6], -"group__options.html":[4,6], -"group__options.html#ga37988264b915a7db92530cc02d5494cb":[4,6,2], -"group__options.html#ga6d45a20a3131f18bc351b69763b38ce4":[4,6,1], -"group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a":[4,6,4], -"group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90":[4,6,6], -"group__options.html#gacebe3f6d91b4a50b54eb84e2a1da1b30":[4,6,3], -"group__options.html#gaf84921c32375e25754dc2ee6a911fa60":[4,6,5], -"group__options.html#gafebf7ed116adb38ae5218bc3ce06884c":[4,6,0], -"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca083ee20765063fc6d727e11d33cf378f":[4,6,0,3], -"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda":[4,6,0,0], -"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b":[4,6,0,4], -"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca32ce97ece29f69e82579679cf8a307ad":[4,6,0,5], -"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4192d491200d0055df0554d4cf65054e":[4,6,0,6], -"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca5b4357b74be0d87568036c32eb1a2e4a":[4,6,0,11], -"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777":[4,6,0,2], -"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cab3a837b5ceee250e14e051dbee2a441b":[4,6,0,10], -"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac2157a0cb79cd996c1db7d9f6a090c07":[4,6,0,8], -"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac81ee965b130fa81238913a3c239d536":[4,6,0,9], -"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cada854dd272c66342f18a93ee254a2968":[4,6,0,7], -"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0":[4,6,0,1], -"group__posix.html":[4,7], -"group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17":[4,7,7], -"group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9":[4,7,3], -"group__posix.html#ga1326d2e4388630b5f81ca7206318b8e5":[4,7,1], -"group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de":[4,7,6], -"group__posix.html#ga48fad8648a2f1dab9c87ea9448a52088":[4,7,15], -"group__posix.html#ga705dc7a64bffacfeeb0141501a5c35d7":[4,7,2], -"group__posix.html#ga72e9d7ffb5fe94d69bc722c8506e27bc":[4,7,5], -"group__posix.html#ga73baaf5951f5165ba0763d0c06b6a93b":[4,7,16], -"group__posix.html#gaab7fa71ea93b96873f5d9883db57d40e":[4,7,8], -"group__posix.html#gaad048a9fce3d02c5909cd05c6ec24545":[4,7,9], -"group__posix.html#gab5e29558926d934c3f1cae8c815f942c":[4,7,11], -"group__posix.html#gacff84f226ba9feb2031b8992e5579447":[4,7,13], -"group__posix.html#gad5a69c8fea96aa2b7a7c818c2130090a":[4,7,0], -"group__posix.html#gae01389eedab8d67341ff52e2aad80ebb":[4,7,4], -"group__posix.html#gaeaded64eda71ed6b1d569d3e723abc4a":[4,7,12], -"group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e":[4,7,14], -"group__posix.html#gaef2c2bdb4f70857902d3c8903ac095f3":[4,7,10], -"group__typed.html":[4,4], -"group__typed.html#ga0619a62c5fd886f1016030abe91f0557":[4,4,6], -"group__typed.html#ga1158b49a55dfa81f58a4426a7578f523":[4,4,8], -"group__typed.html#ga4e5d1f1707c90e5f55e023ac5f45fe74":[4,4,1], -"group__typed.html#ga653bcb24ac495bc19940ecd6898f9cd7":[4,4,2], -"group__typed.html#ga6b75cb9c4b9c647661d0924552dc6e83":[4,4,3], -"group__typed.html#gac77a61bdaf680a803785fe307820b48c":[4,4,9], -"group__typed.html#gad6e87e86e994aa14416ae9b5d4c188fe":[4,4,5], -"group__typed.html#gae5cb6e0fafc9f23169c5622e077afe8b":[4,4,7], -"group__typed.html#gae80c47c9d4cab10961fff1a8ac98fc07":[4,4,0], -"group__typed.html#gaf213d5422ec35e7f6caad827c79bc948":[4,4,4], +"classes.html":[6,1], +"environment.html":[2], +"functions.html":[6,2,0], +"functions_vars.html":[6,2,1], +"group__aligned.html":[5,2], +"group__aligned.html#ga08647c4593f3b2eef24a919a73eba3a3":[5,2,1], +"group__aligned.html#ga0cadbcf5b89a7b6fb171bc8df8734819":[5,2,6], +"group__aligned.html#ga4028d1cf4aa4c87c880747044a8322ae":[5,2,4], +"group__aligned.html#ga53dddb4724042a90315b94bc268fb4c9":[5,2,0], +"group__aligned.html#ga5850da130c936bd77db039dcfbc8295d":[5,2,3], +"group__aligned.html#ga5f8c2353766db522565e642fafd8a3f8":[5,2,7], +"group__aligned.html#ga68930196751fa2cca9e1fd0d71bade56":[5,2,2], +"group__aligned.html#gaf66a9ae6c6f08bd6be6fb6ea771faffb":[5,2,5], +"group__analysis.html":[5,6], +"group__analysis.html#a332a6c14d736a99699d5453a1cb04b41":[5,6,0,0], +"group__analysis.html#ab47526df656d8837ec3e97f11b83f835":[5,6,0,2], +"group__analysis.html#ab820302c5cd0df133eb8e51650a008b4":[5,6,0,4], +"group__analysis.html#ae0085e6e1cf059a4eb7767e30e9991b8":[5,6,0,1], +"group__analysis.html#ae848a3e6840414891035423948ca0383":[5,6,0,3], +"group__analysis.html#ga0d67c1789faaa15ff366c024fcaf6377":[5,6,3], +"group__analysis.html#ga628c237489c2679af84a4d0d143b3dd5":[5,6,2], +"group__analysis.html#ga70c46687dc6e9dc98b232b02646f8bed":[5,6,5], +"group__analysis.html#gaa862aa8ed8d57d84cae41fc1022d71af":[5,6,4], +"group__analysis.html#gadfa01e2900f0e5d515ad5506b26f6d65":[5,6,1], +"group__analysis.html#structmi__heap__area__t":[5,6,0], +"group__extended.html":[5,1], +"group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee":[5,1,17], +"group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf":[5,1,14], +"group__extended.html#ga1ea64283508718d9d645c38efc2f4305":[5,1,0], +"group__extended.html#ga220f29f40a44404b0061c15bc1c31152":[5,1,18], +"group__extended.html#ga22213691c3ce5ab4d91b24aff1023529":[5,1,1], +"group__extended.html#ga24dc9cc6fca8daa2aa30aa8025467ce2":[5,1,8], +"group__extended.html#ga2664f36a2dd557741c429cb799f04641":[5,1,10], +"group__extended.html#ga2bed6d40b74591a67f81daea4b4a246f":[5,1,2], +"group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99":[5,1,13], +"group__extended.html#ga421430e2226d7d468529cec457396756":[5,1,3], +"group__extended.html#ga489670a15d1a257ab4639e645ee4612a":[5,1,16], +"group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6":[5,1,5], +"group__extended.html#ga7136c2e55cb22c98ecf95d08d6debb99":[5,1,7], +"group__extended.html#ga84a0c8b401e42eb5b1bce156852f44c5":[5,1,9], +"group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1":[5,1,11], +"group__extended.html#ga8ca07ccff283956d71f48272f4fd5c01":[5,1,12], +"group__extended.html#gaad25050b19f30cd79397b227e0157a3f":[5,1,6], +"group__extended.html#gac057927cd06c854b45fe7847e921bd47":[5,1,4], +"group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17":[5,1,15], +"group__heap.html":[5,3], +"group__heap.html#ga00e95ba1e01acac3cfd95bb7a357a6f0":[5,3,20], +"group__heap.html#ga08ca6419a5c057a4d965868998eef487":[5,3,3], +"group__heap.html#ga139d6b09dbf50c3c2523d0f4d1cfdeb5":[5,3,22], +"group__heap.html#ga23acd7680fb0976dde3783254c6c874b":[5,3,11], +"group__heap.html#ga2ab1af8d438819b55319c7ef51d1e409":[5,3,5], +"group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2":[5,3,0], +"group__heap.html#ga45fb43a62776fbebbdf1edd99b527954":[5,3,26], +"group__heap.html#ga4a21070eb4e7cce018133c8d5f4b0527":[5,3,18], +"group__heap.html#ga4af03a6e2b93fae77424d93f889705c3":[5,3,2], +"group__heap.html#ga5d03fbe062ffcf38f0f417fd968357fc":[5,3,7], +"group__heap.html#ga766f672ba56f2fbfeb9d9dbb0b7f6b11":[5,3,14], +"group__heap.html#ga7922f7495cde30b1984d0e6072419298":[5,3,4], +"group__heap.html#ga851da6c43fe0b71c1376cee8aef90db0":[5,3,13], +"group__heap.html#ga8db4cbb87314a989a9a187464d6b5e05":[5,3,8], +"group__heap.html#ga8e3dbd46650dd26573cf307a2c8f1f5a":[5,3,23], +"group__heap.html#ga903104592c8ed53417a3762da6241133":[5,3,24], +"group__heap.html#ga9cbed01e42c0647907295de92c3fa296":[5,3,9], +"group__heap.html#ga9f9c0844edb9717f4feacd79116b8e0d":[5,3,6], +"group__heap.html#gaa1a1c7a1f4da6826b5a25b70ef878368":[5,3,12], +"group__heap.html#gaa450a59c6c7ae5fdbd1c2b80a8329ef0":[5,3,25], +"group__heap.html#gaa6702b3c48e9e53e50e81b36f5011d55":[5,3,1], +"group__heap.html#gaaef3395f66be48f37bdc8322509c5d81":[5,3,15], +"group__heap.html#gab5b87e1805306f70df38789fcfcf6653":[5,3,10], +"group__heap.html#gab8631ec88c8d26641b68b5d25dcd4422":[5,3,21], +"group__heap.html#gac74e94ad9b0c9b57c1c4d88b8825b7a8":[5,3,19], +"group__heap.html#gaf96c788a1bf553fe2d371de9365e047c":[5,3,17], +"group__heap.html#gafc603b696bd14cae6da28658f950d98c":[5,3,16], +"group__malloc.html":[5,0], +"group__malloc.html#ga08cec32dd5bbe7da91c78d19f1b5bebe":[5,0,8], +"group__malloc.html#ga0b05e2bf0f73e7401ae08597ff782ac6":[5,0,4], +"group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc":[5,0,9], +"group__malloc.html#ga3406e8b168bc74c8637b11571a6da83a":[5,0,3], +"group__malloc.html#ga61d57b4144ba24fba5c1e9b956d13853":[5,0,7], +"group__malloc.html#ga97fedb4f7107c592fd7f0f0a8949a57d":[5,0,0], +"group__malloc.html#gaaabf971c2571891433477e2d21a35266":[5,0,11], +"group__malloc.html#gaaee66a1d483c3e28f585525fb96707e4":[5,0,1], +"group__malloc.html#gac7cffe13f1f458ed16789488bf92b9b2":[5,0,10], +"group__malloc.html#gaf11eb497da57bdfb2de65eb191c69db6":[5,0,5], +"group__malloc.html#gaf2c7b89c327d1f60f59e68b9ea644d95":[5,0,2], +"group__malloc.html#gafdd9d8bb2986e668ba9884f28af38000":[5,0,12], +"group__malloc.html#gafe68ac7c5e24a65cd55c9d6b152211a0":[5,0,6], +"group__options.html":[5,7], +"group__options.html#ga37988264b915a7db92530cc02d5494cb":[5,7,2], +"group__options.html#ga6d45a20a3131f18bc351b69763b38ce4":[5,7,1], +"group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a":[5,7,4], +"group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90":[5,7,6], +"group__options.html#gacebe3f6d91b4a50b54eb84e2a1da1b30":[5,7,3], +"group__options.html#gaf84921c32375e25754dc2ee6a911fa60":[5,7,5], +"group__options.html#gafebf7ed116adb38ae5218bc3ce06884c":[5,7,0], +"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda":[5,7,0,0], +"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c":[5,7,0,11], +"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b":[5,7,0,3], +"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca2ecbe7ef32f5c84de3739aa4f0b805a1":[5,7,0,7], +"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca32ce97ece29f69e82579679cf8a307ad":[5,7,0,4], +"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4192d491200d0055df0554d4cf65054e":[5,7,0,5], +"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf":[5,7,0,13], +"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca5b4357b74be0d87568036c32eb1a2e4a":[5,7,0,14], +"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777":[5,7,0,2], +"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac2157a0cb79cd996c1db7d9f6a090c07":[5,7,0,9], +"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac81ee965b130fa81238913a3c239d536":[5,7,0,10], +"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2":[5,7,0,6], +"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cada854dd272c66342f18a93ee254a2968":[5,7,0,8], +"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafb121d30d87591850d5410ccc3a95c6d":[5,7,0,12], +"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0":[5,7,0,1], +"group__posix.html":[5,8], +"group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17":[5,8,7], +"group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9":[5,8,3], +"group__posix.html#ga1326d2e4388630b5f81ca7206318b8e5":[5,8,1], +"group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de":[5,8,6], +"group__posix.html#ga48fad8648a2f1dab9c87ea9448a52088":[5,8,15], +"group__posix.html#ga705dc7a64bffacfeeb0141501a5c35d7":[5,8,2], +"group__posix.html#ga72e9d7ffb5fe94d69bc722c8506e27bc":[5,8,5], +"group__posix.html#ga73baaf5951f5165ba0763d0c06b6a93b":[5,8,16], +"group__posix.html#gaab7fa71ea93b96873f5d9883db57d40e":[5,8,8], +"group__posix.html#gaad048a9fce3d02c5909cd05c6ec24545":[5,8,9], +"group__posix.html#gab5e29558926d934c3f1cae8c815f942c":[5,8,11], +"group__posix.html#gacff84f226ba9feb2031b8992e5579447":[5,8,13], +"group__posix.html#gad5a69c8fea96aa2b7a7c818c2130090a":[5,8,0], +"group__posix.html#gae01389eedab8d67341ff52e2aad80ebb":[5,8,4], +"group__posix.html#gaeaded64eda71ed6b1d569d3e723abc4a":[5,8,12], +"group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e":[5,8,14], +"group__posix.html#gaef2c2bdb4f70857902d3c8903ac095f3":[5,8,10], +"group__typed.html":[5,5], +"group__typed.html#ga0619a62c5fd886f1016030abe91f0557":[5,5,7], +"group__typed.html#ga1158b49a55dfa81f58a4426a7578f523":[5,5,9], +"group__typed.html#ga3e50a1600958fcaf1a7f3560c9174f9e":[5,5,5], +"group__typed.html#ga4e5d1f1707c90e5f55e023ac5f45fe74":[5,5,1], +"group__typed.html#ga653bcb24ac495bc19940ecd6898f9cd7":[5,5,2], +"group__typed.html#ga6b75cb9c4b9c647661d0924552dc6e83":[5,5,3], +"group__typed.html#gac77a61bdaf680a803785fe307820b48c":[5,5,10], +"group__typed.html#gad6e87e86e994aa14416ae9b5d4c188fe":[5,5,6], +"group__typed.html#gae5cb6e0fafc9f23169c5622e077afe8b":[5,5,8], +"group__typed.html#gae80c47c9d4cab10961fff1a8ac98fc07":[5,5,0], +"group__typed.html#gaf213d5422ec35e7f6caad827c79bc948":[5,5,4], +"group__zeroinit.html":[5,4], +"group__zeroinit.html#ga375fa8a611c51905e592d5d467c49664":[5,4,4], +"group__zeroinit.html#ga3e7e5c291acf1c7fd7ffd9914a9f945f":[5,4,6], +"group__zeroinit.html#ga496452c96f1de8c500be9fddf52edaf7":[5,4,2], +"group__zeroinit.html#ga4ff5e92ad73585418a072c9d059e5cf9":[5,4,7], +"group__zeroinit.html#ga8648c5fbb22a80f0262859099f06dfbd":[5,4,0], +"group__zeroinit.html#ga8c292e142110229a2980b37ab036dbc6":[5,4,8], +"group__zeroinit.html#ga9f3f999396c8f77ca5e80e7b40ac29e3":[5,4,1], +"group__zeroinit.html#gac90da54fa7e5d10bdc97ce0b51dce2eb":[5,4,5], +"group__zeroinit.html#gacd71a7bce96aab38ae6de17af2eb2cf0":[5,4,9], +"group__zeroinit.html#gacfad83f14eb5d6a42a497a898e19fc76":[5,4,3], +"group__zeroinit.html#gae8b358c417e61d5307da002702b0a8e1":[5,4,10], "index.html":[], -"modules.html":[4], -"overrides.html":[2], +"modules.html":[5], +"overrides.html":[3], "pages.html":[], "using.html":[1] }; diff --git a/docs/overrides.html b/docs/overrides.html index 2833f4f9..74ef9dbd 100644 --- a/docs/overrides.html +++ b/docs/overrides.html @@ -118,9 +118,10 @@ $(document).ready(function(){initNavTree('overrides.html','');});

      Note that certain security restrictions may apply when doing this from the shell.

      Note: unfortunately, at this time, dynamic overriding on macOS seems broken but it is actively worked on to fix this (see issue #50).

      Windows

      -

      On Windows you need to link your program explicitly with the mimalloc DLL, and use the C-runtime library as a DLL (the /MD or /MDd switch). To ensure the mimalloc DLL gets loaded it is easiest to insert some call to the mimalloc API in the main function, like mi_version() (or use the /INCLUDE:mi_version switch on the linker)

      -

      Due to the way mimalloc intercepts the standard malloc at runtime, it is best to link to the mimalloc import library first on the command line so it gets loaded right after the universal C runtime DLL (ucrtbase). See the mimalloc-override-test project for an example.

      -

      Note: the current overriding on Windows works for most programs but some programs still have trouble – the dev-exp branch contains a newer way of overriding that is more robust; try this out if you experience troubles.

      +

      On Windows you need to link your program explicitly with the mimalloc DLL and use the C-runtime library as a DLL (using the /MD or /MDd switch). Moreover, you need to ensure the mimalloc-redirect.dll (or mimalloc-redirect32.dll) is available in the same folder as the mimalloc DLL at runtime (as it as referred to by the mimalloc DLL). The redirection DLL's ensure all calls to the C runtime malloc API get redirected to mimalloc.

      +

      To ensure the mimalloc DLL is loaded at run-time it is easiest to insert some call to the mimalloc API in the main function, like mi_version() (or use the /INCLUDE:mi_version switch on the linker). See the mimalloc-override-test project for an example on how to use this.

      +

      The environment variable MIMALLOC_DISABLE_REDIRECT=1 can be used to disable dynamic overriding at run-time. Use MIMALLOC_VERBOSE=1 to check if mimalloc successfully redirected.

      +

      (Note: in principle, it should be possible to patch existing executables that are linked with the dynamic C runtime (ucrtbase.dll) by just putting the mimalloc DLL into the import table (and putting mimalloc-redirect.dll in the same folder) Such patching can be done for example with CFF Explorer).

      Static override

      On Unix systems, you can also statically link with mimalloc to override the standard malloc interface. The recommended way is to link the final program with the mimalloc single object file (mimalloc-override.o). We use an object file instead of a library file as linkers give preference to that over archives to resolve symbols. To ensure that the standard malloc interface resolves to the mimalloc library, link it as the first object file. For example:

      gcc -o myprogram mimalloc-override.o myfile1.c ...

      List of Overrides:

      diff --git a/docs/pages.html b/docs/pages.html index 30d7a144..d0ee9f7a 100644 --- a/docs/pages.html +++ b/docs/pages.html @@ -106,8 +106,9 @@ $(document).ready(function(){initNavTree('pages.html','');}); - - + + +
       Building
       Using the library
       Overriding Malloc
       Performance
       Environment Options
       Overriding Malloc
       Performance
      diff --git a/docs/search/all_4.js b/docs/search/all_4.js index 68c73dbe..059f44c7 100644 --- a/docs/search/all_4.js +++ b/docs/search/all_4.js @@ -1,4 +1,5 @@ var searchData= [ + ['environment_20options',['Environment Options',['../environment.html',1,'']]], ['extended_20functions',['Extended Functions',['../group__extended.html',1,'']]] ]; diff --git a/docs/search/all_6.js b/docs/search/all_6.js index 58ffa7e6..2edb9986 100644 --- a/docs/search/all_6.js +++ b/docs/search/all_6.js @@ -23,6 +23,7 @@ var searchData= ['mi_5fheap_5fcalloc_5faligned_5fat',['mi_heap_calloc_aligned_at',['../group__heap.html#ga08ca6419a5c057a4d965868998eef487',1,'mimalloc-doc.h']]], ['mi_5fheap_5fcalloc_5ftp',['mi_heap_calloc_tp',['../group__typed.html#ga4e5d1f1707c90e5f55e023ac5f45fe74',1,'mimalloc-doc.h']]], ['mi_5fheap_5fcheck_5fowned',['mi_heap_check_owned',['../group__analysis.html#ga0d67c1789faaa15ff366c024fcaf6377',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcollect',['mi_heap_collect',['../group__heap.html#ga7922f7495cde30b1984d0e6072419298',1,'mimalloc-doc.h']]], ['mi_5fheap_5fcontains_5fblock',['mi_heap_contains_block',['../group__analysis.html#gaa862aa8ed8d57d84cae41fc1022d71af',1,'mimalloc-doc.h']]], ['mi_5fheap_5fdelete',['mi_heap_delete',['../group__heap.html#ga2ab1af8d438819b55319c7ef51d1e409',1,'mimalloc-doc.h']]], ['mi_5fheap_5fdestroy',['mi_heap_destroy',['../group__heap.html#ga9f9c0844edb9717f4feacd79116b8e0d',1,'mimalloc-doc.h']]], @@ -31,6 +32,7 @@ var searchData= ['mi_5fheap_5fmalloc',['mi_heap_malloc',['../group__heap.html#ga9cbed01e42c0647907295de92c3fa296',1,'mimalloc-doc.h']]], ['mi_5fheap_5fmalloc_5faligned',['mi_heap_malloc_aligned',['../group__heap.html#gab5b87e1805306f70df38789fcfcf6653',1,'mimalloc-doc.h']]], ['mi_5fheap_5fmalloc_5faligned_5fat',['mi_heap_malloc_aligned_at',['../group__heap.html#ga23acd7680fb0976dde3783254c6c874b',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5fsmall',['mi_heap_malloc_small',['../group__heap.html#gaa1a1c7a1f4da6826b5a25b70ef878368',1,'mimalloc-doc.h']]], ['mi_5fheap_5fmalloc_5ftp',['mi_heap_malloc_tp',['../group__typed.html#ga653bcb24ac495bc19940ecd6898f9cd7',1,'mimalloc-doc.h']]], ['mi_5fheap_5fmallocn',['mi_heap_mallocn',['../group__heap.html#ga851da6c43fe0b71c1376cee8aef90db0',1,'mimalloc-doc.h']]], ['mi_5fheap_5fmallocn_5ftp',['mi_heap_mallocn_tp',['../group__typed.html#ga6b75cb9c4b9c647661d0924552dc6e83',1,'mimalloc-doc.h']]], @@ -42,6 +44,13 @@ var searchData= ['mi_5fheap_5freallocn',['mi_heap_reallocn',['../group__heap.html#gac74e94ad9b0c9b57c1c4d88b8825b7a8',1,'mimalloc-doc.h']]], ['mi_5fheap_5freallocn_5ftp',['mi_heap_reallocn_tp',['../group__typed.html#gaf213d5422ec35e7f6caad827c79bc948',1,'mimalloc-doc.h']]], ['mi_5fheap_5frealpath',['mi_heap_realpath',['../group__heap.html#ga00e95ba1e01acac3cfd95bb7a357a6f0',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc',['mi_heap_recalloc',['../group__zeroinit.html#ga8648c5fbb22a80f0262859099f06dfbd',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5faligned',['mi_heap_recalloc_aligned',['../group__zeroinit.html#ga9f3f999396c8f77ca5e80e7b40ac29e3',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5faligned_5fat',['mi_heap_recalloc_aligned_at',['../group__zeroinit.html#ga496452c96f1de8c500be9fddf52edaf7',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5ftp',['mi_heap_recalloc_tp',['../group__typed.html#ga3e50a1600958fcaf1a7f3560c9174f9e',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc',['mi_heap_rezalloc',['../group__zeroinit.html#gacfad83f14eb5d6a42a497a898e19fc76',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_5faligned',['mi_heap_rezalloc_aligned',['../group__zeroinit.html#ga375fa8a611c51905e592d5d467c49664',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_5faligned_5fat',['mi_heap_rezalloc_aligned_at',['../group__zeroinit.html#gac90da54fa7e5d10bdc97ce0b51dce2eb',1,'mimalloc-doc.h']]], ['mi_5fheap_5fset_5fdefault',['mi_heap_set_default',['../group__heap.html#gab8631ec88c8d26641b68b5d25dcd4422',1,'mimalloc-doc.h']]], ['mi_5fheap_5fstrdup',['mi_heap_strdup',['../group__heap.html#ga139d6b09dbf50c3c2523d0f4d1cfdeb5',1,'mimalloc-doc.h']]], ['mi_5fheap_5fstrndup',['mi_heap_strndup',['../group__heap.html#ga8e3dbd46650dd26573cf307a2c8f1f5a',1,'mimalloc-doc.h']]], @@ -51,6 +60,8 @@ var searchData= ['mi_5fheap_5fzalloc_5faligned',['mi_heap_zalloc_aligned',['../group__heap.html#gaa450a59c6c7ae5fdbd1c2b80a8329ef0',1,'mimalloc-doc.h']]], ['mi_5fheap_5fzalloc_5faligned_5fat',['mi_heap_zalloc_aligned_at',['../group__heap.html#ga45fb43a62776fbebbdf1edd99b527954',1,'mimalloc-doc.h']]], ['mi_5fheap_5fzalloc_5ftp',['mi_heap_zalloc_tp',['../group__typed.html#gad6e87e86e994aa14416ae9b5d4c188fe',1,'mimalloc-doc.h']]], + ['mi_5fis_5fin_5fheap_5fregion',['mi_is_in_heap_region',['../group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6',1,'mimalloc-doc.h']]], + ['mi_5fis_5fredirected',['mi_is_redirected',['../group__extended.html#gaad25050b19f30cd79397b227e0157a3f',1,'mimalloc-doc.h']]], ['mi_5fmalloc',['mi_malloc',['../group__malloc.html#ga3406e8b168bc74c8637b11571a6da83a',1,'mimalloc-doc.h']]], ['mi_5fmalloc_5faligned',['mi_malloc_aligned',['../group__aligned.html#ga68930196751fa2cca9e1fd0d71bade56',1,'mimalloc-doc.h']]], ['mi_5fmalloc_5faligned_5fat',['mi_malloc_aligned_at',['../group__aligned.html#ga5850da130c936bd77db039dcfbc8295d',1,'mimalloc-doc.h']]], @@ -67,22 +78,26 @@ var searchData= ['mi_5fnew_5fnothrow',['mi_new_nothrow',['../group__posix.html#gaeaded64eda71ed6b1d569d3e723abc4a',1,'mimalloc-doc.h']]], ['mi_5foption_5fcache_5freset',['mi_option_cache_reset',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac2157a0cb79cd996c1db7d9f6a090c07',1,'mimalloc-doc.h']]], ['mi_5foption_5feager_5fcommit',['mi_option_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b',1,'mimalloc-doc.h']]], + ['mi_5foption_5feager_5fcommit_5fdelay',['mi_option_eager_commit_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c',1,'mimalloc-doc.h']]], ['mi_5foption_5feager_5fregion_5fcommit',['mi_option_eager_region_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca32ce97ece29f69e82579679cf8a307ad',1,'mimalloc-doc.h']]], ['mi_5foption_5fenable',['mi_option_enable',['../group__options.html#ga6d45a20a3131f18bc351b69763b38ce4',1,'mimalloc-doc.h']]], ['mi_5foption_5fenable_5fdefault',['mi_option_enable_default',['../group__options.html#ga37988264b915a7db92530cc02d5494cb',1,'mimalloc-doc.h']]], ['mi_5foption_5fenabled',['mi_option_enabled',['../group__options.html#gacebe3f6d91b4a50b54eb84e2a1da1b30',1,'mimalloc-doc.h']]], ['mi_5foption_5fget',['mi_option_get',['../group__options.html#ga7e8af195cc81d3fa64ccf2662caa565a',1,'mimalloc-doc.h']]], ['mi_5foption_5flarge_5fos_5fpages',['mi_option_large_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4192d491200d0055df0554d4cf65054e',1,'mimalloc-doc.h']]], + ['mi_5foption_5fos_5ftag',['mi_option_os_tag',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf',1,'mimalloc-doc.h']]], ['mi_5foption_5fpage_5freset',['mi_option_page_reset',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cada854dd272c66342f18a93ee254a2968',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fhuge_5fos_5fpages',['mi_option_reserve_huge_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2',1,'mimalloc-doc.h']]], ['mi_5foption_5freset_5fdecommits',['mi_option_reset_decommits',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac81ee965b130fa81238913a3c239d536',1,'mimalloc-doc.h']]], - ['mi_5foption_5freset_5fdiscards',['mi_option_reset_discards',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cab3a837b5ceee250e14e051dbee2a441b',1,'mimalloc-doc.h']]], - ['mi_5foption_5fsecure',['mi_option_secure',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca083ee20765063fc6d727e11d33cf378f',1,'mimalloc-doc.h']]], + ['mi_5foption_5fsegment_5fcache',['mi_option_segment_cache',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca2ecbe7ef32f5c84de3739aa4f0b805a1',1,'mimalloc-doc.h']]], + ['mi_5foption_5fsegment_5freset',['mi_option_segment_reset',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafb121d30d87591850d5410ccc3a95c6d',1,'mimalloc-doc.h']]], ['mi_5foption_5fset',['mi_option_set',['../group__options.html#gaf84921c32375e25754dc2ee6a911fa60',1,'mimalloc-doc.h']]], ['mi_5foption_5fset_5fdefault',['mi_option_set_default',['../group__options.html#ga7ef623e440e6e5545cb08c94e71e4b90',1,'mimalloc-doc.h']]], ['mi_5foption_5fshow_5ferrors',['mi_option_show_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0',1,'mimalloc-doc.h']]], ['mi_5foption_5fshow_5fstats',['mi_option_show_stats',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda',1,'mimalloc-doc.h']]], ['mi_5foption_5ft',['mi_option_t',['../group__options.html#gafebf7ed116adb38ae5218bc3ce06884c',1,'mimalloc-doc.h']]], ['mi_5foption_5fverbose',['mi_option_verbose',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777',1,'mimalloc-doc.h']]], + ['mi_5foutput_5ffun',['mi_output_fun',['../group__extended.html#ga2bed6d40b74591a67f81daea4b4a246f',1,'mimalloc-doc.h']]], ['mi_5fposix_5fmemalign',['mi_posix_memalign',['../group__posix.html#gacff84f226ba9feb2031b8992e5579447',1,'mimalloc-doc.h']]], ['mi_5fpvalloc',['mi_pvalloc',['../group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e',1,'mimalloc-doc.h']]], ['mi_5frealloc',['mi_realloc',['../group__malloc.html#gaf11eb497da57bdfb2de65eb191c69db6',1,'mimalloc-doc.h']]], @@ -94,15 +109,23 @@ var searchData= ['mi_5freallocn_5ftp',['mi_reallocn_tp',['../group__typed.html#ga1158b49a55dfa81f58a4426a7578f523',1,'mimalloc-doc.h']]], ['mi_5frealpath',['mi_realpath',['../group__malloc.html#ga08cec32dd5bbe7da91c78d19f1b5bebe',1,'mimalloc-doc.h']]], ['mi_5frecalloc',['mi_recalloc',['../group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_5faligned',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e7e5c291acf1c7fd7ffd9914a9f945f',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_5faligned_5fat',['mi_recalloc_aligned_at',['../group__zeroinit.html#ga4ff5e92ad73585418a072c9d059e5cf9',1,'mimalloc-doc.h']]], ['mi_5fregister_5fdeferred_5ffree',['mi_register_deferred_free',['../group__extended.html#ga24dc9cc6fca8daa2aa30aa8025467ce2',1,'mimalloc-doc.h']]], + ['mi_5fregister_5foutput',['mi_register_output',['../group__extended.html#ga84a0c8b401e42eb5b1bce156852f44c5',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages',['mi_reserve_huge_os_pages',['../group__extended.html#ga2664f36a2dd557741c429cb799f04641',1,'mimalloc-doc.h']]], + ['mi_5frezalloc',['mi_rezalloc',['../group__zeroinit.html#ga8c292e142110229a2980b37ab036dbc6',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_5faligned',['mi_rezalloc_aligned',['../group__zeroinit.html#gacd71a7bce96aab38ae6de17af2eb2cf0',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_5faligned_5fat',['mi_rezalloc_aligned_at',['../group__zeroinit.html#gae8b358c417e61d5307da002702b0a8e1',1,'mimalloc-doc.h']]], ['mi_5fsmall_5fsize_5fmax',['MI_SMALL_SIZE_MAX',['../group__extended.html#ga1ea64283508718d9d645c38efc2f4305',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fprint',['mi_stats_print',['../group__extended.html#ga6bb821ca1b664b452112c0e17b15fcf1',1,'mimalloc-doc.h']]], - ['mi_5fstats_5freset',['mi_stats_reset',['../group__extended.html#ga9883b8a059aed7eb0888a01ec1461161',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fmerge',['mi_stats_merge',['../group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fprint',['mi_stats_print',['../group__extended.html#ga8ca07ccff283956d71f48272f4fd5c01',1,'mimalloc-doc.h']]], + ['mi_5fstats_5freset',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]], ['mi_5fstrdup',['mi_strdup',['../group__malloc.html#gac7cffe13f1f458ed16789488bf92b9b2',1,'mimalloc-doc.h']]], ['mi_5fstrndup',['mi_strndup',['../group__malloc.html#gaaabf971c2571891433477e2d21a35266',1,'mimalloc-doc.h']]], - ['mi_5fthread_5fdone',['mi_thread_done',['../group__extended.html#gac0f4849256aaf677f334690952c6ebbd',1,'mimalloc-doc.h']]], - ['mi_5fthread_5finit',['mi_thread_init',['../group__extended.html#ga9398517f01a1ec971244aa0db084ea46',1,'mimalloc-doc.h']]], - ['mi_5fthread_5fstats_5fprint',['mi_thread_stats_print',['../group__extended.html#ga490826cbd7c494acc9fe69be23f018ac',1,'mimalloc-doc.h']]], + ['mi_5fthread_5fdone',['mi_thread_done',['../group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf',1,'mimalloc-doc.h']]], + ['mi_5fthread_5finit',['mi_thread_init',['../group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17',1,'mimalloc-doc.h']]], + ['mi_5fthread_5fstats_5fprint',['mi_thread_stats_print',['../group__extended.html#ga489670a15d1a257ab4639e645ee4612a',1,'mimalloc-doc.h']]], ['mi_5fusable_5fsize',['mi_usable_size',['../group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee',1,'mimalloc-doc.h']]], ['mi_5fvalloc',['mi_valloc',['../group__posix.html#ga73baaf5951f5165ba0763d0c06b6a93b',1,'mimalloc-doc.h']]], ['mi_5fzalloc',['mi_zalloc',['../group__malloc.html#gafdd9d8bb2986e668ba9884f28af38000',1,'mimalloc-doc.h']]], diff --git a/docs/search/enumvalues_1.js b/docs/search/enumvalues_1.js index b9c9b6f6..3ed91631 100644 --- a/docs/search/enumvalues_1.js +++ b/docs/search/enumvalues_1.js @@ -2,12 +2,15 @@ var searchData= [ ['mi_5foption_5fcache_5freset',['mi_option_cache_reset',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac2157a0cb79cd996c1db7d9f6a090c07',1,'mimalloc-doc.h']]], ['mi_5foption_5feager_5fcommit',['mi_option_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b',1,'mimalloc-doc.h']]], + ['mi_5foption_5feager_5fcommit_5fdelay',['mi_option_eager_commit_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c',1,'mimalloc-doc.h']]], ['mi_5foption_5feager_5fregion_5fcommit',['mi_option_eager_region_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca32ce97ece29f69e82579679cf8a307ad',1,'mimalloc-doc.h']]], ['mi_5foption_5flarge_5fos_5fpages',['mi_option_large_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4192d491200d0055df0554d4cf65054e',1,'mimalloc-doc.h']]], + ['mi_5foption_5fos_5ftag',['mi_option_os_tag',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf',1,'mimalloc-doc.h']]], ['mi_5foption_5fpage_5freset',['mi_option_page_reset',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cada854dd272c66342f18a93ee254a2968',1,'mimalloc-doc.h']]], + ['mi_5foption_5freserve_5fhuge_5fos_5fpages',['mi_option_reserve_huge_os_pages',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884caca7ed041be3b0b9d0b82432c7bf41af2',1,'mimalloc-doc.h']]], ['mi_5foption_5freset_5fdecommits',['mi_option_reset_decommits',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac81ee965b130fa81238913a3c239d536',1,'mimalloc-doc.h']]], - ['mi_5foption_5freset_5fdiscards',['mi_option_reset_discards',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cab3a837b5ceee250e14e051dbee2a441b',1,'mimalloc-doc.h']]], - ['mi_5foption_5fsecure',['mi_option_secure',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca083ee20765063fc6d727e11d33cf378f',1,'mimalloc-doc.h']]], + ['mi_5foption_5fsegment_5fcache',['mi_option_segment_cache',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca2ecbe7ef32f5c84de3739aa4f0b805a1',1,'mimalloc-doc.h']]], + ['mi_5foption_5fsegment_5freset',['mi_option_segment_reset',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafb121d30d87591850d5410ccc3a95c6d',1,'mimalloc-doc.h']]], ['mi_5foption_5fshow_5ferrors',['mi_option_show_errors',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafbf4822e5c00732c5984b32a032837f0',1,'mimalloc-doc.h']]], ['mi_5foption_5fshow_5fstats',['mi_option_show_stats',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0957ef73b2550764b4840edf48422fda',1,'mimalloc-doc.h']]], ['mi_5foption_5fverbose',['mi_option_verbose',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777',1,'mimalloc-doc.h']]] diff --git a/docs/search/functions_0.js b/docs/search/functions_0.js index 2c169f9a..c5eeb540 100644 --- a/docs/search/functions_0.js +++ b/docs/search/functions_0.js @@ -18,6 +18,7 @@ var searchData= ['mi_5fheap_5fcalloc_5faligned',['mi_heap_calloc_aligned',['../group__heap.html#ga4af03a6e2b93fae77424d93f889705c3',1,'mimalloc-doc.h']]], ['mi_5fheap_5fcalloc_5faligned_5fat',['mi_heap_calloc_aligned_at',['../group__heap.html#ga08ca6419a5c057a4d965868998eef487',1,'mimalloc-doc.h']]], ['mi_5fheap_5fcheck_5fowned',['mi_heap_check_owned',['../group__analysis.html#ga0d67c1789faaa15ff366c024fcaf6377',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fcollect',['mi_heap_collect',['../group__heap.html#ga7922f7495cde30b1984d0e6072419298',1,'mimalloc-doc.h']]], ['mi_5fheap_5fcontains_5fblock',['mi_heap_contains_block',['../group__analysis.html#gaa862aa8ed8d57d84cae41fc1022d71af',1,'mimalloc-doc.h']]], ['mi_5fheap_5fdelete',['mi_heap_delete',['../group__heap.html#ga2ab1af8d438819b55319c7ef51d1e409',1,'mimalloc-doc.h']]], ['mi_5fheap_5fdestroy',['mi_heap_destroy',['../group__heap.html#ga9f9c0844edb9717f4feacd79116b8e0d',1,'mimalloc-doc.h']]], @@ -26,6 +27,7 @@ var searchData= ['mi_5fheap_5fmalloc',['mi_heap_malloc',['../group__heap.html#ga9cbed01e42c0647907295de92c3fa296',1,'mimalloc-doc.h']]], ['mi_5fheap_5fmalloc_5faligned',['mi_heap_malloc_aligned',['../group__heap.html#gab5b87e1805306f70df38789fcfcf6653',1,'mimalloc-doc.h']]], ['mi_5fheap_5fmalloc_5faligned_5fat',['mi_heap_malloc_aligned_at',['../group__heap.html#ga23acd7680fb0976dde3783254c6c874b',1,'mimalloc-doc.h']]], + ['mi_5fheap_5fmalloc_5fsmall',['mi_heap_malloc_small',['../group__heap.html#gaa1a1c7a1f4da6826b5a25b70ef878368',1,'mimalloc-doc.h']]], ['mi_5fheap_5fmallocn',['mi_heap_mallocn',['../group__heap.html#ga851da6c43fe0b71c1376cee8aef90db0',1,'mimalloc-doc.h']]], ['mi_5fheap_5fnew',['mi_heap_new',['../group__heap.html#ga766f672ba56f2fbfeb9d9dbb0b7f6b11',1,'mimalloc-doc.h']]], ['mi_5fheap_5frealloc',['mi_heap_realloc',['../group__heap.html#gaaef3395f66be48f37bdc8322509c5d81',1,'mimalloc-doc.h']]], @@ -34,6 +36,12 @@ var searchData= ['mi_5fheap_5freallocf',['mi_heap_reallocf',['../group__heap.html#ga4a21070eb4e7cce018133c8d5f4b0527',1,'mimalloc-doc.h']]], ['mi_5fheap_5freallocn',['mi_heap_reallocn',['../group__heap.html#gac74e94ad9b0c9b57c1c4d88b8825b7a8',1,'mimalloc-doc.h']]], ['mi_5fheap_5frealpath',['mi_heap_realpath',['../group__heap.html#ga00e95ba1e01acac3cfd95bb7a357a6f0',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc',['mi_heap_recalloc',['../group__zeroinit.html#ga8648c5fbb22a80f0262859099f06dfbd',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5faligned',['mi_heap_recalloc_aligned',['../group__zeroinit.html#ga9f3f999396c8f77ca5e80e7b40ac29e3',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frecalloc_5faligned_5fat',['mi_heap_recalloc_aligned_at',['../group__zeroinit.html#ga496452c96f1de8c500be9fddf52edaf7',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc',['mi_heap_rezalloc',['../group__zeroinit.html#gacfad83f14eb5d6a42a497a898e19fc76',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_5faligned',['mi_heap_rezalloc_aligned',['../group__zeroinit.html#ga375fa8a611c51905e592d5d467c49664',1,'mimalloc-doc.h']]], + ['mi_5fheap_5frezalloc_5faligned_5fat',['mi_heap_rezalloc_aligned_at',['../group__zeroinit.html#gac90da54fa7e5d10bdc97ce0b51dce2eb',1,'mimalloc-doc.h']]], ['mi_5fheap_5fset_5fdefault',['mi_heap_set_default',['../group__heap.html#gab8631ec88c8d26641b68b5d25dcd4422',1,'mimalloc-doc.h']]], ['mi_5fheap_5fstrdup',['mi_heap_strdup',['../group__heap.html#ga139d6b09dbf50c3c2523d0f4d1cfdeb5',1,'mimalloc-doc.h']]], ['mi_5fheap_5fstrndup',['mi_heap_strndup',['../group__heap.html#ga8e3dbd46650dd26573cf307a2c8f1f5a',1,'mimalloc-doc.h']]], @@ -41,6 +49,8 @@ var searchData= ['mi_5fheap_5fzalloc',['mi_heap_zalloc',['../group__heap.html#ga903104592c8ed53417a3762da6241133',1,'mimalloc-doc.h']]], ['mi_5fheap_5fzalloc_5faligned',['mi_heap_zalloc_aligned',['../group__heap.html#gaa450a59c6c7ae5fdbd1c2b80a8329ef0',1,'mimalloc-doc.h']]], ['mi_5fheap_5fzalloc_5faligned_5fat',['mi_heap_zalloc_aligned_at',['../group__heap.html#ga45fb43a62776fbebbdf1edd99b527954',1,'mimalloc-doc.h']]], + ['mi_5fis_5fin_5fheap_5fregion',['mi_is_in_heap_region',['../group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6',1,'mimalloc-doc.h']]], + ['mi_5fis_5fredirected',['mi_is_redirected',['../group__extended.html#gaad25050b19f30cd79397b227e0157a3f',1,'mimalloc-doc.h']]], ['mi_5fmalloc',['mi_malloc',['../group__malloc.html#ga3406e8b168bc74c8637b11571a6da83a',1,'mimalloc-doc.h']]], ['mi_5fmalloc_5faligned',['mi_malloc_aligned',['../group__aligned.html#ga68930196751fa2cca9e1fd0d71bade56',1,'mimalloc-doc.h']]], ['mi_5fmalloc_5faligned_5fat',['mi_malloc_aligned_at',['../group__aligned.html#ga5850da130c936bd77db039dcfbc8295d',1,'mimalloc-doc.h']]], @@ -69,14 +79,22 @@ var searchData= ['mi_5freallocn',['mi_reallocn',['../group__malloc.html#ga61d57b4144ba24fba5c1e9b956d13853',1,'mimalloc-doc.h']]], ['mi_5frealpath',['mi_realpath',['../group__malloc.html#ga08cec32dd5bbe7da91c78d19f1b5bebe',1,'mimalloc-doc.h']]], ['mi_5frecalloc',['mi_recalloc',['../group__malloc.html#ga23a0fbb452b5dce8e31fab1a1958cacc',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_5faligned',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e7e5c291acf1c7fd7ffd9914a9f945f',1,'mimalloc-doc.h']]], + ['mi_5frecalloc_5faligned_5fat',['mi_recalloc_aligned_at',['../group__zeroinit.html#ga4ff5e92ad73585418a072c9d059e5cf9',1,'mimalloc-doc.h']]], ['mi_5fregister_5fdeferred_5ffree',['mi_register_deferred_free',['../group__extended.html#ga24dc9cc6fca8daa2aa30aa8025467ce2',1,'mimalloc-doc.h']]], - ['mi_5fstats_5fprint',['mi_stats_print',['../group__extended.html#ga6bb821ca1b664b452112c0e17b15fcf1',1,'mimalloc-doc.h']]], - ['mi_5fstats_5freset',['mi_stats_reset',['../group__extended.html#ga9883b8a059aed7eb0888a01ec1461161',1,'mimalloc-doc.h']]], + ['mi_5fregister_5foutput',['mi_register_output',['../group__extended.html#ga84a0c8b401e42eb5b1bce156852f44c5',1,'mimalloc-doc.h']]], + ['mi_5freserve_5fhuge_5fos_5fpages',['mi_reserve_huge_os_pages',['../group__extended.html#ga2664f36a2dd557741c429cb799f04641',1,'mimalloc-doc.h']]], + ['mi_5frezalloc',['mi_rezalloc',['../group__zeroinit.html#ga8c292e142110229a2980b37ab036dbc6',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_5faligned',['mi_rezalloc_aligned',['../group__zeroinit.html#gacd71a7bce96aab38ae6de17af2eb2cf0',1,'mimalloc-doc.h']]], + ['mi_5frezalloc_5faligned_5fat',['mi_rezalloc_aligned_at',['../group__zeroinit.html#gae8b358c417e61d5307da002702b0a8e1',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fmerge',['mi_stats_merge',['../group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1',1,'mimalloc-doc.h']]], + ['mi_5fstats_5fprint',['mi_stats_print',['../group__extended.html#ga8ca07ccff283956d71f48272f4fd5c01',1,'mimalloc-doc.h']]], + ['mi_5fstats_5freset',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]], ['mi_5fstrdup',['mi_strdup',['../group__malloc.html#gac7cffe13f1f458ed16789488bf92b9b2',1,'mimalloc-doc.h']]], ['mi_5fstrndup',['mi_strndup',['../group__malloc.html#gaaabf971c2571891433477e2d21a35266',1,'mimalloc-doc.h']]], - ['mi_5fthread_5fdone',['mi_thread_done',['../group__extended.html#gac0f4849256aaf677f334690952c6ebbd',1,'mimalloc-doc.h']]], - ['mi_5fthread_5finit',['mi_thread_init',['../group__extended.html#ga9398517f01a1ec971244aa0db084ea46',1,'mimalloc-doc.h']]], - ['mi_5fthread_5fstats_5fprint',['mi_thread_stats_print',['../group__extended.html#ga490826cbd7c494acc9fe69be23f018ac',1,'mimalloc-doc.h']]], + ['mi_5fthread_5fdone',['mi_thread_done',['../group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf',1,'mimalloc-doc.h']]], + ['mi_5fthread_5finit',['mi_thread_init',['../group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17',1,'mimalloc-doc.h']]], + ['mi_5fthread_5fstats_5fprint',['mi_thread_stats_print',['../group__extended.html#ga489670a15d1a257ab4639e645ee4612a',1,'mimalloc-doc.h']]], ['mi_5fusable_5fsize',['mi_usable_size',['../group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee',1,'mimalloc-doc.h']]], ['mi_5fvalloc',['mi_valloc',['../group__posix.html#ga73baaf5951f5165ba0763d0c06b6a93b',1,'mimalloc-doc.h']]], ['mi_5fzalloc',['mi_zalloc',['../group__malloc.html#gafdd9d8bb2986e668ba9884f28af38000',1,'mimalloc-doc.h']]], diff --git a/docs/search/pages_1.js b/docs/search/pages_1.js index df03c8d8..0f2757cb 100644 --- a/docs/search/pages_1.js +++ b/docs/search/pages_1.js @@ -1,4 +1,4 @@ var searchData= [ - ['overriding_20malloc',['Overriding Malloc',['../overrides.html',1,'']]] + ['environment_20options',['Environment Options',['../environment.html',1,'']]] ]; diff --git a/docs/search/pages_2.js b/docs/search/pages_2.js index d7454039..df03c8d8 100644 --- a/docs/search/pages_2.js +++ b/docs/search/pages_2.js @@ -1,4 +1,4 @@ var searchData= [ - ['performance',['Performance',['../bench.html',1,'']]] + ['overriding_20malloc',['Overriding Malloc',['../overrides.html',1,'']]] ]; diff --git a/docs/search/pages_3.js b/docs/search/pages_3.js index b47682a4..d7454039 100644 --- a/docs/search/pages_3.js +++ b/docs/search/pages_3.js @@ -1,4 +1,4 @@ var searchData= [ - ['using_20the_20library',['Using the library',['../using.html',1,'']]] + ['performance',['Performance',['../bench.html',1,'']]] ]; diff --git a/docs/search/searchdata.js b/docs/search/searchdata.js index 7cbd7821..919719e9 100644 --- a/docs/search/searchdata.js +++ b/docs/search/searchdata.js @@ -1,14 +1,14 @@ var indexSectionsWithContent = { - 0: "_abcehmoprtu", + 0: "_abcehmoprtuz", 1: "m", 2: "m", 3: "bcru", 4: "m", 5: "m", 6: "_m", - 7: "abehprt", - 8: "bopu" + 7: "abehprtz", + 8: "beopu" }; var indexSectionNames = diff --git a/docs/search/typedefs_0.js b/docs/search/typedefs_0.js index 2372fd1f..c6f0f7ec 100644 --- a/docs/search/typedefs_0.js +++ b/docs/search/typedefs_0.js @@ -2,5 +2,6 @@ var searchData= [ ['mi_5fblock_5fvisit_5ffun',['mi_block_visit_fun',['../group__analysis.html#gadfa01e2900f0e5d515ad5506b26f6d65',1,'mimalloc-doc.h']]], ['mi_5fdeferred_5ffree_5ffun',['mi_deferred_free_fun',['../group__extended.html#ga22213691c3ce5ab4d91b24aff1023529',1,'mimalloc-doc.h']]], - ['mi_5fheap_5ft',['mi_heap_t',['../group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2',1,'mimalloc-doc.h']]] + ['mi_5fheap_5ft',['mi_heap_t',['../group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2',1,'mimalloc-doc.h']]], + ['mi_5foutput_5ffun',['mi_output_fun',['../group__extended.html#ga2bed6d40b74591a67f81daea4b4a246f',1,'mimalloc-doc.h']]] ]; diff --git a/docs/using.html b/docs/using.html index 04e180ef..9b7305b0 100644 --- a/docs/using.html +++ b/docs/using.html @@ -104,16 +104,7 @@ $(document).ready(function(){initNavTree('using.html','');});

      The preferred usage is including <mimalloc.h>, linking with the shared- or static library, and using the mi_malloc API exclusively for allocation. For example,

      gcc -o myprogram -lmimalloc myfile.c

      mimalloc uses only safe OS calls (mmap and VirtualAlloc) and can co-exist with other allocators linked to the same program. If you use cmake, you can simply use:

      find_package(mimalloc 1.0 REQUIRED)

      in your CMakeLists.txt to find a locally installed mimalloc. Then use either:

      target_link_libraries(myapp PUBLIC mimalloc)

      to link with the shared (dynamic) library, or:

      target_link_libraries(myapp PUBLIC mimalloc-static)

      to link with the static library. See test\CMakeLists.txt for an example.

      You can pass environment variables to print verbose messages (MIMALLOC_VERBOSE=1) and statistics (MIMALLOC_SHOW_STATS=1) (in the debug version):

      > env MIMALLOC_SHOW_STATS=1 ./cfrac 175451865205073170563711388363
      175451865205073170563711388363 = 374456281610909315237213 * 468551
      heap stats: peak total freed unit
      normal 2: 16.4 kb 17.5 mb 17.5 mb 16 b ok
      normal 3: 16.3 kb 15.2 mb 15.2 mb 24 b ok
      normal 4: 64 b 4.6 kb 4.6 kb 32 b ok
      normal 5: 80 b 118.4 kb 118.4 kb 40 b ok
      normal 6: 48 b 48 b 48 b 48 b ok
      normal 17: 960 b 960 b 960 b 320 b ok
      heap stats: peak total freed unit
      normal: 33.9 kb 32.8 mb 32.8 mb 1 b ok
      huge: 0 b 0 b 0 b 1 b ok
      total: 33.9 kb 32.8 mb 32.8 mb 1 b ok
      malloc requested: 32.8 mb
      committed: 58.2 kb 58.2 kb 58.2 kb 1 b ok
      reserved: 2.0 mb 2.0 mb 2.0 mb 1 b ok
      reset: 0 b 0 b 0 b 1 b ok
      segments: 1 1 1
      -abandoned: 0
      pages: 6 6 6
      -abandoned: 0
      mmaps: 3
      mmap fast: 0
      mmap slow: 1
      threads: 0
      elapsed: 2.022s
      process: user: 1.781s, system: 0.016s, faults: 756, reclaims: 0, rss: 2.7 mb

      The above model of using the mi_ prefixed API is not always possible though in existing programs that already use the standard malloc interface, and another option is to override the standard malloc interface completely and redirect all calls to the mimalloc library instead.

      -

      See Overriding Malloc for more info.

      -

      Environment Options

      -

      You can set further options either programmatically (using mi_option_set), or via environment variables.

      -
        -
      • MIMALLOC_SHOW_STATS=1: show statistics when the program terminates.
      • -
      • MIMALLOC_VERBOSE=1: show verbose messages.
      • -
      • MIMALLOC_SHOW_ERRORS=1: show error and warning messages.
      • -
      • MIMALLOC_LARGE_OS_PAGES=1: use large OS pages when available; for some workloads this can significantly improve performance. Use MIMALLOC_VERBOSE to check if the large OS pages are enabled – usually one needs to explicitly allow large OS pages (as on Windows and Linux).
      • -
      • MIMALLOC_EAGER_REGION_COMMIT=1: on Windows, commit large (256MiB) regions eagerly. On Windows, these regions show in the working set even though usually just a small part is committed to physical memory. This is why it turned off by default on Windows as it looks not good in the task manager. However, in reality it is always better to turn it on as it improves performance and has no other drawbacks.
      • -
      +

      See Overriding Malloc for more info.

      From 6896408ab1277d4d4078d3fd2046cf294bbbf313 Mon Sep 17 00:00:00 2001 From: daan Date: Wed, 11 Sep 2019 20:49:18 -0700 Subject: [PATCH 63/92] fix definition of mi_recalloc_tp --- include/mimalloc.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 1d5431ff..5ed3246f 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -181,8 +181,8 @@ mi_decl_export mi_decl_allocator void* mi_heap_realloc_aligned_at(mi_heap_t* hea // -------------------------------------------------------------------------------- -// Zero initialized re-allocation. -// Only valid on memory that was originally allocated with zero initialization too. +// Zero initialized re-allocation. +// Only valid on memory that was originally allocated with zero initialization too. // e.g. `mi_calloc`, `mi_zalloc`, `mi_zalloc_aligned` etc. // see // -------------------------------------------------------------------------------- @@ -246,8 +246,8 @@ mi_decl_export bool mi_is_redirected() mi_attr_noexcept; #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp))) #define mi_heap_calloc_tp(hp,tp,n) ((tp*)mi_heap_calloc(hp,n,sizeof(tp))) #define mi_heap_mallocn_tp(hp,tp,n) ((tp*)mi_heap_mallocn(hp,n,sizeof(tp))) -#define mi_heap_reallocn_tp(hp,tp,n) ((tp*)mi_heap_reallocn(hp,n,sizeof(tp))) -#define mi_heap_recalloc_tp(hp,tp,n) ((tp*)mi_heap_recalloc(hp,n,sizeof(tp))) +#define mi_heap_reallocn_tp(hp,p,tp,n) ((tp*)mi_heap_reallocn(hp,p,n,sizeof(tp))) +#define mi_heap_recalloc_tp(hp,p,tp,n) ((tp*)mi_heap_recalloc(hp,p,n,sizeof(tp))) // ------------------------------------------------------ From adf8e30eda30398701c75a536798d9906f3b09a8 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 14 Sep 2019 15:23:28 -0700 Subject: [PATCH 64/92] ensure large page privileges are acquired on windows when calling reserve_huge_os_pages --- src/os.c | 70 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/src/os.c b/src/os.c index 899f98a2..71c375ec 100644 --- a/src/os.c +++ b/src/os.c @@ -99,6 +99,41 @@ typedef NTSTATUS (__stdcall *PNtAllocateVirtualMemoryEx)(HANDLE, PVOID*, SIZE_T* static PVirtualAlloc2 pVirtualAlloc2 = NULL; static PNtAllocateVirtualMemoryEx pNtAllocateVirtualMemoryEx = NULL; +static bool mi_win_enable_large_os_pages() +{ + if (large_os_page_size > 0) return true; + + // Try to see if large OS pages are supported + // To use large pages on Windows, we first need access permission + // Set "Lock pages in memory" permission in the group policy editor + // + unsigned long err = 0; + HANDLE token = NULL; + BOOL ok = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token); + if (ok) { + TOKEN_PRIVILEGES tp; + ok = LookupPrivilegeValue(NULL, TEXT("SeLockMemoryPrivilege"), &tp.Privileges[0].Luid); + if (ok) { + tp.PrivilegeCount = 1; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + ok = AdjustTokenPrivileges(token, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0); + if (ok) { + err = GetLastError(); + ok = (err == ERROR_SUCCESS); + if (ok) { + large_os_page_size = GetLargePageMinimum(); + } + } + } + CloseHandle(token); + } + if (!ok) { + if (err == 0) err = GetLastError(); + _mi_warning_message("cannot enable large OS page support, error %lu\n", err); + } + return (ok!=0); +} + void _mi_os_init(void) { // get the page size SYSTEM_INFO si; @@ -118,37 +153,9 @@ void _mi_os_init(void) { if (hDll != NULL) { pNtAllocateVirtualMemoryEx = (PNtAllocateVirtualMemoryEx)GetProcAddress(hDll, "NtAllocateVirtualMemoryEx"); FreeLibrary(hDll); - } - // Try to see if large OS pages are supported - unsigned long err = 0; - bool ok = mi_option_is_enabled(mi_option_large_os_pages) || mi_option_is_enabled(mi_option_reserve_huge_os_pages); - if (ok) { - // To use large pages on Windows, we first need access permission - // Set "Lock pages in memory" permission in the group policy editor - // - HANDLE token = NULL; - ok = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token); - if (ok) { - TOKEN_PRIVILEGES tp; - ok = LookupPrivilegeValue(NULL, TEXT("SeLockMemoryPrivilege"), &tp.Privileges[0].Luid); - if (ok) { - tp.PrivilegeCount = 1; - tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - ok = AdjustTokenPrivileges(token, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0); - if (ok) { - err = GetLastError(); - ok = (err == ERROR_SUCCESS); - if (ok) { - large_os_page_size = GetLargePageMinimum(); - } - } - } - CloseHandle(token); - } - if (!ok) { - if (err == 0) err = GetLastError(); - _mi_warning_message("cannot enable large OS page support, error %lu\n", err); - } + } + if (mi_option_is_enabled(mi_option_large_os_pages) || mi_option_is_enabled(mi_option_reserve_huge_os_pages)) { + mi_win_enable_large_os_pages(); } } #elif defined(__wasi__) @@ -887,6 +894,7 @@ int mi_reserve_huge_os_pages( size_t pages, double max_secs, size_t* pages_reser void* p = NULL; bool is_large = true; #ifdef _WIN32 + if (page==0) { mi_win_enable_large_os_pages(); } p = mi_win_virtual_alloc(addr, MI_HUGE_OS_PAGE_SIZE, 0, MEM_LARGE_PAGES | MEM_COMMIT | MEM_RESERVE, true, true, &is_large); #elif defined(MI_OS_USE_MMAP) p = mi_unix_mmap(addr, MI_HUGE_OS_PAGE_SIZE, 0, PROT_READ | PROT_WRITE, true, true, &is_large); From 33f4ec4ac60fabf680878db694909d26f9031a70 Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 15 Sep 2019 19:19:00 -0700 Subject: [PATCH 65/92] put new-delete overrides in separate header file --- CMakeLists.txt | 1 + ide/vs2017/mimalloc-override.vcxproj | 1 + ide/vs2017/mimalloc-override.vcxproj.filters | 3 ++ ide/vs2017/mimalloc.vcxproj | 1 + ide/vs2017/mimalloc.vcxproj.filters | 3 ++ ide/vs2019/mimalloc-override.vcxproj | 1 + ide/vs2019/mimalloc.vcxproj | 1 + include/mimalloc-new-delete.h | 52 ++++++++++++++++++++ include/mimalloc-override.h | 46 +---------------- 9 files changed, 64 insertions(+), 45 deletions(-) create mode 100644 include/mimalloc-new-delete.h diff --git a/CMakeLists.txt b/CMakeLists.txt index caba7d80..55db7232 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -172,6 +172,7 @@ install(TARGETS mimalloc EXPORT mimalloc DESTINATION ${mi_install_dir} LIBRARY N install(TARGETS mimalloc-static EXPORT mimalloc DESTINATION ${mi_install_dir}) install(FILES include/mimalloc.h DESTINATION ${mi_install_dir}/include) install(FILES include/mimalloc-override.h DESTINATION ${mi_install_dir}/include) +install(FILES include/mimalloc-new-delete.h DESTINATION ${mi_install_dir}/include) install(FILES cmake/mimalloc-config.cmake DESTINATION ${mi_install_dir}/cmake) install(FILES cmake/mimalloc-config-version.cmake DESTINATION ${mi_install_dir}/cmake) install(EXPORT mimalloc DESTINATION ${mi_install_dir}/cmake) diff --git a/ide/vs2017/mimalloc-override.vcxproj b/ide/vs2017/mimalloc-override.vcxproj index ffa14a54..511c0fab 100644 --- a/ide/vs2017/mimalloc-override.vcxproj +++ b/ide/vs2017/mimalloc-override.vcxproj @@ -212,6 +212,7 @@ + diff --git a/ide/vs2017/mimalloc-override.vcxproj.filters b/ide/vs2017/mimalloc-override.vcxproj.filters index ffabddac..6ac0c0b5 100644 --- a/ide/vs2017/mimalloc-override.vcxproj.filters +++ b/ide/vs2017/mimalloc-override.vcxproj.filters @@ -26,6 +26,9 @@ Header Files + + Header Files + diff --git a/ide/vs2017/mimalloc.vcxproj b/ide/vs2017/mimalloc.vcxproj index 854bf921..6147c349 100644 --- a/ide/vs2017/mimalloc.vcxproj +++ b/ide/vs2017/mimalloc.vcxproj @@ -238,6 +238,7 @@ + diff --git a/ide/vs2017/mimalloc.vcxproj.filters b/ide/vs2017/mimalloc.vcxproj.filters index 28d94e99..a2b64314 100644 --- a/ide/vs2017/mimalloc.vcxproj.filters +++ b/ide/vs2017/mimalloc.vcxproj.filters @@ -70,5 +70,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/ide/vs2019/mimalloc-override.vcxproj b/ide/vs2019/mimalloc-override.vcxproj index c651879f..96a8924f 100644 --- a/ide/vs2019/mimalloc-override.vcxproj +++ b/ide/vs2019/mimalloc-override.vcxproj @@ -212,6 +212,7 @@ + diff --git a/ide/vs2019/mimalloc.vcxproj b/ide/vs2019/mimalloc.vcxproj index 7e74d881..5658b536 100644 --- a/ide/vs2019/mimalloc.vcxproj +++ b/ide/vs2019/mimalloc.vcxproj @@ -238,6 +238,7 @@ + diff --git a/include/mimalloc-new-delete.h b/include/mimalloc-new-delete.h new file mode 100644 index 00000000..050f9433 --- /dev/null +++ b/include/mimalloc-new-delete.h @@ -0,0 +1,52 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2018,2019 Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ +#pragma once +#ifndef MIMALLOC_NEW_DELETE_H +#define MIMALLOC_NEW_DELETE_H + +// ---------------------------------------------------------------------------- +// This header provides convenient overrides for the new and +// delete operations in C++. +// +// This header should be included in only one source file! +// +// On Windows, or when linking dynamically with mimalloc, these +// can be more performant than the standard new-delete operations. +// See +// --------------------------------------------------------------------------- +#if defined(__cplusplus) + #include + #include + + void operator delete(void* p) noexcept { mi_free(p); }; + void operator delete[](void* p) noexcept { mi_free(p); }; + + void* operator new(std::size_t n) noexcept(false) { return mi_new(n); } + void* operator new[](std::size_t n) noexcept(false) { return mi_new(n); } + + void* operator new (std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_new_nothrow(n); } + void* operator new[](std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_new_nothrow(n); } + + #if (__cplusplus >= 201402L || _MSC_VER >= 1916) + void operator delete (void* p, std::size_t n) { mi_free_size(p,n); }; + void operator delete[](void* p, std::size_t n) { mi_free_size(p,n); }; + #endif + + #if (__cplusplus > 201402L || defined(__cpp_aligned_new)) + void operator delete (void* p, std::align_val_t al) noexcept { mi_free_aligned(p, static_cast(al)); } + void operator delete[](void* p, std::align_val_t al) noexcept { mi_free_aligned(p, static_cast(al)); } + void operator delete (void* p, std::size_t n, std::align_val_t al) noexcept { mi_free_size_aligned(p, n, static_cast(al)); }; + void operator delete[](void* p, std::size_t n, std::align_val_t al) noexcept { mi_free_size_aligned(p, n, static_cast(al)); }; + + void* operator new( std::size_t n, std::align_val_t al) noexcept(false) { return mi_new_aligned(n, static_cast(al)); } + void* operator new[]( std::size_t n, std::align_val_t al) noexcept(false) { return mi_new_aligned(n, static_cast(al)); } + void* operator new (std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return mi_new_aligned_nothrow(n, static_cast(al)); } + void* operator new[](std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return mi_new_aligned_nothrow(n, static_cast(al)); } + #endif +#endif + +#endif // MIMALLOC_NEW_DELETE_H diff --git a/include/mimalloc-override.h b/include/mimalloc-override.h index 56b41e6b..201fb8b4 100644 --- a/include/mimalloc-override.h +++ b/include/mimalloc-override.h @@ -13,14 +13,9 @@ This header can be used to statically redirect malloc/free and new/delete to the mimalloc variants. This can be useful if one can include this file on each source file in a project (but be careful when using external code to not accidentally mix pointers from different allocators). - -On windows it can still be good to always try to include this header even -when dynamically overriding since this will give better performance especially -for new/delete. On Unix dynamic overriding already includes all variants so -including this header is not necessary. -----------------------------------------------------------------------------*/ -#include "mimalloc.h" +#include // Standard C allocation #define malloc(n) mi_malloc(n) @@ -68,43 +63,4 @@ including this header is not necessary. #define _aligned_offset_realloc(p,n,a,o) mi_realloc_aligned_at(p,n,a,o) #define _aligned_offset_recalloc(p,s,n,a,o) mi_recalloc_aligned_at(p,s,n,a,o) - -// ----------------------------------------------------------------- -// With a C++ compiler we can override all the new/delete operators -// by defining 'MIMALLOC_DEFINE_NEW_DELETE' in some source file and -// then including this header file. This is not needed when linking -// statically with the mimalloc library, but it can be more performant -// on Windows when using dynamic overiding as well. -// see -// ----------------------------------------------------------------- -#if defined(__cplusplus) && defined(MIMALLOC_DEFINE_NEW_DELETE) - #include - - void operator delete(void* p) noexcept { mi_free(p); }; - void operator delete[](void* p) noexcept { mi_free(p); }; - - void* operator new(std::size_t n) noexcept(false) { return mi_new(n); } - void* operator new[](std::size_t n) noexcept(false) { return mi_new(n); } - - void* operator new (std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_new_nothrow(n); } - void* operator new[](std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_new_nothrow(n); } - - #if (__cplusplus >= 201402L || _MSC_VER >= 1916) - void operator delete (void* p, std::size_t n) { mi_free_size(p,n); }; - void operator delete[](void* p, std::size_t n) { mi_free_size(p,n); }; - #endif - - #if (__cplusplus > 201402L || defined(__cpp_aligned_new)) - void operator delete (void* p, std::align_val_t al) noexcept { mi_free_aligned(p, static_cast(al)); } - void operator delete[](void* p, std::align_val_t al) noexcept { mi_free_aligned(p, static_cast(al)); } - void operator delete (void* p, std::size_t n, std::align_val_t al) noexcept { mi_free_size_aligned(p, n, static_cast(al)); }; - void operator delete[](void* p, std::size_t n, std::align_val_t al) noexcept { mi_free_size_aligned(p, n, static_cast(al)); }; - - void* operator new( std::size_t n, std::align_val_t al) noexcept(false) { return mi_new_aligned(n, static_cast(al)); } - void* operator new[]( std::size_t n, std::align_val_t al) noexcept(false) { return mi_new_aligned(n, static_cast(al)); } - void* operator new (std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return mi_new_aligned_nothrow(n, static_cast(al)); } - void* operator new[](std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return mi_new_aligned_nothrow(n, static_cast(al)); } - #endif -#endif - #endif // MIMALLOC_OVERRIDE_H From 3a697abf1f2ab0170e14254688a543e42ebba9be Mon Sep 17 00:00:00 2001 From: daan Date: Sun, 15 Sep 2019 20:26:30 -0700 Subject: [PATCH 66/92] set SONAME and use symbolic link at install (issue #9 and #58) --- CMakeLists.txt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 55db7232..443476f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,7 +133,7 @@ endif() # shared library add_library(mimalloc SHARED ${mi_sources}) -set_target_properties(mimalloc PROPERTIES VERSION ${mi_version} NO_SONAME "YES" OUTPUT_NAME ${mi_basename} ) +set_target_properties(mimalloc PROPERTIES VERSION ${mi_version} OUTPUT_NAME ${mi_basename} ) target_compile_definitions(mimalloc PRIVATE ${mi_defines} MI_SHARED_LIB MI_SHARED_LIB_EXPORT) target_compile_options(mimalloc PRIVATE ${mi_cflags}) target_link_libraries(mimalloc PUBLIC ${mi_libraries}) @@ -168,7 +168,7 @@ else() endif() # install static and shared library, and the include files -install(TARGETS mimalloc EXPORT mimalloc DESTINATION ${mi_install_dir} LIBRARY NAMELINK_SKIP) +install(TARGETS mimalloc EXPORT mimalloc DESTINATION ${mi_install_dir} LIBRARY) install(TARGETS mimalloc-static EXPORT mimalloc DESTINATION ${mi_install_dir}) install(FILES include/mimalloc.h DESTINATION ${mi_install_dir}/include) install(FILES include/mimalloc-override.h DESTINATION ${mi_install_dir}/include) @@ -176,7 +176,14 @@ install(FILES include/mimalloc-new-delete.h DESTINATION ${mi_install_dir}/includ install(FILES cmake/mimalloc-config.cmake DESTINATION ${mi_install_dir}/cmake) install(FILES cmake/mimalloc-config-version.cmake DESTINATION ${mi_install_dir}/cmake) install(EXPORT mimalloc DESTINATION ${mi_install_dir}/cmake) -install(FILES "$" DESTINATION lib) # duplicate the .so in the lib directory (unversioned) + +if(NOT WIN32) + # install a symlink in the /usr/local/lib to the versioned library + set(mi_symlink "${CMAKE_SHARED_MODULE_PREFIX}${mi_basename}${CMAKE_SHARED_LIBRARY_SUFFIX}") + set(mi_soname "mimalloc-${mi_version}/${mi_symlink}.${mi_version}") + install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${mi_soname} ${mi_symlink} WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/${mi_install_dir}/..)") + install(CODE "MESSAGE(\"-- Symbolic link: ${CMAKE_INSTALL_PREFIX}/lib/${mi_symlink} -> ${mi_soname}\")") +endif() # single object file for more predictable static overriding add_library(mimalloc-obj OBJECT src/static.c) From d72b5350e3194c8c17562faeb604efb2d11303e3 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 17 Sep 2019 17:23:20 -0700 Subject: [PATCH 67/92] fix error code on mprotect failure --- src/os.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/os.c b/src/os.c index 71c375ec..2ad0648f 100644 --- a/src/os.c +++ b/src/os.c @@ -651,6 +651,7 @@ static bool mi_os_commitx(void* addr, size_t size, bool commit, bool conservativ // WebAssembly guests can't control memory protection #else err = mprotect(start, csize, (commit ? (PROT_READ | PROT_WRITE) : PROT_NONE)); + if (err != 0) { err = errno; } #endif if (err != 0) { _mi_warning_message("commit/decommit error: start: 0x%p, csize: 0x%x, err: %i\n", start, csize, err); @@ -687,7 +688,7 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats) if (!reset) return true; // nothing to do on unreset! #if (MI_DEBUG>1) - if (!mi_option_is_enabled(mi_option_secure)) { + if (MI_SECURE==0) { memset(start, 0, csize); // pretend it is eagerly reset } #endif @@ -767,6 +768,7 @@ static bool mi_os_protectx(void* addr, size_t size, bool protect) { err = 0; #else err = mprotect(start, csize, protect ? PROT_NONE : (PROT_READ | PROT_WRITE)); + if (err != 0) { err = errno; } #endif if (err != 0) { _mi_warning_message("mprotect error: start: 0x%p, csize: 0x%x, err: %i\n", start, csize, err); From 60efb62155a7d9da1858f81e78534125fd610ce9 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 17 Sep 2019 17:31:42 -0700 Subject: [PATCH 68/92] make secure a build option only --- include/mimalloc.h | 1 - src/options.c | 6 ------ src/page.c | 2 +- src/segment.c | 16 ++++++++-------- 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 5ed3246f..b7d21d00 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -260,7 +260,6 @@ typedef enum mi_option_e { mi_option_show_stats, mi_option_verbose, // the following options are experimental - mi_option_secure, mi_option_eager_commit, mi_option_eager_region_commit, mi_option_large_os_pages, // implies eager commit diff --git a/src/options.c b/src/options.c index 37a7c025..09524cb4 100644 --- a/src/options.c +++ b/src/options.c @@ -51,12 +51,6 @@ static mi_option_desc_t options[_mi_option_last] = { 0, UNINIT, MI_OPTION(show_stats) }, { 0, UNINIT, MI_OPTION(verbose) }, - #if MI_SECURE - { MI_SECURE, INITIALIZED, MI_OPTION(secure) }, // in a secure build the environment setting is ignored - #else - { 0, UNINIT, MI_OPTION(secure) }, - #endif - // the following options are experimental and not all combinations make sense. { 1, UNINIT, MI_OPTION(eager_commit) }, // note: needs to be on when eager_region_commit is enabled #ifdef _WIN32 // and BSD? diff --git a/src/page.c b/src/page.c index 8cbf96ad..25e59977 100644 --- a/src/page.c +++ b/src/page.c @@ -679,7 +679,7 @@ static inline mi_page_t* mi_find_free_page(mi_heap_t* heap, size_t size) { mi_page_queue_t* pq = mi_page_queue(heap,size); mi_page_t* page = pq->first; if (page != NULL) { - if (mi_option_get(mi_option_secure) >= 3 && page->capacity < page->reserved && ((_mi_heap_random(heap) & 1) == 1)) { + if ((MI_SECURE >= 3) && page->capacity < page->reserved && ((_mi_heap_random(heap) & 1) == 1)) { // in secure mode, we extend half the time to increase randomness mi_page_extend_free(heap, page, &heap->tld->stats); mi_assert_internal(mi_page_immediate_available(page)); diff --git a/src/segment.c b/src/segment.c index 772f21d5..dcc6a04b 100644 --- a/src/segment.c +++ b/src/segment.c @@ -165,8 +165,8 @@ uint8_t* _mi_segment_page_start(const mi_segment_t* segment, const mi_page_t* pa mi_assert_internal((uintptr_t)p % block_size == 0); } } - long secure = mi_option_get(mi_option_secure); - if (secure > 1 || (secure == 1 && page->segment_idx == segment->capacity - 1)) { + + if (MI_SECURE > 1 || (MI_SECURE == 1 && page->segment_idx == segment->capacity - 1)) { // secure == 1: the last page has an os guard page at the end // secure > 1: every page has an os guard page psize -= _mi_os_page_size(); @@ -190,7 +190,7 @@ static size_t mi_segment_size(size_t capacity, size_t required, size_t* pre_size size_t guardsize = 0; size_t isize = 0; - if (!mi_option_is_enabled(mi_option_secure)) { + if (MI_SECURE == 0) { // normally no guard pages isize = _mi_align_up(minsize, 16 * MI_MAX_ALIGN_SIZE); } @@ -228,7 +228,7 @@ static void mi_segments_track_size(long segment_size, mi_segments_tld_t* tld) { static void mi_segment_os_free(mi_segment_t* segment, size_t segment_size, mi_segments_tld_t* tld) { segment->thread_id = 0; mi_segments_track_size(-((long)segment_size),tld); - if (mi_option_is_enabled(mi_option_secure)) { + if (MI_SECURE != 0) { mi_assert_internal(!segment->mem_is_fixed); _mi_mem_unprotect(segment, segment->segment_size); // ensure no more guard pages are set } @@ -333,7 +333,7 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, bool is_zero = false; mi_segment_t* segment = mi_segment_cache_pop(segment_size, tld); if (segment != NULL) { - if (mi_option_is_enabled(mi_option_secure)) { + if (MI_SECURE!=0) { mi_assert_internal(!segment->mem_is_fixed); if (segment->page_kind != page_kind) { _mi_mem_unprotect(segment, segment->segment_size); // reset protection if the page kind differs @@ -357,7 +357,7 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, else { // Allocate the segment from the OS size_t memid; - bool mem_large = (!eager_delay && !mi_option_is_enabled(mi_option_secure)); // only allow large OS pages once we are no longer lazy + bool mem_large = (!eager_delay && (MI_SECURE==0)); // only allow large OS pages once we are no longer lazy segment = (mi_segment_t*)_mi_mem_alloc_aligned(segment_size, MI_SEGMENT_SIZE, &commit, &mem_large, &is_zero, &memid, os_tld); if (segment == NULL) return NULL; // failed to allocate if (!commit) { @@ -378,13 +378,13 @@ static mi_segment_t* mi_segment_alloc(size_t required, mi_page_kind_t page_kind, memset((uint8_t*)segment + ofs, 0, info_size - ofs); // guard pages - if (mi_option_is_enabled(mi_option_secure) && !protection_still_good) { + if ((MI_SECURE != 0) && !protection_still_good) { // in secure mode, we set up a protected page in between the segment info // and the page data mi_assert_internal( info_size == pre_size - _mi_os_page_size() && info_size % _mi_os_page_size() == 0); _mi_mem_protect( (uint8_t*)segment + info_size, (pre_size - info_size) ); size_t os_page_size = _mi_os_page_size(); - if (mi_option_get(mi_option_secure) <= 1) { + if (MI_SECURE <= 1) { // and protect the last page too _mi_mem_protect( (uint8_t*)segment + segment_size - os_page_size, os_page_size ); } From 5744f90882df3ed31c5781f93c8901e57696d13e Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 17 Sep 2019 17:35:20 -0700 Subject: [PATCH 69/92] remove thread init/done verbose messages --- src/init.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/init.c b/src/init.c index 3d9b4842..5ab39c28 100644 --- a/src/init.c +++ b/src/init.c @@ -352,9 +352,7 @@ void mi_thread_init(void) mi_attr_noexcept pthread_setspecific(mi_pthread_key, (void*)(_mi_thread_id()|1)); // set to a dummy value so that `mi_pthread_done` is called #endif - #if (MI_DEBUG>0 && !defined(_WIN32)) - _mi_verbose_message("thread init: 0x%zx\n", _mi_thread_id()); - #endif + //_mi_verbose_message("thread init: 0x%zx\n", _mi_thread_id()); } void mi_thread_done(void) mi_attr_noexcept { @@ -367,11 +365,9 @@ void mi_thread_done(void) mi_attr_noexcept { // abandon the thread local heap if (_mi_heap_done()) return; // returns true if already ran - #if (MI_DEBUG>0 && !defined(_WIN32)) - if (!_mi_is_main_thread()) { - _mi_verbose_message("thread done: 0x%zx\n", _mi_thread_id()); - } - #endif + //if (!_mi_is_main_thread()) { + // _mi_verbose_message("thread done: 0x%zx\n", _mi_thread_id()); + //} } From 1de6c22b49d3abe1fd7f35e3b64e77218f33872c Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 17 Sep 2019 18:07:32 -0700 Subject: [PATCH 70/92] remove incorrect region_count comment --- src/memory.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/memory.c b/src/memory.c index 52efbace..0ad582cd 100644 --- a/src/memory.c +++ b/src/memory.c @@ -181,7 +181,6 @@ static bool mi_region_commit_blocks(mem_region_t* region, size_t idx, size_t bit else { // failed, another thread allocated just before us! // we assign it to a later slot instead (up to 4 tries). - // note: we don't need to increment the region count, this will happen on another allocation for(size_t i = 1; i <= 4 && idx + i < MI_REGION_MAX; i++) { if (mi_atomic_cas_strong(®ions[idx+i].info, info, 0)) { mi_atomic_increment(®ions_count); From 114d05cd76cdf6b959e8a9ff842d0f0cf20a6071 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Mon, 7 Oct 2019 09:54:23 -0700 Subject: [PATCH 71/92] bump to version 1.1 --- include/mimalloc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index b7d21d00..b63ed79d 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -8,7 +8,7 @@ terms of the MIT license. A copy of the license can be found in the file #ifndef MIMALLOC_H #define MIMALLOC_H -#define MI_MALLOC_VERSION 100 // major + 2 digits minor +#define MI_MALLOC_VERSION 110 // major + 2 digits minor // ------------------------------------------------------ // Compiler specific attributes From 8830c7bccc09b51e1bfd4c9757d84a16ac500e8a Mon Sep 17 00:00:00 2001 From: Daan Date: Mon, 7 Oct 2019 12:08:44 -0700 Subject: [PATCH 72/92] Update readme.md --- readme.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 6da3cf76..0d11db16 100644 --- a/readme.md +++ b/readme.md @@ -20,7 +20,7 @@ without code changes, for example, on dynamically linked ELF-based systems (Linu Notable aspects of the design include: -- __small and consistent__: the library is less than 3500 LOC using simple and +- __small and consistent__: the library is about 6k LOC using simple and consistent data structures. This makes it very suitable to integrate and adapt in other projects. For runtime systems it provides hooks for a monotonic _heartbeat_ and deferred freeing (for @@ -42,7 +42,7 @@ Notable aspects of the design include: - __first-class heaps__: efficiently create and use multiple heaps to allocate across different regions. A heap can be destroyed at once instead of deallocating each object separately. - __bounded__: it does not suffer from _blowup_ \[1\], has bounded worst-case allocation - times (_wcat_), bounded space overhead (~0.2% meta-data, with at most 16.7% waste in allocation sizes), + times (_wcat_), bounded space overhead (~0.2% meta-data, with at most 12.5% waste in allocation sizes), and has no internal points of contention using only atomic operations. - __fast__: In our benchmarks (see [below](#performance)), _mimalloc_ always outperforms all other leading allocators (_jemalloc_, _tcmalloc_, _Hoard_, etc), @@ -56,8 +56,9 @@ Enjoy! ### Releases -* 2019-08-10, `v1.0.6`: pre-release 6: various performance improvements. +* 2019-10-07, `v1.1.0`: stable release 1.1. * 2019-09-01, `v1.0.8`: pre-release 8: more robust windows dynamic overriding, initial huge page support. +* 2019-08-10, `v1.0.6`: pre-release 6: various performance improvements. # Building From c9d474d298d833e6d28b24dc10aa7b8938599a81 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Mon, 7 Oct 2019 12:13:40 -0700 Subject: [PATCH 73/92] update mimalloc build version --- cmake/mimalloc-config-version.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/mimalloc-config-version.cmake b/cmake/mimalloc-config-version.cmake index 0462f4f7..03316948 100644 --- a/cmake/mimalloc-config-version.cmake +++ b/cmake/mimalloc-config-version.cmake @@ -1,5 +1,5 @@ set(mi_version_major 1) -set(mi_version_minor 0) +set(mi_version_minor 1) set(mi_version ${mi_version_major}.${mi_version_minor}) set(PACKAGE_VERSION ${mi_version}) From 5e9b37dc4ec6bbc89c8643f65aecbc5a67484a8e Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Fri, 11 Oct 2019 17:03:09 -0700 Subject: [PATCH 74/92] add delayed output buffer --- src/options.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/options.c b/src/options.c index 09524cb4..5e631b8a 100644 --- a/src/options.c +++ b/src/options.c @@ -140,6 +140,46 @@ static void mi_out_stderr(const char* msg) { #endif } +// Since an output function can be registered earliest in the `main` +// function we also buffer output that happens earlier. When +// an output function is registered it is called immediately with +// the output up to that point. +#define MAX_OUT_BUF (8*1024) +static char out_buf[MAX_OUT_BUF+1]; +static _Atomic(uintptr_t) out_len; + +static void mi_out_buf(const char* msg) { + if (msg==NULL) return; + size_t n = strlen(msg); + if (n==0) return; + // claim + if (mi_atomic_read_relaxed(&out_len)>=MAX_OUT_BUF) return; + uintptr_t start = mi_atomic_addu(&out_len, n); + if (start >= MAX_OUT_BUF) return; + // check bound + if (start+n >= MAX_OUT_BUF) { + n = MAX_OUT_BUF-start-1; + } + memcpy(&out_buf[start], msg, n); +} + +static void mi_out_buf_contents(mi_output_fun* out) { + if (out==NULL) return; + // claim all + size_t count = mi_atomic_addu(&out_len, MAX_OUT_BUF); + // and output it + if (count>MAX_OUT_BUF) count = MAX_OUT_BUF; + out_buf[count] = 0; + out(out_buf); +} + +// The initial default output outputs to stderr and the delayed buffer. +static void mi_out_buf_stderr(const char* msg) { + mi_out_stderr(msg); + mi_out_buf(msg); +} + + // -------------------------------------------------------- // Default output handler // -------------------------------------------------------- @@ -151,11 +191,12 @@ static mi_output_fun* volatile mi_out_default; // = NULL static mi_output_fun* mi_out_get_default(void) { mi_output_fun* out = mi_out_default; - return (out == NULL ? &mi_out_stderr : out); + return (out == NULL ? &mi_out_buf_stderr : out); } void mi_register_output(mi_output_fun* out) mi_attr_noexcept { - mi_out_default = out; + mi_out_default = (out == NULL ? &mi_out_stderr : out); + if (out!=NULL) mi_out_buf_contents(out); } From 480f7683a939da42453518ad63a1d7f3bf40ea89 Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 12 Oct 2019 10:42:04 -0700 Subject: [PATCH 75/92] cleanup delayed output --- src/options.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/options.c b/src/options.c index 5e631b8a..3e10926c 100644 --- a/src/options.c +++ b/src/options.c @@ -150,10 +150,10 @@ static _Atomic(uintptr_t) out_len; static void mi_out_buf(const char* msg) { if (msg==NULL) return; + if (mi_atomic_read_relaxed(&out_len)>=MAX_OUT_BUF) return; size_t n = strlen(msg); if (n==0) return; - // claim - if (mi_atomic_read_relaxed(&out_len)>=MAX_OUT_BUF) return; + // claim space uintptr_t start = mi_atomic_addu(&out_len, n); if (start >= MAX_OUT_BUF) return; // check bound @@ -163,17 +163,17 @@ static void mi_out_buf(const char* msg) { memcpy(&out_buf[start], msg, n); } -static void mi_out_buf_contents(mi_output_fun* out) { +static void mi_out_buf_flush(mi_output_fun* out) { if (out==NULL) return; - // claim all + // claim all (no more output will be added after this point) size_t count = mi_atomic_addu(&out_len, MAX_OUT_BUF); - // and output it + // and output the current contents if (count>MAX_OUT_BUF) count = MAX_OUT_BUF; out_buf[count] = 0; out(out_buf); } -// The initial default output outputs to stderr and the delayed buffer. +// The initial default output, outputs to stderr and the delayed output buffer. static void mi_out_buf_stderr(const char* msg) { mi_out_stderr(msg); mi_out_buf(msg); @@ -195,13 +195,13 @@ static mi_output_fun* mi_out_get_default(void) { } void mi_register_output(mi_output_fun* out) mi_attr_noexcept { - mi_out_default = (out == NULL ? &mi_out_stderr : out); - if (out!=NULL) mi_out_buf_contents(out); + mi_out_default = (out == NULL ? &mi_out_stderr : out); // stop using the delayed output buffer + if (out!=NULL) mi_out_buf_flush(out); // output the delayed output now } // -------------------------------------------------------- -// Messages +// Messages, all end up calling `_mi_fputs`. // -------------------------------------------------------- #define MAX_ERROR_COUNT (10) static volatile _Atomic(uintptr_t) error_count; // = 0; // when MAX_ERROR_COUNT stop emitting errors and warnings From 7441aa42128bc33b06efeb5cb55f002e9a00be3d Mon Sep 17 00:00:00 2001 From: daan Date: Sat, 12 Oct 2019 10:42:34 -0700 Subject: [PATCH 76/92] update redirection module to add additional checks --- bin/mimalloc-redirect.dll | Bin 43520 -> 44544 bytes bin/mimalloc-redirect.lib | Bin 2874 -> 2874 bytes bin/mimalloc-redirect32.dll | Bin 31744 -> 32768 bytes bin/mimalloc-redirect32.lib | Bin 2928 -> 2928 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/mimalloc-redirect.dll b/bin/mimalloc-redirect.dll index 45e0fb4843752d1ecaa1cac4c18a485e4caabf56..98949605fdb7aaeedca3807c97b347638d1a4a98 100644 GIT binary patch delta 5232 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 AN&o-= delta 4875 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 diff --git a/bin/mimalloc-redirect.lib b/bin/mimalloc-redirect.lib index 149dabb71bfbc6b15fecd389ebc5e17af10e40a7..1e22ef12aaec87c9544724a5c766ddbc9bd90ac5 100644 GIT binary patch delta 62 zcmdlbwo7coH5SHMlNs4HCjV!#VVt$uhV=*|Sik^C+OSG*_GOob2&hc%<=}t{Zsh1> F0swn<63qYr delta 62 zcmdlbwo7coH5SH6lNs4HCjV!#VVtzthV=*|Sik^C+OSG*_GOob2&hc%<=}t{Zsh1> F0swVZ5}g15 diff --git a/bin/mimalloc-redirect32.dll b/bin/mimalloc-redirect32.dll index 0b5f515614df59b6ffb87800d0fba95885910459..b19e42cd2a9106bbf80260c29b32ea9f9cfc8a2e 100644 GIT binary patch delta 4050 zcma(UZBSEJ_P$3#5(wl4MWP@C1r!BKAOT`PP9?Tl6g98*tXEFNW~Vf*u_9ztvIcg#v=9gbudMIL?} zh}E!Gz$(VsY=R7QkO)>Yev(blc;P7&*7L9)`V}HnxT?9X@!1^+?F#`0xTIQpJs+@U zrYA#sNEF%{Dn;l{`+NWg76LdE0iYSI-7zu%1TlaX8Gu*g0eln-KtyN>DgYJa>1ql9 zFR`+dX#6(@KEfI{MD8d-9A4&KvQL~1FweJBN4O_66`Le$*tnDUprmdQ5n0Jkb@J0L zCc>x!lni_gVRh44TpMx9-R>#|IRSbSaltP>)~ zZPGd&5k(MXGdqz=W9l+Wom3-W#_>7RN$pYQ+(|%^3vh;Pr^5tK1M4h7fo(35&z9GHSuk=zSU1018Dyxz}a5^da;U8Gh~| z^oR`iJcQb1xc?z^y9{4?2+fz_yHN|UB!&8U>db5?eN-U7x*b6Jt2Vy*pb6Ng?0mVk|2aSN!VS+ zNvH8Xc)s6pS~+TKuhw0p1S@>K^pkzG!+F zUO0?7Q@4mI1vNEy7}tVPT_ZLf_G>h%D?tZW0uHV?Ei)JR)6<}Sfgcq8mTc$Z=;qC! z+i)vU>E=(HtZfb8Wcbcp4UahNBZwUPXwVaxXW(g+db&sul0P|PIQEOsj&SU=aD|Uq zi@~&uA2A7u0c-Cb`~XHkK7q(KUol{u>G+FH?y^YD!m{;LL?o<(-N}Oueilwca$bA@ zq#4CP1ld7+K~O(}G@n13nj998_ZP6MBl6+wQXcs%Y= z#*3FNPGR5XaLM8oY!8QDUc8NsLqXD*f)F31f$i}dS+xR>#P4U{ z`yQJTUVnQ21%8HR%+El`(o%nP9L;vpVV^{ML&*r+Ez0yxTa)%EEen1MCVVm;Pf(^mux%IL=?BNwC-ywj~;gm00lI#Dhy#NZz^`x03F_J58fd!&-&BI zl%G^i4$X2cBK2@l1X7ez5k%*EB&=kC0cR%jhc=K7lHLHzG~HPzyra0_FmZL1aVVq_8s8fYmD_*u<~#BP(NC&(S;L z%z`K&4Ly`(y$D3>wcs`V<0~4LNeKJ-ojdWo^%h|pxl-ZF0GldK5k(*2kZb>AQ1Q}_ z)B<$$M7|Z#+u%&XAz;@*#8i_5s#Qf;q>fsGn!OJ+Ne0=pQ_`(!B1lHs)_`Cj$7m7{ z%|8S90!MjpfisYF0rYeXZc8gl?z$Q{Wy?(GI>L19k)z%7$sj2enXQM3=Eke|PTEp- z-Blc!UO>9ZpA6r!0HqX?N##%GD4b8BibB%Up7!*3CHRW;yuGH5!K3WL%-|O_yvxx} zSf(;q@U=~TL7p6*;X@Uj1Kv5_GsMO-c=Osc*&YrdJFI$7=h`nBZsQwoKBrs$*<-zZ zj!TnYgna6$U9XK`n($py0lsEZ!MD*}Q#q4Cac8NDG2x@7<&2x+xn>n}5SND-WC{?3`>Uu}ag|(L2uAw|0rvr>2CNORGI2FLc`4mg zEf=AH+hTmO8iW8b5!Z)mNcPH_Uxntb0ka@ejfZN=L`^}}>Zj!5gMc*Q=bkDPd*P`K z(kg~RDaY0wmFdQf#WBp5Y zwd$IuZFSA+#W|*&ik#o%*mC#f9?Kohm2B0Y)t@!wU;I4^ncQStN%&=`RX)7rXkm`#!zH< P%wRHXF?h!Is6+k-%YEi5 delta 3652 zcma(UYfxKN`rJ#>gc3-2l~@r11zJETkQZs8pzST_klheWX>DntB)ci4mO^m5BM3C5 z0+C(lai`tU)v(rLXLY3$r*@~04O$D1I>XlP6jzks;?6}_C+^^yv23&7cVo0V`(y9S z`Of*?kMo^#@9pkpy93Nn2{S!hy0xnz>fPncrk6&;rsM4WA~&pu)9#JSci4_Pfbqg6016l-^lwaVb~&u> zdddkY&$l)>8i2N8Gk|(rz}Qan+0;lktVA##qdNctr(_k3R{A8nHl{TKmR=YraMW{_ zH8UqgtGfOzA!Ol50)S>EfYE3G`$21=lmRd;2GAG@;A%2}U#qPSbd=U}K#3p;Z;!E8fVbKWcmer0`uESK$2@{dE`N*_nTnQc}*0GtlDLfnITsb|5MLf zk$nuKqE%5@DOUn0Bkku_oSiGgk?P_CCYMnL(ko{Em}e*|iDjprqUWN!SA~M{Y>auE zjly-<-CRx?RmGm9Q?V5^DgHHjJua5sicgMdV)*T_)ewP+FO^aze$DDIdY_c0#eI+d zM?xO}6na1q{#ZgA?n19fXwO~f?<92OF0@lZ$H8(~w@%`ji+^3TVH;DFKJ zXAH_OSc1Jb9NLRWIyeda_DnQd2AVSL!;O|Sf+cCM*8!H6P#P^Q!3?1-k@iUQ1ji$W zWIp78hfVG^w-x-c5&H)>447k2AINoS`I z+)i*aVYL}Sjhp%X6tv+4=e-6VCb(-ig=un0nBF5#B5?|J294fodv_Cru}=sC`sb#z z^CrOzr^BueOrxmFGTm4PqNv?~P zKxX6@5^;ulu5p&4AaO*yIGHJ!hzN8F^s4K#x;JHb7Yx$!HS6Ab zPk1b@B_Y@*!cXvYFgb-C<>{+1J;l@alQXhcpix3u1%$qDB26TiD034R)d}{qc{-%}jX^cY%|jT{YABPC!4fuEr+DE!q-a+i zhk8FTkHv?3fgiN^;7;JNq;C2}+JfY-w;>6>+Ve?z4I^2c6Iu-J6D2ie6iNzE`K>wH zmysiB`i{4r`Z8XPvI7tA4gQdip3dCHcKGNgnQ2iiNQR4tzdcJ=XH~JRkM7J$iRwTy zY$bnumiA;7voFkgE@iO{vyon1Z;%xCf}g<0^v?Q2UFs&eJr#MY=yIP znY2q?7HPl5zZeM{0k^eKVn4LebuI{fCpFu<(Nc3r$vy-KUT?f3M1Yp-eaDfDyJvq6 z1-FLipv}0rB`Bh-x)`~98y=)N+m$k;2T+PYVtqrwscuK(xEV+w^vbW8&9-_qteo-2Mu( zjf!gi4|geEL`5%haNC~_E6#l_*oODaVyS&nu&Xfft-!WHl!D7?)bt?>`=}N2X5J7Ilwa`TW?(!*&H>=_{#)o(1|@`?%jlRWiPq>* zTfmDSQ8L}M`jJ}3E8slfgff;|#wXyXElSWl4|q9H%V^~eC0K6QQ43m#2LN}|*jm&- zZz-qeYX1!Q_|6JCwo?I;<2#Xqc>OK~Ge(c>s-?%6?AByf>!RUr2IY^Gla&53q-WMUIyRO-y)|084DwRK>T5(vOy*;0JB5%d_x6w z1Ev711+W^i307kQ-LxN7KmsklydQ)higI**vJtb7ZTwMiV~t=IWK49tu|`xMin)^3 zTV>*IKJcNAFR=Q$t~_i);p|3lF;+1e8!h8IjH15KRHcv^mO zTGXX3v=%lM9w~Gd4i)~hC|D#>%hU<#WOcgwSL(0Sk(x?PwdPUH0nK5}lbX*o|I*yn zFxu5xxi(RI$}ncQXVdDE`I65|J}4zB_>qBNMm3*m?$`EcztDcAUC~D9R_oU4s&sWa zhpt0+LPvF0y+i+u{&oG=`cuVEZ1P(+N0cO&oZoV#j1<717#P@CaJFE5k*CO8G*c9z zR;g>X&Dy7R7jz%#w(EE6>-Alr{#*S;{rmbG`rG<@i$5){GMEiJ4SNk%LzAJ!@VJ2x LkFP@&0p0LlA}&@o diff --git a/bin/mimalloc-redirect32.lib b/bin/mimalloc-redirect32.lib index 2bc4b0bc66f9eefadcb14beee53034bf76e3797d..c99aa32ce499240310b8ff1274d1690c85ec9a96 100644 GIT binary patch delta 62 zcmew$_CajJHx|ZOlQr2jCd;$hG0xf?$9jqpEMNd6<5;CPm$J)31Y{ Date: Thu, 17 Oct 2019 09:20:57 -0700 Subject: [PATCH 77/92] updated redirection module on windows --- bin/mimalloc-redirect.dll | Bin 44544 -> 46592 bytes bin/mimalloc-redirect32.dll | Bin 32768 -> 33792 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/mimalloc-redirect.dll b/bin/mimalloc-redirect.dll index 98949605fdb7aaeedca3807c97b347638d1a4a98..ec718f91c10dfe4c47b83739df2764fd25ad8581 100644 GIT binary patch delta 4901 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 delta 4310 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 diff --git a/bin/mimalloc-redirect32.dll b/bin/mimalloc-redirect32.dll index b19e42cd2a9106bbf80260c29b32ea9f9cfc8a2e..9dfb934e8b241c583184d215f183872f17709023 100644 GIT binary patch delta 5422 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 a>b45j4y(sHXPvhOt&7%W>x{N;g8DD65%kCa From 0e188a18a7f8f2c4cf1e2294a5f4c1641d7e5518 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 09:21:20 -0700 Subject: [PATCH 78/92] update test to match malloc with free --- test/main-override.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/main-override.cpp b/test/main-override.cpp index 2cafd2cd..4bc91ae8 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -41,7 +41,7 @@ int main() { p2 = malloc(16); p1 = realloc(p1, 32); free(p1); - mi_free(p2); + free(p2); mi_free(s); Test* t = new Test(42); delete t; From a96c90db5dc29223936cf32e74b2aa78aab93837 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 09:22:23 -0700 Subject: [PATCH 79/92] remove old windows overriding method --- src/alloc-override-win.c | 715 --------------------------------------- 1 file changed, 715 deletions(-) delete mode 100644 src/alloc-override-win.c diff --git a/src/alloc-override-win.c b/src/alloc-override-win.c deleted file mode 100644 index dc4796ab..00000000 --- a/src/alloc-override-win.c +++ /dev/null @@ -1,715 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen -This is free software; you can redistribute it and/or modify it under the -terms of the MIT license. A copy of the license can be found in the file -"LICENSE" at the root of this distribution. ------------------------------------------------------------------------------*/ - -#include "mimalloc.h" -#include "mimalloc-internal.h" - -#if !defined(_WIN32) -#error "this file should only be included on Windows" -#endif - -#include -#include - -#include // getenv -#include // _setmaxstdio -#include // strstr - - -/* -To override the C runtime `malloc` on Windows we need to patch the allocation -functions at runtime initialization. Unfortunately we can never patch before the -runtime initializes itself, because as soon as we call `GetProcAddress` on the -runtime module (a DLL or EXE in Windows speak), it will first load and initialize -(by the OS calling `DllMain` on it). - -This means that some things might be already allocated by the C runtime itself -(and possibly other DLL's) before we get to resolve runtime adresses. This is -no problem if everyone unwinds in order: when we unload, we unpatch and restore -the original crt `free` routines and crt malloc'd memory is freed correctly. - -But things go wrong if such early CRT alloc'd memory is freed or re-allocated -_after_ we patch, but _before_ we unload (and unpatch), or if any memory allocated -by us is freed after we unpatched. - -There are two tricky situations to deal with: - -1. The Thread Local Storage (TLS): when the main thread stops it will call registered - callbacks on TLS entries (allocated by `FlsAlloc`). This is done by the OS - before any DLL's are unloaded. Unfortunately, the C runtime registers such - TLS entries with CRT allocated memory which is freed in the callback. - -2. Inside the CRT: - a. Some variables might get initialized by patched allocated - blocks but freed during CRT unloading after we unpatched - (like temporary file buffers). - b. Some blocks are allocated at CRT and freed by the CRT (like the - environment storage). - c. And some blocks are allocated by the CRT and then reallocated - while patched, and finally freed after unpatching! This - happens with the `atexit` functions for example to grow the array - of registered functions. - -In principle situation 2 is hopeless: since we cannot patch before CRT initialization, -we can never be sure how to free or reallocate a pointer during CRT unloading. -However, in practice there is a good solution: when terminating, we just patch -the reallocation and free routines to no-ops -- we are winding down anyway! This leaves -just the reallocation problm of CRT alloc'd memory once we are patched. Here, a study of the -CRT reveals that there seem to be just three such situations: - -1. When registering `atexit` routines (to grow the exit function table), -2. When calling `_setmaxstdio` (to grow the file handle table), -3. and `_popen`/`_wpopen` (to grow handle pairs). These turn out not to be - a problem as these are NULL initialized. - -We fix these by providing wrappers: - -1. We first register a _global_ `atexit` routine ourselves (`mi_patches_at_exit`) before patching, - and then patch the `_crt_atexit` function to implement our own global exit list (and the - same for `_crt_at_quick_exit`). All module local lists are no problem since they are always fully - (un)patched from initialization to end. We can register in the global list by dynamically - getting the global `_crt_atexit` entry from `ucrtbase.dll`. - -2. The `_setmaxstdio` is _detoured_: we patch it by a stub that unpatches first, - calls the original routine and repatches again. - -That leaves us to reliably shutdown and enter "termination mode": - -1. Using our trick to get the global exit list entry point, we register an exit function `mi_patches_atexit` - that first executes all our home brew list of exit functions, and then enters a _termination_ - phase that patches realloc/free variants with no-ops. Patching later again with special no-ops for - `free` also improves efficiency during the program run since no flags need to be checked. - -2. That is not quite good enough yet since after executing exit routines after us on the - global exit list (registered by the CRT), - the OS starts to unwind the TLS callbacks and we would like to run callbacks registered after loading - our DLL to be done in patched mode. So, we also allocate a TLS entry when our DLL is loaded and when its - callback is called, we re-enable the original patches again. Since TLS is destroyed in FIFO order - this runs any callbacks in later DLL's in patched mode. - -3. Finally the DLL's get unloaded by the OS in order (still patched) until our DLL gets unloaded - and then we start a termination phase again, and patch realloc/free with no-ops for good this time. - -*/ - -static int __cdecl mi_setmaxstdio(int newmax); - -// ------------------------------------------------------ -// Microsoft allocation extensions -// ------------------------------------------------------ - - -typedef size_t mi_nothrow_t; - -static void mi_free_nothrow(void* p, mi_nothrow_t tag) { - UNUSED(tag); - mi_free(p); -} - -// Versions of `free`, `realloc`, `recalloc`, `expand` and `msize` -// that are used during termination and are no-ops. -static void mi_free_term(void* p) { - UNUSED(p); -} - -static void mi_free_size_term(void* p, size_t size) { - UNUSED(size); - UNUSED(p); -} - -static void mi_free_nothrow_term(void* p, mi_nothrow_t tag) { - UNUSED(tag); - UNUSED(p); -} - -static void* mi_realloc_term(void* p, size_t newsize) { - UNUSED(p); UNUSED(newsize); - return NULL; -} - -static void* mi__recalloc_term(void* p, size_t newcount, size_t newsize) { - UNUSED(p); UNUSED(newcount); UNUSED(newsize); - return NULL; -} - -static void* mi__expand_term(void* p, size_t newsize) { - UNUSED(p); UNUSED(newsize); - return NULL; -} - -static size_t mi__msize_term(void* p) { - UNUSED(p); - return 0; -} - - -static void* mi__malloc_dbg(size_t size, int block_type, const char* fname, int line) { - UNUSED(block_type); UNUSED(fname); UNUSED(line); - return _malloc_base(size); -} - -static void* mi__calloc_dbg(size_t count, size_t size, int block_type, const char* fname, int line) { - UNUSED(block_type); UNUSED(fname); UNUSED(line); - return _calloc_base(count, size); -} - -static void* mi__realloc_dbg(void* p, size_t size, int block_type, const char* fname, int line) { - UNUSED(block_type); UNUSED(fname); UNUSED(line); - return _realloc_base(p, size); -} - -static void mi__free_dbg(void* p, int block_type) { - UNUSED(block_type); - _free_base(p); -} - - -// the `recalloc`,`expand`, and `msize` don't have base versions and thus need a separate term version - -static void* mi__recalloc_dbg(void* p, size_t count, size_t size, int block_type, const char* fname, int line) { - UNUSED(block_type); UNUSED(fname); UNUSED(line); - return mi_recalloc(p, count, size); -} - -static void* mi__expand_dbg(void* p, size_t size, int block_type, const char* fname, int line) { - UNUSED(block_type); UNUSED(fname); UNUSED(line); - return mi__expand(p, size); -} - -static size_t mi__msize_dbg(void* p, int block_type) { - UNUSED(block_type); - return mi_usable_size(p); -} - -static void* mi__recalloc_dbg_term(void* p, size_t count, size_t size, int block_type, const char* fname, int line) { - UNUSED(block_type); UNUSED(fname); UNUSED(line); - return mi__recalloc_term(p, count, size); -} - -static void* mi__expand_dbg_term(void* p, size_t size, int block_type, const char* fname, int line) { - UNUSED(block_type); UNUSED(fname); UNUSED(line); - return mi__expand_term(p, size); -} - -static size_t mi__msize_dbg_term(void* p, int block_type) { - UNUSED(block_type); - return mi__msize_term(p); -} - - -// ------------------------------------------------------ -// implement our own global atexit handler -// ------------------------------------------------------ -typedef void (cbfun_t)(void); -typedef int (atexit_fun_t)(cbfun_t* fn); -typedef uintptr_t encoded_t; - -typedef struct exit_list_s { - encoded_t functions; // encoded pointer to array of encoded function pointers - size_t count; - size_t capacity; -} exit_list_t; - -#define MI_EXIT_INC (64) - -static exit_list_t atexit_list = { 0, 0, 0 }; -static exit_list_t at_quick_exit_list = { 0, 0, 0 }; -static CRITICAL_SECTION atexit_lock; - -// encode/decode function pointers with a random canary for security -static encoded_t canary; - -static inline void *decode(encoded_t x) { - return (void*)(x^canary); -} - -static inline encoded_t encode(void* p) { - return ((uintptr_t)p ^ canary); -} - - -static void init_canary() -{ - canary = _mi_random_init(0); - atexit_list.functions = at_quick_exit_list.functions = encode(NULL); -} - - -// initialize the list -static void mi_initialize_atexit(void) { - InitializeCriticalSection(&atexit_lock); - init_canary(); -} - -// register an exit function -static int mi_register_atexit(exit_list_t* list, cbfun_t* fn) { - if (fn == NULL) return EINVAL; - EnterCriticalSection(&atexit_lock); - encoded_t* functions = (encoded_t*)decode(list->functions); - if (list->count >= list->capacity) { // at first `functions == decode(0) == NULL` - encoded_t* newf = (encoded_t*)mi_recalloc(functions, list->capacity + MI_EXIT_INC, sizeof(cbfun_t*)); - if (newf != NULL) { - list->capacity += MI_EXIT_INC; - list->functions = encode(newf); - functions = newf; - } - } - int result; - if (list->count < list->capacity && functions != NULL) { - functions[list->count] = encode(fn); - list->count++; - result = 0; // success - } - else { - result = ENOMEM; - } - LeaveCriticalSection(&atexit_lock); - return result; -} - -// Register a global `atexit` function -static int mi_atexit(cbfun_t* fn) { - return mi_register_atexit(&atexit_list,fn); -} - -static int mi_at_quick_exit(cbfun_t* fn) { - return mi_register_atexit(&at_quick_exit_list,fn); -} - -static int mi_register_onexit(void* table, cbfun_t* fn) { - // TODO: how can we distinguish a quick_exit from atexit? - return mi_atexit(fn); -} - -// Execute exit functions in a list -static void mi_execute_exit_list(exit_list_t* list) { - // copy and zero the list structure - EnterCriticalSection(&atexit_lock); - exit_list_t clist = *list; - memset(list,0,sizeof(*list)); - LeaveCriticalSection(&atexit_lock); - - // now execute the functions outside of the lock - encoded_t* functions = (encoded_t*)decode(clist.functions); - if (functions != NULL) { - for (size_t i = clist.count; i > 0; i--) { // careful with unsigned count down.. - cbfun_t* fn = (cbfun_t*)decode(functions[i-1]); - if (fn==NULL) break; // corrupted! - fn(); - } - mi_free(functions); - } -} - - - -// ------------------------------------------------------ -// Jump assembly instructions for patches -// ------------------------------------------------------ - -#if defined(_M_IX86) || defined(_M_X64) - -#define MI_JUMP_SIZE 14 // at most 2+4+8 for a long jump or 1+5 for a short one - -typedef struct mi_jump_s { - uint8_t opcodes[MI_JUMP_SIZE]; -} mi_jump_t; - -void mi_jump_restore(void* current, const mi_jump_t* saved) { - memcpy(current, &saved->opcodes, MI_JUMP_SIZE); -} - -void mi_jump_write(void* current, void* target, mi_jump_t* save) { - if (save != NULL) { - memcpy(&save->opcodes, current, MI_JUMP_SIZE); - } - uint8_t* opcodes = ((mi_jump_t*)current)->opcodes; - ptrdiff_t diff = (uint8_t*)target - (uint8_t*)current; - uint32_t ofs32 = (uint32_t)diff; - #ifdef _M_X64 - uint64_t ofs64 = (uint64_t)diff; - if (ofs64 != (uint64_t)ofs32) { - // use long jump - opcodes[0] = 0xFF; - opcodes[1] = 0x25; - *((uint32_t*)&opcodes[2]) = 0; - *((uint64_t*)&opcodes[6]) = (uint64_t)target; - } - else - #endif - { - // use short jump - opcodes[0] = 0xE9; - *((uint32_t*)&opcodes[1]) = ofs32 - 5 /* size of the short jump instruction */; - } -} - -#elif defined(_M_ARM64) - -#define MI_JUMP_SIZE 16 - -typedef struct mi_jump_s { - uint8_t opcodes[MI_JUMP_SIZE]; -} mi_jump_t; - -void mi_jump_restore(void* current, const mi_jump_t* saved) { - memcpy(current, &saved->opcodes, MI_JUMP_SIZE); -} - -void mi_jump_write(void* current, void* target, mi_jump_t* save) { - if (save != NULL) { - memcpy(&save->opcodes, current, MI_JUMP_SIZE); - } - uint8_t* opcodes = ((mi_jump_t*)current)->opcodes; - uint64_t diff = (uint8_t*)target - (uint8_t*)current; - - // 0x50 0x00 0x00 0x58 ldr x16, .+8 # load PC relative +8 - // 0x00 0x02 0x3F 0xD6 blr x16 # and jump - //
      - //
      - static const uint8_t jump_opcodes[8] = { 0x50, 0x00, 0x00, 0x58, 0x00, 0x02, 0x3F, 0xD6 }; - memcpy(&opcodes[0], jump_opcodes, sizeof(jump_opcodes)); - *((uint64_t*)&opcodes[8]) = diff; -} - -#else -#error "define jump instructions for this platform" -#endif - - -// ------------------------------------------------------ -// Patches -// ------------------------------------------------------ -typedef enum patch_apply_e { - PATCH_NONE, - PATCH_TARGET, - PATCH_TARGET_TERM -} patch_apply_t; - -#define MAX_ENTRIES 4 // maximum number of patched entry points (like `malloc` in ucrtbase and msvcrt) - -typedef struct mi_patch_s { - const char* name; // name of the function to patch - void* target; // the address of the new target (never NULL) - void* target_term; // the address of the target during termination (or NULL) - patch_apply_t applied; // what target has been applied? - void* originals[MAX_ENTRIES]; // the resolved addresses of the function (or NULLs) - mi_jump_t saves[MAX_ENTRIES]; // the saved instructions in case it was applied -} mi_patch_t; - -#define MI_PATCH_NAME3(name,target,term) { name, &target, &term, PATCH_NONE, {NULL,NULL,NULL,NULL} } -#define MI_PATCH_NAME2(name,target) { name, &target, NULL, PATCH_NONE, {NULL,NULL,NULL,NULL} } -#define MI_PATCH3(name,target,term) MI_PATCH_NAME3(#name, target, term) -#define MI_PATCH2(name,target) MI_PATCH_NAME2(#name, target) -#define MI_PATCH1(name) MI_PATCH2(name,mi_##name) - -static mi_patch_t patches[] = { - // we implement our own global exit handler (as the CRT versions do a realloc internally) - //MI_PATCH2(_crt_atexit, mi_atexit), - //MI_PATCH2(_crt_at_quick_exit, mi_at_quick_exit), - MI_PATCH2(_setmaxstdio, mi_setmaxstdio), - MI_PATCH2(_register_onexit_function, mi_register_onexit), - - // override higher level atexit functions so we can implement at_quick_exit correcty - MI_PATCH2(atexit, mi_atexit), - MI_PATCH2(at_quick_exit, mi_at_quick_exit), - - // regular entries - MI_PATCH2(malloc, mi_malloc), - MI_PATCH2(calloc, mi_calloc), - MI_PATCH3(realloc, mi_realloc,mi_realloc_term), - MI_PATCH3(free, mi_free,mi_free_term), - - // extended api - MI_PATCH2(_strdup, mi_strdup), - MI_PATCH2(_strndup, mi_strndup), - MI_PATCH3(_expand, mi__expand,mi__expand_term), - MI_PATCH3(_recalloc, mi_recalloc,mi__recalloc_term), - MI_PATCH3(_msize, mi_usable_size,mi__msize_term), - - // base versions - MI_PATCH2(_malloc_base, mi_malloc), - MI_PATCH2(_calloc_base, mi_calloc), - MI_PATCH3(_realloc_base, mi_realloc,mi_realloc_term), - MI_PATCH3(_free_base, mi_free,mi_free_term), - - // these base versions are in the crt but without import records - MI_PATCH_NAME3("_recalloc_base", mi_recalloc,mi__recalloc_term), - MI_PATCH_NAME3("_msize_base", mi_usable_size,mi__msize_term), - - // debug - MI_PATCH2(_malloc_dbg, mi__malloc_dbg), - MI_PATCH2(_realloc_dbg, mi__realloc_dbg), - MI_PATCH2(_calloc_dbg, mi__calloc_dbg), - MI_PATCH2(_free_dbg, mi__free_dbg), - - MI_PATCH3(_expand_dbg, mi__expand_dbg, mi__expand_dbg_term), - MI_PATCH3(_recalloc_dbg, mi__recalloc_dbg, mi__recalloc_dbg_term), - MI_PATCH3(_msize_dbg, mi__msize_dbg, mi__msize_dbg_term), - -#if 0 - // override new/delete variants for efficiency (?) -#ifdef _WIN64 - // 64 bit new/delete - MI_PATCH_NAME2("??2@YAPEAX_K@Z", mi_new), - MI_PATCH_NAME2("??_U@YAPEAX_K@Z", mi_new), - MI_PATCH_NAME3("??3@YAXPEAX@Z", mi_free, mi_free_term), - MI_PATCH_NAME3("??_V@YAXPEAX@Z", mi_free, mi_free_term), - MI_PATCH_NAME3("??3@YAXPEAX_K@Z", mi_free_size, mi_free_size_term), // delete sized - MI_PATCH_NAME3("??_V@YAXPEAX_K@Z", mi_free_size, mi_free_size_term), // delete sized - MI_PATCH_NAME2("??2@YAPEAX_KAEBUnothrow_t@std@@@Z", mi_new), - MI_PATCH_NAME2("??_U@YAPEAX_KAEBUnothrow_t@std@@@Z", mi_new), - MI_PATCH_NAME3("??3@YAXPEAXAEBUnothrow_t@std@@@Z", mi_free_nothrow, mi_free_nothrow_term), - MI_PATCH_NAME3("??_V@YAXPEAXAEBUnothrow_t@std@@@Z", mi_free_nothrow, mi_free_nothrow_term), - - -#else - // 32 bit new/delete - MI_PATCH_NAME2("??2@YAPAXI@Z", mi_new), - MI_PATCH_NAME2("??_U@YAPAXI@Z", mi_new), - MI_PATCH_NAME3("??3@YAXPAX@Z", mi_free, mi_free_term), - MI_PATCH_NAME3("??_V@YAXPAX@Z", mi_free, mi_free_term), - MI_PATCH_NAME3("??3@YAXPAXI@Z", mi_free_size, mi_free_size_term), // delete sized - MI_PATCH_NAME3("??_V@YAXPAXI@Z", mi_free_size, mi_free_size_term), // delete sized - - MI_PATCH_NAME2("??2@YAPAXIABUnothrow_t@std@@@Z", mi_new), - MI_PATCH_NAME2("??_U@YAPAXIABUnothrow_t@std@@@Z", mi_new), - MI_PATCH_NAME3("??3@YAXPAXABUnothrow_t@std@@@Z", mi_free_nothrow, mi_free_nothrow_term), - MI_PATCH_NAME3("??_V@YAXPAXABUnothrow_t@std@@@Z", mi_free_nothrow, mi_free_nothrow_term), - -#endif -#endif - { NULL, NULL, NULL, PATCH_NONE, {NULL,NULL,NULL,NULL} } -}; - - -// Apply a patch -static bool mi_patch_apply(mi_patch_t* patch, patch_apply_t apply) -{ - if (patch->originals[0] == NULL) return true; // unresolved - if (apply == PATCH_TARGET_TERM && patch->target_term == NULL) apply = PATCH_TARGET; // avoid re-applying non-term variants - if (patch->applied == apply) return false; - - for (int i = 0; i < MAX_ENTRIES; i++) { - void* original = patch->originals[i]; - if (original == NULL) break; // no more - - DWORD protect = PAGE_READWRITE; - if (!VirtualProtect(original, MI_JUMP_SIZE, PAGE_EXECUTE_READWRITE, &protect)) return false; - if (apply == PATCH_NONE) { - mi_jump_restore(original, &patch->saves[i]); - } - else { - void* target = (apply == PATCH_TARGET ? patch->target : patch->target_term); - mi_assert_internal(target != NULL); - if (target != NULL) mi_jump_write(original, target, &patch->saves[i]); - } - VirtualProtect(original, MI_JUMP_SIZE, protect, &protect); - } - patch->applied = apply; - return true; -} - -// Apply all patches -static bool _mi_patches_apply(patch_apply_t apply, patch_apply_t* previous) { - static patch_apply_t current = PATCH_NONE; - if (previous != NULL) *previous = current; - if (current == apply) return true; - current = apply; - bool ok = true; - for (size_t i = 0; patches[i].name != NULL; i++) { - if (!mi_patch_apply(&patches[i], apply)) ok = false; - } - return ok; -} - -// Export the following three functions just in case -// a user needs that level of control. - -// Disable all patches -mi_decl_export void mi_patches_disable(void) { - _mi_patches_apply(PATCH_NONE, NULL); -} - -// Enable all patches normally -mi_decl_export bool mi_patches_enable(void) { - return _mi_patches_apply( PATCH_TARGET, NULL ); -} - -// Enable all patches in termination phase where free is a no-op -mi_decl_export bool mi_patches_enable_term(void) { - return _mi_patches_apply(PATCH_TARGET_TERM, NULL); -} - -// ------------------------------------------------------ -// Stub for _setmaxstdio -// ------------------------------------------------------ - -static int __cdecl mi_setmaxstdio(int newmax) { - patch_apply_t previous; - _mi_patches_apply(PATCH_NONE, &previous); // disable patches - int result = _setmaxstdio(newmax); // call original function (that calls original CRT recalloc) - _mi_patches_apply(previous,NULL); // and re-enable patches - return result; -} - - -// ------------------------------------------------------ -// Resolve addresses dynamically -// ------------------------------------------------------ - -// Try to resolve patches for a given module (DLL) -static void mi_module_resolve(const char* fname, HMODULE mod, int priority) { - // see if any patches apply - for (size_t i = 0; patches[i].name != NULL; i++) { - mi_patch_t* patch = &patches[i]; - if (patch->applied == PATCH_NONE) { - // find an available entry - int i = 0; - while (i < MAX_ENTRIES && patch->originals[i] != NULL) i++; - if (i < MAX_ENTRIES) { - void* addr = GetProcAddress(mod, patch->name); - if (addr != NULL) { - // found it! set the address - patch->originals[i] = addr; - _mi_trace_message(" found %s at %s!%p (entry %i)\n", patch->name, fname, addr, i); - } - } - } - } -} - -#define MIMALLOC_NAME "mimalloc-override.dll" -#define UCRTBASE_NAME "ucrtbase.dll" -#define UCRTBASED_NAME "ucrtbased.dll" - -// Resolve addresses of all patches by inspecting the loaded modules -static atexit_fun_t* crt_atexit = NULL; -static atexit_fun_t* crt_at_quick_exit = NULL; - - -static bool mi_patches_resolve(void) { - // get all loaded modules - HANDLE process = GetCurrentProcess(); // always -1, no need to release - DWORD needed = 0; - HMODULE modules[400]; // try to stay under 4k to not trigger the guard page - EnumProcessModules(process, modules, sizeof(modules), &needed); - if (needed == 0) return false; - int count = needed / sizeof(HMODULE); - int ucrtbase_index = 0; - int mimalloc_index = 0; - // iterate through the loaded modules - for (int i = 0; i < count; i++) { - HMODULE mod = modules[i]; - char filename[MAX_PATH] = { 0 }; - DWORD slen = GetModuleFileName(mod, filename, MAX_PATH); - if (slen > 0 && slen < MAX_PATH) { - // filter out potential crt modules only - filename[slen] = 0; - const char* lastsep = strrchr(filename, '\\'); - const char* basename = (lastsep==NULL ? filename : lastsep+1); - _mi_trace_message(" %i: dynamic module %s\n", i, filename); - - // remember indices so we can check load order (in debug mode) - if (_stricmp(basename, MIMALLOC_NAME) == 0) mimalloc_index = i; - if (_stricmp(basename, UCRTBASE_NAME) == 0) ucrtbase_index = i; - if (_stricmp(basename, UCRTBASED_NAME) == 0) ucrtbase_index = i; - - // see if we potentially patch in this module - int priority = 0; - if (i == 0) priority = 2; // main module to allow static crt linking - else if (_strnicmp(basename, "ucrt", 4) == 0) priority = 3; // new ucrtbase.dll in windows 10 - // NOTE: don't override msvcr -- leads to crashes in setlocale (needs more testing) - // else if (_strnicmp(basename, "msvcr", 5) == 0) priority = 1; // older runtimes - - if (priority > 0) { - // probably found a crt module, try to patch it - mi_module_resolve(basename,mod,priority); - - // try to find the atexit functions for the main process (in `ucrtbase.dll`) - if (crt_atexit==NULL) crt_atexit = (atexit_fun_t*)GetProcAddress(mod, "_crt_atexit"); - if (crt_at_quick_exit == NULL) crt_at_quick_exit = (atexit_fun_t*)GetProcAddress(mod, "_crt_at_quick_exit"); - } - } - } - int diff = mimalloc_index - ucrtbase_index; - if (diff > 1) { - _mi_warning_message("warning: the \"mimalloc-override\" DLL seems not to load before or right after the C runtime (\"ucrtbase\").\n" - " Try to fix this by changing the linking order.\n"); - } - return true; -} - - -// ------------------------------------------------------ -// Dll Entry -// ------------------------------------------------------ - -extern BOOL WINAPI _DllMainCRTStartup(HINSTANCE inst, DWORD reason, LPVOID reserved); - -static DWORD mi_fls_unwind_entry; -static void NTAPI mi_fls_unwind(PVOID value) { - if (value != NULL) mi_patches_enable(); // and re-enable normal patches again for DLL's loaded after us - return; -} - -static void mi_patches_atexit(void) { - mi_execute_exit_list(&atexit_list); - mi_patches_enable_term(); // enter termination phase and patch realloc/free with a no-op -} - -static void mi_patches_at_quick_exit(void) { - mi_execute_exit_list(&at_quick_exit_list); - mi_patches_enable_term(); // enter termination phase and patch realloc/free with a no-op -} - -BOOL WINAPI DllEntry(HINSTANCE inst, DWORD reason, LPVOID reserved) { - if (reason == DLL_PROCESS_ATTACH) { - __security_init_cookie(); - } - else if (reason == DLL_PROCESS_DETACH) { - // enter termination phase for good now - mi_patches_enable_term(); - } - // C runtime main - BOOL ok = _DllMainCRTStartup(inst, reason, reserved); - if (reason == DLL_PROCESS_ATTACH && ok) { - // initialize at exit lists - mi_initialize_atexit(); - - // Now resolve patches - ok = mi_patches_resolve(); - if (ok) { - // check if patching is not disabled - #pragma warning(suppress:4996) - const char* s = getenv("MIMALLOC_DISABLE_OVERRIDE"); - bool enabled = (s == NULL || !(strstr("1;TRUE;YES;ON", s) != NULL)); - if (!enabled) { - _mi_verbose_message("override is disabled\n"); - } - else { - // and register our unwind entry (this must be after resolving due to possible delayed DLL initialization from GetProcAddress) - mi_fls_unwind_entry = FlsAlloc(&mi_fls_unwind); - if (mi_fls_unwind_entry != FLS_OUT_OF_INDEXES) { - FlsSetValue(mi_fls_unwind_entry, (void*)1); - } - - // register our patch disabler in the global exit list - if (crt_atexit != NULL) (*crt_atexit)(&mi_patches_atexit); - if (crt_at_quick_exit != NULL) (*crt_at_quick_exit)(&mi_patches_at_quick_exit); - - // and patch ! this also redirects the `atexit` handling for the global exit list - mi_patches_enable(); - _mi_verbose_message("override is enabled\n"); - - // hide internal allocation - mi_stats_reset(); - } - } - } - return ok; -} From 08d83cc33dcb1338428821f94e50bd436ef5f656 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 09:24:57 -0700 Subject: [PATCH 80/92] disallow regular allocation from the huge reserved area --- src/os.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/os.c b/src/os.c index 2ad0648f..e7313c80 100644 --- a/src/os.c +++ b/src/os.c @@ -456,6 +456,7 @@ static void* mi_os_mem_alloc(size_t size, size_t try_alignment, bool commit, boo if (!commit) allow_large = false; void* p = NULL; + /* if (commit && allow_large) { p = _mi_os_try_alloc_from_huge_reserved(size, try_alignment); if (p != NULL) { @@ -463,6 +464,7 @@ static void* mi_os_mem_alloc(size_t size, size_t try_alignment, bool commit, boo return p; } } + */ #if defined(_WIN32) int flags = MEM_RESERVE; From 4609537b8ae05f135d51c5d608398df303ae7dc6 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 09:47:12 -0700 Subject: [PATCH 81/92] pick better umul_overflow variant based on intptr size --- include/mimalloc-internal.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index e99e6df6..c4f85ca4 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -156,10 +156,13 @@ bool _mi_page_is_valid(mi_page_t* page); #define MI_MUL_NO_OVERFLOW ((size_t)1 << (4*sizeof(size_t))) // sqrt(SIZE_MAX) static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) { #if __has_builtin(__builtin_umul_overflow) || __GNUC__ >= 5 -#if (MI_INTPTR_SIZE == 4) +#include // INT_MAX, LONG_MAX +#if (INTPTR_MAX == INT_MAX) return __builtin_umul_overflow(count, size, total); -#else +#elif (INTPTR_MAX == LONG_MAX) return __builtin_umull_overflow(count, size, total); +#else + return __builtin_umulll_overflow(count, size, total); #endif #else /* __builtin_umul_overflow is unavailable */ *total = count * size; From f3a162f09527922aa9c6fdf333cd3a87aafd5682 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 09:52:10 -0700 Subject: [PATCH 82/92] pick better umul_overflow variant based on size_t size --- include/mimalloc-internal.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index c4f85ca4..1a5b639d 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -156,10 +156,10 @@ bool _mi_page_is_valid(mi_page_t* page); #define MI_MUL_NO_OVERFLOW ((size_t)1 << (4*sizeof(size_t))) // sqrt(SIZE_MAX) static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) { #if __has_builtin(__builtin_umul_overflow) || __GNUC__ >= 5 -#include // INT_MAX, LONG_MAX -#if (INTPTR_MAX == INT_MAX) +#include // UINT_MAX, ULONG_MAX +#if (SIZE_MAX == UINT_MAX) return __builtin_umul_overflow(count, size, total); -#elif (INTPTR_MAX == LONG_MAX) +#elif (SIZE_MAX == ULONG_MAX) return __builtin_umull_overflow(count, size, total); #else return __builtin_umulll_overflow(count, size, total); From e747a6f3a6283699ee7b51a5dc1ce9b396a1106c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 17 Oct 2019 17:01:56 +0200 Subject: [PATCH 83/92] Use `unsigned` for bit-field variables It is actually non-standard to use `bool` with a bit-field quantifier, and VS 2019 complains about this. Signed-off-by: Johannes Schindelin --- include/mimalloc-types.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index 72fb7e7e..4d0ade1b 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -136,8 +136,8 @@ typedef union mi_page_flags_u { uint16_t value; uint8_t full_aligned; struct { - bool in_full:1; - bool has_aligned:1; + unsigned in_full:1; + unsigned has_aligned:1; bool is_zero; // `true` if the blocks in the free list are zero initialized }; } mi_page_flags_t; @@ -167,10 +167,10 @@ typedef uintptr_t mi_thread_free_t; typedef struct mi_page_s { // "owned" by the segment uint8_t segment_idx; // index in the segment `pages` array, `page == &segment->pages[page->segment_idx]` - bool segment_in_use:1; // `true` if the segment allocated this page - bool is_reset:1; // `true` if the page memory was reset - bool is_committed:1; // `true` if the page virtual memory is committed - bool is_zero_init:1; // `true` if the page was zero initialized + unsigned segment_in_use:1; // `true` if the segment allocated this page + unsigned is_reset:1; // `true` if the page memory was reset + unsigned is_committed:1; // `true` if the page virtual memory is committed + unsigned is_zero_init:1; // `true` if the page was zero initialized // layout like this to optimize access in `mi_malloc` and `mi_free` uint16_t capacity; // number of blocks committed, must be the first field, see `segment.c:page_clear` From 5bd8ea2e4feaa3e6ce8aa96b9c32994182aa812d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 17 Oct 2019 17:02:51 +0200 Subject: [PATCH 84/92] Repeat `mi_decl_allocator` in functions' definitions Quite a few functions are declared with that attribute, and VS 2019 complains if the definition does not repeat it. Signed-off-by: Johannes Schindelin --- src/alloc-aligned.c | 48 ++++++++++++++++++++++----------------------- src/alloc.c | 44 ++++++++++++++++++++--------------------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index 352f07b2..99347933 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -61,53 +61,53 @@ static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* const heap, const size_t } -void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_malloc_zero_aligned_at(heap, size, alignment, offset, false); } -void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept { return mi_heap_malloc_aligned_at(heap, size, alignment, 0); } -void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_malloc_zero_aligned_at(heap, size, alignment, offset, true); } -void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept { return mi_heap_zalloc_aligned_at(heap, size, alignment, 0); } -void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { size_t total; if (mi_mul_overflow(count, size, &total)) return NULL; return mi_heap_zalloc_aligned_at(heap, total, alignment, offset); } -void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment) mi_attr_noexcept { return mi_heap_calloc_aligned_at(heap,count,size,alignment,0); } -void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_malloc_aligned_at(mi_get_default_heap(), size, alignment, offset); } -void* mi_malloc_aligned(size_t size, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_malloc_aligned(size_t size, size_t alignment) mi_attr_noexcept { return mi_heap_malloc_aligned(mi_get_default_heap(), size, alignment); } -void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_zalloc_aligned_at(mi_get_default_heap(), size, alignment, offset); } -void* mi_zalloc_aligned(size_t size, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_zalloc_aligned(size_t size, size_t alignment) mi_attr_noexcept { return mi_heap_zalloc_aligned(mi_get_default_heap(), size, alignment); } -void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_calloc_aligned_at(mi_get_default_heap(), count, size, alignment, offset); } -void* mi_calloc_aligned(size_t count, size_t size, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_calloc_aligned(size_t count, size_t size, size_t alignment) mi_attr_noexcept { return mi_heap_calloc_aligned(mi_get_default_heap(), count, size, alignment); } @@ -150,55 +150,55 @@ static void* mi_heap_realloc_zero_aligned(mi_heap_t* heap, void* p, size_t newsi return mi_heap_realloc_zero_aligned_at(heap,p,newsize,alignment,offset,zero); } -void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_realloc_zero_aligned_at(heap,p,newsize,alignment,offset,false); } -void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment) mi_attr_noexcept { return mi_heap_realloc_zero_aligned(heap,p,newsize,alignment,false); } -void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_realloc_zero_aligned_at(heap, p, newsize, alignment, offset, true); } -void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment) mi_attr_noexcept { return mi_heap_realloc_zero_aligned(heap, p, newsize, alignment, true); } -void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { size_t total; if (mi_mul_overflow(newcount, size, &total)) return NULL; return mi_heap_rezalloc_aligned_at(heap, p, total, alignment, offset); } -void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept { size_t total; if (mi_mul_overflow(newcount, size, &total)) return NULL; return mi_heap_rezalloc_aligned(heap, p, total, alignment); } -void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_realloc_aligned_at(mi_get_default_heap(), p, newsize, alignment, offset); } -void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment) mi_attr_noexcept { return mi_heap_realloc_aligned(mi_get_default_heap(), p, newsize, alignment); } -void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_rezalloc_aligned_at(mi_get_default_heap(), p, newsize, alignment, offset); } -void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment) mi_attr_noexcept { return mi_heap_rezalloc_aligned(mi_get_default_heap(), p, newsize, alignment); } -void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { +mi_decl_allocator void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { return mi_heap_recalloc_aligned_at(mi_get_default_heap(), p, newcount, size, alignment, offset); } -void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept { +mi_decl_allocator void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept { return mi_heap_recalloc_aligned(mi_get_default_heap(), p, newcount, size, alignment); } diff --git a/src/alloc.c b/src/alloc.c index 9d50bf9f..3950496a 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -47,26 +47,26 @@ extern inline void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t siz } // allocate a small block -extern inline void* mi_heap_malloc_small(mi_heap_t* heap, size_t size) mi_attr_noexcept { +extern inline mi_decl_allocator void* mi_heap_malloc_small(mi_heap_t* heap, size_t size) mi_attr_noexcept { mi_assert(size <= MI_SMALL_SIZE_MAX); mi_page_t* page = _mi_heap_get_free_small_page(heap,size); return _mi_page_malloc(heap, page, size); } -extern inline void* mi_malloc_small(size_t size) mi_attr_noexcept { +extern inline mi_decl_allocator void* mi_malloc_small(size_t size) mi_attr_noexcept { return mi_heap_malloc_small(mi_get_default_heap(), size); } // zero initialized small block -void* mi_zalloc_small(size_t size) mi_attr_noexcept { +mi_decl_allocator void* mi_zalloc_small(size_t size) mi_attr_noexcept { void* p = mi_malloc_small(size); if (p != NULL) { memset(p, 0, size); } return p; } // The main allocation function -extern inline void* mi_heap_malloc(mi_heap_t* heap, size_t size) mi_attr_noexcept { +extern inline mi_decl_allocator void* mi_heap_malloc(mi_heap_t* heap, size_t size) mi_attr_noexcept { mi_assert(heap!=NULL); mi_assert(heap->thread_id == 0 || heap->thread_id == _mi_thread_id()); // heaps are thread local void* p; @@ -85,7 +85,7 @@ extern inline void* mi_heap_malloc(mi_heap_t* heap, size_t size) mi_attr_noexcep return p; } -extern inline void* mi_malloc(size_t size) mi_attr_noexcept { +extern inline mi_decl_allocator void* mi_malloc(size_t size) mi_attr_noexcept { return mi_heap_malloc(mi_get_default_heap(), size); } @@ -115,11 +115,11 @@ void* _mi_heap_malloc_zero(mi_heap_t* heap, size_t size, bool zero) { return p; } -extern inline void* mi_heap_zalloc(mi_heap_t* heap, size_t size) mi_attr_noexcept { +extern inline mi_decl_allocator void* mi_heap_zalloc(mi_heap_t* heap, size_t size) mi_attr_noexcept { return _mi_heap_malloc_zero(heap, size, true); } -void* mi_zalloc(size_t size) mi_attr_noexcept { +mi_decl_allocator void* mi_zalloc(size_t size) mi_attr_noexcept { return mi_heap_zalloc(mi_get_default_heap(),size); } @@ -360,29 +360,29 @@ void mi_free_aligned(void* p, size_t alignment) mi_attr_noexcept { mi_free(p); } -extern inline void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size) mi_attr_noexcept { +extern inline mi_decl_allocator void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size) mi_attr_noexcept { size_t total; if (mi_mul_overflow(count,size,&total)) return NULL; return mi_heap_zalloc(heap,total); } -void* mi_calloc(size_t count, size_t size) mi_attr_noexcept { +mi_decl_allocator void* mi_calloc(size_t count, size_t size) mi_attr_noexcept { return mi_heap_calloc(mi_get_default_heap(),count,size); } // Uninitialized `calloc` -extern void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size) mi_attr_noexcept { +extern mi_decl_allocator void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size) mi_attr_noexcept { size_t total; if (mi_mul_overflow(count,size,&total)) return NULL; return mi_heap_malloc(heap, total); } -void* mi_mallocn(size_t count, size_t size) mi_attr_noexcept { +mi_decl_allocator void* mi_mallocn(size_t count, size_t size) mi_attr_noexcept { return mi_heap_mallocn(mi_get_default_heap(),count,size); } // Expand in place or fail -void* mi_expand(void* p, size_t newsize) mi_attr_noexcept { +mi_decl_allocator void* mi_expand(void* p, size_t newsize) mi_attr_noexcept { if (p == NULL) return NULL; size_t size = mi_usable_size(p); if (newsize > size) return NULL; @@ -408,11 +408,11 @@ void* _mi_heap_realloc_zero(mi_heap_t* heap, void* p, size_t newsize, bool zero) return newp; } -void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept { return _mi_heap_realloc_zero(heap, p, newsize, false); } -void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size) mi_attr_noexcept { size_t total; if (mi_mul_overflow(count, size, &total)) return NULL; return mi_heap_realloc(heap, p, total); @@ -420,41 +420,41 @@ void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size) mi_a // Reallocate but free `p` on errors -void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept { void* newp = mi_heap_realloc(heap, p, newsize); if (newp==NULL && p!=NULL) mi_free(p); return newp; } -void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept { return _mi_heap_realloc_zero(heap, p, newsize, true); } -void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t count, size_t size) mi_attr_noexcept { +mi_decl_allocator void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t count, size_t size) mi_attr_noexcept { size_t total; if (mi_mul_overflow(count, size, &total)) return NULL; return mi_heap_rezalloc(heap, p, total); } -void* mi_realloc(void* p, size_t newsize) mi_attr_noexcept { +mi_decl_allocator void* mi_realloc(void* p, size_t newsize) mi_attr_noexcept { return mi_heap_realloc(mi_get_default_heap(),p,newsize); } -void* mi_reallocn(void* p, size_t count, size_t size) mi_attr_noexcept { +mi_decl_allocator void* mi_reallocn(void* p, size_t count, size_t size) mi_attr_noexcept { return mi_heap_reallocn(mi_get_default_heap(),p,count,size); } // Reallocate but free `p` on errors -void* mi_reallocf(void* p, size_t newsize) mi_attr_noexcept { +mi_decl_allocator void* mi_reallocf(void* p, size_t newsize) mi_attr_noexcept { return mi_heap_reallocf(mi_get_default_heap(),p,newsize); } -void* mi_rezalloc(void* p, size_t newsize) mi_attr_noexcept { +mi_decl_allocator void* mi_rezalloc(void* p, size_t newsize) mi_attr_noexcept { return mi_heap_rezalloc(mi_get_default_heap(), p, newsize); } -void* mi_recalloc(void* p, size_t count, size_t size) mi_attr_noexcept { +mi_decl_allocator void* mi_recalloc(void* p, size_t count, size_t size) mi_attr_noexcept { return mi_heap_recalloc(mi_get_default_heap(), p, count, size); } From 0fd0122c0a478d75d08b434ee1e66f51331d3d69 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 16 Oct 2019 22:43:57 +0200 Subject: [PATCH 85/92] Avoid compiler warning when casting the result of `GetProcAddress()` It is most unfortunate that the return type of `GetProcAddress()` is `FARPROC` (which is essentially `intptr_t(*)(void)): this type cannot be cast by GCC without warnings to anything but the generic function pointer type `void(*)(void)`. Let's work around that. Signed-off-by: Johannes Schindelin --- src/os.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/os.c b/src/os.c index e7313c80..cc69123a 100644 --- a/src/os.c +++ b/src/os.c @@ -145,13 +145,13 @@ void _mi_os_init(void) { hDll = LoadLibrary(TEXT("kernelbase.dll")); if (hDll != NULL) { // use VirtualAlloc2FromApp if possible as it is available to Windows store apps - pVirtualAlloc2 = (PVirtualAlloc2)GetProcAddress(hDll, "VirtualAlloc2FromApp"); - if (pVirtualAlloc2==NULL) pVirtualAlloc2 = (PVirtualAlloc2)GetProcAddress(hDll, "VirtualAlloc2"); + pVirtualAlloc2 = (PVirtualAlloc2)(void (*)(void))GetProcAddress(hDll, "VirtualAlloc2FromApp"); + if (pVirtualAlloc2==NULL) pVirtualAlloc2 = (PVirtualAlloc2)(void (*)(void))GetProcAddress(hDll, "VirtualAlloc2"); FreeLibrary(hDll); } hDll = LoadLibrary(TEXT("ntdll.dll")); if (hDll != NULL) { - pNtAllocateVirtualMemoryEx = (PNtAllocateVirtualMemoryEx)GetProcAddress(hDll, "NtAllocateVirtualMemoryEx"); + pNtAllocateVirtualMemoryEx = (PNtAllocateVirtualMemoryEx)(void (*)(void))GetProcAddress(hDll, "NtAllocateVirtualMemoryEx"); FreeLibrary(hDll); } if (mi_option_is_enabled(mi_option_large_os_pages) || mi_option_is_enabled(mi_option_reserve_huge_os_pages)) { From 559688ec6468c26b3831004301d727f0dce2437b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 16 Oct 2019 23:40:25 +0200 Subject: [PATCH 86/92] Suppress warning about unnamed struct This prevents MSVC complaining with warning C4201: nonstandard extension used: nameless struct/union The struct might seem unnecessary to the occasional reader (it did seem so to this commit's author), but it is not! It is required to align the fields to a boundary, which is verified by the test suite. Removing that "unnecessary" `struct` results in this failure: 1: Test command: mimalloc-test-api [...] 1: test: malloc-zero... mimalloc: assertion failed: at src/page.c:591, mi_page_init 1: assertion: "!mi_page_has_aligned(page)" Signed-off-by: Johannes Schindelin --- include/mimalloc-types.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index 4d0ade1b..c538d165 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -135,10 +135,11 @@ typedef enum mi_delayed_e { typedef union mi_page_flags_u { uint16_t value; uint8_t full_aligned; - struct { + struct { // force alignment unsigned in_full:1; unsigned has_aligned:1; bool is_zero; // `true` if the blocks in the free list are zero initialized +#pragma warning(suppress:4201) }; } mi_page_flags_t; From 26c27fbf587627caabc1e72c2b7d5a813a097464 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 12:07:26 -0700 Subject: [PATCH 87/92] use uint8_t bit fields, and improve portability of page_flags type --- include/mimalloc-types.h | 25 +++++++++++++------------ src/init.c | 2 +- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index c538d165..c2df6340 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -132,15 +132,16 @@ typedef enum mi_delayed_e { // The `in_full` and `has_aligned` page flags are put in a union to efficiently // test if both are false (`value == 0`) in the `mi_free` routine. -typedef union mi_page_flags_u { - uint16_t value; - uint8_t full_aligned; - struct { // force alignment - unsigned in_full:1; - unsigned has_aligned:1; - bool is_zero; // `true` if the blocks in the free list are zero initialized -#pragma warning(suppress:4201) +typedef struct mi_page_flags_s { + #pragma warning(suppress:4201) + union { + uint8_t full_aligned; + struct { + uint8_t in_full : 1; + uint8_t has_aligned : 1; + }; }; + bool is_zero; // `true` if the blocks in the free list are zero initialized } mi_page_flags_t; // Thread free list. @@ -168,10 +169,10 @@ typedef uintptr_t mi_thread_free_t; typedef struct mi_page_s { // "owned" by the segment uint8_t segment_idx; // index in the segment `pages` array, `page == &segment->pages[page->segment_idx]` - unsigned segment_in_use:1; // `true` if the segment allocated this page - unsigned is_reset:1; // `true` if the page memory was reset - unsigned is_committed:1; // `true` if the page virtual memory is committed - unsigned is_zero_init:1; // `true` if the page was zero initialized + uint8_t segment_in_use:1; // `true` if the segment allocated this page + uint8_t is_reset:1; // `true` if the page memory was reset + uint8_t is_committed:1; // `true` if the page virtual memory is committed + uint8_t is_zero_init:1; // `true` if the page was zero initialized // layout like this to optimize access in `mi_malloc` and `mi_free` uint16_t capacity; // number of blocks committed, must be the first field, see `segment.c:page_clear` diff --git a/src/init.c b/src/init.c index 5ab39c28..d62a2d34 100644 --- a/src/init.c +++ b/src/init.c @@ -13,7 +13,7 @@ terms of the MIT license. A copy of the license can be found in the file // Empty page used to initialize the small free pages array const mi_page_t _mi_page_empty = { 0, false, false, false, false, 0, 0, - { 0 }, + { { 0 }, false }, NULL, // free #if MI_SECURE 0, From 6e94950de329f0817ad8853b658aa15dc09984ab Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 12:13:45 -0700 Subject: [PATCH 88/92] update redirection modules --- bin/mimalloc-redirect.dll | Bin 46592 -> 46592 bytes bin/mimalloc-redirect32.dll | Bin 33792 -> 33792 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/mimalloc-redirect.dll b/bin/mimalloc-redirect.dll index ec718f91c10dfe4c47b83739df2764fd25ad8581..a1daf316b56cb3c885dc48f1c5fd1ef0ffa302b9 100644 GIT binary patch delta 690 zcmZp8!_@GGX~GRA=Dizlu`x0p-TaWznTc`7W>uCCN{pG4#ncxt-kQ8!{UMN?siDuf zVe&~07sk%Xe46!4A4MkjYp!Orm~5@3!zeg8L#vIkW%GM2Zx+UY&DQ#FSs1r$)-*|G z75&M;z|ifY641$-#m&gjT%!`eP?9uxp`{L^!Q^w6T5P>Q`Pb_v^IF9+PMn-=)iU{m zRivqQ9s|P*os<9ndjPe1cy#-yD0p=9oOrSI1W>5cMMdNFG7q3p8VscZ9=*JxAl1Al zC)ZiavIYM9|Nq6Y$qTJ>8O0~_+sM{8WHT^;3p6E8k}gIJ*Ox&|m(0@r&Ds0^yN7_N67L~j&S?>4wz2cX^vh_ZU1#j_Baqv4v9 zAex<^nycWNS&R?7wg&l5fuU3nXpjL^i^Gc;pcejZ2Y~Jn^8p2^M|X${&?;Uzpo$mb zAoGBt3LeczEDoQ6fyr_FPLnsVuuLwnEoO9@{KQs;ZAunUx$I;#0m;n=?Sut^M)FL);%_jCnO}~1?}}JpBr-4oaXJvY zBm!|DNQ8lbdGBVW05wJdlQhxv#v6kE3*XEPeDr{6(IU!noZVU_osSFGcfb>dt i1_l8T8%PU!GB88{*$F_}-iv`DBXx6Qs1Vbl6?_2Ufdkk8 delta 702 zcmZp8!_@GGX~GSr`BOIDVq;{yviTvSGZW*9&8jRPlo%@~i>WVQd^LHy`a>W&Q$wHe zz~qw}E{roL^J&&IF^W#^*Ido$G1*#6hf#5IhE^Nnl+Ew8yjd6%He2hzWnnzBS<@t$ zRg{B~fuY+)C7_cvi<^<5xke>`p`>u~LQ5S+`^o1lwM6GIFfe!kg$=k$*^Lgo>;-aP z&!7CyGM2Gva*S2WC({{Qa*G|9uG+ebygqnqc%i=`)kLY*!u8n2gu zjL={x74YcgWd*7Jdt!2)wJe+C&;S2lY@0mMI+u}s@_%dD`hskrbwC3GUN8YQw;m`} z_vjU^h6;MTICUIoVy|cvSm4BqN8cb8D7>x#il)Hz9s??a>P?30?Sts`g6drc*Xsb( z>j6<#545-oq1hX*IS8WJ2&y>?u9?O7z-w!e?-UqH^?(K`K(#o$@BwP!-*y1#4ly54 z2zzvgr~s|vihTV>69Iw#;&qCA}}XJYpxpu sLqIA6!v`R})184q0K^8;ik=J%5kPhUkoNatV8}?_+!!jvv}gq%09^zIeEXT>FI!%u0W~f3lda6=TxmK;6{M z2Xr$;HtRUuV4P^cBG*4 Date: Thu, 17 Oct 2019 12:14:15 -0700 Subject: [PATCH 89/92] increase delayed output buffer to 32k --- src/options.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/options.c b/src/options.c index 3e10926c..413ea765 100644 --- a/src/options.c +++ b/src/options.c @@ -144,21 +144,23 @@ static void mi_out_stderr(const char* msg) { // function we also buffer output that happens earlier. When // an output function is registered it is called immediately with // the output up to that point. -#define MAX_OUT_BUF (8*1024) -static char out_buf[MAX_OUT_BUF+1]; +#ifndef MI_MAX_DELAY_OUTPUT +#define MI_MAX_DELAY_OUTPUT (32*1024) +#endif +static char out_buf[MI_MAX_DELAY_OUTPUT+1]; static _Atomic(uintptr_t) out_len; static void mi_out_buf(const char* msg) { if (msg==NULL) return; - if (mi_atomic_read_relaxed(&out_len)>=MAX_OUT_BUF) return; + if (mi_atomic_read_relaxed(&out_len)>=MI_MAX_DELAY_OUTPUT) return; size_t n = strlen(msg); if (n==0) return; // claim space uintptr_t start = mi_atomic_addu(&out_len, n); - if (start >= MAX_OUT_BUF) return; + if (start >= MI_MAX_DELAY_OUTPUT) return; // check bound - if (start+n >= MAX_OUT_BUF) { - n = MAX_OUT_BUF-start-1; + if (start+n >= MI_MAX_DELAY_OUTPUT) { + n = MI_MAX_DELAY_OUTPUT-start-1; } memcpy(&out_buf[start], msg, n); } @@ -166,9 +168,9 @@ static void mi_out_buf(const char* msg) { static void mi_out_buf_flush(mi_output_fun* out) { if (out==NULL) return; // claim all (no more output will be added after this point) - size_t count = mi_atomic_addu(&out_len, MAX_OUT_BUF); + size_t count = mi_atomic_addu(&out_len, MI_MAX_DELAY_OUTPUT); // and output the current contents - if (count>MAX_OUT_BUF) count = MAX_OUT_BUF; + if (count>MI_MAX_DELAY_OUTPUT) count = MI_MAX_DELAY_OUTPUT; out_buf[count] = 0; out(out_buf); } From 93b4281b82768023563bc2eb4a1441d83f53efa4 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 12:35:35 -0700 Subject: [PATCH 90/92] ensure randomized huge page start address in 1GiB aligned --- src/os.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/os.c b/src/os.c index cc69123a..c6ab4ab6 100644 --- a/src/os.c +++ b/src/os.c @@ -886,7 +886,7 @@ int mi_reserve_huge_os_pages( size_t pages, double max_secs, size_t* pages_reser uint8_t* start = (uint8_t*)((uintptr_t)32 << 40); // 32TiB virtual start address #if (MI_SECURE>0 || MI_DEBUG==0) // security: randomize start of huge pages unless in debug mode uintptr_t r = _mi_random_init((uintptr_t)&mi_reserve_huge_os_pages); - start = start + ((uintptr_t)MI_SEGMENT_SIZE * ((r>>17) & 0xFFFF)); // (randomly 0-64k)*4MiB == 0 to 256GiB + start = start + ((uintptr_t)MI_HUGE_OS_PAGE_SIZE * ((r>>17) & 0x3FF)); // (randomly 0-1024)*1GiB == 0 to 1TiB #endif // Allocate one page at the time but try to place them contiguously From 5de851a84d20835de2429ed60a6eeac3b0a8b6eb Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 16:48:16 -0700 Subject: [PATCH 91/92] update page_flags to have more portable definition --- ide/vs2019/mimalloc.vcxproj | 2 +- include/mimalloc-internal.h | 8 ++++---- include/mimalloc-types.h | 21 +++++++++------------ src/alloc-aligned.c | 2 +- src/alloc.c | 6 +++--- src/init.c | 2 +- src/page.c | 8 ++++---- 7 files changed, 23 insertions(+), 26 deletions(-) diff --git a/ide/vs2019/mimalloc.vcxproj b/ide/vs2019/mimalloc.vcxproj index 5658b536..56beeff9 100644 --- a/ide/vs2019/mimalloc.vcxproj +++ b/ide/vs2019/mimalloc.vcxproj @@ -111,7 +111,7 @@ - Level3 + Level4 Disabled true true diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 1a5b639d..4c47af94 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -345,19 +345,19 @@ static inline mi_page_queue_t* mi_page_queue(const mi_heap_t* heap, size_t size) // Page flags //----------------------------------------------------------- static inline bool mi_page_is_in_full(const mi_page_t* page) { - return page->flags.in_full; + return page->flags.x.in_full; } static inline void mi_page_set_in_full(mi_page_t* page, bool in_full) { - page->flags.in_full = in_full; + page->flags.x.in_full = in_full; } static inline bool mi_page_has_aligned(const mi_page_t* page) { - return page->flags.has_aligned; + return page->flags.x.has_aligned; } static inline void mi_page_set_has_aligned(mi_page_t* page, bool has_aligned) { - page->flags.has_aligned = has_aligned; + page->flags.x.has_aligned = has_aligned; } diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index c2df6340..eea76a25 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -131,17 +131,13 @@ typedef enum mi_delayed_e { // The `in_full` and `has_aligned` page flags are put in a union to efficiently -// test if both are false (`value == 0`) in the `mi_free` routine. -typedef struct mi_page_flags_s { - #pragma warning(suppress:4201) - union { - uint8_t full_aligned; - struct { - uint8_t in_full : 1; - uint8_t has_aligned : 1; - }; - }; - bool is_zero; // `true` if the blocks in the free list are zero initialized +// test if both are false (`full_aligned == 0`) in the `mi_free` routine. +typedef union mi_page_flags_s { + uint8_t full_aligned; + struct { + uint8_t in_full : 1; + uint8_t has_aligned : 1; + } x; } mi_page_flags_t; // Thread free list. @@ -177,7 +173,8 @@ typedef struct mi_page_s { // layout like this to optimize access in `mi_malloc` and `mi_free` uint16_t capacity; // number of blocks committed, must be the first field, see `segment.c:page_clear` uint16_t reserved; // number of blocks reserved in memory - mi_page_flags_t flags; // `in_full` and `has_aligned` flags (16 bits) + mi_page_flags_t flags; // `in_full` and `has_aligned` flags (8 bits) + bool is_zero; // `true` if the blocks in the free list are zero initialized mi_block_t* free; // list of available free blocks (`malloc` allocates from this list) #if MI_SECURE diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index 99347933..5a59a63a 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -126,7 +126,7 @@ static void* mi_heap_realloc_zero_aligned_at(mi_heap_t* heap, void* p, size_t ne if (newp != NULL) { if (zero && newsize > size) { const mi_page_t* page = _mi_ptr_page(newp); - if (page->flags.is_zero) { + if (page->is_zero) { // already zero initialized mi_assert_expensive(mi_mem_is_zero(newp,newsize)); } diff --git a/src/alloc.c b/src/alloc.c index 3950496a..0c399671 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -33,7 +33,7 @@ extern inline void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t siz page->used++; mi_assert_internal(page->free == NULL || _mi_ptr_page(page->free) == page); #if (MI_DEBUG) - if (!page->flags.is_zero) { memset(block, MI_DEBUG_UNINIT, size); } + if (!page->is_zero) { memset(block, MI_DEBUG_UNINIT, size); } #elif (MI_SECURE) block->next = 0; #endif @@ -96,7 +96,7 @@ void _mi_block_zero_init(const mi_page_t* page, void* p, size_t size) { mi_assert_internal(p != NULL); mi_assert_internal(size > 0 && page->block_size >= size); mi_assert_internal(_mi_ptr_page(p)==page); - if (page->flags.is_zero) { + if (page->is_zero) { // already zero initialized memory? ((mi_block_t*)p)->next = 0; // clear the free list pointer mi_assert_expensive(mi_mem_is_zero(p,page->block_size)); @@ -147,7 +147,7 @@ static mi_decl_noinline void _mi_free_block_mt(mi_page_t* page, mi_block_t* bloc mi_block_set_next(page, block, page->free); page->free = block; page->used--; - page->flags.is_zero = false; + page->is_zero = false; _mi_segment_page_free(page,true,&heap->tld->segments); } return; diff --git a/src/init.c b/src/init.c index d62a2d34..75836aca 100644 --- a/src/init.c +++ b/src/init.c @@ -13,7 +13,7 @@ terms of the MIT license. A copy of the license can be found in the file // Empty page used to initialize the small free pages array const mi_page_t _mi_page_empty = { 0, false, false, false, false, 0, 0, - { { 0 }, false }, + { 0 }, false, NULL, // free #if MI_SECURE 0, diff --git a/src/page.c b/src/page.c index 25e59977..77d98f11 100644 --- a/src/page.c +++ b/src/page.c @@ -192,7 +192,7 @@ void _mi_page_free_collect(mi_page_t* page, bool force) { // usual case page->free = page->local_free; page->local_free = NULL; - page->flags.is_zero = false; + page->is_zero = false; } else if (force) { // append -- only on shutdown (force) as this is a linear operation @@ -204,7 +204,7 @@ void _mi_page_free_collect(mi_page_t* page, bool force) { mi_block_set_next(page, tail, page->free); page->free = page->local_free; page->local_free = NULL; - page->flags.is_zero = false; + page->is_zero = false; } } @@ -559,7 +559,7 @@ static void mi_page_extend_free(mi_heap_t* heap, mi_page_t* page, mi_stats_t* st // extension into zero initialized memory preserves the zero'd free list if (!page->is_zero_init) { - page->flags.is_zero = false; + page->is_zero = false; } mi_assert_expensive(mi_page_is_valid_init(page)); } @@ -579,7 +579,7 @@ static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t block_size, mi #if MI_SECURE page->cookie = _mi_heap_random(heap) | 1; #endif - page->flags.is_zero = page->is_zero_init; + page->is_zero = page->is_zero_init; mi_assert_internal(page->capacity == 0); mi_assert_internal(page->free == NULL); From fdfa6ed2602f2e6cbd6d5d466b24a7e447cc0e42 Mon Sep 17 00:00:00 2001 From: daan Date: Thu, 17 Oct 2019 16:56:57 -0700 Subject: [PATCH 92/92] fix warnings at high warning level in msvc --- ide/vs2019/mimalloc.vcxproj | 2 +- include/mimalloc-atomic.h | 2 +- src/memory.c | 2 +- src/options.c | 2 +- src/os.c | 2 +- src/page-queue.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ide/vs2019/mimalloc.vcxproj b/ide/vs2019/mimalloc.vcxproj index 56beeff9..5658b536 100644 --- a/ide/vs2019/mimalloc.vcxproj +++ b/ide/vs2019/mimalloc.vcxproj @@ -111,7 +111,7 @@ - Level4 + Level3 Disabled true true diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index 8b254d3e..dff0f011 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -130,7 +130,7 @@ static inline intptr_t mi_atomic_add(volatile _Atomic(intptr_t)* p, intptr_t add return (intptr_t)RC64(_InterlockedExchangeAdd)((volatile msc_intptr_t*)p, (msc_intptr_t)add); } static inline bool mi_atomic_cas_strong(volatile _Atomic(uintptr_t)* p, uintptr_t desired, uintptr_t expected) { - return (expected == RC64(_InterlockedCompareExchange)((volatile msc_intptr_t*)p, (msc_intptr_t)desired, (msc_intptr_t)expected)); + return (expected == (uintptr_t)RC64(_InterlockedCompareExchange)((volatile msc_intptr_t*)p, (msc_intptr_t)desired, (msc_intptr_t)expected)); } static inline bool mi_atomic_cas_weak(volatile _Atomic(uintptr_t)* p, uintptr_t desired, uintptr_t expected) { return mi_atomic_cas_strong(p,desired,expected); diff --git a/src/memory.c b/src/memory.c index 0ad582cd..f9c53782 100644 --- a/src/memory.c +++ b/src/memory.c @@ -71,7 +71,7 @@ bool _mi_os_is_huge_reserved(void* p); typedef uintptr_t mi_region_info_t; static inline mi_region_info_t mi_region_info_create(void* start, bool is_large, bool is_committed) { - return ((uintptr_t)start | ((is_large?1:0) << 1) | (is_committed?1:0)); + return ((uintptr_t)start | ((uintptr_t)(is_large?1:0) << 1) | (is_committed?1:0)); } static inline void* mi_region_info_read(mi_region_info_t info, bool* is_large, bool* is_committed) { diff --git a/src/options.c b/src/options.c index 413ea765..4e2bdeaa 100644 --- a/src/options.c +++ b/src/options.c @@ -346,7 +346,7 @@ static void mi_option_init(mi_option_desc_t* desc) { size_t len = strlen(s); if (len >= sizeof(buf)) len = sizeof(buf) - 1; for (size_t i = 0; i < len; i++) { - buf[i] = toupper(s[i]); + buf[i] = (char)toupper(s[i]); } buf[len] = 0; if (buf[0]==0 || strstr("1;TRUE;YES;ON", buf) != NULL) { diff --git a/src/os.c b/src/os.c index c6ab4ab6..ed938221 100644 --- a/src/os.c +++ b/src/os.c @@ -700,7 +700,7 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats) void* p = VirtualAlloc(start, csize, MEM_RESET, PAGE_READWRITE); mi_assert_internal(p == start); #if 1 - if (p == start) { + if (p == start && start != NULL) { VirtualUnlock(start,csize); // VirtualUnlock after MEM_RESET removes the memory from the working set } #endif diff --git a/src/page-queue.c b/src/page-queue.c index d613095f..4af70b50 100644 --- a/src/page-queue.c +++ b/src/page-queue.c @@ -57,7 +57,7 @@ static inline uint8_t mi_bsr32(uint32_t x); static inline uint8_t mi_bsr32(uint32_t x) { uint32_t idx; _BitScanReverse((DWORD*)&idx, x); - return idx; + return (uint8_t)idx; } #elif defined(__GNUC__) || defined(__clang__) static inline uint8_t mi_bsr32(uint32_t x) {