microsoft / mimalloc Goto Github PK
View Code? Open in Web Editor NEWmimalloc is a compact general purpose allocator with excellent performance.
License: MIT License
mimalloc is a compact general purpose allocator with excellent performance.
License: MIT License
I had already spotted this in dev, but now it's in master:
os.c(96): warning C4133: 'function': incompatible types - from 'char [15]' to 'LPCWSTR'
os.c(113): warning C4133: 'function': incompatible types - from 'char [22]' to 'LPCWSTR'
A narrow c-string is consumed by a function that expects a wide-string (when compiled with _UNICODE
).
To fix this warning, the most simple is to use the TEXT()
macro:
hDll = LoadLibrary(TEXT("kernelbase.dll")); // 96
and
ok = LookupPrivilegeValue(NULL, TEXT("SeLockMemoryPrivilege"), &tp.Privileges[0].Luid); // 113
This will then also work correctly with _MBCS
.
GetProcAddress
(line 99) doesn't need this, as GetProcAddress
consumes a narrow string (https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress), just for the purpose of consistency and added fun ;-) .
Building a monolithic project with CMake+Ninja (default behaviour in Visual Studio these days) that adds mimalloc via add_subdirectory
:
ninja : warning : multiple rules generate lib/mimalloc-debug.lib. builds involving this target will not be correct; continuing anyway [-w dupbuild=warn]
The problem appears to be that both the shared and static versions of the library end up creating a mimalloc-static.lib
file (the import library for the DLL and the static library itself). This is because both libraries set:
set_target_properties(mimalloc-static PROPERTIES OUTPUT_NAME ${mi_basename})
Which causes both the DLL's import library and the static library's name to be identical.
#############################################
# Link the shared library bin\mimalloc-debug.dll
build bin\mimalloc-debug.dll lib\mimalloc-debug.lib: C_SHARED_LIBRARY_LINKER__mimalloc
...stuff...
TARGET_FILE = bin\mimalloc-debug.dll
TARGET_IMPLIB = lib\mimalloc-debug.lib
TARGET_PDB = bin\mimalloc-debug.pdb
#############################################
# Link the static library lib\mimalloc-debug.lib
build lib\mimalloc-debug.lib: C_STATIC_LIBRARY_LINKER__mimalloc-static
...stuff...
TARGET_FILE = lib\mimalloc-debug.lib
TARGET_PDB = lib\mimalloc-debug.pdb
It is not possible to build master (or the newest release 1.0.3) using cmake.
Full output:
elszben@elx78373ycn:~/Downloads/mimalloc-1.0.3$ cmake .
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- No build type selected, default to *** Release ***
-- Override standard malloc (MI_OVERRIDE=ON)
-- Output library name : mimalloc
-- Installation directory: lib/mimalloc-1.0
-- Configuring done
CMake Error:
Error evaluating generator expression:
$<TARGET_OBJECTS:mimalloc-obj>
The evaluation of the TARGET_OBJECTS generator expression is only suitable
for consumption by CMake. It is not suitable for writing out elsewhere.
-- Generating done
-- Build files have been written to: /home/elszben/Downloads/mimalloc-1.0.3
Any idea how to fix it?
Thanks in advance.
currently mi_heap_malloc_zero_aligned_at is not on the public api, and there is no aligned heap api's, it should be fairly simple and useful to have this as a public api right?
I can make a PR if wanted, I just got curious why it isn't so already.
pkg-config support makes much easier to deal with libraries.
firefox[7891]: segfault at 28 ip 00007f40c0d8bfa0 sp 00007ffed98afff8 error 4 in libpthread-2.27.so[7f40c0d82000+1a000]
version: 06f8da4
Description: Ubuntu 18.04.2 LTS
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) stable release version 2.27.
There does not appear to be a sized-deallocation API (e.g. free_(void*, size_t)
) where the user promises that the size passed is the size hint in range [requested_size, alloction_size] where allocation size is the maximum of mi_good_size
and mi_usable_size
.
In the Static override section section in the readme.md, the mimalloc-override.o
file is mentiond.
But when I build mimalloc and run "make install", I got only mimalloc.o
.
Is the readme wrong? Or some option is needed to produce mimalloc-override.o
?
ntdll.dll!00000000773af3af() Unknown
ntdll.dll!00000000773af9c6() Unknown
ntdll.dll!00000000773b0592() Unknown
ntdll.dll!00000000773b2204() Unknown
ntdll.dll!000000007734d21c() Unknown
ucrtbase.dll!000007fef636419b() Unknown
> mimalloc-override-test.exe!main() Line 29 C++
[External Code]
version: 875ecbd
Description: Win7 x64 SP1 vs communtity 2017 15.9.11
Solution Config: Release x64
Uploading dump-and-pdb-files.zip…
Hi there,
For the linux side of things making the .a/.so should be straighforward enough.
For the windows side of things however, it would have been nice to release some pre-build binaries for windows 10 to things out with.
Also, it would have been nice to simply msbuild.exe ide/vs2017/mimalloc.sln
giving examples to build it at the command line with different mstools versions.
How do we query for the available install mstools versions we have to pass it at the msbuild command line and force it to use that?
Thank you for listening.
To support a large chunk of memory, we might set MAP_NORESERVE
flag to mmap
to get either proper memory accounting or full overcommit on both Linux and macOS. Would it make sense?
When pulling in sources to build and package this library, the ideal case is for the library authors to use Github releases with periodic versioned releases. Currently we're pulling from Master and pinning to commits, but that is sub-optimal. It doesn't even need to be a 1.0
release, it could be some 0.1.0
pre-release.
For certain desireable .exe's we don't have the sources.
That means we can't use the windows import libraries to link mimalloc.lib into the target .exe on windows 10.
feature request:
https://github.com/stevemk14ebr/PolyHook
https://easyhook.github.io/
are tools that patch at runtime to hook up the existing dll calls within a running binary, but that's not something I would prefer to do.
In linux land we have patchelf/prelink which can change the search path and the dll's the linux binary is attempting to use AFTER BUILD TIME. It's an patch/instrumentation tool. I was looking for a similar tool for windows 10 binaries. Is there such a beast? If not could the Microsoft team develop/provide one? Thank you for listening.
The default solution file on Windows/VS20XX compiles the code as Multi Byte Character Set. This appears to have been done quite deliberately.
Is this really necessary or can the code also be compiled as UNICODE, which would be preferable.
It would be great if the library could always expose a standard C and POSIX API, e.g., for example, right now, mi_aligned_alloc
and mi_posix_memalign
are missing.
Ideally, they would always be available. This would allow writing a wrapper that uses the standard C names, e.g., aligned_alloc
, and just always calls mi_aligned_alloc
internally, instead of having some logic to do different things depending on MI_OVERRIDE
.
While destroying a heap from a thread that is different from the heap's creator, the mi_segment_is_valid
assertion under _mi_segment_page_free
fails. What would be required to add support for destroying heaps from arbitrary threads?
Compiling with Mingw gives two errors:
[1]
/at/rust/projects/mimalloc/target/x86_64-pc-windows-gnu/debug/build/mimalloc-sys-49105590189f0a7b/out/build/mimalloc/src/alloc.c:416:13: error: ‘EINVAL’ undeclared (first use in this function); did you mean ‘WINVER’?
errno = EINVAL; return NULL;
^~~~~~
WINVER
/at/rust/projects/mimalloc/target/x86_64-pc-windows-gnu/debug/build/mimalloc-sys-49105590189f0a7b/out/build/mimalloc/src/alloc.c:416:13: note: each undeclared identifier is reported only once for each function it appears in
make[2]: *** [CMakeFiles/mimalloc-static.dir/src/alloc.c.obj] Error 1
It may be fixed with add
#ifndef EINVAL
#define EINVAL 22
#endif
in the alloc.c
. I took the code from alloc-override.c
.
[2]
/at/rust/projects/mimalloc/target/x86_64-pc-windows-gnu/debug/build/mimalloc-sys-49105590189f0a7b/out/build/mimalloc/src/init.c:388:12: fatal error: Windows.h: No such file or directory
#include <Windows.h>
^~~~~~~~~~~
If the header <Windows.h>
is the same as <windows.h>
then it my be fixed with rename the header to <windows.h>
in the init.c
.
With these two fixes and with this patch (#22) I can compile mimalloc with Mingw on Linux.
The file alloc-override-win.c
is never included or built on Windows when using CMake. It appears that the file is only referenced at all in the provided .vcxproj
files, which are not of help to parent CMake projects that are building via add_subdirectory
(and may not even be using MSBuild anyway but rather Ninja, which is also the default CMake build system in Visual Studio itself these days).
I'm compiling the static library manually as follows:
"/usr/bin/clang" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC"
"-g" "-fno-omit-frame-pointer" "--target=x86_64-apple-darwin" "-I"
"mimalloc/include" "-I" "mimalloc/src" "-std=gnu11" "-Wall" "-Wextra"
"-Wno-unknown-pragmas" "-ftls-model=initial-exec" "-DMI_STATIC_LIB"
"-DMI_DEBUG=3" "-DMI_SECURE=2" "-DMI_STAT=0" "-o"
"target/debug/build/mimalloc-sys-329fad58db2cfb59/out/mimalloc/src/static.o"
"-c" "mimalloc/src/static.c"
Note that MI_STAT=0. Still, i'm getting output of the form:
mimalloc: option 'page_reset': 0
mimalloc: option 'show_stats': 0
heap stats: peak total freed unit count
elapsed: 0.003 s
process: user: 0.004 s, system: 0.004 s, faults: 0, reclaims: 707, rss: 2.0 mb
mimalloc: process done: 0x104de25c0
This issue is for a feature request to support basic C leak detection. I'm aware that CRT has leak detection, however that is Windows only. I would imagine something similar to:
https://stackoverflow.com/questions/9074229/detecting-memory-leaks-in-c-programs
That prints the allocs that have not been freed and their line and filename at the end of the application when it is done.
I would like to point out that an identifier like “__MIMALLOC_H
” does eventually not fit to the expected naming convention of the C language standard.
Would you like to adjust your selection for unique names?
In posix_memalign
override, the function modifies the resulting pointer, even if the allocation fails due to ENOMEM
. Accodring to docs, posix_memalign
should not modify the returned pointer on failure.
I've added support for mimalloc
to pt::pector
. pt::pector
is a 'better' std::vector (not always) written by Adrien Guinet, who has dropped of the radar, I hope he's doing well. So I have forked that project and I'm doing some minor maintenance. Its license is LGPL (but header only, so I don't really know what that means). pt::pector
intends to be a better std::vector
. To that purpose (a.o.) a pt::malloc_allocator
was added to pt::pector
, in order to benefit from std::realloc
. This allowed for marginal improvements over std::vector
. Now I've added a pt::mimalloc_allocator
, so, same thing, just replaced std::malloc
and friends with mi_malloc
and its girl-friends. This has had a dramatic change in the resulting benchmark numbers.
What I'm doing in the bench-marking is to emplace_back() on a vector of vector-type containers, randomly selected and of random length within a range. The ranges are then iteratively increased and the length of the vectors increases as well. It sounds more complicated than it is, the code is here.
I'm testing this both with VS2019 and with Clang/LLVM-9.0 (trunk) on Windows 10-1903 x64, Intel Ci3 5005U. For VC with LTCG and for Clang with Thin LTO.
Results for VS2019:
06/28/19 12:00:18
Running Y:\REPOS\podder\x64\Release\benchmark.exe
Run on (4 X 1995 MHz CPU s)
CPU Caches:
L1 Data 32K (x2)
L1 Instruction 32K (x2)
L2 Unified 262K (x2)
L3 Unified 3145K (x1)
----------------------------------------------------------------------------------------------------------------------------------
Benchmark Time CPU Iterations
----------------------------------------------------------------------------------------------------------------------------------
bm_emplace_back_random<std::vector<std::uint8_t>>/23/8192/repeats:4_mean 747 ns 802 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/23/8192/repeats:4_median 746 ns 809 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/23/8192/repeats:4_stddev 10.9 ns 26.7 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/32/8192/repeats:4_mean 871 ns 848 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/32/8192/repeats:4_median 873 ns 889 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/32/8192/repeats:4_stddev 3.91 ns 91.2 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/64/8192/repeats:4_mean 874 ns 907 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/64/8192/repeats:4_median 871 ns 893 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/64/8192/repeats:4_stddev 8.87 ns 70.2 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/128/8192/repeats:4_mean 873 ns 834 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/128/8192/repeats:4_median 871 ns 830 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/128/8192/repeats:4_stddev 9.96 ns 38.4 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/256/8192/repeats:4_mean 951 ns 977 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/256/8192/repeats:4_median 948 ns 991 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/256/8192/repeats:4_stddev 17.9 ns 63.4 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/512/8192/repeats:4_mean 1275 ns 1231 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/512/8192/repeats:4_median 1270 ns 1235 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/512/8192/repeats:4_stddev 19.4 ns 79.2 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/1024/8192/repeats:4_mean 1866 ns 1836 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/1024/8192/repeats:4_median 1834 ns 1859 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/1024/8192/repeats:4_stddev 107 ns 78.5 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/2048/8192/repeats:4_mean 2652 ns 2576 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/2048/8192/repeats:4_median 2570 ns 2539 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/2048/8192/repeats:4_stddev 226 ns 201 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/4096/8192/repeats:4_mean 4005 ns 3838 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/4096/8192/repeats:4_median 3980 ns 3838 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/4096/8192/repeats:4_stddev 302 ns 291 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/8192/8192/repeats:4_mean 6496 ns 6719 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/8192/8192/repeats:4_median 6501 ns 6563 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/8192/8192/repeats:4_stddev 367 ns 442 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/23/8192/repeats:4_mean 770 ns 750 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/23/8192/repeats:4_median 766 ns 759 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/23/8192/repeats:4_stddev 9.64 ns 74.0 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/32/8192/repeats:4_mean 866 ns 885 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/32/8192/repeats:4_median 866 ns 907 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/32/8192/repeats:4_stddev 1.75 ns 74.5 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/64/8192/repeats:4_mean 859 ns 859 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/64/8192/repeats:4_median 860 ns 859 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/64/8192/repeats:4_stddev 2.75 ns 46.0 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/128/8192/repeats:4_mean 870 ns 931 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/128/8192/repeats:4_median 870 ns 935 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/128/8192/repeats:4_stddev 1.54 ns 20.9 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/256/8192/repeats:4_mean 923 ns 977 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/256/8192/repeats:4_median 921 ns 1004 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/256/8192/repeats:4_stddev 7.22 ns 78.9 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/512/8192/repeats:4_mean 1164 ns 1193 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/512/8192/repeats:4_median 1166 ns 1224 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/512/8192/repeats:4_stddev 9.91 ns 70.4 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/1024/8192/repeats:4_mean 1607 ns 1656 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/1024/8192/repeats:4_median 1607 ns 1679 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/1024/8192/repeats:4_stddev 5.47 ns 137 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/2048/8192/repeats:4_mean 2000 ns 1978 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/2048/8192/repeats:4_median 2001 ns 1904 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/2048/8192/repeats:4_stddev 8.88 ns 228 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/4096/8192/repeats:4_mean 2777 ns 2920 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/4096/8192/repeats:4_median 2767 ns 2905 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/4096/8192/repeats:4_stddev 32.1 ns 156 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/8192/8192/repeats:4_mean 4755 ns 4883 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/8192/8192/repeats:4_median 4752 ns 4883 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/8192/8192/repeats:4_stddev 58.6 ns 114 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/23/8192/repeats:4_mean 408 ns 432 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/23/8192/repeats:4_median 407 ns 430 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/23/8192/repeats:4_stddev 3.49 ns 25.7 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/32/8192/repeats:4_mean 416 ns 430 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/32/8192/repeats:4_median 417 ns 425 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/32/8192/repeats:4_stddev 1.58 ns 25.5 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/64/8192/repeats:4_mean 435 ns 475 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/64/8192/repeats:4_median 434 ns 477 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/64/8192/repeats:4_stddev 3.69 ns 46.5 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/128/8192/repeats:4_mean 463 ns 445 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/128/8192/repeats:4_median 464 ns 452 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/128/8192/repeats:4_stddev 2.66 ns 48.1 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/256/8192/repeats:4_mean 530 ns 509 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/256/8192/repeats:4_median 525 ns 502 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/256/8192/repeats:4_stddev 10.9 ns 58.6 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/512/8192/repeats:4_mean 606 ns 645 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/512/8192/repeats:4_median 607 ns 637 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/512/8192/repeats:4_stddev 1.27 ns 65.2 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/1024/8192/repeats:4_mean 798 ns 792 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/1024/8192/repeats:4_median 783 ns 795 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/1024/8192/repeats:4_stddev 34.9 ns 41.7 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/2048/8192/repeats:4_mean 1078 ns 1130 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/2048/8192/repeats:4_median 1077 ns 1109 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/2048/8192/repeats:4_stddev 4.59 ns 80.1 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/4096/8192/repeats:4_mean 1652 ns 1611 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/4096/8192/repeats:4_median 1653 ns 1592 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/4096/8192/repeats:4_stddev 8.64 ns 180 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/8192/8192/repeats:4_mean 2931 ns 2965 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/8192/8192/repeats:4_median 2934 ns 2965 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/8192/8192/repeats:4_stddev 15.1 ns 90.1 ns 4
And with Clang the results are [very different, but still putting mipector
(the one backed by mimalloc
) in the lead]:
06/28/19 12:04:41
Running podder-benchmark.exe
Run on (4 X 1995 MHz CPU s)
CPU Caches:
L1 Data 32K (x2)
L1 Instruction 32K (x2)
L2 Unified 262K (x2)
L3 Unified 3145K (x1)
----------------------------------------------------------------------------------------------------------------------------------
Benchmark Time CPU Iterations
----------------------------------------------------------------------------------------------------------------------------------
bm_emplace_back_random<std::vector<std::uint8_t>>/23/8192/repeats:4_mean 710 ns 698 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/23/8192/repeats:4_median 707 ns 715 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/23/8192/repeats:4_stddev 6.30 ns 88.9 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/32/8192/repeats:4_mean 710 ns 725 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/32/8192/repeats:4_median 710 ns 732 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/32/8192/repeats:4_stddev 2.46 ns 19.7 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/64/8192/repeats:4_mean 723 ns 774 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/64/8192/repeats:4_median 725 ns 781 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/64/8192/repeats:4_stddev 6.81 ns 47.7 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/128/8192/repeats:4_mean 745 ns 734 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/128/8192/repeats:4_median 745 ns 719 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/128/8192/repeats:4_stddev 7.13 ns 44.2 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/256/8192/repeats:4_mean 792 ns 802 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/256/8192/repeats:4_median 794 ns 816 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/256/8192/repeats:4_stddev 8.04 ns 33.2 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/512/8192/repeats:4_mean 1052 ns 1011 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/512/8192/repeats:4_median 1057 ns 1018 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/512/8192/repeats:4_stddev 12.1 ns 47.7 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/1024/8192/repeats:4_mean 1532 ns 1583 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/1024/8192/repeats:4_median 1518 ns 1573 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/1024/8192/repeats:4_stddev 43.8 ns 85.1 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/2048/8192/repeats:4_mean 1933 ns 2026 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/2048/8192/repeats:4_median 1933 ns 2026 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/2048/8192/repeats:4_stddev 53.8 ns 63.0 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/4096/8192/repeats:4_mean 2597 ns 2667 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/4096/8192/repeats:4_median 2625 ns 2651 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/4096/8192/repeats:4_stddev 108 ns 147 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/8192/8192/repeats:4_mean 3843 ns 3578 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/8192/8192/repeats:4_median 3828 ns 3432 ns 4
bm_emplace_back_random<std::vector<std::uint8_t>>/8192/8192/repeats:4_stddev 51.7 ns 293 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/23/8192/repeats:4_mean 765 ns 764 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/23/8192/repeats:4_median 765 ns 746 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/23/8192/repeats:4_stddev 3.74 ns 40.1 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/32/8192/repeats:4_mean 790 ns 766 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/32/8192/repeats:4_median 784 ns 727 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/32/8192/repeats:4_stddev 19.5 ns 83.7 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/64/8192/repeats:4_mean 803 ns 813 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/64/8192/repeats:4_median 801 ns 766 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/64/8192/repeats:4_stddev 7.03 ns 129 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/128/8192/repeats:4_mean 877 ns 886 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/128/8192/repeats:4_median 844 ns 865 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/128/8192/repeats:4_stddev 73.8 ns 86.4 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/256/8192/repeats:4_mean 910 ns 949 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/256/8192/repeats:4_median 912 ns 893 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/256/8192/repeats:4_stddev 5.99 ns 133 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/512/8192/repeats:4_mean 1164 ns 1248 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/512/8192/repeats:4_median 1165 ns 1224 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/512/8192/repeats:4_stddev 10.7 ns 176 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/1024/8192/repeats:4_mean 1701 ns 1822 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/1024/8192/repeats:4_median 1701 ns 1822 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/1024/8192/repeats:4_stddev 8.86 ns 179 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/2048/8192/repeats:4_mean 2207 ns 2225 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/2048/8192/repeats:4_median 2210 ns 2225 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/2048/8192/repeats:4_stddev 21.1 ns 169 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/4096/8192/repeats:4_mean 3127 ns 3058 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/4096/8192/repeats:4_median 3128 ns 3040 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/4096/8192/repeats:4_stddev 7.67 ns 70.1 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/8192/8192/repeats:4_mean 5252 ns 4778 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/8192/8192/repeats:4_median 5256 ns 4743 ns 4
bm_emplace_back_random<pector<std::uint8_t, std::int64_t>>/8192/8192/repeats:4_stddev 138 ns 562 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/23/8192/repeats:4_mean 412 ns 377 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/23/8192/repeats:4_median 412 ns 374 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/23/8192/repeats:4_stddev 1.15 ns 53.8 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/32/8192/repeats:4_mean 421 ns 415 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/32/8192/repeats:4_median 421 ns 413 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/32/8192/repeats:4_stddev 1.44 ns 26.5 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/64/8192/repeats:4_mean 443 ns 439 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/64/8192/repeats:4_median 442 ns 454 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/64/8192/repeats:4_stddev 2.38 ns 42.0 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/128/8192/repeats:4_mean 484 ns 502 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/128/8192/repeats:4_median 484 ns 495 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/128/8192/repeats:4_stddev 0.331 ns 52.2 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/256/8192/repeats:4_mean 552 ns 559 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/256/8192/repeats:4_median 552 ns 578 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/256/8192/repeats:4_stddev 1.31 ns 39.1 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/512/8192/repeats:4_mean 657 ns 698 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/512/8192/repeats:4_median 657 ns 705 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/512/8192/repeats:4_stddev 2.61 ns 41.1 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/1024/8192/repeats:4_mean 866 ns 848 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/1024/8192/repeats:4_median 868 ns 858 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/1024/8192/repeats:4_stddev 5.89 ns 71.5 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/2048/8192/repeats:4_mean 1249 ns 1311 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/2048/8192/repeats:4_median 1250 ns 1283 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/2048/8192/repeats:4_stddev 4.56 ns 96.7 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/4096/8192/repeats:4_mean 1995 ns 2053 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/4096/8192/repeats:4_median 1998 ns 2066 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/4096/8192/repeats:4_stddev 13.5 ns 50.1 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/8192/8192/repeats:4_mean 3626 ns 3721 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/8192/8192/repeats:4_median 3618 ns 3721 ns 4
bm_emplace_back_random<mipector<std::uint8_t, std::int64_t>>/8192/8192/repeats:4_stddev 46.5 ns 133 ns 4
Just sharing, time for a better vector has never looked better than now! Thanks for this great allocator.
So I'm trying to build a Rust toolchain with mimalloc that works here: rust-lang/rust#62340 , such that we can use the Rust toolchain compiler benchmark suite to test whether it would be worth it switching to mimalloc from jemalloc.
I think I've managed so far to link mimalloc properly, and built a toolchain that's statically linked with it and uses it. When that toolchain is used to build another toolchain, after building a chunk of it, it segfaults with: signal: 11, SIGSEGV: invalid memory reference. Target is x86_64-unknown-linux-gnu , and I'm using the master branch of mimalloc, via the mimalloc-sys bindings, which are here: https://github.com/gnzlbg/mimallocator/tree/master/mimalloc-sys
I'm building mimalloc following the steps from this script: https://github.com/gnzlbg/mimallocator/blob/master/mimalloc-sys/build.rs
Setting MI_USE_CXX
to ON
and compiling with MSC (latest version in 16.1.5 / 2019.1) a number of instances of this error occur:
C:\Users\Sean\Documents\Projects\test\mimalloc-src\include\mimalloc-atomic.h(68): error C2665: '_InterlockedIncrement': none of the 4 overloads could convert all the argument types
C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\um\winbase.h(9283): note: could be 'unsigned __int64 _InterlockedIncrement(volatile unsigned __int64 *)'
C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\um\winbase.h(9271): note: or 'unsigned long _InterlockedIncrement(volatile unsigned long *)'
C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\um\winbase.h(9262): note: or 'unsigned int _InterlockedIncrement(volatile unsigned int *)'
C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\um\winnt.h(2954): note: or 'LONG _InterlockedIncrement(volatile LONG *)'
I haven't dug too deep, but looking in the Win10 SDK's copy of WinBase.h
I'm only seeing overloads for unsigned
types. This issue might then be more of an issue with the Win10 SDK and not actually the compiler, though I didn't get these errors when compiling with the C compiler.
There's also a few instances of:
C:\Users\Sean\Documents\Projects\test\mimalloc-src\src\alloc.c(114): error C2679: binary '=': no operator found which takes a right-hand operand of type 'volatile mi_thread_free_t' (or there is no acceptable conversion)
C:\Users\Sean\Documents\Projects\test\mimalloc-src\include\mimalloc-types.h(142): note: could be 'mi_thread_free_u &mi_thread_free_u::operator =(mi_thread_free_u &&)'
C:\Users\Sean\Documents\Projects\test\mimalloc-src\include\mimalloc-types.h(142): note: or 'mi_thread_free_u &mi_thread_free_u::operator =(const mi_thread_free_u &)'
C:\Users\Sean\Documents\Projects\test\mimalloc-src\src\alloc.c(114): note: while trying to match the argument list '(mi_thread_free_t, volatile mi_thread_free_t)'
All of these look like issues with (missing) volatile
reference overloads in mimalloc C++ wrappers, I think, though I haven't really looked into this one at all.
This is related to outstanding PR: #22
Ping @myd7349
I hit this issue last night as well, so I'm glad someone is already working on it, but I don't think that change is necessary or the best approach.
I believe the root cause here is that there's currently no way to choose between the SHARED
and the STATIC
builds. The CMakeLists.txt
currently builds both no matter what which causes a problem in this case. It's also generally undesirable in a lot of other cases. The suggestion is simply to add the choice of SHARED
vs STATIC
vs BOTH
for the consumer via a CMake
option(s), and raise the CMake error when compiler is MSVC
, OVERRIDE
is ON
, and MI_BUILD_STATIC
is ON
.
It's a pretty common convention to use options to expose the shared/static choice to consumers:
https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html
Note: Libraries such as this should not use the BUILD_SHARED_LIBS
global value, but instead should use their own specific option name such as MI_BUILD_SHARED
and/or MI_BUILD_STATIC
. There are a few ways to model that, depending on whether or not BUILD_BOTH
is really a valid and necessary scenario.
Regarding PR #22
It is intended to workaround this issue via conditionally forcing of CMake options, which is generally confusing to consumers who explicitly request OVERRIDE ON
and get something built with OVERRIDE OFF
. For this reason, it's considered by many to be an anti-pattern. Instead, it's usually preferable to explicitly raise an error in the build system for invalid configurations. The pre-processor error below is currently doing that job successfully:
Line 12 in 9122269
However, this pre-processor approach has the disadvantage of being declared far away from where options are declared and used in CMakeLists.txt
, which makes it impossible to see that it is part of a build-level invariant when looking at the CMakeLists.txt
. There are comments in various parts of documentation, but the suggestion to declare the invariant in CMakeLists.txt
has obvious advantages.
Regarding Visual Studio Solution versus CMake:
The current situation is that VS Solution
intends to be the supported/promoted way to build on Windows, so nobody probably encountered this issue while testing for Windows. However, we don't want to use the VS Solution
, we want to build with CMake
on all platforms, and we are planning on submitting future PR's to make the CMake
output equivalent to the VS Solution
on Windows eventually.
While #85 makes this somewhat moot for me right now, it appears that overriding operator new
in C++ on Windows is incomplete in mimalloc.
There's an #if 0
around the code in alloc-override-win.c
that appears to be necessary to patch the operators. It's not documented why that's there.
Further, not all modern overloads of new
are patched as of C++17. For example, there does not appear to be any patching for the std::align_val_t
overloads, despite the mimalloc documentation.
The cmake install script should install the shared library to libmimalloc.so.<ABI version>
and point a symlink to libmimalloc.so
, instead it just installs to the latter. It should also add execution bit to it (chmod 755 instead of 644).
References 5 and 6 are affected.
Is there any plans to have a way to walk all per thread default heaps? There seems that all stats and walk functions work either in the current thread heap or on a passed on heap and no way to access all heaps.
Enabling -DMI_DEBUG=3
produces output even when no errors are encountered. The library should only print when there is something to print.
The callback mi_block_visit_fun
is missing a calling convention specification (e.g. __cdecl
or the like), which can cause linkage problems when mixing a mimalloc
library compiled with one ABI but linked into a target that uses a different default ABI (e.g. using the /Gv
switch that can be common in performance-oriented codebases).
Its standard practice in Windows code to always tag a calling convention on callback function declarations to avoid this issue. Windows headers use the CALLBACK
macro for this purpose though specifying a new macro for mimalloc's purpose would suffice too so the code remains portable.
The idea is that this function can be declared in mimalloc.h
using this specifier and then any user code that is defining a callback for mi_heap_visit_blocks
would use the same specifier macro for the callback declaration, guaranteeing compatibility even if the default calling conventions differ.
Overrides for C++ operator new
and operator delete
taking std::nothrow_t
arguments are missing.
Why you write #pragma once
in these header files?
I think we can eliminate it because first it works only on Windows and second there is no reason to use it because we already have header guards:
#ifndef __MIMALLOC_X_H
#define __MIMALLOC_X_H
On Arch Linux, ARM 32 bit:
$ cmake ../../
-- The C compiler identification is GNU 8.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- No build type selected, default to *** Release ***
-- Override standard malloc (OVERRIDE=ON)
-- Output library name : mimalloc
-- Installation directory: lib/mimalloc-1.0
-- Configuring done
-- Generating done
-- Build files have been written to: /home/jrh/Projects/mimalloc/out/release
$ make
Scanning dependencies of target mimalloc-static
[ 4%] Building C object CMakeFiles/mimalloc-static.dir/src/stats.c.o
In file included from /home/jrh/Projects/mimalloc/src/stats.c:8:
/home/jrh/Projects/mimalloc/include/mimalloc-internal.h: In function ‘_mi_thread_id’:
/home/jrh/Projects/mimalloc/include/mimalloc-internal.h:312:22: error: ‘_mi_backing_heap’ undeclared (first use in this function); did you mean ‘_mi_bin_size’?
return (uintptr_t)&_mi_backing_heap;
^~~~~~~~~~~~~~~~
_mi_bin_size
/home/jrh/Projects/mimalloc/include/mimalloc-internal.h:312:22: note: each undeclared identifier is reported only once for each function it appears in
make[2]: *** [CMakeFiles/mimalloc-static.dir/build.make:63: CMakeFiles/mimalloc-static.dir/src/stats.c.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:73: CMakeFiles/mimalloc-static.dir/all] Error 2
make: *** [Makefile:130: all] Error 2
After instinctively running make test
, I discovered that the main cmake targets don't include tests.
The tests in ./test
are rather ... sparse.
Seems like this might be an good thing to work on in the future. ;)
I would like to know the situation regarding the rights to use the mimalloc logo.
I would like to use it personally for my wrapper that I am creating to allow the use of mimalloc in the programming language D
In _mi_realloc_zero() and _mi_heap_malloc_zero() only the requested size and not the possibly larger allocated size is initialized to zero.
This may lead to uninitialized 'new' memory from the applications point of view in a following call to _mi_realloc_zero(), where the 'fits' test using mi_usable_size(p) and the memcpy(newp, p, ...) relies on a defined state of the previously allocated and not only the previously requested memory range.
Also take into account, that using mi_rezalloc() on a pointer from a call to mi_malloc() is legal but would lead to uninitialized memory in the range from the requested size to the allocated size too. It seems to me that the rezalloc feature requires to store the requested size or at least to zero out the implicit allocated range form requested size to allocated size in all allocations.
I wonder if this is why posix doesn't specify rezalloc().
On my windows machine this code sample can reproduce the problem:
int main()
{
// mi_rezalloc() is not safe!
// test precondition: first allocation on page!
// force allocating the last block in the page next, so it will be 'recycled' immediately...
for (int idx = 0; idx < 127; ++idx)
::mi_free(::mi_malloc(128));
// force known state of 'uninitialized' memory (by mi_malloc debug initialization or explicit memset)
auto uninitialized = static_cast< unsigned char* >(::mi_malloc(128));
assert(mi_usable_size(uninitialized) == 128);
::memset(uninitialized, 0xD0, 128);
::mi_free(uninitialized);
// this initialized allocation recycles the uninitialized pointer (if not, adapt forcing loop above or use a different size class...)
auto initialized = static_cast< unsigned char* >(::mi_rezalloc(nullptr, 121));
assert(mi_usable_size(initialized) == 128);
assert(uninitialized == initialized);
assert(initialized[ 0] == 0); // access in requested range; mimalloc has initialized this!
assert(initialized[120] == 0); // access in requested range; mimalloc has initialized this!
assert(initialized[121] == 0xd0); // access in verified usable range; mimalloc has not initialized this!
initialized[ 0] = 'A';
initialized[120] = 'Z';
// grow with initialization! remember what the api documentation says:
// > If the newsize is larger than the original allocated size of p, the extra bytes are initialized to zero.
initialized = static_cast< unsigned char* >(::mi_rezalloc(initialized, 122));
assert(mi_usable_size(initialized) == 128);
assert(uninitialized == initialized);
assert(initialized[ 0] == 'A'); // access in requested old range; mimalloc has not re-initialized this!
assert(initialized[120] == 'Z'); // access in requested old range; mimalloc has not re-initialized this!
assert(initialized[121] == 0x00); // access in requested initialized new memory; mimalloc has not initialized this!
}
The problem does not occur on linux.
https://github.com/microsoft/mimalloc/blob/master/src/alloc.c#L212
(lldb) r
Process 93543 launched: './bin/arangodbtests' (x86_64)
mimalloc: option 'secure': 0
mimalloc: option 'pool_commit': 0
mimalloc: process init: 0x7fffc980c3c0
mimalloc: debug level : 1
mimalloc: option 'show_errors': 1
mimalloc: error: trying to mi_free a pointer that does not point to a valid heap space: 0x111040000
mimalloc: assertion failed: at "/Users/jenkins/arangodb/3rdParty/mimalloc/src/options.c":121, _mi_error_message
assertion: "false"
Process 93543 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
frame #0: 0x00007fffc0a21d42 libsystem_kernel.dylib`__pthread_kill + 10
libsystem_kernel.dylib`__pthread_kill:
-> 0x7fffc0a21d42 <+10>: jae 0x7fffc0a21d4c ; <+20>
0x7fffc0a21d44 <+12>: movq %rax, %rdi
0x7fffc0a21d47 <+15>: jmp 0x7fffc0a1acaf ; cerror_nocancel
0x7fffc0a21d4c <+20>: retq
Target 0: (arangodbtests) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
* frame #0: 0x00007fffc0a21d42 libsystem_kernel.dylib`__pthread_kill + 10
frame #1: 0x00007fffc0b0f457 libsystem_pthread.dylib`pthread_kill + 90
frame #2: 0x00007fffc0987420 libsystem_c.dylib`abort + 129
frame #3: 0x00000001055e339f arangodbtests`_mi_assert_fail(assertion="false", fname="/Users/jenkins/arangodb/3rdParty/mimalloc/src/options.c", line=121, func="_mi_error_message") at options.c:136
frame #4: 0x00000001055e3e24 arangodbtests`_mi_error_message(fmt="trying to mi_free a pointer that does not point to a valid heap space: %p\n") at options.c:121
frame #5: 0x00000001055dfa53 arangodbtests`mi_free(p=0x0000000111040000) at alloc.c:212
frame #6: 0x00000001055dfbc5 arangodbtests`_ZdlPv(p=0x0000000111040000) at alloc-override.c:90
frame #7: 0x0000000105573910 arangodbtests`testing::internal::MakeAndRegisterTestInfo(test_case_name="ActiveFailover", name="creating_a_job_should_create_a_job_in_todo", type_param=0x0000000000000000, value_param=0x0000000000000000, code_location=(file = "/Users/jenkins/arangodb/tests/Agency/ActiveFailoverTest.cpp", line = 113), fixture_class_id=0x0000000109537728, set_up_tc=(arangodbtests`testing::Test::SetUpTestCase() at gtest.h:20190), tear_down_tc=(arangodbtests`testing::Test::TearDownTestCase() at gtest.h:20198), factory=0x0000000111020000)(), void (*)(), testing::internal::TestFactoryBase*) at gtest-all.cc:4053
frame #8: 0x00000001000ae474 arangodbtests`::__cxx_global_var_init.29() at ActiveFailoverTest.cpp:113
frame #9: 0x00000001000aee64 arangodbtests`_GLOBAL__sub_I_ActiveFailoverTest.cpp at ActiveFailoverTest.cpp:0
frame #10: 0x000000010f80ca1b dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) + 385
frame #11: 0x000000010f80cc1e dyld`ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) + 40
frame #12: 0x000000010f8084aa dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 338
frame #13: 0x000000010f807524 dyld`ImageLoader::processInitializers(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 138
frame #14: 0x000000010f8075b9 dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) + 75
frame #15: 0x000000010f7f947a dyld`dyld::initializeMainExecutable() + 195
frame #16: 0x000000010f7fd8c6 dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) + 3966
frame #17: 0x000000010f7f8249 dyld`dyldbootstrap::start(macho_header const*, int, char const**, long, macho_header const*, unsigned long*) + 470
frame #18: 0x000000010f7f8036 dyld`_dyld_start + 54
(lldb)
In order to reproduce you could build the tests in this branch:
https://github.com/arangodb/arangodb/tree/feature/mimalloc
IIUC if I compile src/static.c
and statically link it to my binary, all calls to malloc
and similar APIs will be overriden by mimalloc
. Is this correct on all platforms ? (Windows, Linux, MacOSX, Android, FreeBSD, OpenBSD, NetBSD, etc.) ?
That is, it doesn't matter whether I define MI_OVERRIDE / MI_INTERSPERSE for this configuration ?
It would be worth it to document the CMake options somewhere, explaining specifically what they do, and how they interact with the different ways in which the library can be built.
At present, directory docs
contains the files generated by Doxygen, which are tracked in git repository. I just wonder whether it would better to eliminate them.
Hi, I tried mimalloc in ClickHouse and faced some (I hope so) interesting issues.
The slowdown against default jemalloc was big -- the query processing is approximately two times slower than usual.
I looked around and have some questions with examples of why something is happening.
First of all, everything is done under Linux x86-64.
The example
#include <memory>
int main() {
std::unique_ptr<int[]> a(new int[1ull << 30]);
return 0;
}
With standard allocator, I have only 1 mmap and 1 munmap which is pretty cool and expected because allocation is huge.
strace -fe mmap,munmap ./test
...
mmap(NULL, 4294971392, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5c63616000
munmap(0x7f5c63616000, 4294971392) = 0
With mimalloc, I have 6 mmaps and munmaps with rather big ones that are doubled.
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8f24999000
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8f24996000
munmap(0x7f8f24e71000, 193620) = 0
mmap(NULL, 4194304, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8f24596000
munmap(0x7f8f24596000, 4194304) = 0
mmap(NULL, 8388608, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8f24196000
munmap(0x7f8f24196000, 2531328) = 0
munmap(0x7f8f24800000, 1662976) = 0
mmap(NULL, 4294967504, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8e243ff000
munmap(0x7f8e243ff000, 4294967504) = 0
mmap(NULL, 4299161808, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8e23fff000
munmap(0x7f8e23fff000, 4096) = 0
munmap(0x7f8f24001000, 4186320) = 0
munmap(0x7f8e24000000, 4294967504) = 0
Then I read some code and saw the https://github.com/microsoft/mimalloc/blob/master/src/segment.c#L290 and https://github.com/microsoft/mimalloc/blob/master/src/os.c#L284 that wants 4mb alignment and it is highly unlikely for Linux to have such address after mmap syscall. So we do munmap once, then use the slow method to mmap once and munmap two times more because we don't want to store mmap useless regions https://github.com/microsoft/mimalloc/blob/master/src/os.c#L245. I am not sure this behavior is somehow optimal (at least with Linux we should not wait for 4mb alignment after mmap).
And is there any deallocated regions reuse? Because I tried such code below and saw a lot of mmap and munmap calls (for each construction and destruction many times).
#include <memory>
#include <thread>
#include <vector>
void Foo() {
for (size_t i = 0; i < 10000; ++i) {
std::unique_ptr<int[]> a(new int[1ull << 18]);
}
}
int main() {
std::vector<std::thread> thrs;
for (size_t i = 0; i < 10; ++i) {
thrs.emplace_back(Foo);
}
for (auto&& thr : thrs) {
thr.join();
}
return 0;
}
With jemalloc and default allocator such code works almost immediately
time ./test
./test 0.02s user 0.00s system 205% cpu 0.011 total
With mimalloc it is extremely slow
time LD_PRELOAD=mimalloc/build/libmimalloc.so ./test
LD_PRELOAD=mimalloc/build/libmimalloc.so ./test 0.42s user 4.62s system 164% cpu 3.055 total
And such usage of the allocator is common, for example, in server applications, when you accept the query, process it and then again accept the query, memory reuse can help to avoid syscall penalty.
So the question is -- what are the best practices of using mimalloc? :)
Is WebAssembly a target mimalloc may eventually support?
WebAssembly doesn't have mmap()
; only a single, linear memory segment that can grow. Allocating memory from the host must be done in a way similar to sbrk(2)
as in the good old days.
Is it something mimalloc
could do?
The CMakeLists.txt
currently unprefixed variables like SECURE
or OVERRIDE
. This can be messy and problematic when mimalloc is added to a project via add_subdirectory
. Library projects like this ideally should use prefixed variables, e.g. MIMALLOC_SECURE
rather than SECURE
, so that amalgamations of multiple third-party dependencies used in larger monolithic projects don't end up with name conflicts or messy configuration pages.
Is there any way right now to use a pre-allocated piece of memory for mimalloc? maybe just being able to create a heap with overriden mmap and munmap can be enough.
Thank you for making this library available! I'm enjoying playing around with it.
In Windows, the flags MEM_COMMIT and MEM_RESERVE are passed together to VirtualAlloc, yet the 'committed' heap stat does not equal 'reserved'. It seems like the library's intention is for those stats to have the equivalent API semantics of 'backed by physical' vs 'reserved virtual address space'.
The same bug appears to apply to the other platforms, though I'm not as familiar with mmap and could be wrong.
jemalloc provides smallocx
(e.g. see implementation here: https://github.com/jemalloc/jemalloc/blob/dev/src/jemalloc.c#L3015), which not only returns a pointer to the allocation, but also the size of the allocation size class (that is , the usable allocation size).
It would be nice if for all allocating and resizing operations a similar API could be provided, so that users that might want to use all usable space don't have to query the size class.
It appears that there's no option to turn on large page support on windows?
Searched the code base, VirtualAlloc was called without MEM_LARGE_PAGES.
Any future plan to support it? It was said to significantly reduce TLB misses and may lead to notable gains in memory intensive scenarios.
Passing a FILE* to mi_stats_print is very difficult from non console applications. je_malloc has a very simple interface to pass a function that receives a pointer to a buffer and that seems much better for all the cases were writing to a file is complicated. It could by default have a function that writes to stderr for simplicity.
AFAICT Azure Pipelines only checks that the library builds, but it does not run any tests.
Changes to the library should IMO be gated on all tests passing, and probably on checking that running the test suite of some multi-threaded allocation heavy program with a statically and dynamically linked mimalloc also passes.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.